/turf icon = 'icons/turf/floors.dmi' level = 1 var/intact = 1 // baseturfs can be either a list or a single turf type. // In class definition like here it should always be a single type. // A list will be created in initialization that figures out the baseturf's baseturf etc. // In the case of a list it is sorted from bottom layer to top. // This shouldn't be modified directly, use the helper procs. var/list/baseturfs = /turf/baseturf_bottom var/temperature = T20C var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to var/blocks_air = FALSE flags_1 = CAN_BE_DIRTY_1 var/list/image/blueprint_data //for the station blueprints, images of objects eg: pipes var/explosion_level = 0 //for preventing explosion dodging var/explosion_id = 0 var/requires_activation //add to air processing after initialize? var/changing_turf = FALSE var/bullet_bounce_sound = 'sound/weapons/bulletremove.ogg' //sound played when a shell casing is ejected ontop of the turf. var/bullet_sizzle = FALSE //used by ammo_casing/bounce_away() to determine if the shell casing should make a sizzle sound when it's ejected over the turf //IE if the turf is supposed to be water, set TRUE. var/tiled_dirt = FALSE // use smooth tiled dirt decal /turf/vv_edit_var(var_name, new_value) var/static/list/banned_edits = list("x", "y", "z") if(var_name in banned_edits) return FALSE . = ..() /turf/Initialize(mapload) if(flags_1 & INITIALIZED_1) stack_trace("Warning: [src]([type]) initialized multiple times!") flags_1 |= INITIALIZED_1 // by default, vis_contents is inherited from the turf that was here before vis_contents.Cut() if(color) add_atom_colour(color, FIXED_COLOUR_PRIORITY) assemble_baseturfs() levelupdate() if(smooth) queue_smooth(src) visibilityChanged() for(var/atom/movable/AM in src) Entered(AM) var/area/A = loc if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) add_overlay(/obj/effect/fullbright) if(requires_activation) CALCULATE_ADJACENT_TURFS(src) SSair.add_to_active(src) if (light_power && light_range) update_light() var/turf/T = SSmapping.get_turf_above(src) if(T) T.multiz_turf_new(src, DOWN) SEND_SIGNAL(T, COMSIG_TURF_MULTIZ_NEW, src, DOWN) T = SSmapping.get_turf_below(src) if(T) T.multiz_turf_new(src, UP) SEND_SIGNAL(T, COMSIG_TURF_MULTIZ_NEW, src, UP) if (opacity) has_opaque_atom = TRUE ComponentInitialize() return INITIALIZE_HINT_NORMAL /turf/proc/Initalize_Atmos(times_fired) CALCULATE_ADJACENT_TURFS(src) /turf/Destroy(force) . = QDEL_HINT_IWILLGC if(!changing_turf) stack_trace("Incorrect turf deletion") changing_turf = FALSE var/turf/T = SSmapping.get_turf_above(src) if(T) T.multiz_turf_del(src, DOWN) T = SSmapping.get_turf_below(src) if(T) T.multiz_turf_del(src, UP) if(force) ..() //this will completely wipe turf state var/turf/B = new world.turf(src) for(var/A in B.contents) qdel(A) for(var/I in B.vars) B.vars[I] = null return SSair.remove_from_active(src) visibilityChanged() QDEL_LIST(blueprint_data) flags_1 &= ~INITIALIZED_1 requires_activation = FALSE ..() /turf/attack_hand(mob/user) . = ..() if(.) return user.Move_Pulled(src) /turf/proc/multiz_turf_del(turf/T, dir) /turf/proc/multiz_turf_new(turf/T, dir) //zPassIn doesn't necessarily pass an atom! //direction is direction of travel of air /turf/proc/zPassIn(atom/movable/A, direction, turf/source) return FALSE //direction is direction of travel of air /turf/proc/zPassOut(atom/movable/A, direction, turf/destination) return FALSE //direction is direction of travel of air /turf/proc/zAirIn(direction, turf/source) return FALSE //direction is direction of travel of air /turf/proc/zAirOut(direction, turf/source) return FALSE /turf/proc/zImpact(atom/movable/A, levels = 1, turf/prev_turf) var/flags = NONE var/mov_name = A.name for(var/i in contents) var/atom/thing = i flags |= thing.intercept_zImpact(A, levels) if(flags & FALL_STOP_INTERCEPTING) break if(prev_turf && !(flags & FALL_NO_MESSAGE)) prev_turf.visible_message("[mov_name] falls through [prev_turf]!") if(flags & FALL_INTERCEPTED) return if(zFall(A, ++levels)) return FALSE A.visible_message("[A] crashes into [src]!") A.onZImpact(src, levels) return TRUE /turf/proc/can_zFall(atom/movable/A, levels = 1, turf/target) return zPassOut(A, DOWN, target) && target.zPassIn(A, DOWN, src) /turf/proc/zFall(atom/movable/A, levels = 1, force = FALSE) var/turf/target = get_step_multiz(src, DOWN) if(!target || (!isobj(A) && !ismob(A))) return FALSE if(!force && (!can_zFall(A, levels, target) || !A.can_zFall(src, levels, target, DOWN))) return FALSE A.zfalling = TRUE A.forceMove(target) A.zfalling = FALSE target.zImpact(A, levels, src) return TRUE /turf/proc/handleRCL(obj/item/twohanded/rcl/C, mob/user) if(C.loaded) for(var/obj/structure/cable/LC in src) if(!LC.d1 || !LC.d2) LC.handlecable(C, user) return C.loaded.place_turf(src, user) if(C.wiring_gui_menu) C.wiringGuiUpdate(user) C.is_empty(user) /turf/attackby(obj/item/C, mob/user, params) if(..()) return TRUE if(can_lay_cable() && istype(C, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = C for(var/obj/structure/cable/LC in src) if(!LC.d1 || !LC.d2) LC.attackby(C,user) return coil.place_turf(src, user) return TRUE else if(istype(C, /obj/item/twohanded/rcl)) handleRCL(C, user) return FALSE /turf/CanPass(atom/movable/mover, turf/target) if(!target) return FALSE if(istype(mover)) // turf/Enter(...) will perform more advanced checks return !density stack_trace("Non movable passed to turf CanPass : [mover]") return FALSE /turf/Enter(atom/movable/mover, atom/oldloc) // Do not call ..() // Byond's default turf/Enter() doesn't have the behaviour we want with Bump() // By default byond will call Bump() on the first dense object in contents // Here's hoping it doesn't stay like this for years before we finish conversion to step_ var/atom/firstbump if(!CanPass(mover, src)) firstbump = src else for(var/i in contents) if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects continue if(QDELETED(mover)) break var/atom/movable/thing = i if(!thing.Cross(mover)) if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)) mover.Bump(thing) continue else if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1))) firstbump = thing if(firstbump) if(!QDELETED(mover)) mover.Bump(firstbump) return CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE) return TRUE /turf/Exit(atom/movable/mover, atom/newloc) . = ..() if(!.) return FALSE for(var/i in contents) if(QDELETED(mover)) break if(i == mover) continue var/atom/movable/thing = i if(!thing.Uncross(mover, newloc)) if(thing.flags_1 & ON_BORDER_1) mover.Bump(thing) if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)) return FALSE /turf/Entered(atom/movable/AM) ..() if(explosion_level && AM.ex_check(explosion_id)) AM.ex_act(explosion_level) // If an opaque movable atom moves around we need to potentially update visibility. if (AM.opacity) has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. reconsider_lights() /turf/open/Entered(atom/movable/AM) ..() //melting if(isobj(AM) && air && air.temperature > T0C) var/obj/O = AM if(O.obj_flags & FROZEN) O.make_unfrozen() if(!AM.zfalling) zFall(AM) /turf/proc/is_plasteel_floor() return FALSE // A proc in case it needs to be recreated or badmins want to change the baseturfs /turf/proc/assemble_baseturfs(turf/fake_baseturf_type) var/static/list/created_baseturf_lists = list() var/turf/current_target if(fake_baseturf_type) if(length(fake_baseturf_type)) // We were given a list, just apply it and move on baseturfs = fake_baseturf_type return current_target = fake_baseturf_type else if(length(baseturfs)) return // No replacement baseturf has been given and the current baseturfs value is already a list/assembled if(!baseturfs) current_target = initial(baseturfs) || type // This should never happen but just in case... stack_trace("baseturfs var was null for [type]. Failsafe activated and it has been given a new baseturfs value of [current_target].") else current_target = baseturfs // If we've made the output before we don't need to regenerate it if(created_baseturf_lists[current_target]) var/list/premade_baseturfs = created_baseturf_lists[current_target] if(length(premade_baseturfs)) baseturfs = premade_baseturfs.Copy() else baseturfs = premade_baseturfs return baseturfs var/turf/next_target = initial(current_target.baseturfs) //Most things only have 1 baseturf so this loop won't run in most cases if(current_target == next_target) baseturfs = current_target created_baseturf_lists[current_target] = current_target return current_target var/list/new_baseturfs = list(current_target) for(var/i=0;current_target != next_target;i++) if(i > 100) // A baseturfs list over 100 members long is silly // Because of how this is all structured it will only runtime/message once per type stack_trace("A turf <[type]> created a baseturfs list over 100 members long. This is most likely an infinite loop.") message_admins("A turf <[type]> created a baseturfs list over 100 members long. This is most likely an infinite loop.") break new_baseturfs.Insert(1, next_target) current_target = next_target next_target = initial(current_target.baseturfs) baseturfs = new_baseturfs created_baseturf_lists[new_baseturfs[new_baseturfs.len]] = new_baseturfs.Copy() return new_baseturfs /turf/proc/levelupdate() for(var/obj/O in src) if(O.level == 1 && (O.flags_1 & INITIALIZED_1)) O.hide(src.intact) // override for space turfs, since they should never hide anything /turf/open/space/levelupdate() for(var/obj/O in src) if(O.level == 1 && (O.flags_1 & INITIALIZED_1)) O.hide(0) // Removes all signs of lattice on the pos of the turf -Donkieyo /turf/proc/RemoveLattice() var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L && (L.flags_1 & INITIALIZED_1)) qdel(L) /turf/proc/phase_damage_creatures(damage,mob/U = null)//>Ninja Code. Hurts and knocks out creatures on this turf //NINJACODE for(var/mob/living/M in src) if(M==U) continue//Will not harm U. Since null != M, can be excluded to kill everyone. M.adjustBruteLoss(damage) M.Unconscious(damage * 4) for(var/obj/mecha/M in src) M.take_damage(damage*2, BRUTE, "melee", 1) /turf/proc/Bless() new /obj/effect/blessing(src) /turf/storage_contents_dump_act(datum/component/storage/src_object, mob/user) . = ..() if(.) return if(length(src_object.contents())) to_chat(user, "You start dumping out the contents...") if(!do_after(user,20,target=src_object.parent)) return FALSE var/list/things = src_object.contents() var/datum/progressbar/progress = new(user, things.len, src) while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress))) stoplag(1) qdel(progress) return TRUE ////////////////////////////// //Distance procs ////////////////////////////// //Distance associates with all directions movement /turf/proc/Distance(var/turf/T) return get_dist(src,T) // This Distance proc assumes that only cardinal movement is // possible. It results in more efficient (CPU-wise) pathing // for bots and anything else that only moves in cardinal dirs. /turf/proc/Distance_cardinal(turf/T) if(!src || !T) return FALSE return abs(x - T.x) + abs(y - T.y) //////////////////////////////////////////////////// /turf/singularity_act() if(intact) for(var/obj/O in contents) //this is for deleting things like wires contained in the turf if(O.level != 1) continue if(O.invisibility == INVISIBILITY_MAXIMUM) O.singularity_act() ScrapeAway(flags = CHANGETURF_INHERIT_AIR) return(2) /turf/proc/can_have_cabling() return TRUE /turf/proc/can_lay_cable() return can_have_cabling() & !intact /turf/proc/visibilityChanged() GLOB.cameranet.updateVisibility(src) // The cameranet usually handles this for us, but if we've just been // recreated we should make sure we have the cameranet vis_contents. var/datum/camerachunk/C = GLOB.cameranet.chunkGenerated(x, y, z) if(C) if(C.obscuredTurfs[src]) vis_contents += GLOB.cameranet.vis_contents_objects else vis_contents -= GLOB.cameranet.vis_contents_objects /turf/proc/burn_tile() /turf/proc/is_shielded() /turf/contents_explosion(severity, target) var/affecting_level if(severity == 1) affecting_level = 1 else if(is_shielded()) affecting_level = 3 else if(intact) affecting_level = 2 else affecting_level = 1 for(var/V in contents) var/atom/A = V if(!QDELETED(A) && A.level >= affecting_level) if(ismovableatom(A)) var/atom/movable/AM = A if(!AM.ex_check(explosion_id)) continue A.ex_act(severity, target) CHECK_TICK /turf/narsie_act(force, ignore_mobs, probability = 20) . = (prob(probability) || force) for(var/I in src) var/atom/A = I if(ignore_mobs && ismob(A)) continue if(ismob(A) || .) A.narsie_act() /turf/ratvar_act(force, ignore_mobs, probability = 40) . = (prob(probability) || force) for(var/I in src) var/atom/A = I if(ignore_mobs && ismob(A)) continue if(ismob(A) || .) A.ratvar_act() //called on /datum/species/proc/altdisarm() /turf/shove_act(mob/living/target, mob/living/user, pre_act = FALSE) var/list/possibilities for(var/obj/O in contents) if(CHECK_BITFIELD(O.obj_flags, SHOVABLE_ONTO)) LAZYADD(possibilities, O) else if(!O.CanPass(target, src)) return FALSE if(possibilities) var/obj/O = pick(possibilities) return O.shove_act(target, user) return FALSE /turf/proc/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) underlay_appearance.icon = icon underlay_appearance.icon_state = icon_state underlay_appearance.dir = adjacency_dir return TRUE /turf/proc/add_blueprints(atom/movable/AM) var/image/I = new I.appearance = AM.appearance I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM I.loc = src I.setDir(AM.dir) I.alpha = 128 LAZYADD(blueprint_data, I) /turf/proc/add_blueprints_preround(atom/movable/AM) if(!SSticker.HasRoundStarted()) add_blueprints(AM) /turf/proc/is_transition_turf() return /turf/acid_act(acidpwr, acid_volume) . = 1 var/acid_type = /obj/effect/acid if(acidpwr >= 200) //alien acid power acid_type = /obj/effect/acid/alien var/has_acid_effect = FALSE for(var/obj/O in src) if(intact && O.level == 1) //hidden under the floor continue if(istype(O, acid_type)) var/obj/effect/acid/A = O A.acid_level = min(A.level + acid_volume * acidpwr, 12000)//capping acid level to limit power of the acid has_acid_effect = 1 continue O.acid_act(acidpwr, acid_volume) if(!has_acid_effect) new acid_type(src, acidpwr, acid_volume) /turf/proc/acid_melt() return /turf/handle_fall(mob/faller, forced) faller.lying = pick(90, 270) if(!forced) return if(has_gravity(src)) playsound(src, "bodyfall", 50, 1) faller.drop_all_held_items() /turf/proc/photograph(limit=20) var/image/I = new() I.add_overlay(src) for(var/V in contents) var/atom/A = V if(A.invisibility) continue I.add_overlay(A) if(limit) limit-- else return I return I /turf/AllowDrop() return TRUE /turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE) var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses()) //if the vomit combined, apply toxicity and reagents to the old vomit if (QDELETED(V)) V = locate() in src if(!V) //the decal was spawned on a wall or groundless turf and promptly qdeleted. return // Make toxins and blazaam vomit look different if(toxvomit == VOMIT_PURPLE) V.icon_state = "vomitpurp_[pick(1,4)]" else if (toxvomit == VOMIT_TOXIC) V.icon_state = "vomittox_[pick(1,4)]" if (iscarbon(M)) var/mob/living/carbon/C = M if(C.reagents) clear_reagents_to_vomit_pool(C,V) /proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V) for(var/datum/reagent/consumable/R in M.reagents.reagent_list) //clears the stomach of anything that might be digested as food if(R.nutriment_factor > 0) M.reagents.del_reagent(R.type) M.reagents.trans_to(V, M.reagents.total_volume / 10) //Whatever happens after high temperature fire dies out or thermite reaction works. //Should return new turf /turf/proc/Melt() return ScrapeAway(flags = CHANGETURF_INHERIT_AIR) /turf/bullet_act(obj/item/projectile/P) . = ..() if(. != BULLET_ACT_FORCE_PIERCE) . = BULLET_ACT_TURF