// This is a list of turf types we dont want to assign to baseturfs unless through initialization or explicitly GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( /turf/open/space, /turf/baseturf_bottom ))) /turf/proc/empty(turf_type=/turf/open/space, baseturf_type, list/ignore_typecache, flags) // Remove all atoms except observers, landmarks, docking ports var/static/list/ignored_atoms = typecacheof(list(/mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object)) var/list/allowed_contents = typecache_filter_list_reverse(GetAllContentsIgnoring(ignore_typecache), ignored_atoms) allowed_contents -= src for(var/i in 1 to allowed_contents.len) var/thing = allowed_contents[i] qdel(thing, force=TRUE) if(turf_type) var/turf/newT = ChangeTurf(turf_type, baseturf_type, flags) newT.ImmediateCalculateAdjacentTurfs() /turf/proc/copyTurf(turf/T) if(T.type != type) var/obj/O if(underlays.len) //we have underlays, which implies some sort of transparency, so we want to a snapshot of the previous turf as an underlay O = new() O.underlays.Add(T) T.ChangeTurf(type) if(underlays.len) T.underlays = O.underlays if(T.icon_state != icon_state) T.icon_state = icon_state if(T.icon != icon) T.icon = icon if(color) T.atom_colours = atom_colours.Copy() T.update_atom_colour() if(T.dir != dir) T.setDir(dir) return T /turf/open/copyTurf(turf/T, copy_air = FALSE) . = ..() if (isopenturf(T)) var/datum/component/wet_floor/slip = GetComponent(/datum/component/wet_floor) if(slip) var/datum/component/wet_floor/WF = T.AddComponent(/datum/component/wet_floor) WF.InheritComponent(slip) if (copy_air) var/turf/open/openTurf = T openTurf.air.copy_from(air) //wrapper for ChangeTurf()s that you want to prevent/affect without overriding ChangeTurf() itself /turf/proc/TerraformTurf(path, new_baseturf, flags) return ChangeTurf(path, new_baseturf, flags) /turf/proc/get_z_base_turf() . = SSmapping.level_trait(z, ZTRAIT_BASETURF) || /turf/open/space if (!ispath(.)) . = text2path(.) if (!ispath(.)) warning("Z-level [z] has invalid baseturf '[SSmapping.level_trait(z, ZTRAIT_BASETURF)]'") . = /turf/open/space // Creates a new turf // new_baseturfs can be either a single type or list of types, formated the same as baseturfs. see turf.dm /turf/proc/ChangeTurf(path, list/new_baseturfs, flags) switch(path) if(null) return if(/turf/baseturf_bottom) path = get_z_base_turf() if(/turf/open/space/basic) // basic doesn't initialize and this will cause issues // no warning though because this can happen naturaly as a result of it being built on top of path = /turf/open/space if(!GLOB.use_preloader && path == type && !(flags & CHANGETURF_FORCEOP) && (baseturfs == new_baseturfs)) // Don't no-op if the map loader requires it to be reconstructed, or if this is a new set of baseturfs return src if(flags & CHANGETURF_SKIP) return new path(src) var/old_opacity = opacity var/old_dynamic_lighting = dynamic_lighting var/old_affecting_lights = affecting_lights var/old_lighting_object = lighting_object var/old_lc_topright = lc_topright var/old_lc_topleft = lc_topleft var/old_lc_bottomright = lc_bottomright var/old_lc_bottomleft = lc_bottomleft var/old_exl = explosion_level var/old_exi = explosion_id var/old_bp = blueprint_data blueprint_data = null var/list/old_baseturfs = baseturfs var/list/transferring_comps = list() SEND_SIGNAL(src, COMSIG_TURF_CHANGE, path, new_baseturfs, flags, transferring_comps) for(var/i in transferring_comps) var/datum/component/comp = i comp.RemoveComponent() changing_turf = TRUE qdel(src) //Just get the side effects and call Destroy var/turf/W = new path(src) for(var/i in transferring_comps) W.TakeComponent(i) if(new_baseturfs) W.baseturfs = new_baseturfs else W.baseturfs = old_baseturfs W.explosion_id = old_exi W.explosion_level = old_exl if(!(flags & CHANGETURF_DEFER_CHANGE)) W.AfterChange(flags) W.blueprint_data = old_bp if(SSlighting.initialized) recalc_atom_opacity() lighting_object = old_lighting_object affecting_lights = old_affecting_lights lc_topright = old_lc_topright lc_topleft = old_lc_topleft lc_bottomright = old_lc_bottomright lc_bottomleft = old_lc_bottomleft if (old_opacity != opacity || dynamic_lighting != old_dynamic_lighting) reconsider_lights() if (dynamic_lighting != old_dynamic_lighting) if (IS_DYNAMIC_LIGHTING(src)) lighting_build_overlay() else lighting_clear_overlay() for(var/turf/open/space/S in RANGE_TURFS(1, src)) //RANGE_TURFS is in code\__HELPERS\game.dm S.update_starlight() return W /turf/open/ChangeTurf(path, list/new_baseturfs, flags) //don't if(!SSair.initialized) return ..() if ((flags & CHANGETURF_INHERIT_AIR) && ispath(path, /turf/open)) var/datum/gas_mixture/stashed_air = new() stashed_air.copy_from(air) . = ..() if (!.) // changeturf failed or didn't do anything QDEL_NULL(stashed_air) return var/turf/open/newTurf = . newTurf.air.copy_from(stashed_air) newTurf.update_air_ref(planetary_atmos ? 1 : 2) QDEL_NULL(stashed_air) else flags |= CHANGETURF_RECALC_ADJACENT if(ispath(path,/turf/closed)) . = ..() var/turf/open/newTurf = . newTurf.update_air_ref(-1) else . = ..() var/turf/open/newTurf = . newTurf.Initalize_Atmos(0) // Take off the top layer turf and replace it with the next baseturf down /turf/proc/ScrapeAway(amount=1, flags) if(!amount) return if(length(baseturfs)) var/list/new_baseturfs = baseturfs.Copy() var/turf_type = new_baseturfs[max(1, new_baseturfs.len - amount + 1)] while(ispath(turf_type, /turf/baseturf_skipover)) amount++ if(amount > new_baseturfs.len) CRASH("The bottomost baseturf of a turf is a skipover [src]([type])") turf_type = new_baseturfs[max(1, new_baseturfs.len - amount + 1)] new_baseturfs.len -= min(amount, new_baseturfs.len - 1) // No removing the very bottom if(new_baseturfs.len == 1) new_baseturfs = new_baseturfs[1] return ChangeTurf(turf_type, new_baseturfs, flags) if(baseturfs == type) return src return ChangeTurf(baseturfs, baseturfs, flags) // The bottom baseturf will never go away // Take the input as baseturfs and put it underneath the current baseturfs // If fake_turf_type is provided and new_baseturfs is not the baseturfs list will be created identical to the turf type's // If both or just new_baseturfs is provided they will be inserted below the existing baseturfs /turf/proc/PlaceOnBottom(list/new_baseturfs, turf/fake_turf_type) if(fake_turf_type) if(!new_baseturfs) if(!length(baseturfs)) baseturfs = list(baseturfs) var/list/old_baseturfs = baseturfs.Copy() assemble_baseturfs(fake_turf_type) if(!length(baseturfs)) baseturfs = list(baseturfs) baseturfs -= baseturfs & GLOB.blacklisted_automated_baseturfs baseturfs += old_baseturfs return else if(!length(new_baseturfs)) new_baseturfs = list(new_baseturfs, fake_turf_type) else new_baseturfs += fake_turf_type if(!length(baseturfs)) baseturfs = list(baseturfs) baseturfs.Insert(1, new_baseturfs) // Make a new turf and put it on top // The args behave identical to PlaceOnBottom except they go on top // Things placed on top of closed turfs will ignore the topmost closed turf // Returns the new turf /turf/proc/PlaceOnTop(list/new_baseturfs, turf/fake_turf_type, flags) var/area/turf_area = loc if(new_baseturfs && !length(new_baseturfs)) new_baseturfs = list(new_baseturfs) flags = turf_area.PlaceOnTopReact(new_baseturfs, fake_turf_type, flags) // A hook so areas can modify the incoming args var/turf/newT if(flags & CHANGETURF_SKIP) // We haven't been initialized if(flags_1 & INITIALIZED_1) stack_trace("CHANGETURF_SKIP was used in a PlaceOnTop call for a turf that's initialized. This is a mistake. [src]([type])") assemble_baseturfs() if(fake_turf_type) if(!new_baseturfs) // If no baseturfs list then we want to create one from the turf type if(!length(baseturfs)) baseturfs = list(baseturfs) var/list/old_baseturfs = baseturfs.Copy() if(!istype(src, /turf/closed)) old_baseturfs += type newT = ChangeTurf(fake_turf_type, null, flags) newT.assemble_baseturfs(initial(fake_turf_type.baseturfs)) // The baseturfs list is created like roundstart if(!length(newT.baseturfs)) newT.baseturfs = list(baseturfs) newT.baseturfs -= GLOB.blacklisted_automated_baseturfs newT.baseturfs.Insert(1, old_baseturfs) // The old baseturfs are put underneath return newT if(!length(baseturfs)) baseturfs = list(baseturfs) if(!istype(src, /turf/closed)) baseturfs += type baseturfs += new_baseturfs return ChangeTurf(fake_turf_type, null, flags) if(!length(baseturfs)) baseturfs = list(baseturfs) if(!istype(src, /turf/closed)) baseturfs += type var/turf/change_type if(length(new_baseturfs)) change_type = new_baseturfs[new_baseturfs.len] new_baseturfs.len-- if(new_baseturfs.len) baseturfs += new_baseturfs else change_type = new_baseturfs return ChangeTurf(change_type, null, flags) // Copy an existing turf and put it on top // Returns the new turf /turf/proc/CopyOnTop(turf/copytarget, ignore_bottom=1, depth=INFINITY, copy_air = FALSE) var/list/new_baseturfs = list() new_baseturfs += baseturfs new_baseturfs += type if(depth) var/list/target_baseturfs if(length(copytarget.baseturfs)) // with default inputs this would be Copy(clamp(2, -INFINITY, baseturfs.len)) // Don't forget a lower index is lower in the baseturfs stack, the bottom is baseturfs[1] target_baseturfs = copytarget.baseturfs.Copy(clamp(1 + ignore_bottom, 1 + copytarget.baseturfs.len - depth, copytarget.baseturfs.len)) else if(!ignore_bottom) target_baseturfs = list(copytarget.baseturfs) if(target_baseturfs) target_baseturfs -= new_baseturfs & GLOB.blacklisted_automated_baseturfs new_baseturfs += target_baseturfs var/turf/newT = copytarget.copyTurf(src, copy_air) newT.baseturfs = new_baseturfs return newT //If you modify this function, ensure it works correctly with lateloaded map templates. /turf/proc/AfterChange(flags) //called after a turf has been replaced in ChangeTurf() levelupdate() ImmediateCalculateAdjacentTurfs() //update firedoor adjacency var/list/turfs_to_check = get_adjacent_open_turfs(src) | src for(var/I in turfs_to_check) var/turf/T = I for(var/obj/machinery/door/firedoor/FD in T) FD.CalculateAffectingAreas() queue_smooth_neighbors(src) HandleTurfChange(src) /turf/open/AfterChange(flags) ..() RemoveLattice() if(!(flags & (CHANGETURF_IGNORE_AIR | CHANGETURF_INHERIT_AIR))) Assimilate_Air() //////Assimilate Air////// /turf/open/proc/Assimilate_Air() var/turf_count = LAZYLEN(atmos_adjacent_turfs) if(blocks_air || !turf_count) //if there weren't any open turfs, no need to update. return var/datum/gas_mixture/total = new//Holders to assimilate air from nearby turfs for(var/T in atmos_adjacent_turfs) var/turf/open/S = T if(!S.air) continue total.merge(S.air) air.copy_from(total.remove_ratio(1/turf_count)) /turf/proc/ReplaceWithLattice() ScrapeAway(flags = CHANGETURF_INHERIT_AIR) new /obj/structure/lattice(locate(x, y, z))