Merge pull request #4780 from Crazylemon64/space_ruins

Crazypilot's Space Ruins Port
This commit is contained in:
Fox McCloud
2016-07-15 22:55:51 -04:00
committed by GitHub
108 changed files with 3107 additions and 569 deletions
+19 -14
View File
@@ -92,7 +92,7 @@
qdel(I)
/obj/effect/buildmode_line
var/image/I
var/image/I
var/client/cl
/obj/effect/buildmode_line/New(var/client/c, var/atom/atom_a, var/atom/atom_b, var/linename)
@@ -101,13 +101,13 @@
I = image('icons/misc/mark.dmi', src, "line", 19.0)
var/x_offset = ((atom_b.x * 32) + atom_b.pixel_x) - ((atom_a.x * 32) + atom_a.pixel_x)
var/y_offset = ((atom_b.y * 32) + atom_b.pixel_y) - ((atom_a.y * 32) + atom_a.pixel_y)
var/matrix/M = matrix()
M.Translate(0, 16)
M.Scale(1, sqrt((x_offset * x_offset) + (y_offset * y_offset)) / 32)
M.Turn(90 - Atan2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2.
M.Translate(atom_a.pixel_x, atom_a.pixel_y)
transform = M
cl = c
cl.images += I
@@ -242,6 +242,7 @@
if(FILL_BUILDMODE)
to_chat(user, "<span class='notice'>***********************************************************</span>")
to_chat(user, "<span class='notice'>Left Mouse Button on turf/obj/mob = Select corner</span>")
to_chat(user, "<span class='notice'>Left Mouse Button + Alt on turf/obj/mob = Delete region</span>")
to_chat(user, "<span class='notice'>Right Mouse Button on buildmode button = Select object type</span>")
to_chat(user, "<span class='notice'>***********************************************************</span>")
if(LINK_BUILDMODE)
@@ -509,16 +510,20 @@
cornerB = select_tile(get_turf(object))
if(left_click) //rectangular
if(cornerA && cornerB)
if(!objholder)
to_chat(user, "<span class='warning'>Select object type first.</span>")
if(alt_click)
empty_region(block(get_turf(cornerA),get_turf(cornerB)))
deselect_region()
else
for(var/turf/T in block(get_turf(cornerA),get_turf(cornerB)))
if(ispath(objholder,/turf))
T.ChangeTurf(objholder)
else
var/obj/A = new objholder(T)
A.dir = build_dir
deselect_region()
if(!objholder)
to_chat(user, "<span class='warning'>Select object type first.</span>")
else
for(var/turf/T in block(get_turf(cornerA),get_turf(cornerB)))
if(ispath(objholder,/turf))
T.ChangeTurf(objholder)
else
var/obj/A = new objholder(T)
A.dir = build_dir
deselect_region()
return
//Something wrong - Reset
@@ -567,13 +572,13 @@
if(P.id_tag && P.id_tag != 1 && alert(holder, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No")
goto(line_jump)
P.id_tag = M.id
line_jump // For the goto
valid_links = 0
for(var/obj/effect/buildmode_line/L in link_lines)
qdel(L)
link_lines -= L
if(istype(link_obj, /obj/machinery/door_control))
var/obj/machinery/door_control/M = link_obj
for(var/obj/machinery/door/airlock/P in range(M.range,M))
@@ -1,10 +1,9 @@
/client/proc/map_template_load()
set category = "Debug"
set name = "Map Template - Place"
set name = "Map template - Place"
if(!holder)
return
var/datum/map_template/template
var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in map_templates
@@ -16,22 +15,27 @@
if(!T)
return
if(!template.fits_in_map_bounds(T, centered = TRUE))
to_chat(usr, "Map is too large to fit in bounds. Map's dimensions: ([template.width], [template.height])")
return
var/list/preview = list()
for(var/S in template.get_affected_turfs(T,centered = TRUE))
preview += image('icons/turf/overlays.dmi',S,"greenOverlay")
usr.client.images += preview
if(alert(usr,"Confirm location.","Template Confirm","Yes","No") == "Yes")
template.load(T, centered = TRUE)
message_admins("[key_name_admin(usr)] has placed a map template ([template.name]) at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>(JMP)</A>")
var/timer = start_watch()
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has started to place the map template ([template.name]) at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>(JMP)</a></span>")
if(template.load(T, centered = TRUE))
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has placed a map template ([template.name]) at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>(JMP)</a>. Took [stop_watch(timer)]s.</span>")
else
to_chat(usr, "Failed to place map")
usr.client.images -= preview
/client/proc/map_template_upload()
set category = "Debug"
set name = "Map Template - Upload"
if(!holder)
return
var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
if(!map)
return
@@ -39,7 +43,12 @@
to_chat(usr, "Bad map file: [map]")
return
var/timer = start_watch()
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has begun uploading a map template ([map])</span>")
var/datum/map_template/M = new(map=map, rename="[map]")
M.preload_size(map)
map_templates[M.name] = M
message_admins("[key_name_admin(usr)] has uploaded a map template ([map])")
if(M.preload_size(map))
to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])")
map_templates[M.name] = M
message_admins("<span class='adminnotice'>[key_name_admin(usr)] has uploaded a map template ([map]). Took [stop_watch(timer)]s.</span>")
else
to_chat(usr, "Map template '[map]' failed to load properly")
+10
View File
@@ -7,6 +7,7 @@
/obj/effect/landmark/corpse
name = "Unknown"
var/mobname = "Unknown" //Unused now but it'd fuck up maps to remove it now
var/mob_species = null //Set to make a mob of another race, currently used only in ruins
var/corpseuniform = null //Set this to an object path to have the slot filled with said object on the corpse.
var/corpsesuit = null
var/corpseshoes = null
@@ -37,6 +38,8 @@
M.real_name = src.name
M.death(1) //Kills the new mob
M.timeofdeath = timeofdeath
if(src.mob_species)
M.set_species(src.mob_species)
if(src.corpseuniform)
M.equip_to_slot_or_del(new src.corpseuniform(M), slot_w_uniform)
if(src.corpsesuit)
@@ -285,3 +288,10 @@
corpseid = 1
corpseidjob = "Commander"
corpseidaccess = "Captain"
/obj/effect/landmark/corpse/abductor //Connected to ruins, for some reason?
name = "abductor"
mobname = "???"
mob_species = "abductor"
corpseuniform = /obj/item/clothing/under/color/grey
corpseshoes = /obj/item/clothing/shoes/combat
+22 -9
View File
@@ -9,30 +9,43 @@
var/template_name = null
var/datum/map_template/template = null
var/centered = 1
var/loaded = 0
/obj/effect/landmark/map_loader/New(loc, tname)
/obj/effect/landmark/map_loader/New(turf/loc, tname)
..()
if(tname)
template_name = tname
if(template_name)
template = map_templates[template_name]
/obj/effect/landmark/map_loader/initialize()
..()
if(template)
load(template)
/obj/effect/landmark/map_loader/set_tag()
return
/obj/effect/landmark/map_loader/proc/load(datum/map_template/t)
spawn(1)
if(!t)
return
t.load(get_turf(src), centered = centered)
t.loaded++
qdel(src)
if(!t)
return
if(loaded) // I wanna be super sure this loads only once
return
loaded = 1
var/turf/pos = get_turf(src)
// Hop to nullspace so we don't get re-initialized by the map we're loading
loc = null
t.load(pos, centered = centered)
t.loaded++
qdel(src)
/obj/effect/landmark/map_loader/random
var/template_list = ""
/obj/effect/landmark/map_loader/random/New()
/obj/effect/landmark/map_loader/random/initialize()
..()
if(template_list)
template_name = safepick(splittext(template_list, ";"))
template = map_templates[template_name]
load(template)
load(template)
+245 -125
View File
@@ -2,10 +2,22 @@
//SS13 Optimized Map loader
//////////////////////////////////////////////////////////////
//As of 3.6.2016
//global datum that will preload variables on atoms instanciation
var/global/use_preloader = FALSE
var/global/dmm_suite/preloader/_preloader = new
/dmm_suite
// These regexes are global - meaning that starting the maploader again mid-load will
// reset progress - which means we need to track our index per-map, or we'll
// eternally recurse
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
// /^[\s\n]+"?|"?[\s\n]+$|^"|"$/g
var/static/regex/trimQuotesRegex = new/regex({"^\[\\s\n]+"?|"?\[\\s\n]+$|^"|"$"}, "g")
// /^[\s\n]+|[\s\n]+$/
var/static/regex/trimRegex = new/regex("^\[\\s\n]+|\[\\s\n]+$", "g")
var/static/list/modelCache = list()
/**
* Construct the model map and control the loading process
@@ -16,87 +28,156 @@ var/global/dmm_suite/preloader/_preloader = new
* e.g aa = /turf/unsimulated/wall{icon_state = "rock"}
* 2) Read the map line by line, parsing the result (using parse_grid)
*
* If `measureOnly` is set, then no atoms will be created, and all this will do
* is return the bounds after parsing the file
*
* If you need to freeze init while you're working, you can use the spacial allocator's
* "add_dirt" and "remove_dirt" which will put initializations on hold until you say
* the word. This is important for loading large maps such as the cyberiad, where
* atmos will attempt to start before it's ready, causing runtimes galore if init is
* allowed to romp unchecked.
*/
/dmm_suite/load_map(dmm_file as file, x_offset = 0 as num, y_offset = 0 as num, z_offset as num, do_sleep = 1 as num)
if(!z_offset)//what z_level we are creating the map on
/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num)
var/tfile = dmm_file//the map file we're creating
var/fname = "Lambda"
if(isfile(tfile))
fname = "[tfile]"
tfile = file2text(tfile)
if(!x_offset)
x_offset = 1
if(!y_offset)
y_offset = 1
if(!z_offset)
z_offset = world.maxz + 1
var/quote = ascii2text(34)
var/tfile = file2text(dmm_file)//the map file we're creating
var/tfile_len = length(tfile)
var/lpos = 1 // the models definition index
///////////////////////////////////////////////////////////////////////////////////////
//first let's map model keys (e.g "aa") to their contents (e.g /turf/space{variables})
///////////////////////////////////////////////////////////////////////////////////////
var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
var/list/grid_models = list()
var/key_len = length(copytext(tfile,2,findtext(tfile,quote,2,0)))//the length of the model key (e.g "aa" or "aba")
var/key_len = 0
//proceed line by line
for(lpos=1; lpos<tfile_len; lpos=findtext(tfile,"\n",lpos,0)+1)
var/tline = copytext(tfile,lpos,findtext(tfile,"\n",lpos,0))
if(copytext(tline,1,2) != quote)//we reached the map "layout"
break
var/model_key = copytext(tline,2,2+key_len)
var/model_contents = copytext(tline,findtext(tfile,"=")+3,length(tline))
grid_models[model_key] = model_contents
if(do_sleep)
sleep(-1)
///////////////////////////////////////////////////////////////////////////////////////
//now let's fill the map with turf and objects using the constructed model map
///////////////////////////////////////////////////////////////////////////////////////
//position of the currently processed square
var/zcrd=-1
var/ycrd=y_offset
var/xcrd=x_offset
var/dmm_suite/loaded_map/LM = new
// This try-catch is used as a budget "Finally" clause, as the dirt count
// needs to be reset
var/watch = start_watch()
log_debug("[measureOnly ? "Measuring" : "Loading"] map: [fname]")
try
LM.index = 1
while(dmmRegex.Find(tfile, LM.index))
LM.index = dmmRegex.next
for(var/zpos=findtext(tfile,"\n(1,1,",lpos,0);zpos!=0;zpos=findtext(tfile,"\n(1,1,",zpos+1,0)) //in case there's several maps to load
// "aa" = (/type{vars=blah})
if(dmmRegex.group[1]) // Model
var/key = dmmRegex.group[1]
if(grid_models[key]) // Duplicate model keys are ignored in DMMs
continue
if(key_len != length(key))
if(!key_len)
key_len = length(key)
else
throw EXCEPTION("Inconsistant key length in DMM")
if(!measureOnly)
grid_models[key] = dmmRegex.group[2]
zcrd++
world.maxz = max(world.maxz, zcrd+z_offset)//create a new z_level if needed
// (1,1,1) = {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
else if(dmmRegex.group[3]) // Coords
if(!key_len)
throw EXCEPTION("Coords before model definition in DMM")
var/zgrid = copytext(tfile,findtext(tfile,quote+"\n",zpos,0)+2,findtext(tfile,"\n"+quote,zpos,0)+1) //copy the whole map grid
var/z_depth = length(zgrid)
var/xcrdStart = text2num(dmmRegex.group[3]) + x_offset - 1
//position of the currently processed square
var/xcrd
var/ycrd = text2num(dmmRegex.group[4]) + y_offset - 1
var/zcrd = text2num(dmmRegex.group[5]) + z_offset - 1
//if exceeding the world max x or y, increase it
var/x_depth = length(copytext(zgrid,1,findtext(zgrid,"\n",2,0)))
var/x_tilecount = x_depth/key_len
if(world.maxx<x_tilecount)
world.maxx=x_tilecount
if(!measureOnly)
if(zcrd > world.maxz)
if(cropMap)
continue
else
zlevels.increase_max_zlevel_to(zcrd) //create a new z_level if needed
var/y_depth = z_depth / (x_depth+1)//x_depth + 1 because we're counting the '\n' characters in z_depth
if(world.maxy<y_depth)
world.maxy=y_depth
bounds[MAP_MINX] = min(bounds[MAP_MINX], xcrdStart)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd)
//then proceed it line by line, starting from top
ycrd = y_depth
var/list/gridLines = splittext(dmmRegex.group[6], "\n")
for(var/gpos=1;gpos!=0;gpos=findtext(zgrid,"\n",gpos,0)+1)
var/grid_line = copytext(zgrid,gpos,findtext(zgrid,"\n",gpos,0))
var/leadingBlanks = 0
while(leadingBlanks < gridLines.len && gridLines[++leadingBlanks] == "")
if(leadingBlanks > 1)
gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines.
//fill the current square using the model map
xcrd=0
if(!gridLines.len) // Skip it if only blank lines exist.
continue
for(var/mpos in 1 to x_depth step key_len)
xcrd++
var/model_key = copytext(grid_line,mpos,mpos+key_len)
parse_grid(grid_models[model_key], xcrd + x_offset, ycrd + y_offset, zcrd + z_offset, do_sleep)
if(gridLines.len && gridLines[gridLines.len] == "")
gridLines.Cut(gridLines.len) // Remove only one blank line at the end.
//reached end of current map
if(gpos+x_depth+1>z_depth)
break
bounds[MAP_MINY] = min(bounds[MAP_MINY], ycrd)
ycrd += gridLines.len - 1 // Start at the top and work down
ycrd--
if(do_sleep)
sleep(-1)
if(!cropMap && ycrd > world.maxy)
if(!measureOnly)
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], ycrd)
else
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], min(ycrd, world.maxy))
//reached End Of File
if(findtext(tfile,quote+"}",zpos,0)+2==tfile_len)
break
if(do_sleep)
sleep(-1)
var/maxx = xcrdStart
if(measureOnly)
for(var/line in gridLines)
maxx = max(maxx, xcrdStart + length(line) / key_len - 1)
else
for(var/line in gridLines)
if(ycrd <= world.maxy && ycrd >= 1)
xcrd = xcrdStart
for(var/tpos = 1 to length(line) - key_len + 1 step key_len)
if(xcrd > world.maxx)
if(cropMap)
break
else
world.maxx = xcrd
if(xcrd >= 1)
var/model_key = copytext(line, tpos, tpos + key_len)
if(!grid_models[model_key])
throw EXCEPTION("Undefined model key in DMM: [model_key]. Map file: [fname].")
parse_grid(grid_models[model_key], xcrd, ycrd, zcrd, LM)
// After this call, it is NOT safe to reference `dmmRegex` without another call to
// "Find" - we might've hit a map loader here and changed its state
CHECK_TICK
maxx = max(maxx, xcrd)
++xcrd
--ycrd
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], cropMap ? min(maxx, world.maxx) : maxx)
CHECK_TICK
catch(var/exception/e)
_preloader.reset()
throw e
_preloader.reset()
log_debug("Loaded map in [stop_watch(watch)]s.")
qdel(LM)
if(bounds[MAP_MINX] == 1.#INF) // Shouldn't need to check every item
log_debug("Min x: bounds[MAP_MINX]")
log_debug("Min y: bounds[MAP_MINY]")
log_debug("Min z: bounds[MAP_MINZ]")
log_debug("Max x: bounds[MAP_MAXX]")
log_debug("Max y: bounds[MAP_MAXY]")
log_debug("Max z: bounds[MAP_MAXZ]")
return null
else
if(!measureOnly)
for(var/t in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
var/turf/T = t
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
T.AfterChange(1,keep_cabling = TRUE)
return bounds
/**
* Fill a given tile with its area/turf/objects/mobs
@@ -115,48 +196,60 @@ var/global/dmm_suite/preloader/_preloader = new
* 4) Instanciates the atom with its variables
*
*/
/dmm_suite/proc/parse_grid(model as text, xcrd as num, ycrd as num, zcrd as num, do_sleep = 1)
/dmm_suite/proc/parse_grid(model as text,xcrd as num,ycrd as num,zcrd as num, dmm_suite/loaded_map/LM)
/*Method parse_grid()
- Accepts a text string containing a comma separated list of type paths of the
same construction as those contained in a .dmm file, and instantiates them.
*/
var/list/members = list()//will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/explored)
var/list/members_attributes = list()//will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list())
var/list/members //will contain all members (paths) in model (in our example : /turf/unsimulated/wall and /area/mine/explored)
var/list/members_attributes //will contain lists filled with corresponding variables, if any (in our example : list(icon_state = "rock") and list())
var/list/cached = modelCache[model]
var/index
if(cached)
members = cached[1]
members_attributes = cached[2]
else
/////////////////////////////////////////////////////////
//Constructing members and corresponding variables lists
////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
//Constructing members and corresponding variables lists
////////////////////////////////////////////////////////
members = list()
members_attributes = list()
index = 1
var/index=1
var/old_position = 1
var/dpos
var/old_position = 1
var/dpos
do
//finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/explored)
dpos= find_next_delimiter_position(model,old_position,",","{","}")//find next delimiter (comma here) that's not within {...}
do
//finding next member (e.g /turf/unsimulated/wall{icon_state = "rock"} or /area/mine/explored)
dpos = find_next_delimiter_position(model, old_position, ",", "{", "}") //find next delimiter (comma here) that's not within {...}
var/full_def = copytext(model,old_position,dpos)//full definition, e.g : /obj/foo/bar{variables=derp}
var/atom_def = text2path(copytext(full_def,1,findtext(full_def,"{")))//path definition, e.g /obj/foo/bar
members.Add(atom_def)
old_position = dpos + 1
var/full_def = trim_text(copytext(model, old_position, dpos)) //full definition, e.g : /obj/foo/bar{variables=derp}
var/variables_start = findtext(full_def, "{")
var/atom_def = text2path(trim_text(copytext(full_def, 1, variables_start))) //path definition, e.g /obj/foo/bar
old_position = dpos + 1
//transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
var/list/fields = list()
if(!atom_def) // Skip the item if the path does not exist. Fix your crap, mappers!
continue
members.Add(atom_def)
var/variables_start = findtext(full_def,"{")
if(variables_start)//if there's any variable
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
fields = readlist(full_def, ";")
//transform the variables in text format into a list (e.g {var1="derp"; var2; var3=7} => list(var1="derp", var2, var3=7))
var/list/fields = list()
//then fill the members_attributes list with the corresponding variables
members_attributes.len++
members_attributes[index++] = fields
if(variables_start)//if there's any variable
full_def = copytext(full_def,variables_start+1,length(full_def))//removing the last '}'
fields = readlist(full_def, ";")
if(do_sleep)
sleep(-1)
while(dpos != 0)
//then fill the members_attributes list with the corresponding variables
members_attributes.len++
members_attributes[index++] = fields
CHECK_TICK
while(dpos != 0)
modelCache[model] = list(members, members_attributes)
////////////////
@@ -165,24 +258,25 @@ var/global/dmm_suite/preloader/_preloader = new
//The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
//in case of multiples turfs on one tile,
//will contains the images of all underlying turfs, to simulate the DMM multiple tiles piling
var/list/turfs_underlays = list()
//first instance the /area and remove it from the members list
index = members.len
var/turf/crds = locate(xcrd,ycrd,zcrd)
if(members[index] != /area/template_noop)
// We assume `members[index]` is an area path, as above, yes? I will operate
// on that assumption.
if(!ispath(members[index], /area))
throw EXCEPTION("Oh no, I thought this was an area!")
var/atom/instance
_preloader.setup(members_attributes[index])//preloader for assigning set variables on atom creation
instance = LM.area_path_to_real_area(members[index])
instance = locate(members[index])
var/turf/crds = locate(xcrd,ycrd,zcrd)
if(crds)
instance.contents.Add(crds)
if(use_preloader && instance)
_preloader.load(instance)
members.Remove(members[index])
//then instance the /turf and, if multiple tiles are presents, simulates the DMM underlays piling effect
@@ -198,18 +292,20 @@ var/global/dmm_suite/preloader/_preloader = new
if(T)
//if others /turf are presents, simulates the underlays piling effect
index = first_turf_index + 1
while(index <= members.len)
turfs_underlays.Insert(1,image(T.icon,null,T.icon_state,T.layer,T.dir))//add the current turf image to the underlays list
var/turf/UT = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)//instance new turf
add_underlying_turf(UT,T,turfs_underlays)//simulates the DMM piling effect
T = UT
while(index <= members.len - 1) // Last item is an /area
var/underlay
if(istype(T, /turf)) // I blame this on the stupid clown who coded the BYOND map editor
underlay = T.appearance
T = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)//instance new turf
if(ispath(members[index],/turf))
T.underlays += underlay
index++
//finally instance all remainings objects/mobs
for(index in 1 to first_turf_index - 1)
for(index in 1 to first_turf_index-1)
instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)
if(do_sleep)
sleep(-1)
CHECK_TICK
////////////////
//Helpers procs
@@ -222,7 +318,13 @@ var/global/dmm_suite/preloader/_preloader = new
var/turf/T = locate(x,y,z)
if(T)
instance = new path (T)//first preloader pass
if(ispath(path, /turf))
T.ChangeTurf(path, 1, 0)
instance = T
else if(ispath(path, /area))
else
instance = new path (T)//first preloader pass
if(use_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
_preloader.load(instance)
@@ -232,16 +334,11 @@ var/global/dmm_suite/preloader/_preloader = new
//text trimming (both directions) helper proc
//optionally removes quotes before and after the text (for variable name)
/dmm_suite/proc/trim_text(what as text,trim_quotes=0)
while(length(what) && (findtext(what," ",1,2)))
what=copytext(what,2,0)
while(length(what) && (findtext(what," ",length(what),0)))
what=copytext(what,1,length(what))
if(trim_quotes)
while(length(what) && (findtext(what,quote,1,2)))
what=copytext(what,2,0)
while(length(what) && (findtext(what,quote,length(what),0)))
what=copytext(what,1,length(what))
return what
return trimQuotesRegex.Replace(what, "")
else
return trimRegex.Replace(what, "")
//find the position of the next delimiter,skipping whatever is comprised between opening_escape and closing_escape
//returns 0 if reached the last delimiter
@@ -313,14 +410,6 @@ var/global/dmm_suite/preloader/_preloader = new
return to_return
//simulates the DM multiple turfs on one tile underlaying
/dmm_suite/proc/add_underlying_turf(turf/placed,turf/underturf, list/turfs_underlays)
if(underturf.density)
placed.density = 1
if(underturf.opacity)
placed.opacity = 1
placed.underlays += turfs_underlays
//atom creation method that preloads variables at creation
/atom/New()
if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -336,6 +425,7 @@ var/global/dmm_suite/preloader/_preloader = new
//Preloader datum
//////////////////
// This ain't re-entrant, but we had this before the maploader update
/dmm_suite/preloader
parent_type = /datum
var/list/attributes
@@ -349,11 +439,41 @@ var/global/dmm_suite/preloader/_preloader = new
/dmm_suite/preloader/proc/load(atom/what)
for(var/attribute in attributes)
what.vars[attribute] = attributes[attribute]
var/value = attributes[attribute]
if(islist(value))
value = deepCopyList(value)
what.vars[attribute] = value
use_preloader = FALSE
// If the map loader fails, make this safe
/dmm_suite/preloader/proc/reset()
use_preloader = FALSE
attributes = list()
target_path = null
// A datum for use within the context of loading a single map,
// so that one can have separate "unpowered" areas for ruins or whatever,
// yet have a single area type for use of mapping, instead of creating
// a new area type for each new ruin
/dmm_suite/loaded_map
parent_type = /datum
var/list/area_list = list()
var/index = 1 // To store the state of the regex
/dmm_suite/loaded_map/proc/area_path_to_real_area(area/A)
if(!ispath(A, /area))
throw EXCEPTION("Wrong argument to `area_path_to_real_area`")
if(!(A in area_list))
if(initial(A.there_can_be_many))
area_list[A] = new A
else
area_list[A] = locate(A)
return area_list[A]
/area/template_noop
name = "Area Passthrough"
/turf/template_noop
name = "Turf Passthrough"
name = "Turf Passthrough"
@@ -326,7 +326,7 @@ swapmap
x2+=x1-1
y2+=y1-1
z2+=z1-1
world.maxz=max(z2,world.maxz) // stretch z if necessary
zlevels.increase_max_zlevel_to(z2) // stretch z if necessary
if(!ischunk)
swapmaps_loaded[src]=null
swapmaps_byname[id]=src
@@ -373,7 +373,7 @@ swapmap
mz=max(mz,M.z2)
world.maxx=mx
world.maxy=my
world.maxz=mz
zlevels.cut_levels_downto(mz)
// save and delete
proc/Unload()
@@ -54,9 +54,8 @@
name = "space hotel pamphlet"
info = "<h3>Welcome to Deep Space Hotel 419!</h3>Thank you for choosing our hotel. Simply hand your credit or debit card to the concierge and get your room key! To check out, hand your credit card back.<small><h4>Conditions:</h4><ul><li>The hotel is not responsible for any losses due to time or space anomalies.<li>The hotel is not responsible for events that occur outside of the hotel station, including, but not limited to, events that occur inside of dimensional pockets.<li>The hotel is not responsible for overcharging your account.<li>The hotel is not responsible for missing persons.<li>The hotel is not responsible for mind-altering effects due to drugs, magic, demons, or space worms.</ul></small>"
/obj/effect/landmark/map_loader/hotel_room/New()
/obj/effect/landmark/map_loader/hotel_room/initialize()
..()
// load and randomly assign rooms
var/global/list/south_room_templates = list()
var/global/list/north_room_templates = list()
@@ -65,26 +64,27 @@
if(!loaded)
loaded = 1
for(var/map in flist(path))
var/datum/map_template/T = new(path = "[path][map]", rename = "[map]")
if(copytext(map, 1, 3) == "n_")
north_room_templates += T
else if(copytext(map, 1, 3) == "s_")
south_room_templates += T
else
// omnidirectional rooms are randomly assigned
if(prob(50))
if(cmptext(copytext(map, length(map) - 3), ".dmm"))
var/datum/map_template/T = new(path = "[path][map]", rename = "[map]")
if(copytext(map, 1, 3) == "n_")
north_room_templates += T
else
else if(copytext(map, 1, 3) == "s_")
south_room_templates += T
else
// omnidirectional rooms are randomly assigned
if(prob(50))
north_room_templates += T
else
south_room_templates += T
var/datum/map_template/M = safepick(dir == NORTH ? north_room_templates : south_room_templates)
if(M)
template = M
load(M)
if(dir == NORTH)
north_room_templates -= M
else
south_room_templates -= M
load(M)
// The door to a hotel room, but also metadata for the room itself
/obj/machinery/door/unpowered/hotel_door
@@ -305,4 +305,4 @@
S.retal_target = target
S.retal = 1
#undef CHECKOUT_TIME
#undef CHECKOUT_TIME
+166 -29
View File
@@ -1,14 +1,27 @@
var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away_mission_config.txt")
// Call this before you remove the last dirt on a z level - that way, all objects
// will have proper atmos and other important enviro things
/proc/late_setup_level(turfs, smoothTurfs)
var/total_timer = start_watch()
var/subtimer = start_watch()
if(!smoothTurfs)
smoothTurfs = turfs
log_debug("Setting up atmos")
if(air_master)
air_master.setup_allturfs(turfs)
log_debug("\tTook [stop_watch(subtimer)]s")
subtimer = start_watch()
log_debug("Initializing lighting")
for(var/turf/T in turfs)
if(T.dynamic_lighting)
T.lighting_build_overlays()
for(var/obj/structure/cable/PC in T)
makepowernet_for(PC)
log_debug("\tTook [stop_watch(subtimer)]s")
subtimer = start_watch()
log_debug("Smoothing tiles")
for(var/turf/T in smoothTurfs)
if(T.smooth)
smooth_icon(T)
@@ -16,20 +29,95 @@
var/atom/A = R
if(A.smooth)
smooth_icon(A)
if(istype(T, /turf/simulated/mineral)) // For the listening post, among other maps
var/turf/simulated/mineral/MT = T
MT.add_edges()
log_debug("\tTook [stop_watch(subtimer)]s")
log_debug("Late setup finished - took [stop_watch(total_timer)]s")
/proc/empty_rect(low_x,low_y, hi_x,hi_y, z)
var/timer = start_watch()
log_debug("Emptying region: ([low_x], [low_y]) to ([hi_x], [hi_y]) on z '[z]'")
empty_region(block(locate(low_x, low_y, z), locate(hi_x, hi_y, z)))
log_debug("Took [stop_watch(timer)]s")
/proc/empty_region(list/turfs)
for(var/thing in turfs)
var/turf/T = thing
for(var/otherthing in T)
qdel(otherthing)
T.ChangeTurf(/turf/space)
/proc/createRandomZlevel()
if(awaydestinations.len) //crude, but it saves another var!
return
var/list/potentialRandomZlevels = list()
log_startup_progress("Searching for away missions...")
var/list/Lines
if(fexists("config/away_mission_config.txt"))
Lines = file2list("config/away_mission_config.txt")
else
Lines = file2list("config/example/away_mission_config.txt")
if(potentialRandomZlevels && potentialRandomZlevels.len)
var/watch = start_watch()
log_startup_progress("Loading away mission...")
if(!Lines.len) return
var/map = pick(potentialRandomZlevels)
var/file = file(map)
if(isfile(file))
var/zlev = zlevels.add_new_zlevel()
zlevels.add_dirt(zlev)
maploader.load_map(file, z_offset = zlev)
late_setup_level(block(locate(1, 1, zlev), locate(world.maxx, world.maxy, zlev)))
zlevels.remove_dirt(zlev)
log_to_dd(" Away mission loaded: [map]")
//map_transition_config.Add(AWAY_MISSION_LIST)
for(var/obj/effect/landmark/L in landmarks_list)
if(L.name != "awaystart")
continue
awaydestinations.Add(L)
log_startup_progress(" Away mission loaded in [stop_watch(watch)]s.")
else
log_startup_progress(" No away missions found.")
return
/proc/createALLZlevels()
if(awaydestinations.len) //crude, but it saves another var!
return
if(potentialRandomZlevels && potentialRandomZlevels.len)
var/watch = start_watch()
log_startup_progress("Loading away missions...")
for(var/map in potentialRandomZlevels)
var/file = file(map)
if(isfile(file))
log_startup_progress("Loading away mission: [map]")
var/zlev = zlevels.add_new_zlevel()
zlevels.add_dirt(zlev)
maploader.load_map(file, z_offset = zlev)
late_setup_level(block(locate(1, 1, zlev), locate(world.maxx, world.maxy, zlev)))
zlevels.remove_dirt(zlev)
log_to_dd(" Away mission loaded: [map]")
//map_transition_config.Add(AWAY_MISSION_LIST)
for(var/obj/effect/landmark/L in landmarks_list)
if(L.name != "awaystart")
continue
awaydestinations.Add(L)
log_startup_progress(" Away mission loaded in [stop_watch(watch)]s.")
watch = start_watch()
else
log_startup_progress(" No away missions found.")
return
/proc/generateMapList(filename)
var/list/potentialMaps = list()
var/list/Lines = file2list(filename)
if(!Lines.len)
return
for(var/t in Lines)
if(!t)
continue
@@ -42,38 +130,87 @@
var/pos = findtext(t, " ")
var/name = null
// var/value = null
if(pos)
name = lowertext(copytext(t, 1, pos))
// value = copytext(t, pos + 1)
else
name = lowertext(t)
if(!name)
continue
potentialRandomZlevels.Add(t)
potentialMaps.Add(t)
return potentialMaps
if(potentialRandomZlevels.len)
var/watch = start_watch()
log_startup_progress("Loading away mission...")
/proc/seedRuins(z_level = 1, budget = 0, whitelist = /area/space, list/potentialRuins = space_ruins_templates)
var/overall_sanity = 100
var/ruins = potentialRuins.Copy()
var/initialbudget = budget
var/watch = start_watch()
var/map = pick(potentialRandomZlevels)
var/file = file(map)
if(isfile(file))
maploader.load_map(file, do_sleep = 0)
late_setup_level(block(locate(1, 1, world.maxz), locate(world.maxx, world.maxy, world.maxz)))
log_to_dd(" Away mission loaded: [map]")
log_startup_progress("Loading ruins...")
for(var/obj/effect/landmark/L in landmarks_list)
if(L.name != "awaystart")
while(budget > 0 && overall_sanity > 0)
// Pick a ruin
var/datum/map_template/ruin/ruin = ruins[pick(ruins)]
// Can we afford it
if(ruin.cost > budget)
overall_sanity--
continue
// If so, try to place it
var/sanity = 100
// And if we can't fit it anywhere, give up, try again
while(sanity > 0)
sanity--
var/turf/T = locate(rand(25, world.maxx - 25), rand(25, world.maxy - 25), z_level)
var/valid = 1
for(var/turf/check in ruin.get_affected_turfs(T,1))
var/area/new_area = get_area(check)
if(!(istype(new_area, whitelist)))
valid = 0
break
if(!valid)
continue
awaydestinations.Add(L)
log_startup_progress(" Away mission loaded in [stop_watch(watch)]s.")
log_to_dd(" Ruin \"[ruin.name]\" loaded in [stop_watch(watch)]s at ([T.x], [T.y], [T.z]).")
else
log_startup_progress(" No away missions found.")
return
var/obj/effect/ruin_loader/R = new /obj/effect/ruin_loader(T)
R.Load(ruins,ruin)
budget -= ruin.cost
if(!ruin.allow_duplicates)
ruins -= ruin.name
break
to_chat(world, "<span class='danger'> Loaded ruins. Or not.</span>") //So the players don't know if we loaded ruins, but we do have a message
if(initialbudget == budget) //Kill me
log_to_dd(" No ruins loaded.")
/obj/effect/ruin_loader
name = "random ruin"
desc = "If you got lucky enough to see this..."
icon = 'icons/obj/weapons.dmi'
icon_state = "syndballoon"
invisibility = 0
/obj/effect/ruin_loader/proc/Load(list/potentialRuins = space_ruins_templates, datum/map_template/template = null)
var/list/possible_ruins = list()
for(var/A in potentialRuins)
var/datum/map_template/T = potentialRuins[A]
if(!T.loaded)
possible_ruins += T
if(!template && possible_ruins.len)
template = safepick(possible_ruins)
if(!template)
return 0
template.load(get_turf(src),centered = 1)
template.loaded++
qdel(src)
return 1
+7 -2
View File
@@ -21,6 +21,9 @@
/obj/effect/levelref/New()
..()
levels += src
/obj/effect/levelref/initialize()
..()
for(var/obj/effect/levelref/O in levels)
if(id == O.id && O != src)
other = O
@@ -104,7 +107,7 @@
/turf/unsimulated/floor/upperlevel/New()
..()
var/obj/effect/levelref/R = locate() in get_area(src)
if(R)
if(R && R.other)
init(R)
/turf/unsimulated/floor/upperlevel/Destroy()
@@ -159,6 +162,8 @@
..()
portals += src
/obj/effect/view_portal/initialize()
..()
if(id)
for(var/obj/effect/view_portal/O in portals)
if(id == O.id && O != src && can_link(O))
@@ -361,4 +366,4 @@
screen_loc = "CENTER[ox >= 0 ? "+" : ""][ox],CENTER[oy >= 0 ? "+" : ""][oy]"
/obj/effect/view_portal_dummy/attack_ghost(mob/user)
owner.attack_ghost(user)
owner.attack_ghost(user)
+1
View File
@@ -26,6 +26,7 @@
/obj/item/weapon/storage/bible)
/obj/structure/bookcase/initialize()
..()
for(var/obj/item/I in loc)
if(is_type_in_list(I, valid_types))
I.forceMove(src)
+2 -1
View File
@@ -9,6 +9,7 @@
invisibility = INVISIBILITY_LIGHTING
color = "#000000"
icon_state = "light1"
auto_init = 0 // doesn't need special init
var/lum_r
var/lum_g
@@ -104,4 +105,4 @@
if(istype(T))
T.lighting_overlay = null
return ..()
return ..()
@@ -8,6 +8,7 @@
var/on=0
/obj/machinery/media/receiver/boombox/initialize()
..()
if(on)
update_on()
update_icon()
@@ -80,4 +81,4 @@
if(on)
icon_state="wallradio-p"
else
icon_state="wallradio"
icon_state="wallradio"
@@ -19,6 +19,7 @@
var/const/MAX_TEMP=70 // Celsius
/obj/machinery/media/transmitter/broadcast/initialize()
..()
testing("[type]/initialize() called!")
if(autolink && autolink.len)
for(var/obj/machinery/media/source in orange(20, src))
@@ -303,7 +303,7 @@
/mob/living/silicon/robot/drone/Bump(atom/movable/AM as mob|obj, yes)
if (!yes || ( \
if(!yes || ( \
!istype(AM,/obj/machinery/door) && \
!istype(AM,/obj/machinery/recharge_station) && \
!istype(AM,/obj/machinery/disposal/deliveryChute) && \
@@ -135,6 +135,7 @@
var/alerted = 0
var/ore_eaten = 1
var/chase_time = 100
var/will_burrow = 1
/mob/living/simple_animal/hostile/asteroid/goldgrub/New()
..()
@@ -170,7 +171,7 @@
visible_message("<span class='notice'>The ore was swallowed whole!</span>")
/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time
if(!alerted)
if(!alerted && will_burrow)
alerted = 1
spawn(chase_time)
if(alerted)
+22 -7
View File
@@ -99,11 +99,22 @@
var/global/list/status_overlays_lighting
var/global/list/status_overlays_environ
var/indestructible = 0 // If set, prevents aliens from destroying it
var/keep_preset_name = 0
var/report_power_alarm = 1
var/shock_proof = 0 //if set to 1, this APC will not arc bolts of electricity if it's overloaded.
/obj/machinery/power/apc/worn_out
name = "\improper Worn out APC"
keep_preset_name = 1
locked = 0
environ = 0
equipment = 0
lighting = 0
operating = 0
/obj/machinery/power/apc/noalarm
report_power_alarm = 0
@@ -192,15 +203,19 @@
cell.maxcharge = cell_type // cell_type is maximum charge (old default was 1000 or 2500 (values one and two respectively)
cell.charge = start_charge * cell.maxcharge / 100.0 // (convert percentage to actual value)
var/area/A = src.loc.loc
var/area/A = get_area(src)
//if area isn't specified use current
if(isarea(A) && src.areastring == null)
src.area = A
if(keep_preset_name)
if(isarea(A))
area = A
// no-op, keep the name
else if(isarea(A) && src.areastring == null)
area = A
name = "\improper [area.name] APC"
else
src.area = get_area_name(areastring)
area = get_area_name(areastring)
name = "\improper [area.name] APC"
area.apc |= src
update_icon()
@@ -623,7 +638,7 @@
else
if(istype(user, /mob/living/silicon))
return src.attack_hand(user)
if (!opened && wiresexposed && \
if(!opened && wiresexposed && \
(istype(W, /obj/item/device/multitool) || \
istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/assembly/signaler)))
return src.attack_hand(user)
@@ -853,7 +868,7 @@
if(istype(user, /mob/living/silicon))
var/mob/living/silicon/ai/AI = user
var/mob/living/silicon/robot/robot = user
if ( \
if( \
src.aidisabled || \
malfhack && istype(malfai) && \
( \
@@ -1382,4 +1397,4 @@
else
return 0
#undef APC_UPDATE_ICON_COOLDOWN
#undef APC_UPDATE_ICON_COOLDOWN
+4 -3
View File
@@ -82,6 +82,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
//
/obj/machinery/gravity_generator/main/station/initialize()
..()
setup_parts()
middle.overlays += "activated"
update_list()
@@ -215,17 +216,17 @@ var/const/GRAV_NEEDS_WRENCH = 3
/obj/machinery/gravity_generator/main/attack_hand(mob/user as mob)
if(!..())
return interact(user)
/obj/machinery/gravity_generator/main/attack_ai(mob/user as mob)
return 1
/obj/machinery/gravity_generator/main/attack_ghost(mob/user as mob)
return interact(user)
/obj/machinery/gravity_generator/main/interact(mob/user as mob)
if(stat & BROKEN)
return
var/dat = "Gravity Generator Breaker: "
if(breaker)
dat += "<span class='linkOn'>ON</span> <A href='?src=\ref[src];gentoggle=1'>OFF</A>"
+2 -1
View File
@@ -138,6 +138,7 @@
var/redeem_immediately = 0 // redeem immediately for holding cell
/obj/machinery/treadmill_monitor/initialize()
..()
if(id)
for(var/obj/machinery/power/treadmill/T in machines)
if(T.id == id)
@@ -222,4 +223,4 @@
#undef FONT_SIZE
#undef FONT_COLOR
#undef FONT_STYLE
#undef CHARS_PER_LINE
#undef CHARS_PER_LINE
@@ -146,7 +146,7 @@
return
else
return 1
if ( \
if( \
!isturf(src.loc) || \
!(locate(/obj/structure/table) in src.loc) && \
!(locate(/obj/machinery/optable) in src.loc) && \
@@ -712,6 +712,18 @@
reagents.add_reagent("toxin", 3)
bitesize = 3
/obj/item/weapon/reagent_containers/food/snacks/lizardmeat
name = "mutant lizard meat"
desc = "Seems to be a slab of meat from some mutant lizard thing?"
icon_state = "xenomeat"
filling_color = "#43DE18"
New()
..()
reagents.add_reagent("protein", 3)
reagents.add_reagent("toxin", 3)
bitesize = 3
/obj/item/weapon/reagent_containers/food/snacks/spiderleg
name = "spider leg"
desc = "A still twitching leg of a giant spider... you don't really want to eat this, do you?"
+49
View File
@@ -0,0 +1,49 @@
//Parent types
/area/ruin/
name = "\improper Unexplored Location"
icon_state = "away"
has_gravity = 1
there_can_be_many = 1
/area/ruin/unpowered
always_unpowered = 0
/area/ruin/unpowered/no_grav
has_gravity = 0
/area/ruin/powered
requires_power = 0
//Areas
/area/ruin/unpowered/no_grav/way_home
name = "\improper Salvation"
icon_state = "away"
/area/ruin/powered/snow_biodome
/area/ruin/powered/golem_ship
name = "Free Golem Ship"
// Ruins of "onehalf" ship
/area/ruin/onehalf/hallway
name = "Hallway"
icon_state = "hallC"
/area/ruin/onehalf/drone_bay
name = "Mining Drone Bay"
icon_state = "engine"
/area/ruin/onehalf/dorms_med
name = "Crew Quarters"
icon_state = "Sleep"
/area/ruin/onehalf/bridge
name = "Bridge"
icon_state = "bridge"
+2 -2
View File
@@ -843,7 +843,7 @@
name = "\improper Airtight plastic flaps"
desc = "Heavy duty, airtight, plastic flaps."
/obj/structure/plasticflaps/mining/New()
/obj/structure/plasticflaps/mining/initialize()
air_update_turf(1)
..()
@@ -857,4 +857,4 @@
#undef ORDER_SCREEN_WIDTH
#undef ORDER_SCREEN_HEIGHT
#undef SUPPLY_SCREEN_WIDTH
#undef SUPPLY_SCREEN_HEIGHT
#undef SUPPLY_SCREEN_HEIGHT
+73
View File
@@ -0,0 +1,73 @@
/datum/zlevel
var/flags = 0
var/dirt_count = 0
var/zpos
var/list/init_list = list()
/datum/zlevel/New(z)
zpos = z
/datum/zlevel/proc/resume_init()
if(dirt_count > 0)
throw EXCEPTION("Init told to resume when z-level still dirty. Z level: '[zpos]'")
log_debug("Releasing freeze on z-level '[zpos]'!")
log_debug("Beginning initialization!")
var/list/our_atoms = init_list // OURS NOW!!! (Keeping this list to ourselves will prevent hijack)
init_list = list()
var/list/late_maps = list()
var/list/pipes = list()
var/list/cables = list()
var/watch = start_watch()
for(var/schmoo in our_atoms)
var/atom/movable/AM = schmoo
if(AM) // to catch stuff like the nuke disk that no longer exists
// This can mess with our state - we leave these for last
if(istype(AM, /obj/effect/landmark/map_loader))
late_maps.Add(AM)
continue
AM.initialize()
if(istype(AM, /obj/machinery/atmospherics))
pipes.Add(AM)
else if(istype(AM, /obj/structure/cable))
cables.Add(AM)
log_debug("Primary initialization finished in [stop_watch(watch)]s.")
our_atoms.Cut()
if(pipes.len)
do_pipes(pipes)
if(cables.len)
do_cables(cables)
if(late_maps.len)
do_late_maps(late_maps)
/datum/zlevel/proc/do_pipes(list/pipes)
var/watch = start_watch()
log_debug("Building pipenets on z-level '[zpos]'!")
for(var/schmoo in pipes)
var/obj/machinery/atmospherics/machine = schmoo
if(machine)
machine.build_network()
pipes.Cut()
log_debug("Took [stop_watch(watch)]s")
/datum/zlevel/proc/do_cables(list/cables)
var/watch = start_watch()
log_debug("Building powernets on z-level '[zpos]'!")
for(var/schmoo in cables)
var/obj/structure/cable/C = schmoo
if(C)
makepowernet_for(C)
cables.Cut()
log_debug("Took [stop_watch(watch)]s")
/datum/zlevel/proc/do_late_maps(list/late_maps)
var/watch = start_watch()
log_debug("Loading map templates on z-level '[zpos]'!")
zlevels.add_dirt(zpos) // Let's not repeatedly resume init for each template
for(var/schmoo in late_maps)
var/obj/effect/landmark/map_loader/ML = schmoo
if(ML)
ML.initialize()
late_maps.Cut()
zlevels.remove_dirt(zpos)
log_debug("Took [stop_watch(watch)]s")
@@ -0,0 +1,89 @@
var/global/datum/zlev_manager/zlevels = new
/datum/zlev_manager
// A list of z-levels
var/list/z_list = list()
// Populate our z level list
/datum/zlev_manager/proc/initialize()
z_list.len = world.maxz
for(var/i = 1, i <= world.maxz, i++)
z_list[i] = new /datum/zlevel(i)
/datum/zlev_manager/proc/get_zlev(z)
if(z < 1)
throw EXCEPTION("Non-positive z level given!")
else if(z > z_list.len)
throw EXCEPTION("Untracked z level: '[z]'")
else
return z_list[z]
// For when you need the z-level to be at a certain point
/datum/zlev_manager/proc/increase_max_zlevel_to(new_maxz)
if(world.maxz>=new_maxz)
return
while(world.maxz<new_maxz)
add_new_zlevel()
// Increments the max z-level by one
// For convenience's sake returns the z-level added
/datum/zlev_manager/proc/add_new_zlevel()
world.maxz++
var/our_z = world.maxz
z_list.len++
z_list[our_z] = new /datum/zlevel(our_z)
return our_z
/datum/zlev_manager/proc/cut_levels_downto(new_maxz)
if(world.maxz <= new_maxz)
return
while(world.maxz>new_maxz)
kill_topmost_zlevel()
// Decrements the max z-level by one
// not normally used, but hey the swapmap loader wanted it
/datum/zlev_manager/proc/kill_topmost_zlevel()
var/our_z = world.maxz
qdel(z_list[our_z])
z_list.len--
world.maxz--
/*
* "Dirt" management
* "Dirt" is used to keep track of whether a z level should automatically have
* stuff on it initialize or not - the map loaders, when set to defer init, place
* a freeze on the z levels they touch so as to prevent atmos from exploding,
* among other things
*/
// Returns whether the given z level has a freeze on initialization
/datum/zlev_manager/proc/is_zlevel_dirty(z)
var/datum/zlevel/our_z = get_zlev(z)
return (our_z.dirt_count > 0)
// Increases the dirt count on a z level
/datum/zlev_manager/proc/add_dirt(z)
var/datum/zlevel/our_z = get_zlev(z)
if(our_z.dirt_count == 0)
log_debug("Placing an init freeze on z-level '[our_z.zpos]'!")
our_z.dirt_count++
// Decreases the dirt count on a z level
/datum/zlev_manager/proc/remove_dirt(z)
var/datum/zlevel/our_z = get_zlev(z)
our_z.dirt_count--
if(our_z.dirt_count == 0)
our_z.resume_init()
if(our_z.dirt_count < 0)
log_debug("WARNING: Imbalanced dirt removal")
our_z.dirt_count = 0
/datum/zlev_manager/proc/postpone_init(z, thing)
var/datum/zlevel/our_z = get_zlev(z)
our_z.init_list.Add(thing)