diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index 639724eca2..6221409788 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -49,11 +49,10 @@ What is the naming convention for planes or layers? #define PLANE_LOOKINGGLASS -78 // For the Looking Glass holodecks #define PLANE_LOOKINGGLASS_IMG -77 // For the Looking Glass holodecks -// OPENSPACE_PLANE reserves all planes between OPENSPACE_PLANE_START and OPENSPACE_PLANE_END inclusive -#define OPENSPACE_PLANE -75 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 27) //VOREStation Edit -#define OPENSPACE_PLANE_START -73 -#define OPENSPACE_PLANE_END -48 //VOREStation Edit -#define OVER_OPENSPACE_PLANE -47 //VOREStation Edit + +#define OPENSPACE_PLANE -51 // Has to be lower than turfs + #define OPENSPACE_LAYER 600 // Above every other layer +#define OPENSPACE_BACKDROP_PLANE -50 // Black square has to be above openspace turfs // Turf Planes #define PLATING_PLANE -44 // Plating @@ -70,8 +69,11 @@ What is the naming convention for planes or layers? #define WATER_LAYER 3.0 // Layer for water overlays. #define ABOVE_TURF_LAYER 3.1 // Snow and wallmounted/floormounted equipment #define DECAL_PLANE -44 // Permanent decals + #define DECAL_LAYER 10 #define DIRTY_PLANE -43 // Nonpermanent decals + #define DIRTY_LAYER 11 #define BLOOD_PLANE -42 // Blood is really dirty, but we can do special stuff if we separate it + #define BLOOD_DECAL_LAYER 12 // Obj planes #define OBJ_PLANE -35 diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index 9ca46ce7e8..3561178d6b 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -218,7 +218,9 @@ #define COMSIG_TURF_CHANGE "turf_change" ///from base of atom/has_gravity(): (atom/asker, list/forced_gravities) #define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity" -///from base of turf/New(): (turf/source, direction) +///from base of turf/multiz_turf_del(): (turf/source, direction) +#define COMSIG_TURF_MULTIZ_DEL "turf_multiz_del" +///from base of turf/multiz_turf_new: (turf/source, direction) #define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new" // /atom/movable signals diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index a78d9147e2..092b5e677a 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -379,38 +379,39 @@ #define VIS_LIGHTING 2 #define VIS_O_LIGHT 3 #define VIS_EMISSIVE 4 +#define VIS_OPENSPACE 5 -#define VIS_GHOSTS 5 -#define VIS_AI_EYE 6 +#define VIS_GHOSTS 6 +#define VIS_AI_EYE 7 -#define VIS_CH_STATUS 7 -#define VIS_CH_HEALTH 8 -#define VIS_CH_LIFE 9 -#define VIS_CH_ID 10 -#define VIS_CH_WANTED 11 -#define VIS_CH_IMPLOYAL 12 -#define VIS_CH_IMPTRACK 13 -#define VIS_CH_IMPCHEM 14 -#define VIS_CH_SPECIAL 15 -#define VIS_CH_STATUS_OOC 16 +#define VIS_CH_STATUS 8 +#define VIS_CH_HEALTH 9 +#define VIS_CH_LIFE 10 +#define VIS_CH_ID 11 +#define VIS_CH_WANTED 12 +#define VIS_CH_IMPLOYAL 13 +#define VIS_CH_IMPTRACK 14 +#define VIS_CH_IMPCHEM 15 +#define VIS_CH_SPECIAL 16 +#define VIS_CH_STATUS_OOC 17 -#define VIS_ADMIN1 17 -#define VIS_ADMIN2 18 -#define VIS_ADMIN3 19 +#define VIS_ADMIN1 18 +#define VIS_ADMIN2 19 +#define VIS_ADMIN3 20 -#define VIS_MESONS 20 +#define VIS_MESONS 21 -#define VIS_TURFS 21 -#define VIS_OBJS 22 -#define VIS_MOBS 23 +#define VIS_TURFS 22 +#define VIS_OBJS 23 +#define VIS_MOBS 24 -#define VIS_BUILDMODE 24 +#define VIS_BUILDMODE 25 -#define VIS_CLOAKED 25 +#define VIS_CLOAKED 26 -#define VIS_STATUS 26 +#define VIS_STATUS 27 -#define VIS_COUNT 26 //Must be highest number from above. +#define VIS_COUNT 27 //Must be highest number from above. //Some mob icon layering defines #define BODY_LAYER -100 diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm index 116358e577..be17f09c39 100644 --- a/code/__defines/mobs_vr.dm +++ b/code/__defines/mobs_vr.dm @@ -1,13 +1,13 @@ #undef VIS_COUNT -#define VIS_CH_STATUS_R 27 -#define VIS_CH_HEALTH_VR 28 -#define VIS_CH_BACKUP 29 -#define VIS_CH_VANTAG 30 +#define VIS_CH_STATUS_R 28 +#define VIS_CH_HEALTH_VR 29 +#define VIS_CH_BACKUP 30 +#define VIS_CH_VANTAG 31 -#define VIS_AUGMENTED 31 +#define VIS_AUGMENTED 32 -#define VIS_COUNT 31 +#define VIS_COUNT 32 //Protean organs #define O_ORCH "orchestrator" diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 6453f4bba4..60a0ec8858 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -79,7 +79,6 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_HOLOMAPS -5 #define INIT_ORDER_NIGHTSHIFT -6 #define INIT_ORDER_OVERLAY -7 -#define INIT_ORDER_OPENSPACE -10 #define INIT_ORDER_XENOARCH -20 #define INIT_ORDER_CIRCUIT -21 #define INIT_ORDER_AI -22 diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index 5781543089..179f7251d9 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -286,9 +286,24 @@ var/mobs_radio_range_fired = 1 //CHOMPEdit var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM) var/list/hearturfs = list() + + // Openspace visibility handling + // Below turfs we can see + for(var/turf/simulated/open/O in hear) + var/turf/U = GetBelow(O) + while(istype(U)) + hearturfs |= U + U = GetBelow(U) + + // Above us + var/above_range = range + var/turf/Ab = GetAbove(T) + while(isopenspace(Ab) && --above_range > 0) + hear |= dview(above_range,Ab,INVISIBILITY_MAXIMUM) + Ab = GetAbove(Ab) for(var/thing in hear) - if(istype(thing, /obj)) //Can't use isobj() because /atom/movable returns true in that, and so lighting overlays would be included + if(istype(thing, /obj)) //Can't use isobj() because /atom/movable returns true in that objs += thing hearturfs |= get_turf(thing) if(ismob(thing)) diff --git a/code/_helpers/turfs.dm b/code/_helpers/turfs.dm index 5a0a519743..ffef724172 100644 --- a/code/_helpers/turfs.dm +++ b/code/_helpers/turfs.dm @@ -156,10 +156,6 @@ if(z_level_change) // Same goes for mobs. M.onTransitZ(T.z, X.z) - if(istype(M, /mob/living)) - var/mob/living/LM = M - LM.check_shadow() // Need to check their Z-shadow, which is normally done in forceMove(). - if(shuttlework) var/turf/simulated/shuttle/SS = T SS.landed_holder.leave_turf(turftoleave) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index a989dcbede..66a0dc6ce1 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -851,10 +851,6 @@ Turf and target are seperate in case you want to teleport some distance from a t if(z_level_change) // Same goes for mobs. M.onTransitZ(T.z, X.z) - if(istype(M, /mob/living)) - var/mob/living/LM = M - LM.check_shadow() // Need to check their Z-shadow, which is normally done in forceMove(). - if(shuttlework) var/turf/simulated/shuttle/SS = T SS.landed_holder.leave_turf() diff --git a/code/controllers/subsystems/open_space.dm b/code/controllers/subsystems/open_space.dm deleted file mode 100644 index 4e96dbfda4..0000000000 --- a/code/controllers/subsystems/open_space.dm +++ /dev/null @@ -1,107 +0,0 @@ -// -// Controller handling icon updates of open space turfs -// - -GLOBAL_VAR_INIT(open_space_initialised, FALSE) - -SUBSYSTEM_DEF(open_space) - name = "Open Space" - wait = 2 // 5 times per second. - init_order = INIT_ORDER_OPENSPACE - var/list/turfs_to_process = list() // List of turfs queued for update. - var/list/turfs_to_process_old = null // List of turfs currently being updated. - var/counter = 1 // Can't use .len because we need to iterate in order - var/static/image/over_OS_darkness // Image overlayed over the bottom turf with stuff in it. - -/datum/controller/subsystem/open_space/Initialize(timeofday) - over_OS_darkness = image('icons/turf/open_space.dmi', "black_open") - over_OS_darkness.plane = OVER_OPENSPACE_PLANE - over_OS_darkness.layer = MOB_LAYER - initialize_open_space() - // Pre-process open space turfs once before the round starts. - fire(FALSE, TRUE) - return ..() - -/datum/controller/subsystem/open_space/Recover() - flags |= SS_NO_INIT // Make extra sure we don't initialize twice. - . = ..() - -/datum/controller/subsystem/open_space/fire(resumed = 0, init_tick_checks = FALSE) - // We use a different list so any additions to the update lists during a delay from MC_TICK_CHECK - // don't cause things to be cut from the list without being updated. - - //If we're not resuming, this must mean it's a new iteration so we have to grab the turfs - if (!resumed) - src.counter = 1 - src.turfs_to_process_old = turfs_to_process - turfs_to_process = list() - - //cache for sanic speed (lists are references anyways) - var/list/turfs_to_process_old = src.turfs_to_process_old - var/counter = src.counter - while(counter <= turfs_to_process_old.len) - var/turf/T = turfs_to_process_old[counter] - counter += 1 - if(!QDELETED(T)) - update_turf(T) - if (init_tick_checks) - CHECK_TICK // Used during initialization processing - else if (MC_TICK_CHECK) - src.counter = counter // Save for when we're resumed - return // Used during normal MC processing. - -/datum/controller/subsystem/open_space/proc/update_turf(var/turf/T) - for(var/atom/movable/A in T) - A.fall() - T.update_icon() - -/datum/controller/subsystem/open_space/proc/add_turf(var/turf/T, var/recursive = 0) - ASSERT(isturf(T)) - // Check for multiple additions - // Pointless to process the same turf twice. But we need to push it to the end of the list - // because any turfs below it need to process first. - turfs_to_process -= T - turfs_to_process += T - if(recursive > 0) - var/turf/above = GetAbove(T) - if(above && isopenspace(above)) - add_turf(above, recursive) - -// Queue the initial updates of open space turfs when the game starts. This will lag! -/datum/controller/subsystem/open_space/proc/initialize_open_space() - // Do initial setup from bottom to top. - for(var/zlevel = 1 to world.maxz) - for(var/turf/simulated/open/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) - add_turf(T) - CHECK_TICK - GLOB.open_space_initialised = TRUE - -/datum/controller/subsystem/open_space/stat_entry(msg_prefix) - return ..("T [turfs_to_process.len]") - -/obj/update_icon() - . = ..() - if(GLOB.open_space_initialised && !invisibility && isturf(loc)) - var/turf/T = GetAbove(src) - if(isopenspace(T)) - // log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].update_icon()") - SSopen_space.add_turf(T, 1) - -// Ouch... this is painful. But is there any other way? -/* - No for now -/obj/New() - . = ..() - if(open_space_initialised && !invisibility) - var/turf/T = GetAbove(src) - if(isopenspace(T)) - // log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src]New()") - OS_controller.add_turf(T, 1) -*/ - -// We probably should hook Destroy() If we can think of something more efficient, lets hear it. -/obj/Destroy() - if(GLOB.open_space_initialised && !invisibility && isturf(loc)) - var/turf/T = GetAbove(src) - if(isopenspace(T)) - SSopen_space.add_turf(T, 1) - . = ..() // Important that this be at the bottom, or we will have been moved to nullspace. diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm new file mode 100644 index 0000000000..df2446cd46 --- /dev/null +++ b/code/datums/elements/turf_transparency.dm @@ -0,0 +1,82 @@ +/datum/element/turf_z_transparency + var/show_bottom_level = FALSE + +///This proc sets up the signals to handle updating viscontents when turfs above/below update. Handle plane and layer here too so that they don't cover other obs/turfs in Dream Maker +/datum/element/turf_z_transparency/Attach(datum/target, show_bottom_level = TRUE) + . = ..() + if(!isturf(target)) + return ELEMENT_INCOMPATIBLE + + var/turf/our_turf = target + + src.show_bottom_level = show_bottom_level + + our_turf.plane = OPENSPACE_PLANE + our_turf.layer = OPENSPACE_LAYER + + RegisterSignal(target, COMSIG_TURF_MULTIZ_DEL, .proc/on_multiz_turf_del) + RegisterSignal(target, COMSIG_TURF_MULTIZ_NEW, .proc/on_multiz_turf_new) + + update_multiz(our_turf, TRUE, TRUE) + +/datum/element/turf_z_transparency/Detach(datum/source) + . = ..() + var/turf/our_turf = source + our_turf.vis_contents.len = 0 + +///Updates the viscontents or underlays below this tile. +/datum/element/turf_z_transparency/proc/update_multiz(turf/our_turf, prune_on_fail = FALSE, init = FALSE) + var/turf/below_turf = GetBelow(our_turf) + if(!below_turf) + our_turf.vis_contents.len = 0 + if(!show_bottom_level(our_turf) && prune_on_fail) //If we cant show whats below, and we prune on fail, change the turf to plating as a fallback + our_turf.ChangeTurf(/turf/simulated/floor/plating) + return FALSE + if(init) + below_turf?.update_icon() // So the 'ceiling-less' overlay gets added. + our_turf.vis_contents += below_turf + + if(is_blocked_turf(our_turf)) //Show girders below closed turfs + var/mutable_appearance/girder_underlay = mutable_appearance('icons/obj/structures.dmi', "girder", layer = TURF_LAYER-0.01) + girder_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR + our_turf.underlays += girder_underlay + var/mutable_appearance/plating_underlay = mutable_appearance('icons/turf/floors.dmi', "plating", layer = TURF_LAYER-0.02) + plating_underlay = RESET_ALPHA | RESET_COLOR + our_turf.underlays += plating_underlay + return TRUE + +/datum/element/turf_z_transparency/proc/on_multiz_turf_del(turf/our_turf, turf/below_turf, dir) + SIGNAL_HANDLER + + if(dir != DOWN) + return + + update_multiz(our_turf) + +/datum/element/turf_z_transparency/proc/on_multiz_turf_new(turf/our_turf, turf/below_turf, dir) + SIGNAL_HANDLER + + if(dir != DOWN) + return + + update_multiz(our_turf) + +///Called when there is no real turf below this turf +/datum/element/turf_z_transparency/proc/show_bottom_level(turf/our_turf) + if(!show_bottom_level) + return FALSE + var/turf/path = get_base_turf(our_turf.z) || /turf/space + if(!ispath(path)) + path = text2path(path) + if(!ispath(path)) + warning("Z-level [our_turf.z] has invalid baseturf '[get_base_turf(our_turf.z)]'") + path = /turf/space + + var/do_plane = ispath(path, /turf/space) ? SPACE_PLANE : null + var/do_state = ispath(path, /turf/space) ? "white" : initial(path.icon_state) + + var/mutable_appearance/underlay_appearance = mutable_appearance(initial(path.icon), do_state, layer = TURF_LAYER-0.02, plane = do_plane) + underlay_appearance.appearance_flags = RESET_ALPHA | RESET_COLOR + our_turf.underlays += underlay_appearance + + return TRUE \ No newline at end of file diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index 4c3b406fed..d8dfa00fa3 100644 --- a/code/game/machinery/air_alarm.dm +++ b/code/game/machinery/air_alarm.dm @@ -30,6 +30,7 @@ icon = 'icons/obj/monitors_vr.dmi' //CHOMPEdit: Continues using new air alarm sprite, contrary to YW icon_state = "alarm0" layer = ABOVE_WINDOW_LAYER + vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature anchored = 1 use_power = USE_POWER_IDLE idle_power_usage = 80 diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index e2e1535728..fd56eb45dd 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -82,6 +82,7 @@ desc = "Used to print temporary passes for people. Handy!" icon_state = "guest" layer = ABOVE_WINDOW_LAYER + vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature icon_keyboard = null icon_screen = "pass" density = 0 diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm index a1a22b80c8..6c5e6400d4 100644 --- a/code/game/machinery/fire_alarm.dm +++ b/code/game/machinery/fire_alarm.dm @@ -8,6 +8,7 @@ FIRE ALARM icon_state = "fire" layer = ABOVE_WINDOW_LAYER blocks_emissive = FALSE + vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature var/detecting = 1.0 var/working = 1.0 var/time = 10.0 diff --git a/code/game/machinery/holoposter.dm b/code/game/machinery/holoposter.dm index a273cc1474..61cc5c3c17 100644 --- a/code/game/machinery/holoposter.dm +++ b/code/game/machinery/holoposter.dm @@ -8,6 +8,7 @@ GLOBAL_LIST_EMPTY(holoposters) use_power = 1 idle_power_usage = 80 power_channel = ENVIRON + vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature var/icon_forced = FALSE var/examine_addon = "It appears to be powered off." var/mytimer diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 89bd996dea..44a80c4445 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -12,6 +12,7 @@ idle_power_usage = 10 power_channel = LIGHT blocks_emissive = FALSE + vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature var/on = 1 var/area/area = null var/otherarea = null diff --git a/code/game/objects/effects/decals/Cleanable/fuel.dm b/code/game/objects/effects/decals/Cleanable/fuel.dm index bd6e1e97f6..deb8ec8a0c 100644 --- a/code/game/objects/effects/decals/Cleanable/fuel.dm +++ b/code/game/objects/effects/decals/Cleanable/fuel.dm @@ -3,6 +3,7 @@ icon = 'icons/effects/effects.dmi' icon_state = "fuel" plane = DIRTY_PLANE + layer = DIRTY_LAYER anchored = 1 var/amount = 1 generic_filth = TRUE diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index c9ae326bf2..7692dd334e 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -11,6 +11,7 @@ var/global/list/image/splatter_cache=list() density = 0 anchored = 1 plane = BLOOD_PLANE + layer = BLOOD_DECAL_LAYER icon = 'icons/effects/blood.dmi' icon_state = "mfloor1" random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 0df27515c7..ed411a67ab 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -7,6 +7,7 @@ generic_filth = TRUE means when the decal is saved, it will be switched out for /obj/effect/decal/cleanable plane = DIRTY_PLANE + layer = DIRTY_LAYER var/persistent = FALSE var/generic_filth = FALSE var/age = 0 diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index 559157af29..8f92ea0089 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -3,6 +3,7 @@ desc = "A rune drawn in crayon." icon = 'icons/obj/rune.dmi' plane = DIRTY_PLANE + layer = DIRTY_LAYER anchored = 1 /obj/effect/decal/cleanable/crayon/New(location,main = "#FFFFFF",shade = "#000000",var/type = "rune") diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 2432e79008..9f16a6b9c9 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -1,6 +1,7 @@ /obj layer = OBJ_LAYER plane = OBJ_PLANE + vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of obj in openspace. //Used to store information about the contents of the object. var/list/matter var/w_class // Size of the object. diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index c8c312334f..58674def1a 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -4,7 +4,7 @@ icon = 'icons/turf/catwalks.dmi' icon_state = "catwalk" plane = DECAL_PLANE - layer = ABOVE_UTILITY + layer = DECAL_LAYER density = 0 anchored = 1.0 var/hatch_open = FALSE @@ -140,7 +140,7 @@ anchored = 1.0 var/activated = FALSE plane = DECAL_PLANE - layer = ABOVE_UTILITY + layer = DECAL_LAYER var/tile = /obj/item/stack/tile/floor var/platecolor = "#858a8f" diff --git a/code/game/objects/structures/flora/flora.dm b/code/game/objects/structures/flora/flora.dm index e73e2a1758..ccb3106886 100644 --- a/code/game/objects/structures/flora/flora.dm +++ b/code/game/objects/structures/flora/flora.dm @@ -5,7 +5,7 @@ anchored = TRUE // Usually, plants don't move. Usually. plane = DECAL_PLANE - layer = BELOW_MOB_LAYER + layer = DECAL_LAYER var/randomize_size = FALSE var/max_x_scale = 1.25 diff --git a/code/game/turfs/flooring/flooring_decals.dm b/code/game/turfs/flooring/flooring_decals.dm index 31c8168a1c..2de2dc2991 100644 --- a/code/game/turfs/flooring/flooring_decals.dm +++ b/code/game/turfs/flooring/flooring_decals.dm @@ -7,7 +7,7 @@ var/list/floor_decals = list() name = "floor decal" icon = 'icons/turf/flooring/decals_vr.dmi' // VOREStation Edit plane = DECAL_PLANE - layer = MAPPER_DECAL_LAYER + layer = DECAL_LAYER var/supplied_dir /obj/effect/floor_decal/New(var/newloc, var/newdir, var/newcolour) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 76aa5985a2..d9162aceba 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -2,6 +2,7 @@ icon = 'icons/turf/floors.dmi' layer = TURF_LAYER plane = TURF_PLANE + vis_flags = VIS_INHERIT_ID | VIS_INHERIT_PLANE// Important for interaction with and visualization of openspace. level = 1 var/holy = 0 @@ -50,6 +51,13 @@ if(movement_cost && pathweight == 1) // This updates pathweight automatically. pathweight = movement_cost + var/turf/Ab = GetAbove(src) + if(Ab) + Ab.multiz_turf_new(src, DOWN) + var/turf/Be = GetBelow(src) + if(Be) + Be.multiz_turf_new(src, UP) + /turf/Destroy() . = QDEL_HINT_IWILLGC cleanbot_reserved_turfs -= src diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index efbea4ffb3..e826867ab7 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -42,7 +42,12 @@ var/old_outdoors = outdoors var/old_dangerous_objects = dangerous_objects - //to_world("Replacing [src.type] with [N]") + var/turf/Ab = GetAbove(src) + if(Ab) + Ab.multiz_turf_del(src, DOWN) + var/turf/Be = GetBelow(src) + if(Be) + Be.multiz_turf_del(src, UP) if(connections) connections.erase_all() @@ -53,6 +58,8 @@ var/turf/simulated/S = src if(S.zone) S.zone.rebuild() + cut_overlays(TRUE) + if(ispath(N, /turf/simulated/floor)) var/turf/simulated/W = new N( locate(src.x, src.y, src.z) ) if(old_fire) diff --git a/code/modules/holomap/station_holomap.dm b/code/modules/holomap/station_holomap.dm index 9d56943856..2430267981 100644 --- a/code/modules/holomap/station_holomap.dm +++ b/code/modules/holomap/station_holomap.dm @@ -13,6 +13,7 @@ idle_power_usage = 10 active_power_usage = 500 circuit = /obj/item/weapon/circuitboard/station_map + vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature // TODO - Port use_auto_lights from /vg - for now declare here var/use_auto_lights = 1 diff --git a/code/modules/lighting/emissive_blocker.dm b/code/modules/lighting/emissive_blocker.dm index 690b9b5216..b65c714d1f 100644 --- a/code/modules/lighting/emissive_blocker.dm +++ b/code/modules/lighting/emissive_blocker.dm @@ -11,6 +11,7 @@ plane = PLANE_EMISSIVE layer = FLOAT_LAYER mouse_opacity = MOUSE_OPACITY_TRANSPARENT + vis_flags = VIS_HIDE //Why? //render_targets copy the transform of the target as well, but vis_contents also applies the transform //to what's in it. Applying RESET_TRANSFORM here makes vis_contents not apply the transform. diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index bd3c70f994..6a7ba88d57 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /mob/observer name = "observer" desc = "This shouldn't appear" @@ -967,3 +968,1949 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set name = "Respawn" set category = "Ghost" src.abandon_mob() +||||||| parent of b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz +/mob/observer + name = "observer" + desc = "This shouldn't appear" + density = 0 + +/mob/observer/dead + name = "ghost" + desc = "It's a g-g-g-g-ghooooost!" //jinkies! + icon = 'icons/mob/ghost.dmi' + icon_state = "ghost" + stat = DEAD + canmove = 0 + blinded = 0 + anchored = 1 // don't get pushed around + + var/can_reenter_corpse + var/datum/hud/living/carbon/hud = null // hud + var/bootime = 0 + var/started_as_observer //This variable is set to 1 when you enter the game as an observer. + //If you died in the game and are a ghsot - this will remain as null. + //Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot. + var/has_enabled_antagHUD = 0 + var/medHUD = 0 + var/secHUD = 0 + var/antagHUD = 0 + universal_speak = 1 + var/atom/movable/following = null + var/admin_ghosted = 0 + var/anonsay = 0 + var/ghostvision = 1 //is the ghost able to see things humans can't? + incorporeal_move = 1 + + var/is_manifest = 0 //If set to 1, the ghost is able to whisper. Usually only set if a cultist drags them through the veil. + var/ghost_sprite = null + var/global/list/possible_ghost_sprites = list( + "Clear" = "blank", + "Green Blob" = "otherthing", + "Bland" = "ghost", + "Robed-B" = "ghost1", + "Robed-BAlt" = "ghost2", + "King" = "ghostking", + "Shade" = "shade", + "Hecate" = "ghost-narsie", + "Glowing Statue" = "armour", + "Artificer" = "artificer", + "Behemoth" = "behemoth", + "Harvester" = "harvester", + "Wraith" = "wraith", + "Viscerator" = "viscerator", + "Corgi" = "corgi", + "Tamaskan" = "tamaskan", + "Black Cat" = "blackcat", + "Lizard" = "lizard", + "Goat" = "goat", + "Space Bear" = "bear", + "Bats" = "bat", + "Chicken" = "chicken_white", + "Parrot"= "parrot_fly", + "Goose" = "goose", + "Penguin" = "penguin", + "Brown Crab" = "crab", + "Gray Crab" = "evilcrab", + "Trout" = "trout-swim", + "Salmon" = "salmon-swim", + "Pike" = "pike-swim", + "Koi" = "koi-swim", + "Carp" = "carp", + "Red Robes" = "robe_red", + "Faithless" = "faithless", + "Shadowform" = "forgotten", + "Dark Ethereal" = "bloodguardian", + "Holy Ethereal" = "lightguardian", + "Red Elemental" = "magicRed", + "Blue Elemental" = "magicBlue", + "Pink Elemental" = "magicPink", + "Orange Elemental" = "magicOrange", + "Green Elemental" = "magicGreen", + "Daemon" = "daemon", + "Guard Spider" = "guard", + "Hunter Spider" = "hunter", + "Nurse Spider" = "nurse", + "Rogue Drone" = "drone", + "ED-209" = "ed209", + "Beepsky" = "secbot" + ) + var/last_revive_notification = null // world.time of last notification, used to avoid spamming players from defibs or cloners. + var/cleanup_timer // Refernece to a timer that will delete this mob if no client returns + +/mob/observer/dead/New(mob/body) + + appearance = body + invisibility = INVISIBILITY_OBSERVER + layer = BELOW_MOB_LAYER + plane = PLANE_GHOSTS + alpha = 127 + + sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF + see_invisible = SEE_INVISIBLE_OBSERVER + see_in_dark = world.view //I mean. I don't even know if byond has occlusion culling... but... + verbs += /mob/observer/dead/proc/dead_tele + + var/turf/T + if(ismob(body)) + T = get_turf(body) //Where is the body located? + attack_log = body.attack_log //preserve our attack logs by copying them to our ghost + gender = body.gender + if(body.mind && body.mind.name) + name = body.mind.name + else + if(body.real_name) + name = body.real_name + else + if(gender == MALE) + name = capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) + else + name = capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) + + mind = body.mind //we don't transfer the mind but we keep a reference to it. + + // Fix for naked ghosts. + // Unclear why this isn't being grabbed by appearance. + if(ishuman(body)) + var/mob/living/carbon/human/H = body + add_overlay(H.overlays_standing) + + if(!T) T = pick(latejoin) //Safety in case we cannot find the body's position + forceMove(T) + + if(!name) //To prevent nameless ghosts + name = capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) + real_name = name + animate(src, pixel_y = 2, time = 10, loop = -1) + observer_mob_list += src + ..() + +/mob/observer/dead/Topic(href, href_list) + if (href_list["track"]) + var/mob/target = locate(href_list["track"]) in mob_list + if(target) + ManualFollow(target) + if(href_list["reenter"]) + reenter_corpse() + return + +/mob/observer/dead/attackby(obj/item/W, mob/user) + if(istype(W,/obj/item/weapon/book/tome)) + var/mob/observer/dead/M = src + M.manifest(user) + +/mob/observer/dead/CanPass(atom/movable/mover, turf/target) + return TRUE + +/mob/observer/dead/set_stat(var/new_stat) + if(new_stat != DEAD) + CRASH("It is best if observers stay dead, thank you.") + +/mob/observer/dead/examine_icon() + var/icon/I = get_cached_examine_icon(src) + if(!I) + I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE) + set_cached_examine_icon(src, I, 200 SECONDS) + return I + +/mob/observer/dead/examine(mob/user) + . = ..() + + if(is_admin(user)) + . += "\t>[ADMIN_FULLMONTY(src)]" + +/* +Transfer_mind is there to check if mob is being deleted/not going to have a body. +Works together with spawning an observer, noted above. +*/ + +/mob/observer/dead/Life() + ..() + if(!loc) return + if(!client) return 0 + + handle_regular_hud_updates() + handle_vision() + +/mob/proc/ghostize(var/can_reenter_corpse = 1) + if(key) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(H.vr_holder && !can_reenter_corpse) + H.exit_vr() + return 0 + var/mob/observer/dead/ghost = new(src) //Transfer safety to observer spawning proc. + ghost.can_reenter_corpse = can_reenter_corpse + ghost.timeofdeath = src.timeofdeath //BS12 EDIT + ghost.key = key + if(istype(loc, /obj/structure/morgue)) + var/obj/structure/morgue/M = loc + M.update() + else if(istype(loc, /obj/structure/closet/body_bag)) + var/obj/structure/closet/body_bag/B = loc + B.update() + if(ghost.client) + ghost.client.time_died_as_mouse = ghost.timeofdeath + if(ghost.client && !ghost.client.holder && !config.antag_hud_allowed) // For new ghosts we remove the verb from even showing up if it's not allowed. + ghost.verbs -= /mob/observer/dead/verb/toggle_antagHUD // Poor guys, don't know what they are missing! + return ghost + +/* +This is the proc mobs get to turn into a ghost. Forked from ghostize due to compatibility issues. +*/ +/mob/living/verb/ghost() + set category = "OOC" + set name = "Ghost" + set desc = "Relinquish your life and enter the land of the dead." + + if(stat == DEAD && !forbid_seeing_deadchat) + announce_ghost_joinleave(ghostize(1)) + else + var/response + if(src.client && src.client.holder) + response = tgui_alert(src, "You have the ability to Admin-Ghost. The regular Ghost verb will announce your presence to dead chat. Both variants will allow you to return to your body using 'aghost'.\n\nWhat do you wish to do?", "Are you sure you want to ghost?", "Ghost", list("Admin Ghost", "Stay in body")) + if(response == "Admin Ghost") + if(!src.client) + return + src.client.admin_ghost() + else + response = tgui_alert(src, "Are you -sure- you want to ghost?\n(You are alive, or otherwise have the potential to become alive. Don't abuse ghost unless you are inside a cryopod or equivalent! You can't change your mind so choose wisely!)", "Are you sure you want to ghost?", list("Ghost", "Stay in body")) // VOREStation edit because we don't make players stay dead for 30 minutes. + if(response != "Ghost") + return + resting = 1 + var/turf/location = get_turf(src) + var/special_role = check_special_role() + if(!istype(loc,/obj/machinery/cryopod)) + log_and_message_admins("has ghosted outside cryo[special_role ? " as [special_role]" : ""]. (JMP)",usr) + else if(special_role) + log_and_message_admins("has ghosted in cryo as [special_role]. (JMP)",usr) + var/mob/observer/dead/ghost = ghostize(0) // 0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 + if(ghost) + ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly. + ghost.set_respawn_timer() + announce_ghost_joinleave(ghost) + +/mob/observer/dead/can_use_hands() return 0 +/mob/observer/dead/is_active() return 0 + +/mob/observer/dead/Stat() + ..() + if(statpanel("Status")) + if(emergency_shuttle) + var/eta_status = emergency_shuttle.get_status_panel_eta() + if(eta_status) + stat(null, eta_status) + +/mob/observer/dead/verb/reenter_corpse() + set category = "Ghost" + set name = "Re-enter Corpse" + if(!client) return + if(!(mind && mind.current && can_reenter_corpse)) + to_chat(src, "You have no body.") + return + if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients + to_chat(usr, "Another consciousness is in your body... it is resisting you.") + return + //VOREStation Add + if(prevent_respawns.Find(mind.name)) + to_chat(usr, "You already quit this round as this character, sorry!") + return + //VOREStation Add End + if(mind.current.ajourn && mind.current.stat != DEAD) //check if the corpse is astral-journeying (it's client ghosted using a cultist rune). + var/found_rune + for(var/obj/effect/rune/R in mind.current.loc) //whilst corpse is alive, we can only reenter the body if it's on the rune + if(R && R.word1 == cultwords["hell"] && R.word2 == cultwords["travel"] && R.word3 == cultwords["self"]) // Found an astral journey rune. + found_rune = 1 + break + if(!found_rune) + to_chat(usr, "The astral cord that ties your body and your spirit has been severed. You are likely to wander the realm beyond until your body is finally dead and thus reunited with you.") + return + mind.current.ajourn=0 + mind.current.key = key + mind.current.teleop = null + if(istype(mind.current.loc, /obj/structure/morgue)) + var/obj/structure/morgue/M = mind.current.loc + M.update(1) + else if(istype(mind.current.loc, /obj/structure/closet/body_bag)) + var/obj/structure/closet/body_bag/B = mind.current.loc + B.update(1) + if(!admin_ghosted) + announce_ghost_joinleave(mind, 0, "They now occupy their body again.") + return 1 + +/mob/observer/dead/verb/toggle_medHUD() + set category = "Ghost" + set name = "Toggle MedicHUD" + set desc = "Toggles Medical HUD allowing you to see how everyone is doing" + + medHUD = !medHUD + plane_holder.set_vis(VIS_CH_HEALTH, medHUD) + plane_holder.set_vis(VIS_CH_STATUS_OOC, medHUD) + to_chat(src, "Medical HUD [medHUD ? "Enabled" : "Disabled"]") + +/mob/observer/dead/verb/toggle_secHUD() + set category = "Ghost" + set name = "Toggle Security HUD" + set desc = "Toggles Security HUD allowing you to see people's displayed ID's job, wanted status, etc" + + secHUD = !secHUD + plane_holder.set_vis(VIS_CH_ID, secHUD) + plane_holder.set_vis(VIS_CH_WANTED, secHUD) + plane_holder.set_vis(VIS_CH_IMPTRACK, secHUD) + plane_holder.set_vis(VIS_CH_IMPLOYAL, secHUD) + plane_holder.set_vis(VIS_CH_IMPCHEM, secHUD) + to_chat(src, "Security HUD [secHUD ? "Enabled" : "Disabled"]") + +/mob/observer/dead/verb/toggle_antagHUD() + set category = "Ghost" + set name = "Toggle AntagHUD" + set desc = "Toggles AntagHUD allowing you to see who is the antagonist" + + if(!config.antag_hud_allowed && !client.holder) + to_chat(src, "Admins have disabled this for this round.") + return + if(jobban_isbanned(src, "AntagHUD")) + to_chat(src, "You have been banned from using this feature") + return + if(config.antag_hud_restricted && !has_enabled_antagHUD && !client.holder) + var/response = tgui_alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?",list("Yes","No")) + if(response == "No") return + can_reenter_corpse = FALSE + set_respawn_timer(-1) // Foreeeever + if(!has_enabled_antagHUD && !client.holder) + has_enabled_antagHUD = TRUE + + antagHUD = !antagHUD + plane_holder.set_vis(VIS_CH_SPECIAL, antagHUD) + to_chat(src, "AntagHUD [antagHUD ? "Enabled" : "Disabled"]") + +/mob/observer/dead/proc/jumpable_areas() + var/list/areas = return_areas() + if(client?.holder) + return areas + + for(var/area/A as anything in areas) + if(A.z in using_map?.secret_levels) + areas -= A + return areas + +/mob/observer/dead/proc/jumpable_mobs() + var/list/mobs = getmobs() + if(client?.holder) + return mobs + + for(var/key in mobs) + var/mobz = get_z(mobs[key]) + if(mobz in using_map?.secret_levels) + mobs -= key + return mobs + +/mob/observer/dead/proc/dead_tele() + set category = "Ghost" + set name = "Teleport" + set desc = "Teleport to a location" + + if(!istype(usr, /mob/observer/dead)) + to_chat(usr, "Not when you're not dead!") + return + + + var/area/A = tgui_input_list(usr, "Select an area:", "Ghost Teleport", jumpable_areas()) + if(!A) + return + + usr.forceMove(pick(get_area_turfs(A))) + usr.on_mob_jump() + +/mob/observer/dead/verb/follow() + set category = "Ghost" + set name = "Follow" // "Haunt" + set desc = "Follow and haunt a mob." + + var/list/possible_mobs = jumpable_mobs() + var/input = tgui_input_list(usr, "Select a mob:", "Ghost Follow", possible_mobs) + if(!input) + return + + var/target = possible_mobs[input] + if(!target) return + ManualFollow(target) + +/mob/observer/dead/forceMove(atom/destination) + if(client?.holder) + return ..() + + if(get_z(destination) in using_map?.secret_levels) + to_chat(src,SPAN_WARNING("Sorry, that z-level does not allow ghosts.")) + if(following) + stop_following() + return + + return ..() + +/mob/observer/dead/Move(atom/newloc, direct = 0, movetime) + if(client?.holder) + return ..() + + if(get_z(newloc) in using_map?.secret_levels) + to_chat(src,SPAN_WARNING("Sorry, that z-level does not allow ghosts.")) + if(following) + stop_following() + return + + return ..() + +// This is the ghost's follow verb with an argument +/mob/observer/dead/proc/ManualFollow(var/atom/movable/target) + if(!target) + return + + var/turf/targetloc = get_turf(target) + if(check_holy(targetloc)) + to_chat(usr, "You cannot follow a mob standing on holy grounds!") + return + if(get_z(target) in using_map?.secret_levels) + to_chat(src, SPAN_WARNING("Sorry, that target is in an area that ghosts aren't allowed to go.")) + return + if(target != src) + if(following && following == target) + return + following = target + to_chat(src, "Now following [target]") + if(ismob(target)) + forceMove(get_turf(target)) + var/mob/M = target + M.following_mobs += src + else + spawn(0) + while(target && following == target && client) + var/turf/T = get_turf(target) + if(!T) + break + // To stop the ghost flickering. + if(loc != T) + forceMove(T) + sleep(15) + + var/icon/I = icon(target.icon,target.icon_state,target.dir) + + var/orbitsize = (I.Width()+I.Height())*0.5 + orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25) + + var/rot_seg + + /* We don't have this pref yet + switch(ghost_orbit) + if(GHOST_ORBIT_TRIANGLE) + rot_seg = 3 + if(GHOST_ORBIT_SQUARE) + rot_seg = 4 + if(GHOST_ORBIT_PENTAGON) + rot_seg = 5 + if(GHOST_ORBIT_HEXAGON) + rot_seg = 6 + else //Circular + rot_seg = 36 //360/10 bby, smooth enough aproximation of a circle + */ + + orbit(target, orbitsize, FALSE, 20, rot_seg) + +/mob/observer/dead/orbit() + set_dir(2) //reset dir so the right directional sprites show up + return ..() + +/mob/observer/dead/stop_orbit() + . = ..() + //restart our floating animation after orbit is done. + pixel_y = 0 + pixel_x = 0 + transform = null + animate(src, pixel_y = 2, time = 10, loop = -1) + +/mob/observer/dead/proc/stop_following() + following = null + stop_orbit() + +/mob/proc/update_following() + . = get_turf(src) + for(var/mob/observer/dead/M in following_mobs) + if(!.) + M.stop_following() + + if(M.following != src) + following_mobs -= M + else + if(M.loc != .) + M.forceMove(.) + +/mob + var/list/following_mobs = list() + +/mob/Destroy() + for(var/mob/observer/dead/M in following_mobs) + M.stop_following() + following_mobs = null + return ..() + +/mob/observer/dead/Destroy() + if(ismob(following)) + var/mob/M = following + M.following_mobs -= src + stop_following() + observer_mob_list -= src + return ..() + +/mob/Moved(atom/old_loc, direction, forced = FALSE) + . = ..() + update_following() + +/mob/Life() + // to catch teleports etc which directly set loc + update_following() + return ..() + +/mob/proc/check_holy(var/turf/T) + return 0 + +/mob/observer/dead/check_holy(var/turf/T) + if(check_rights(R_ADMIN|R_FUN|R_EVENT, 0, src)) + return 0 + + return (T && T.holy) && (is_manifest || (mind in cult.current_antagonists)) + +/mob/observer/dead/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak + set category = "Ghost" + set name = "Jump to Mob" + set desc = "Teleport to a mob" + set popup_menu = FALSE + + if(!istype(usr, /mob/observer/dead)) //Make sure they're an observer! + return + + var/list/possible_mobs = jumpable_mobs() + var/input = tgui_input_list(usr, "Select a mob:", "Ghost Jump", possible_mobs) + if(!input) + return + + var/target = possible_mobs[input] + if (!target)//Make sure we actually have a target + return + else + var/mob/M = target //Destination mob + var/turf/T = get_turf(M) //Turf of the destination mob + + if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination. + forceMove(T) + stop_following() + else + to_chat(src, "This mob is not located in the game world.") + +/mob/observer/dead/memory() + set hidden = 1 + to_chat(src, "You are dead! You have no mind to store memory!") + +/mob/observer/dead/add_memory() + set hidden = 1 + to_chat(src, "You are dead! You have no mind to store memory!") + +/mob/observer/dead/Post_Incorpmove() + stop_following() + +/mob/observer/dead/verb/analyze_air() + set name = "Analyze Air" + set category = "Ghost" + + if(!istype(usr, /mob/observer/dead)) return + + // Shamelessly copied from the Gas Analyzers + if (!( istype(usr.loc, /turf) )) + return + + var/datum/gas_mixture/environment = usr.loc.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + + to_chat(src, "Results:") + if(abs(pressure - ONE_ATMOSPHERE) < 10) + to_chat(src, "Pressure: [round(pressure,0.1)] kPa") + else + to_chat(src, "Pressure: [round(pressure,0.1)] kPa") + if(total_moles) + for(var/g in environment.gas) + to_chat(src, "[gas_data.name[g]]: [round((environment.gas[g] / total_moles) * 100)]% ([round(environment.gas[g], 0.01)] moles)") + to_chat(src, "Temperature: [round(environment.temperature-T0C,0.1)]°C ([round(environment.temperature,0.1)]K)") + to_chat(src, "Heat Capacity: [round(environment.heat_capacity(),0.1)]") + +/mob/observer/dead/verb/check_radiation() + set name = "Check Radiation" + set category = "Ghost" + + var/turf/t = get_turf(src) + if(t) + var/rads = SSradiation.get_rads_at_turf(t) + to_chat(src, "Radiation level: [rads ? rads : "0"] Bq.") + + +/mob/observer/dead/verb/become_mouse() + set name = "Become mouse" + set category = "Ghost" + + if(config.disable_player_mice) + to_chat(src, "Spawning as a mouse is currently disabled.") + return + + if(!MayRespawn(1)) + return + + var/turf/T = get_turf(src) + if(!T || (T.z in using_map.admin_levels)) + to_chat(src, "You may not spawn as a mouse on this Z-level.") + return + + var/timedifference = world.time - client.time_died_as_mouse + if(client.time_died_as_mouse && timedifference <= mouse_respawn_time * 600) + var/timedifference_text + timedifference_text = time2text(mouse_respawn_time * 600 - timedifference,"mm:ss") + to_chat(src, "You may only spawn again as a mouse more than [mouse_respawn_time] minutes after your death. You have [timedifference_text] left.") + return + + var/response = tgui_alert(src, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?",list("Squeek!","Nope!")) + if(response != "Squeek!") return //Hit the wrong key...again. + + + //find a viable mouse candidate + var/mob/living/simple_mob/animal/passive/mouse/host + var/obj/machinery/atmospherics/unary/vent_pump/vent_found + var/list/found_vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/v in machines) + if(!v.welded && v.z == T.z && v.network && v.network.normal_members.len > 20) + found_vents.Add(v) + if(found_vents.len) + vent_found = pick(found_vents) + host = new /mob/living/simple_mob/animal/passive/mouse(vent_found) + else + to_chat(src, "Unable to find any unwelded vents to spawn mice at.") + + if(host) + if(config.uneducated_mice) + host.universal_understand = 0 + announce_ghost_joinleave(src, 0, "They are now a mouse.") + host.ckey = src.ckey + host.add_ventcrawl(vent_found) + to_chat(host, "You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.") + +/mob/observer/dead/verb/view_manfiest() + set name = "Show Crew Manifest" + set category = "Ghost" + + var/dat + dat += "
"
+ for(var/t in typesof(/area))
+ master += text("[]\n", t)
+ //Foreach goto(26)
+ src << browse(master)
+ return
+*/
+
+/mob/verb/memory()
+ set name = "Notes"
+ set category = "IC"
+ if(mind)
+ mind.show_memory(src)
+ else
+ to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
+
+/mob/verb/add_memory(msg as message)
+ set name = "Add Note"
+ set category = "IC"
+
+ msg = sanitize(msg)
+
+ if(mind)
+ mind.store_memory(msg)
+ else
+ to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
+
+/mob/proc/store_memory(msg as message, popup, sane = 1)
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+
+ if (sane)
+ msg = sanitize(msg)
+
+ if (length(memory) == 0)
+ memory += msg
+ else
+ memory += "
[msg]"
+
+ if (popup)
+ memory()
+
+/mob/proc/update_flavor_text()
+ set src in usr
+ if(usr != src)
+ to_chat(usr, "No.")
+ var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb.","Flavor Text",html_decode(flavor_text)) as message|null, extra = 0) //VOREStation Edit: separating out OOC notes
+
+ if(msg != null)
+ flavor_text = msg
+
+/mob/proc/warn_flavor_changed()
+ if(flavor_text && flavor_text != "") // don't spam people that don't use it!
+ to_chat(src, "OOC Warning:
")
+ to_chat(src, "Your flavor text is likely out of date! Change")
+
+/mob/proc/print_flavor_text()
+ if (flavor_text && flavor_text != "")
+ var/msg = replacetext(flavor_text, "\n", " ")
+ if(length(msg) <= 40)
+ return "[msg]"
+ else
+ return "[copytext_preserve_html(msg, 1, 37)]... More..."
+
+/*
+/mob/verb/help()
+ set name = "Help"
+ src << browse('html/help.html', "window=help")
+ return
+*/
+
+/mob/proc/set_respawn_timer(var/time)
+ // Try to figure out what time to use
+
+ // Special cases, can never respawn
+ if(ticker?.mode?.deny_respawn)
+ time = -1
+ else if(!config.abandon_allowed)
+ time = -1
+ else if(!config.respawn)
+ time = -1
+
+ // Special case for observing before game start
+ else if(ticker?.current_state <= GAME_STATE_SETTING_UP)
+ time = 1 MINUTE
+
+ // Wasn't given a time, use the config time
+ else if(!time)
+ time = config.respawn_time
+
+ var/keytouse = ckey
+ // Try harder to find a key to use
+ if(!keytouse && key)
+ keytouse = ckey(key)
+ else if(!keytouse && mind?.key)
+ keytouse = ckey(mind.key)
+
+ GLOB.respawn_timers[keytouse] = world.time + time
+
+/mob/observer/dead/set_respawn_timer()
+ if(config.antag_hud_restricted && has_enabled_antagHUD)
+ ..(-1)
+ else
+ return // Don't set it, no need
+
+/mob/verb/abandon_mob()
+ set name = "Return to Menu"
+ set category = "OOC"
+
+ if(stat != DEAD || !ticker)
+ to_chat(usr, "You must be dead to use this!")
+ return
+
+ // Final chance to abort "respawning"
+ if(mind && timeofdeath) // They had spawned before
+ var/choice = tgui_alert(usr, "Returning to the menu will prevent your character from being revived in-round. Are you sure?", "Confirmation", list("No, wait", "Yes, leave"))
+ if(choice == "No, wait")
+ return
+
+ // Beyond this point, you're going to respawn
+ to_chat(usr, config.respawn_message)
+
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ return
+ client.screen.Cut()
+ client.screen += client.void
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ return
+
+ announce_ghost_joinleave(client, 0)
+
+ var/mob/new_player/M = new /mob/new_player()
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ qdel(M)
+ return
+
+ M.key = key
+ if(M.mind)
+ M.mind.reset()
+ return
+
+/client/verb/changes()
+ set name = "Changelog"
+ set category = "OOC"
+ src << browse('html/changelog.html', "window=changes;size=675x650")
+ if(prefs.lastchangelog != changelog_hash)
+ prefs.lastchangelog = changelog_hash
+ SScharacter_setup.queue_preferences_save(prefs)
+ winset(src, "rpane.changelog", "background-color=none;font-style=;")
+
+/mob/verb/observe()
+ set name = "Observe"
+ set category = "OOC"
+ var/is_admin = 0
+
+ if(client.holder && (client.holder.rights & R_ADMIN|R_EVENT))
+ is_admin = 1
+ else if(stat != DEAD || istype(src, /mob/new_player))
+ to_chat(usr, "You must be observing to use this!")
+ return
+
+ if(is_admin && stat == DEAD)
+ is_admin = 0
+
+ var/list/targets = list()
+
+
+ targets += observe_list_format(nuke_disks)
+ targets += observe_list_format(all_singularities)
+ targets += getmobs()
+ targets += observe_list_format(sortAtom(mechas_list))
+ targets += observe_list_format(SSshuttles.ships)
+
+ client.perspective = EYE_PERSPECTIVE
+
+ var/eye_name = null
+
+ var/ok = "[is_admin ? "Admin Observe" : "Observe"]"
+ eye_name = tgui_input_list(usr, "Select something to [ok]:", "Select Target", targets)
+
+ if (!eye_name)
+ return
+
+ var/mob/mob_eye = targets[eye_name]
+
+ if(client && mob_eye)
+ client.eye = mob_eye
+ if (is_admin)
+ client.adminobs = 1
+ if(mob_eye == client.mob || client.eye == client.mob)
+ client.adminobs = 0
+
+/mob/verb/cancel_camera()
+ set name = "Cancel Camera View"
+ set category = "OOC"
+ unset_machine()
+ reset_view(null)
+
+/mob/Topic(href, href_list)
+ if(href_list["mach_close"])
+ var/t1 = text("window=[href_list["mach_close"]]")
+ unset_machine()
+ src << browse(null, t1)
+
+ if(href_list["flavor_more"])
+ usr << browse(text("[] []", name, replacetext(flavor_text, "\n", "
")), text("window=[];size=500x200", name))
+ onclose(usr, "[name]")
+ if(href_list["flavor_change"])
+ update_flavor_text()
+// ..()
+ return
+
+
+/mob/proc/pull_damage()
+ return 0
+
+/mob/verb/stop_pulling()
+
+ set name = "Stop Pulling"
+ set category = "IC"
+
+ if(pulling)
+ if(ishuman(pulling))
+ var/mob/living/carbon/human/H = pulling
+ visible_message(SPAN_WARNING("\The [src] lets go of \the [H]."), SPAN_NOTICE("You let go of \the [H]."), exclude_mobs = list(H))
+ if(!H.stat)
+ to_chat(H, SPAN_WARNING("\The [src] lets go of you."))
+ pulling.pulledby = null
+ pulling = null
+ if(pullin)
+ pullin.icon_state = "pull0"
+
+/mob/proc/start_pulling(var/atom/movable/AM)
+
+ if ( !AM || !usr || src==AM || !isturf(src.loc) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort!
+ return
+
+ if (AM.anchored)
+ to_chat(src, "It won't budge!")
+ return
+
+ var/mob/M = AM
+ if(ismob(AM))
+
+ if(!can_pull_mobs || !can_pull_size)
+ to_chat(src, "They won't budge!")
+ return
+
+ if((mob_size < M.mob_size) && (can_pull_mobs != MOB_PULL_LARGER))
+ to_chat(src, "[M] is too large for you to move!")
+ return
+
+ if((mob_size == M.mob_size) && (can_pull_mobs == MOB_PULL_SMALLER))
+ to_chat(src, "[M] is too heavy for you to move!")
+ return
+
+ // If your size is larger than theirs and you have some
+ // kind of mob pull value AT ALL, you will be able to pull
+ // them, so don't bother checking that explicitly.
+
+ if(M.grabbed_by.len)
+ // Only start pulling when nobody else has a grab on them
+ . = 1
+ for(var/obj/item/weapon/grab/G in M.grabbed_by)
+ if(G.assailant != usr)
+ . = 0
+ else
+ qdel(G)
+ if(!.)
+ to_chat(src, "Somebody has a grip on them!")
+ return
+
+ if(!iscarbon(src))
+ M.LAssailant = null
+ else
+ M.LAssailant = usr
+
+ else if(isobj(AM))
+ var/obj/I = AM
+ if(!can_pull_size || can_pull_size < I.w_class)
+ to_chat(src, "It won't budge!")
+ return
+
+ if(pulling)
+ var/pulling_old = pulling
+ stop_pulling()
+ // Are we pulling the same thing twice? Just stop pulling.
+ if(pulling_old == AM)
+ return
+
+ src.pulling = AM
+ AM.pulledby = src
+
+ if(pullin)
+ pullin.icon_state = "pull1"
+
+ if(ishuman(AM))
+ var/mob/living/carbon/human/H = AM
+ if(H.lying) // If they're on the ground we're probably dragging their arms to move them
+ visible_message(SPAN_WARNING("\The [src] leans down and grips \the [H]'s arms."), SPAN_NOTICE("You lean down and grip \the [H]'s arms."), exclude_mobs = list(H))
+ if(!H.stat)
+ to_chat(H, SPAN_WARNING("\The [src] leans down and grips your arms."))
+ else //Otherwise we're probably just holding their arm to lead them somewhere
+ visible_message(SPAN_WARNING("\The [src] grips \the [H]'s arm."), SPAN_NOTICE("You grip \the [H]'s arm."), exclude_mobs = list(H))
+ if(!H.stat)
+ to_chat(H, SPAN_WARNING("\The [src] grips your arm."))
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 25) //Quieter than hugging/grabbing but we still want some audio feedback
+
+ if(H.pull_damage())
+ to_chat(src, "Pulling \the [H] in their current condition would probably be a bad idea.")
+
+ //Attempted fix for people flying away through space when cuffed and dragged.
+ if(ismob(AM))
+ var/mob/pulled = AM
+ pulled.inertia_dir = 0
+
+/mob/proc/can_use_hands()
+ return
+
+/mob/proc/is_active()
+ return (0 >= usr.stat)
+
+/mob/proc/is_dead()
+ return stat == DEAD
+
+/mob/proc/is_mechanical()
+ if(mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI"))
+ return 1
+ return istype(src, /mob/living/silicon) || get_species() == "Machine"
+
+/mob/proc/is_ready()
+ return client && !!mind
+
+/mob/proc/get_gender()
+ return gender
+
+/mob/proc/see(message)
+ if(!is_active())
+ return 0
+ to_chat(src,message)
+ return 1
+
+/mob/proc/show_viewers(message)
+ for(var/mob/M in viewers())
+ M.see(message)
+
+/mob/Stat()
+ ..()
+ . = (is_client_active(10 MINUTES))
+
+ if(.)
+ if(statpanel("Status"))
+ stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
+ if(ticker && ticker.current_state != GAME_STATE_PREGAME)
+ stat("Station Time", stationtime2text())
+ stat("Station Date", stationdate2text())
+ stat("Round Duration", roundduration2text())
+
+ if(client.holder)
+ if(statpanel("Status"))
+ stat("Location:", "([x], [y], [z]) [loc]")
+ stat("CPU:","[world.cpu]")
+ stat("Instances:","[world.contents.len]")
+ stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
+
+ if(statpanel("MC"))
+ stat("Location:", "([x], [y], [z]) [loc]")
+ stat("CPU:","[world.cpu]")
+ stat("Instances:","[world.contents.len]")
+ stat("World Time:", world.time)
+ stat("Real time of day:", REALTIMEOFDAY)
+ stat(null)
+ if(GLOB)
+ GLOB.stat_entry()
+ else
+ stat("Globals:", "ERROR")
+ if(Master)
+ Master.stat_entry()
+ else
+ stat("Master Controller:", "ERROR")
+ if(Failsafe)
+ Failsafe.stat_entry()
+ else
+ stat("Failsafe Controller:", "ERROR")
+ if(Master)
+ stat(null)
+ for(var/datum/controller/subsystem/SS in Master.subsystems)
+ SS.stat_entry()
+
+ if(statpanel("Tickets"))
+ GLOB.ahelp_tickets.stat_entry()
+
+
+ if(length(GLOB.sdql2_queries))
+ if(statpanel("SDQL2"))
+ stat("Access Global SDQL2 List", GLOB.sdql2_vv_statobj)
+ for(var/i in GLOB.sdql2_queries)
+ var/datum/SDQL2_query/Q = i
+ Q.generate_stat()
+
+ if(listed_turf && client)
+ if(!TurfAdjacent(listed_turf))
+ listed_turf = null
+ else
+ if(statpanel("Turf"))
+ stat(listed_turf)
+ for(var/atom/A in listed_turf)
+ if(!A.mouse_opacity)
+ continue
+ if(A.invisibility > see_invisible)
+ continue
+ if(is_type_in_list(A, shouldnt_see))
+ continue
+ if(A.plane > plane)
+ continue
+ stat(A)
+
+
+// facing verbs
+/mob/proc/canface()
+// if(!canmove) return 0 //VOREStation Edit. Redundant check that only affects conscious proning, actual inability to turn and shift around handled by actual inabilities.
+ if(stat) return 0
+ if(anchored) return 0
+ if(transforming) return 0
+ return 1
+
+// Not sure what to call this. Used to check if humans are wearing an AI-controlled exosuit and hence don't need to fall over yet.
+/mob/proc/can_stand_overridden()
+ return 0
+
+//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
+/mob/proc/update_canmove()
+ return canmove
+
+
+/mob/proc/facedir(var/ndir)
+ if(!canface() || (client && (client.moving || !checkMoveCooldown())))
+ return 0
+ set_dir(ndir)
+ if(buckled && buckled.buckle_movable)
+ buckled.set_dir(ndir)
+ setMoveCooldown(movement_delay())
+ return 1
+
+
+/mob/verb/eastface()
+ set hidden = 1
+ return facedir(client.client_dir(EAST))
+
+
+/mob/verb/westface()
+ set hidden = 1
+ return facedir(client.client_dir(WEST))
+
+
+/mob/verb/northface()
+ set hidden = 1
+ return facedir(client.client_dir(NORTH))
+
+
+/mob/verb/southface()
+ set hidden = 1
+ return facedir(client.client_dir(SOUTH))
+
+
+//This might need a rename but it should replace the can this mob use things check
+/mob/proc/IsAdvancedToolUser()
+ return 0
+
+/mob/proc/Stun(amount)
+ if(status_flags & CANSTUN)
+ facing_dir = null
+ stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
+ if(status_flags & CANSTUN)
+ stunned = max(amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/AdjustStunned(amount)
+ if(status_flags & CANSTUN)
+ stunned = max(stunned + amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/Weaken(amount)
+ if(status_flags & CANWEAKEN)
+ facing_dir = null
+ weakened = max(max(weakened,amount),0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/SetWeakened(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(amount,0)
+ update_canmove() //can you guess what this does yet?
+ return
+
+/mob/proc/AdjustWeakened(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(weakened + amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/Paralyse(amount)
+ if(status_flags & CANPARALYSE)
+ facing_dir = null
+ paralysis = max(max(paralysis,amount),0)
+ return
+
+/mob/proc/SetParalysis(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(amount,0)
+ return
+
+/mob/proc/AdjustParalysis(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(paralysis + amount,0)
+ return
+
+/mob/proc/Sleeping(amount)
+ facing_dir = null
+ sleeping = max(max(sleeping,amount),0)
+ return
+
+/mob/proc/SetSleeping(amount)
+ sleeping = max(amount,0)
+ return
+
+/mob/proc/AdjustSleeping(amount)
+ sleeping = max(sleeping + amount,0)
+ return
+
+/mob/proc/Confuse(amount)
+ confused = max(max(confused,amount),0)
+ return
+
+/mob/proc/SetConfused(amount)
+ confused = max(amount,0)
+ return
+
+/mob/proc/AdjustConfused(amount)
+ confused = max(confused + amount,0)
+ return
+
+/mob/proc/Blind(amount)
+ eye_blind = max(max(eye_blind,amount),0)
+ return
+
+/mob/proc/SetBlinded(amount)
+ eye_blind = max(amount,0)
+ return
+
+/mob/proc/AdjustBlinded(amount)
+ eye_blind = max(eye_blind + amount,0)
+ return
+
+/mob/proc/Resting(amount)
+ facing_dir = null
+ resting = max(max(resting,amount),0)
+ update_canmove()
+ return
+
+/mob/proc/SetResting(amount)
+ resting = max(amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustResting(amount)
+ resting = max(resting + amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustLosebreath(amount)
+ losebreath = CLAMP(losebreath + amount, 0, 25)
+
+/mob/proc/SetLosebreath(amount)
+ losebreath = CLAMP(amount, 0, 25)
+
+/mob/proc/get_species()
+ return ""
+
+/mob/proc/flash_weak_pain()
+ flick("weak_pain",pain)
+
+/mob/proc/get_visible_implants(var/class = 0)
+ var/list/visible_implants = list()
+ for(var/obj/item/O in embedded)
+ if(O.w_class > class)
+ visible_implants += O
+ return visible_implants
+
+/mob/proc/embedded_needs_process()
+ return (embedded.len > 0)
+
+/mob/proc/yank_out_object()
+ set category = "Object"
+ set name = "Yank out object"
+ set desc = "Remove an embedded item at the cost of bleeding and pain."
+ set src in view(1)
+
+ if(!isliving(usr) || !usr.checkClickCooldown())
+ return
+ usr.setClickCooldown(20)
+
+ if(usr.stat == 1)
+ to_chat(usr, "You are unconcious and cannot do that!")
+ return
+
+ if(usr.restrained())
+ to_chat(usr, "You are restrained and cannot do that!")
+ return
+
+ var/mob/S = src
+ var/mob/U = usr
+ var/list/valid_objects = list()
+ var/self = null
+
+ if(S == U)
+ self = 1 // Removing object from yourself.
+
+ valid_objects = get_visible_implants(0)
+ if(!valid_objects.len)
+ if(self)
+ to_chat(src, "You have nothing stuck in your body that is large enough to remove.")
+ else
+ to_chat(U, "[src] has nothing stuck in their wounds that is large enough to remove.")
+ return
+
+ var/obj/item/weapon/selection = tgui_input_list(usr, "What do you want to yank out?", "Embedded objects", valid_objects)
+
+ if(self)
+ to_chat(src, "You attempt to get a good grip on [selection] in your body.")
+ else
+ to_chat(U, "You attempt to get a good grip on [selection] in [S]'s body.")
+
+ if(!do_after(U, 30))
+ return
+ if(!selection || !S || !U)
+ return
+
+ if(self)
+ visible_message("[src] rips [selection] out of their body.","You rip [selection] out of your body.")
+ else
+ visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.")
+ valid_objects = get_visible_implants(0)
+ if(valid_objects.len == 1) //Yanking out last object - removing verb.
+ src.verbs -= /mob/proc/yank_out_object
+ clear_alert("embeddedobject")
+
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ var/obj/item/organ/external/affected
+
+ for(var/obj/item/organ/external/organ in H.organs) //Grab the organ holding the implant.
+ for(var/obj/item/O in organ.implants)
+ if(O == selection)
+ affected = organ
+
+ affected.implants -= selection
+ H.shock_stage+=20
+ affected.take_damage((selection.w_class * 3), 0, 0, 1, "Embedded object extraction")
+
+ if(prob(selection.w_class * 5) && (affected.robotic < ORGAN_ROBOT)) //I'M SO ANEMIC I COULD JUST -DIE-.
+ var/datum/wound/internal_bleeding/I = new (min(selection.w_class * 5, 15))
+ affected.wounds += I
+ H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 50)
+
+ if (ishuman(U))
+ var/mob/living/carbon/human/human_user = U
+ human_user.bloody_hands(H)
+
+ else if(issilicon(src))
+ var/mob/living/silicon/robot/R = src
+ R.embedded -= selection
+ R.adjustBruteLoss(5)
+ R.adjustFireLoss(10)
+
+ selection.forceMove(get_turf(src))
+ U.put_in_hands(selection)
+
+ for(var/obj/item/weapon/O in pinned)
+ if(O == selection)
+ pinned -= O
+ if(!pinned.len)
+ anchored = 0
+ return 1
+
+//Check for brain worms in head.
+/mob/proc/has_brain_worms()
+
+ for(var/I in contents)
+ if(istype(I,/mob/living/simple_mob/animal/borer))
+ return I
+
+ return 0
+
+/mob/proc/updateicon()
+ return
+
+// Please always use this proc, never just set the var directly.
+/mob/proc/set_stat(var/new_stat)
+ . = (stat != new_stat)
+ stat = new_stat
+
+/mob/verb/face_direction()
+
+ set name = "Face Direction"
+ set category = "IC"
+ set src = usr
+
+ set_face_dir()
+
+ if(!facing_dir)
+ to_chat(usr, "You are now not facing anything.")
+ else
+ to_chat(usr, "You are now facing [dir2text(facing_dir)].")
+
+/mob/proc/set_face_dir(var/newdir)
+ if(newdir == facing_dir)
+ facing_dir = null
+ else if(newdir)
+ set_dir(newdir)
+ facing_dir = newdir
+ else if(facing_dir)
+ facing_dir = null
+ else
+ set_dir(dir)
+ facing_dir = dir
+
+/mob/set_dir()
+ if(facing_dir)
+ if(!canface() || lying || buckled || restrained())
+ facing_dir = null
+ else if(dir != facing_dir)
+ return ..(facing_dir)
+ else
+ return ..()
+
+/mob/verb/northfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(NORTH))
+
+/mob/verb/southfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(SOUTH))
+
+/mob/verb/eastfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(EAST))
+
+/mob/verb/westfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(WEST))
+
+// Begin VOREstation edit
+/mob/verb/shiftnorth()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_y <= (default_pixel_y + 16))
+ pixel_y++
+ is_shifted = TRUE
+
+/mob/verb/shiftsouth()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_y >= (default_pixel_y - 16))
+ pixel_y--
+ is_shifted = TRUE
+
+/mob/verb/shiftwest()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_x >= (default_pixel_x - 16))
+ pixel_x--
+ is_shifted = TRUE
+
+/mob/verb/shifteast()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_x <= (default_pixel_x + 16))
+ pixel_x++
+ is_shifted = TRUE
+// End VOREstation edit
+
+/mob/proc/adjustEarDamage()
+ return
+
+/mob/proc/setEarDamage()
+ return
+
+// Set client view distance (size of client's screen). Returns TRUE if anything changed.
+/mob/proc/set_viewsize(var/new_view = world.view)
+ if (client && new_view != client.view)
+ client.view = new_view
+ return TRUE
+ return FALSE
+
+//Throwing stuff
+
+/mob/proc/toggle_throw_mode()
+ if (src.in_throw_mode)
+ throw_mode_off()
+ else
+ throw_mode_on()
+
+/mob/proc/throw_mode_off()
+ src.in_throw_mode = 0
+ if(src.throw_icon) //in case we don't have the HUD and we use the hotkey
+ src.throw_icon.icon_state = "act_throw_off"
+
+/mob/proc/throw_mode_on()
+ src.in_throw_mode = 1
+ if(src.throw_icon)
+ src.throw_icon.icon_state = "act_throw_on"
+
+/mob/proc/isSynthetic()
+ return 0
+
+/mob/proc/is_muzzled()
+ return 0
+
+//Exploitable Info Update
+
+/mob/proc/amend_exploitable(var/obj/item/I)
+ if(istype(I))
+ exploit_addons |= I
+ var/exploitmsg = html_decode("\n" + "Has " + I.name + ".")
+ exploit_record += exploitmsg
+
+/client/proc/check_has_body_select()
+ return mob && mob.hud_used && istype(mob.zone_sel, /obj/screen/zone_sel)
+
+/client/verb/body_toggle_head()
+ set name = "body-toggle-head"
+ set hidden = 1
+ toggle_zone_sel(list(BP_HEAD, O_EYES, O_MOUTH))
+
+/client/verb/body_r_arm()
+ set name = "body-r-arm"
+ set hidden = 1
+ toggle_zone_sel(list(BP_R_ARM,BP_R_HAND))
+
+/client/verb/body_l_arm()
+ set name = "body-l-arm"
+ set hidden = 1
+ toggle_zone_sel(list(BP_L_ARM,BP_L_HAND))
+
+/client/verb/body_chest()
+ set name = "body-chest"
+ set hidden = 1
+ toggle_zone_sel(list(BP_TORSO))
+
+/client/verb/body_groin()
+ set name = "body-groin"
+ set hidden = 1
+ toggle_zone_sel(list(BP_GROIN))
+
+/client/verb/body_r_leg()
+ set name = "body-r-leg"
+ set hidden = 1
+ toggle_zone_sel(list(BP_R_LEG,BP_R_FOOT))
+
+/client/verb/body_l_leg()
+ set name = "body-l-leg"
+ set hidden = 1
+ toggle_zone_sel(list(BP_L_LEG,BP_L_FOOT))
+
+/client/proc/toggle_zone_sel(list/zones)
+ if(!check_has_body_select())
+ return
+ var/obj/screen/zone_sel/selector = mob.zone_sel
+ selector.set_selected_zone(next_in_list(mob.zone_sel.selecting,zones))
+
+// This handles setting the client's color variable, which makes everything look a specific color.
+// This proc is here so it can be called without needing to check if the client exists, or if the client relogs.
+// This is for inheritence since /mob/living will serve most cases. If you need ghosts to use this you'll have to implement that yourself.
+/mob/proc/update_client_color()
+ if(client && client.color)
+ animate(client, color = null, time = 10)
+ return
+
+/mob/proc/swap_hand()
+ return
+
+//Throwing stuff
+/mob/proc/throw_item(atom/target)
+ return
+
+/mob/proc/will_show_tooltip()
+ if(alpha <= EFFECTIVE_INVIS)
+ return FALSE
+ return TRUE
+
+/mob/MouseEntered(location, control, params)
+ if(usr != src && usr.is_preference_enabled(/datum/client_preference/mob_tooltips) && src.will_show_tooltip())
+ openToolTip(user = usr, tip_src = src, params = params, title = get_nametag_name(usr), content = get_nametag_desc(usr))
+
+ ..()
+
+/mob/MouseDown()
+ closeToolTip(usr) //No reason not to, really
+
+ ..()
+
+/mob/MouseExited()
+ closeToolTip(usr) //No reason not to, really
+
+ ..()
+
+// Manages a global list of mobs with clients attached, indexed by z-level.
+/mob/proc/update_client_z(new_z) // +1 to register, null to unregister.
+ if(registered_z != new_z)
+ if(registered_z)
+ GLOB.players_by_zlevel[registered_z] -= src
+ if(client)
+ if(new_z)
+ GLOB.players_by_zlevel[new_z] += src
+ registered_z = new_z
+ else
+ registered_z = null
+
+GLOBAL_LIST_EMPTY_TYPED(living_players_by_zlevel, /list)
+/mob/living/update_client_z(new_z)
+ var/precall_reg_z = registered_z
+ . = ..() // will update registered_z if necessary
+ if(precall_reg_z != registered_z) // parent did work, let's do work too
+ if(precall_reg_z)
+ GLOB.living_players_by_zlevel[precall_reg_z] -= src
+ if(registered_z)
+ GLOB.living_players_by_zlevel[registered_z] += src
+
+/mob/onTransitZ(old_z, new_z)
+ ..()
+ update_client_z(new_z)
+
+/mob/cloak()
+ . = ..()
+ if(client && cloaked_selfimage)
+ client.images += cloaked_selfimage
+
+/mob/uncloak()
+ if(client && cloaked_selfimage)
+ client.images -= cloaked_selfimage
+ return ..()
+
+/mob/get_cloaked_selfimage()
+ var/icon/selficon = getCompoundIcon(src)
+ selficon.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) //White
+ var/image/selfimage = image(selficon)
+ selfimage.color = "#0000FF"
+ selfimage.alpha = 100
+ selfimage.layer = initial(layer)
+ selfimage.plane = initial(plane)
+ selfimage.loc = src
+
+ return selfimage
+
+/mob/proc/GetAltName()
+ return ""
+
+/mob/proc/get_ghost(even_if_they_cant_reenter = 0)
+ if(mind)
+ return mind.get_ghost(even_if_they_cant_reenter)
+
+/mob/proc/grab_ghost(force)
+ if(mind)
+ return mind.grab_ghost(force = force)
+=======
+/mob/Destroy()//This makes sure that mobs withGLOB.clients/keys are not just deleted from the game.
+ mob_list -= src
+ dead_mob_list -= src
+ living_mob_list -= src
+ unset_machine()
+ qdel(hud_used)
+ clear_fullscreen()
+ if(client)
+ for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
+ qdel(spell_master)
+ remove_screen_obj_references()
+ client.screen = list()
+ if(mind && mind.current == src)
+ spellremove(src)
+ ghostize()
+ QDEL_NULL(plane_holder)
+ ..()
+ return QDEL_HINT_HARDDEL_NOW
+
+/mob/proc/remove_screen_obj_references()
+ hands = null
+ pullin = null
+ purged = null
+ internals = null
+ i_select = null
+ m_select = null
+ healths = null
+ throw_icon = null
+ pain = null
+ item_use_icon = null
+ gun_move_icon = null
+ gun_setting_icon = null
+ spell_masters = null
+ zone_sel = null
+
+/mob/Initialize()
+ mob_list += src
+ if(stat == DEAD)
+ dead_mob_list += src
+ else
+ living_mob_list += src
+ lastarea = get_area(src)
+ hook_vr("mob_new",list(src)) //VOREStation Code
+ update_transform() // Some mobs may start bigger or smaller than normal.
+ return ..()
+
+/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
+
+ if(!client && !teleop) return
+
+ if (type)
+ if((type & VISIBLE_MESSAGE) && (is_blind() || paralysis) )//Vision related
+ if (!( alt ))
+ return
+ else
+ msg = alt
+ type = alt_type
+ if ((type & AUDIBLE_MESSAGE) && is_deaf())//Hearing related
+ if (!( alt ))
+ return
+ else
+ msg = alt
+ type = alt_type
+ if ((type & VISIBLE_MESSAGE) && (sdisabilities & BLIND))
+ return
+ // Added voice muffling for Issue 41.
+ if(stat == UNCONSCIOUS || sleeping > 0)
+ to_chat(src, "... You can almost hear someone talking ...")
+ else
+ to_chat(src,msg)
+ if(teleop)
+ to_chat(teleop, create_text_tag("body", "BODY:", teleop) + "[msg]")
+ return
+
+// Show a message to all mobs and objects in sight of this one
+// This would be for visible actions by the src mob
+// message is the message output to anyone who can see e.g. "[src] does something!"
+// self_message (optional) is what the src mob sees e.g. "You do something!"
+// blind_message (optional) is what blind people will hear e.g. "You hear something!"
+/mob/visible_message(var/message, var/self_message, var/blind_message, var/list/exclude_mobs = null, var/range = world.view, var/runemessage)
+ if(self_message)
+ if(LAZYLEN(exclude_mobs))
+ exclude_mobs |= src
+ else
+ exclude_mobs = list(src)
+ src.show_message(self_message, 1, blind_message, 2)
+ if(isnull(runemessage))
+ runemessage = -1
+ . = ..(message, blind_message, exclude_mobs, range, runemessage) // Really not ideal that atom/visible_message has different arg numbering :(
+
+// Returns an amount of power drawn from the object (-1 if it's not viable).
+// If drain_check is set it will not actually drain power, just return a value.
+// If surge is set, it will destroy/damage the recipient and not return any power.
+// Not sure where to define this, so it can sit here for the rest of time.
+/atom/proc/drain_power(var/drain_check,var/surge, var/amount = 0)
+ return -1
+
+// Show a message to all mobs and objects in earshot of this one
+// This would be for audible actions by the src mob
+// message is the message output to anyone who can hear.
+// self_message (optional) is what the src mob hears.
+// deaf_message (optional) is what deaf people will see.
+// hearing_distance (optional) is the range, how many tiles away the message can be heard.
+/mob/audible_message(var/message, var/deaf_message, var/hearing_distance, var/self_message, var/radio_message, var/runemessage)
+
+ var/range = hearing_distance || world.view
+ var/list/hear = get_mobs_and_objs_in_view_fast(get_turf(src),range,remote_ghosts = FALSE)
+
+ var/list/hearing_mobs = hear["mobs"]
+ var/list/hearing_objs = hear["objs"]
+
+ if(isnull(runemessage))
+ runemessage = -1 // Symmetry with mob/audible_message, despite the fact this one doesn't call parent. Maybe it should!
+
+ if(radio_message)
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.hear_talk(src, list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], radio_message)), null)
+ else
+ for(var/obj in hearing_objs)
+ var/obj/O = obj
+ O.show_message(message, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
+
+ for(var/mob in hearing_mobs)
+ var/mob/M = mob
+ var/msg = message
+ if(self_message && M==src)
+ msg = self_message
+ M.show_message(msg, AUDIBLE_MESSAGE, deaf_message, VISIBLE_MESSAGE)
+ if(runemessage != -1)
+ M.create_chat_message(src, "[runemessage || message]", FALSE, list("emote"), audible = FALSE)
+
+/mob/proc/findname(msg)
+ for(var/mob/M in mob_list)
+ if (M.real_name == text("[]", msg))
+ return M
+ return 0
+
+/mob/proc/Life()
+// if(organStructure)
+// organStructure.ProcessOrgans()
+ return
+
+#define UNBUCKLED 0
+#define PARTIALLY_BUCKLED 1
+#define FULLY_BUCKLED 2
+/mob/proc/buckled()
+ // Preliminary work for a future buckle rewrite,
+ // where one might be fully restrained (like an elecrical chair), or merely secured (shuttle chair, keeping you safe but not otherwise restrained from acting)
+ if(!buckled)
+ return UNBUCKLED
+ return restrained() ? FULLY_BUCKLED : PARTIALLY_BUCKLED
+
+/mob/proc/is_blind()
+ return ((sdisabilities & BLIND) || blinded || incapacitated(INCAPACITATION_KNOCKOUT))
+
+/mob/proc/is_deaf()
+ return ((sdisabilities & DEAF) || ear_deaf || incapacitated(INCAPACITATION_KNOCKOUT))
+
+/mob/proc/is_physically_disabled()
+ return incapacitated(INCAPACITATION_DISABLED)
+
+/mob/proc/cannot_stand()
+ return incapacitated(INCAPACITATION_KNOCKDOWN)
+
+/mob/proc/incapacitated(var/incapacitation_flags = INCAPACITATION_DEFAULT)
+ if ((incapacitation_flags & INCAPACITATION_STUNNED) && stunned)
+ return 1
+
+ if ((incapacitation_flags & INCAPACITATION_FORCELYING) && (weakened || resting))
+ return 1
+
+ if ((incapacitation_flags & INCAPACITATION_KNOCKOUT) && (stat || paralysis || sleeping || (status_flags & FAKEDEATH)))
+ return 1
+
+ if((incapacitation_flags & INCAPACITATION_RESTRAINED) && restrained())
+ return 1
+
+ if((incapacitation_flags & (INCAPACITATION_BUCKLED_PARTIALLY|INCAPACITATION_BUCKLED_FULLY)))
+ var/buckling = buckled()
+ if(buckling >= PARTIALLY_BUCKLED && (incapacitation_flags & INCAPACITATION_BUCKLED_PARTIALLY))
+ return 1
+ if(buckling == FULLY_BUCKLED && (incapacitation_flags & INCAPACITATION_BUCKLED_FULLY))
+ return 1
+
+ return 0
+
+#undef UNBUCKLED
+#undef PARTIALLY_BUCKLED
+#undef FULLY_BUCKLED
+
+/mob/proc/restrained()
+ return
+
+/mob/proc/reset_view(atom/A)
+ if (client)
+ if (istype(A, /atom/movable))
+ client.perspective = EYE_PERSPECTIVE
+ client.eye = A
+ else
+ if (isturf(loc))
+ client.eye = client.mob
+ client.perspective = MOB_PERSPECTIVE
+ else
+ client.perspective = EYE_PERSPECTIVE
+ client.eye = loc
+ return TRUE
+
+/mob/verb/pointed(atom/A as mob|obj|turf in view())
+ set name = "Point To"
+ set category = "Object"
+
+ if(!src || !isturf(src.loc) || !(A in view(src.loc)))
+ return 0
+ if(istype(A, /obj/effect/decal/point))
+ return 0
+
+ var/turf/tile = get_turf(A)
+ if (!tile)
+ return 0
+
+ var/turf/our_tile = get_turf(src)
+ var/obj/visual = new /obj/effect/decal/point(our_tile)
+ visual.invisibility = invisibility
+ visual.plane = ABOVE_PLANE
+ visual.layer = FLY_LAYER
+
+ animate(visual,
+ pixel_x = (tile.x - our_tile.x) * world.icon_size + A.pixel_x,
+ pixel_y = (tile.y - our_tile.y) * world.icon_size + A.pixel_y,
+ time = 1.7,
+ easing = EASE_OUT)
+
+ QDEL_IN(visual, 2 SECONDS) //Better qdel
+
+ face_atom(A)
+ return 1
+
+
+/mob/proc/ret_grab(list/L, flag)
+ return
+
+/mob/verb/mode()
+ set name = "Activate Held Object"
+ set category = "Object"
+ set src = usr
+
+ return
+
+/*
+/mob/verb/dump_source()
+
+ var/master = ""
+ for(var/t in typesof(/area))
+ master += text("[]\n", t)
+ //Foreach goto(26)
+ src << browse(master)
+ return
+*/
+
+/mob/verb/memory()
+ set name = "Notes"
+ set category = "IC"
+ if(mind)
+ mind.show_memory(src)
+ else
+ to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
+
+/mob/verb/add_memory(msg as message)
+ set name = "Add Note"
+ set category = "IC"
+
+ msg = sanitize(msg)
+
+ if(mind)
+ mind.store_memory(msg)
+ else
+ to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
+
+/mob/proc/store_memory(msg as message, popup, sane = 1)
+ msg = copytext(msg, 1, MAX_MESSAGE_LEN)
+
+ if (sane)
+ msg = sanitize(msg)
+
+ if (length(memory) == 0)
+ memory += msg
+ else
+ memory += "
[msg]"
+
+ if (popup)
+ memory()
+
+/mob/proc/update_flavor_text()
+ set src in usr
+ if(usr != src)
+ to_chat(usr, "No.")
+ var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb.","Flavor Text",html_decode(flavor_text)) as message|null, extra = 0) //VOREStation Edit: separating out OOC notes
+
+ if(msg != null)
+ flavor_text = msg
+
+/mob/proc/warn_flavor_changed()
+ if(flavor_text && flavor_text != "") // don't spam people that don't use it!
+ to_chat(src, "OOC Warning:
")
+ to_chat(src, "Your flavor text is likely out of date! Change")
+
+/mob/proc/print_flavor_text()
+ if (flavor_text && flavor_text != "")
+ var/msg = replacetext(flavor_text, "\n", " ")
+ if(length(msg) <= 40)
+ return "[msg]"
+ else
+ return "[copytext_preserve_html(msg, 1, 37)]... More..."
+
+/*
+/mob/verb/help()
+ set name = "Help"
+ src << browse('html/help.html', "window=help")
+ return
+*/
+
+/mob/proc/set_respawn_timer(var/time)
+ // Try to figure out what time to use
+
+ // Special cases, can never respawn
+ if(ticker?.mode?.deny_respawn)
+ time = -1
+ else if(!config.abandon_allowed)
+ time = -1
+ else if(!config.respawn)
+ time = -1
+
+ // Special case for observing before game start
+ else if(ticker?.current_state <= GAME_STATE_SETTING_UP)
+ time = 1 MINUTE
+
+ // Wasn't given a time, use the config time
+ else if(!time)
+ time = config.respawn_time
+
+ var/keytouse = ckey
+ // Try harder to find a key to use
+ if(!keytouse && key)
+ keytouse = ckey(key)
+ else if(!keytouse && mind?.key)
+ keytouse = ckey(mind.key)
+
+ GLOB.respawn_timers[keytouse] = world.time + time
+
+/mob/observer/dead/set_respawn_timer()
+ if(config.antag_hud_restricted && has_enabled_antagHUD)
+ ..(-1)
+ else
+ return // Don't set it, no need
+
+/mob/verb/abandon_mob()
+ set name = "Return to Menu"
+ set category = "OOC"
+
+ if(stat != DEAD || !ticker)
+ to_chat(usr, "You must be dead to use this!")
+ return
+
+ // Final chance to abort "respawning"
+ if(mind && timeofdeath) // They had spawned before
+ var/choice = tgui_alert(usr, "Returning to the menu will prevent your character from being revived in-round. Are you sure?", "Confirmation", list("No, wait", "Yes, leave"))
+ if(choice == "No, wait")
+ return
+
+ // Beyond this point, you're going to respawn
+ to_chat(usr, config.respawn_message)
+
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ return
+ client.screen.Cut()
+ client.screen += client.void
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ return
+
+ announce_ghost_joinleave(client, 0)
+
+ var/mob/new_player/M = new /mob/new_player()
+ if(!client)
+ log_game("[usr.key] AM failed due to disconnect.")
+ qdel(M)
+ return
+
+ M.key = key
+ if(M.mind)
+ M.mind.reset()
+ return
+
+/client/verb/changes()
+ set name = "Changelog"
+ set category = "OOC"
+ src << browse('html/changelog.html', "window=changes;size=675x650")
+ if(prefs.lastchangelog != changelog_hash)
+ prefs.lastchangelog = changelog_hash
+ SScharacter_setup.queue_preferences_save(prefs)
+ winset(src, "rpane.changelog", "background-color=none;font-style=;")
+
+/mob/verb/observe()
+ set name = "Observe"
+ set category = "OOC"
+ var/is_admin = 0
+
+ if(client.holder && (client.holder.rights & R_ADMIN|R_EVENT))
+ is_admin = 1
+ else if(stat != DEAD || istype(src, /mob/new_player))
+ to_chat(usr, "You must be observing to use this!")
+ return
+
+ if(is_admin && stat == DEAD)
+ is_admin = 0
+
+ var/list/targets = list()
+
+
+ targets += observe_list_format(nuke_disks)
+ targets += observe_list_format(all_singularities)
+ targets += getmobs()
+ targets += observe_list_format(sortAtom(mechas_list))
+ targets += observe_list_format(SSshuttles.ships)
+
+ client.perspective = EYE_PERSPECTIVE
+
+ var/eye_name = null
+
+ var/ok = "[is_admin ? "Admin Observe" : "Observe"]"
+ eye_name = tgui_input_list(usr, "Select something to [ok]:", "Select Target", targets)
+
+ if (!eye_name)
+ return
+
+ var/mob/mob_eye = targets[eye_name]
+
+ if(client && mob_eye)
+ client.eye = mob_eye
+ if (is_admin)
+ client.adminobs = 1
+ if(mob_eye == client.mob || client.eye == client.mob)
+ client.adminobs = 0
+
+/mob/verb/cancel_camera()
+ set name = "Cancel Camera View"
+ set category = "OOC"
+ unset_machine()
+ reset_view(null)
+
+/mob/Topic(href, href_list)
+ if(href_list["mach_close"])
+ var/t1 = text("window=[href_list["mach_close"]]")
+ unset_machine()
+ src << browse(null, t1)
+
+ if(href_list["flavor_more"])
+ usr << browse(text("[] []", name, replacetext(flavor_text, "\n", "
")), text("window=[];size=500x200", name))
+ onclose(usr, "[name]")
+ if(href_list["flavor_change"])
+ update_flavor_text()
+// ..()
+ return
+
+
+/mob/proc/pull_damage()
+ return 0
+
+/mob/verb/stop_pulling()
+
+ set name = "Stop Pulling"
+ set category = "IC"
+
+ if(pulling)
+ if(ishuman(pulling))
+ var/mob/living/carbon/human/H = pulling
+ visible_message(SPAN_WARNING("\The [src] lets go of \the [H]."), SPAN_NOTICE("You let go of \the [H]."), exclude_mobs = list(H))
+ if(!H.stat)
+ to_chat(H, SPAN_WARNING("\The [src] lets go of you."))
+ pulling.pulledby = null
+ pulling = null
+ if(pullin)
+ pullin.icon_state = "pull0"
+
+/mob/proc/start_pulling(var/atom/movable/AM)
+
+ if ( !AM || !usr || src==AM || !isturf(src.loc) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort!
+ return
+
+ if (AM.anchored)
+ to_chat(src, "It won't budge!")
+ return
+
+ var/mob/M = AM
+ if(ismob(AM))
+
+ if(!can_pull_mobs || !can_pull_size)
+ to_chat(src, "They won't budge!")
+ return
+
+ if((mob_size < M.mob_size) && (can_pull_mobs != MOB_PULL_LARGER))
+ to_chat(src, "[M] is too large for you to move!")
+ return
+
+ if((mob_size == M.mob_size) && (can_pull_mobs == MOB_PULL_SMALLER))
+ to_chat(src, "[M] is too heavy for you to move!")
+ return
+
+ // If your size is larger than theirs and you have some
+ // kind of mob pull value AT ALL, you will be able to pull
+ // them, so don't bother checking that explicitly.
+
+ if(M.grabbed_by.len)
+ // Only start pulling when nobody else has a grab on them
+ . = 1
+ for(var/obj/item/weapon/grab/G in M.grabbed_by)
+ if(G.assailant != usr)
+ . = 0
+ else
+ qdel(G)
+ if(!.)
+ to_chat(src, "Somebody has a grip on them!")
+ return
+
+ if(!iscarbon(src))
+ M.LAssailant = null
+ else
+ M.LAssailant = usr
+
+ else if(isobj(AM))
+ var/obj/I = AM
+ if(!can_pull_size || can_pull_size < I.w_class)
+ to_chat(src, "It won't budge!")
+ return
+
+ if(pulling)
+ var/pulling_old = pulling
+ stop_pulling()
+ // Are we pulling the same thing twice? Just stop pulling.
+ if(pulling_old == AM)
+ return
+
+ src.pulling = AM
+ AM.pulledby = src
+
+ if(pullin)
+ pullin.icon_state = "pull1"
+
+ if(ishuman(AM))
+ var/mob/living/carbon/human/H = AM
+ if(H.lying) // If they're on the ground we're probably dragging their arms to move them
+ visible_message(SPAN_WARNING("\The [src] leans down and grips \the [H]'s arms."), SPAN_NOTICE("You lean down and grip \the [H]'s arms."), exclude_mobs = list(H))
+ if(!H.stat)
+ to_chat(H, SPAN_WARNING("\The [src] leans down and grips your arms."))
+ else //Otherwise we're probably just holding their arm to lead them somewhere
+ visible_message(SPAN_WARNING("\The [src] grips \the [H]'s arm."), SPAN_NOTICE("You grip \the [H]'s arm."), exclude_mobs = list(H))
+ if(!H.stat)
+ to_chat(H, SPAN_WARNING("\The [src] grips your arm."))
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 25) //Quieter than hugging/grabbing but we still want some audio feedback
+
+ if(H.pull_damage())
+ to_chat(src, "Pulling \the [H] in their current condition would probably be a bad idea.")
+
+ //Attempted fix for people flying away through space when cuffed and dragged.
+ if(ismob(AM))
+ var/mob/pulled = AM
+ pulled.inertia_dir = 0
+
+/mob/proc/can_use_hands()
+ return
+
+/mob/proc/is_active()
+ return (0 >= usr.stat)
+
+/mob/proc/is_dead()
+ return stat == DEAD
+
+/mob/proc/is_mechanical()
+ if(mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI"))
+ return 1
+ return istype(src, /mob/living/silicon) || get_species() == "Machine"
+
+/mob/proc/is_ready()
+ return client && !!mind
+
+/mob/proc/get_gender()
+ return gender
+
+/mob/proc/see(message)
+ if(!is_active())
+ return 0
+ to_chat(src,message)
+ return 1
+
+/mob/proc/show_viewers(message)
+ for(var/mob/M in viewers())
+ M.see(message)
+
+/mob/Stat()
+ ..()
+ . = (is_client_active(10 MINUTES))
+
+ if(.)
+ if(statpanel("Status"))
+ stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
+ if(ticker && ticker.current_state != GAME_STATE_PREGAME)
+ stat("Station Time", stationtime2text())
+ stat("Station Date", stationdate2text())
+ stat("Round Duration", roundduration2text())
+
+ if(client.holder)
+ if(statpanel("Status"))
+ stat("Location:", "([x], [y], [z]) [loc]")
+ stat("CPU:","[world.cpu]")
+ stat("Instances:","[world.contents.len]")
+ stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
+
+ if(statpanel("MC"))
+ stat("Location:", "([x], [y], [z]) [loc]")
+ stat("CPU:","[world.cpu]")
+ stat("Instances:","[world.contents.len]")
+ stat("World Time:", world.time)
+ stat("Real time of day:", REALTIMEOFDAY)
+ stat(null)
+ if(GLOB)
+ GLOB.stat_entry()
+ else
+ stat("Globals:", "ERROR")
+ if(Master)
+ Master.stat_entry()
+ else
+ stat("Master Controller:", "ERROR")
+ if(Failsafe)
+ Failsafe.stat_entry()
+ else
+ stat("Failsafe Controller:", "ERROR")
+ if(Master)
+ stat(null)
+ for(var/datum/controller/subsystem/SS in Master.subsystems)
+ SS.stat_entry()
+
+ if(statpanel("Tickets"))
+ GLOB.ahelp_tickets.stat_entry()
+
+
+ if(length(GLOB.sdql2_queries))
+ if(statpanel("SDQL2"))
+ stat("Access Global SDQL2 List", GLOB.sdql2_vv_statobj)
+ for(var/i in GLOB.sdql2_queries)
+ var/datum/SDQL2_query/Q = i
+ Q.generate_stat()
+
+ if(listed_turf && client)
+ if(!TurfAdjacent(listed_turf))
+ listed_turf = null
+ else
+ if(statpanel("Turf"))
+ stat(listed_turf)
+ for(var/atom/A in listed_turf)
+ if(!A.mouse_opacity)
+ continue
+ if(A.invisibility > see_invisible)
+ continue
+ if(is_type_in_list(A, shouldnt_see))
+ continue
+ if(A.plane > plane)
+ continue
+ stat(A)
+
+
+// facing verbs
+/mob/proc/canface()
+// if(!canmove) return 0 //VOREStation Edit. Redundant check that only affects conscious proning, actual inability to turn and shift around handled by actual inabilities.
+ if(stat) return 0
+ if(anchored) return 0
+ if(transforming) return 0
+ return 1
+
+// Not sure what to call this. Used to check if humans are wearing an AI-controlled exosuit and hence don't need to fall over yet.
+/mob/proc/can_stand_overridden()
+ return 0
+
+//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
+/mob/proc/update_canmove()
+ return canmove
+
+
+/mob/proc/facedir(var/ndir)
+ if(!canface() || (client && (client.moving || !checkMoveCooldown())))
+ return 0
+ set_dir(ndir)
+ if(buckled && buckled.buckle_movable)
+ buckled.set_dir(ndir)
+ setMoveCooldown(movement_delay())
+ return 1
+
+
+/mob/verb/eastface()
+ set hidden = 1
+ return facedir(client.client_dir(EAST))
+
+
+/mob/verb/westface()
+ set hidden = 1
+ return facedir(client.client_dir(WEST))
+
+
+/mob/verb/northface()
+ set hidden = 1
+ return facedir(client.client_dir(NORTH))
+
+
+/mob/verb/southface()
+ set hidden = 1
+ return facedir(client.client_dir(SOUTH))
+
+
+//This might need a rename but it should replace the can this mob use things check
+/mob/proc/IsAdvancedToolUser()
+ return 0
+
+/mob/proc/Stun(amount)
+ if(status_flags & CANSTUN)
+ facing_dir = null
+ stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
+ if(status_flags & CANSTUN)
+ stunned = max(amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/AdjustStunned(amount)
+ if(status_flags & CANSTUN)
+ stunned = max(stunned + amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/Weaken(amount)
+ if(status_flags & CANWEAKEN)
+ facing_dir = null
+ weakened = max(max(weakened,amount),0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/SetWeakened(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(amount,0)
+ update_canmove() //can you guess what this does yet?
+ return
+
+/mob/proc/AdjustWeakened(amount)
+ if(status_flags & CANWEAKEN)
+ weakened = max(weakened + amount,0)
+ update_canmove() //updates lying, canmove and icons
+ return
+
+/mob/proc/Paralyse(amount)
+ if(status_flags & CANPARALYSE)
+ facing_dir = null
+ paralysis = max(max(paralysis,amount),0)
+ return
+
+/mob/proc/SetParalysis(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(amount,0)
+ return
+
+/mob/proc/AdjustParalysis(amount)
+ if(status_flags & CANPARALYSE)
+ paralysis = max(paralysis + amount,0)
+ return
+
+/mob/proc/Sleeping(amount)
+ facing_dir = null
+ sleeping = max(max(sleeping,amount),0)
+ return
+
+/mob/proc/SetSleeping(amount)
+ sleeping = max(amount,0)
+ return
+
+/mob/proc/AdjustSleeping(amount)
+ sleeping = max(sleeping + amount,0)
+ return
+
+/mob/proc/Confuse(amount)
+ confused = max(max(confused,amount),0)
+ return
+
+/mob/proc/SetConfused(amount)
+ confused = max(amount,0)
+ return
+
+/mob/proc/AdjustConfused(amount)
+ confused = max(confused + amount,0)
+ return
+
+/mob/proc/Blind(amount)
+ eye_blind = max(max(eye_blind,amount),0)
+ return
+
+/mob/proc/SetBlinded(amount)
+ eye_blind = max(amount,0)
+ return
+
+/mob/proc/AdjustBlinded(amount)
+ eye_blind = max(eye_blind + amount,0)
+ return
+
+/mob/proc/Resting(amount)
+ facing_dir = null
+ resting = max(max(resting,amount),0)
+ update_canmove()
+ return
+
+/mob/proc/SetResting(amount)
+ resting = max(amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustResting(amount)
+ resting = max(resting + amount,0)
+ update_canmove()
+ return
+
+/mob/proc/AdjustLosebreath(amount)
+ losebreath = CLAMP(losebreath + amount, 0, 25)
+
+/mob/proc/SetLosebreath(amount)
+ losebreath = CLAMP(amount, 0, 25)
+
+/mob/proc/get_species()
+ return ""
+
+/mob/proc/flash_weak_pain()
+ flick("weak_pain",pain)
+
+/mob/proc/get_visible_implants(var/class = 0)
+ var/list/visible_implants = list()
+ for(var/obj/item/O in embedded)
+ if(O.w_class > class)
+ visible_implants += O
+ return visible_implants
+
+/mob/proc/embedded_needs_process()
+ return (embedded.len > 0)
+
+/mob/proc/yank_out_object()
+ set category = "Object"
+ set name = "Yank out object"
+ set desc = "Remove an embedded item at the cost of bleeding and pain."
+ set src in view(1)
+
+ if(!isliving(usr) || !usr.checkClickCooldown())
+ return
+ usr.setClickCooldown(20)
+
+ if(usr.stat == 1)
+ to_chat(usr, "You are unconcious and cannot do that!")
+ return
+
+ if(usr.restrained())
+ to_chat(usr, "You are restrained and cannot do that!")
+ return
+
+ var/mob/S = src
+ var/mob/U = usr
+ var/list/valid_objects = list()
+ var/self = null
+
+ if(S == U)
+ self = 1 // Removing object from yourself.
+
+ valid_objects = get_visible_implants(0)
+ if(!valid_objects.len)
+ if(self)
+ to_chat(src, "You have nothing stuck in your body that is large enough to remove.")
+ else
+ to_chat(U, "[src] has nothing stuck in their wounds that is large enough to remove.")
+ return
+
+ var/obj/item/weapon/selection = tgui_input_list(usr, "What do you want to yank out?", "Embedded objects", valid_objects)
+
+ if(self)
+ to_chat(src, "You attempt to get a good grip on [selection] in your body.")
+ else
+ to_chat(U, "You attempt to get a good grip on [selection] in [S]'s body.")
+
+ if(!do_after(U, 30))
+ return
+ if(!selection || !S || !U)
+ return
+
+ if(self)
+ visible_message("[src] rips [selection] out of their body.","You rip [selection] out of your body.")
+ else
+ visible_message("[usr] rips [selection] out of [src]'s body.","[usr] rips [selection] out of your body.")
+ valid_objects = get_visible_implants(0)
+ if(valid_objects.len == 1) //Yanking out last object - removing verb.
+ src.verbs -= /mob/proc/yank_out_object
+ clear_alert("embeddedobject")
+
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ var/obj/item/organ/external/affected
+
+ for(var/obj/item/organ/external/organ in H.organs) //Grab the organ holding the implant.
+ for(var/obj/item/O in organ.implants)
+ if(O == selection)
+ affected = organ
+
+ affected.implants -= selection
+ H.shock_stage+=20
+ affected.take_damage((selection.w_class * 3), 0, 0, 1, "Embedded object extraction")
+
+ if(prob(selection.w_class * 5) && (affected.robotic < ORGAN_ROBOT)) //I'M SO ANEMIC I COULD JUST -DIE-.
+ var/datum/wound/internal_bleeding/I = new (min(selection.w_class * 5, 15))
+ affected.wounds += I
+ H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 50)
+
+ if (ishuman(U))
+ var/mob/living/carbon/human/human_user = U
+ human_user.bloody_hands(H)
+
+ else if(issilicon(src))
+ var/mob/living/silicon/robot/R = src
+ R.embedded -= selection
+ R.adjustBruteLoss(5)
+ R.adjustFireLoss(10)
+
+ selection.forceMove(get_turf(src))
+ U.put_in_hands(selection)
+
+ for(var/obj/item/weapon/O in pinned)
+ if(O == selection)
+ pinned -= O
+ if(!pinned.len)
+ anchored = 0
+ return 1
+
+//Check for brain worms in head.
+/mob/proc/has_brain_worms()
+
+ for(var/I in contents)
+ if(istype(I,/mob/living/simple_mob/animal/borer))
+ return I
+
+ return 0
+
+/mob/proc/updateicon()
+ return
+
+// Please always use this proc, never just set the var directly.
+/mob/proc/set_stat(var/new_stat)
+ . = (stat != new_stat)
+ stat = new_stat
+
+/mob/verb/face_direction()
+
+ set name = "Face Direction"
+ set category = "IC"
+ set src = usr
+
+ set_face_dir()
+
+ if(!facing_dir)
+ to_chat(usr, "You are now not facing anything.")
+ else
+ to_chat(usr, "You are now facing [dir2text(facing_dir)].")
+
+/mob/proc/set_face_dir(var/newdir)
+ if(newdir == facing_dir)
+ facing_dir = null
+ else if(newdir)
+ set_dir(newdir)
+ facing_dir = newdir
+ else if(facing_dir)
+ facing_dir = null
+ else
+ set_dir(dir)
+ facing_dir = dir
+
+/mob/set_dir()
+ if(facing_dir)
+ if(!canface() || lying || buckled || restrained())
+ facing_dir = null
+ else if(dir != facing_dir)
+ return ..(facing_dir)
+ else
+ return ..()
+
+/mob/verb/northfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(NORTH))
+
+/mob/verb/southfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(SOUTH))
+
+/mob/verb/eastfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(EAST))
+
+/mob/verb/westfaceperm()
+ set hidden = 1
+ set_face_dir(client.client_dir(WEST))
+
+// Begin VOREstation edit
+/mob/verb/shiftnorth()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_y <= (default_pixel_y + 16))
+ pixel_y++
+ is_shifted = TRUE
+
+/mob/verb/shiftsouth()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_y >= (default_pixel_y - 16))
+ pixel_y--
+ is_shifted = TRUE
+
+/mob/verb/shiftwest()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_x >= (default_pixel_x - 16))
+ pixel_x--
+ is_shifted = TRUE
+
+/mob/verb/shifteast()
+ set hidden = TRUE
+ if(!canface())
+ return FALSE
+ if(pixel_x <= (default_pixel_x + 16))
+ pixel_x++
+ is_shifted = TRUE
+// End VOREstation edit
+
+/mob/proc/adjustEarDamage()
+ return
+
+/mob/proc/setEarDamage()
+ return
+
+// Set client view distance (size of client's screen). Returns TRUE if anything changed.
+/mob/proc/set_viewsize(var/new_view = world.view)
+ if (client && new_view != client.view)
+ client.view = new_view
+ return TRUE
+ return FALSE
+
+//Throwing stuff
+
+/mob/proc/toggle_throw_mode()
+ if (src.in_throw_mode)
+ throw_mode_off()
+ else
+ throw_mode_on()
+
+/mob/proc/throw_mode_off()
+ src.in_throw_mode = 0
+ if(src.throw_icon) //in case we don't have the HUD and we use the hotkey
+ src.throw_icon.icon_state = "act_throw_off"
+
+/mob/proc/throw_mode_on()
+ src.in_throw_mode = 1
+ if(src.throw_icon)
+ src.throw_icon.icon_state = "act_throw_on"
+
+/mob/proc/isSynthetic()
+ return 0
+
+/mob/proc/is_muzzled()
+ return 0
+
+//Exploitable Info Update
+
+/mob/proc/amend_exploitable(var/obj/item/I)
+ if(istype(I))
+ exploit_addons |= I
+ var/exploitmsg = html_decode("\n" + "Has " + I.name + ".")
+ exploit_record += exploitmsg
+
+/client/proc/check_has_body_select()
+ return mob && mob.hud_used && istype(mob.zone_sel, /obj/screen/zone_sel)
+
+/client/verb/body_toggle_head()
+ set name = "body-toggle-head"
+ set hidden = 1
+ toggle_zone_sel(list(BP_HEAD, O_EYES, O_MOUTH))
+
+/client/verb/body_r_arm()
+ set name = "body-r-arm"
+ set hidden = 1
+ toggle_zone_sel(list(BP_R_ARM,BP_R_HAND))
+
+/client/verb/body_l_arm()
+ set name = "body-l-arm"
+ set hidden = 1
+ toggle_zone_sel(list(BP_L_ARM,BP_L_HAND))
+
+/client/verb/body_chest()
+ set name = "body-chest"
+ set hidden = 1
+ toggle_zone_sel(list(BP_TORSO))
+
+/client/verb/body_groin()
+ set name = "body-groin"
+ set hidden = 1
+ toggle_zone_sel(list(BP_GROIN))
+
+/client/verb/body_r_leg()
+ set name = "body-r-leg"
+ set hidden = 1
+ toggle_zone_sel(list(BP_R_LEG,BP_R_FOOT))
+
+/client/verb/body_l_leg()
+ set name = "body-l-leg"
+ set hidden = 1
+ toggle_zone_sel(list(BP_L_LEG,BP_L_FOOT))
+
+/client/proc/toggle_zone_sel(list/zones)
+ if(!check_has_body_select())
+ return
+ var/obj/screen/zone_sel/selector = mob.zone_sel
+ selector.set_selected_zone(next_in_list(mob.zone_sel.selecting,zones))
+
+// This handles setting the client's color variable, which makes everything look a specific color.
+// This proc is here so it can be called without needing to check if the client exists, or if the client relogs.
+// This is for inheritence since /mob/living will serve most cases. If you need ghosts to use this you'll have to implement that yourself.
+/mob/proc/update_client_color()
+ if(client && client.color)
+ animate(client, color = null, time = 10)
+ return
+
+/mob/proc/swap_hand()
+ return
+
+//Throwing stuff
+/mob/proc/throw_item(atom/target)
+ return
+
+/mob/proc/will_show_tooltip()
+ if(alpha <= EFFECTIVE_INVIS)
+ return FALSE
+ return TRUE
+
+/mob/MouseEntered(location, control, params)
+ if(usr != src && usr.is_preference_enabled(/datum/client_preference/mob_tooltips) && src.will_show_tooltip())
+ openToolTip(user = usr, tip_src = src, params = params, title = get_nametag_name(usr), content = get_nametag_desc(usr))
+
+ ..()
+
+/mob/MouseDown()
+ closeToolTip(usr) //No reason not to, really
+
+ ..()
+
+/mob/MouseExited()
+ closeToolTip(usr) //No reason not to, really
+
+ ..()
+
+// Manages a global list of mobs with clients attached, indexed by z-level.
+/mob/proc/update_client_z(new_z) // +1 to register, null to unregister.
+ if(registered_z != new_z)
+ if(registered_z)
+ GLOB.players_by_zlevel[registered_z] -= src
+ if(client)
+ if(new_z)
+ GLOB.players_by_zlevel[new_z] += src
+ registered_z = new_z
+ else
+ registered_z = null
+
+GLOBAL_LIST_EMPTY_TYPED(living_players_by_zlevel, /list)
+/mob/living/update_client_z(new_z)
+ var/precall_reg_z = registered_z
+ . = ..() // will update registered_z if necessary
+ if(precall_reg_z != registered_z) // parent did work, let's do work too
+ if(precall_reg_z)
+ GLOB.living_players_by_zlevel[precall_reg_z] -= src
+ if(registered_z)
+ GLOB.living_players_by_zlevel[registered_z] += src
+
+/mob/onTransitZ(old_z, new_z)
+ ..()
+ update_client_z(new_z)
+
+/mob/cloak()
+ . = ..()
+ if(client && cloaked_selfimage)
+ client.images += cloaked_selfimage
+
+/mob/uncloak()
+ if(client && cloaked_selfimage)
+ client.images -= cloaked_selfimage
+ return ..()
+
+/mob/get_cloaked_selfimage()
+ var/icon/selficon = getCompoundIcon(src)
+ selficon.MapColors(0,0,0, 0,0,0, 0,0,0, 1,1,1) //White
+ var/image/selfimage = image(selficon)
+ selfimage.color = "#0000FF"
+ selfimage.alpha = 100
+ selfimage.layer = initial(layer)
+ selfimage.plane = initial(plane)
+ selfimage.loc = src
+
+ return selfimage
+
+/mob/proc/GetAltName()
+ return ""
+
+/mob/proc/get_ghost(even_if_they_cant_reenter = 0)
+ if(mind)
+ return mind.get_ghost(even_if_they_cant_reenter)
+
+/mob/proc/grab_ghost(force)
+ if(mind)
+ return mind.grab_ghost(force = force)
+>>>>>>> b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index a0ca4cd492..b2c1ca4ede 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -4,6 +4,8 @@
plane = MOB_PLANE
animate_movement = 2
blocks_emissive = EMISSIVE_BLOCK_GENERIC
+ ///when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
+ vis_flags = VIS_INHERIT_PLANE
var/datum/mind/mind
var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak
diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm
index cfd4a91729..49d90a5a95 100644
--- a/code/modules/mob/mob_planes.dm
+++ b/code/modules/mob/mob_planes.dm
@@ -18,6 +18,7 @@
plane_masters[VIS_LIGHTING] = new /obj/screen/plane_master/lighting //Lighting system (but different!)
plane_masters[VIS_O_LIGHT] = new /obj/screen/plane_master/o_light_visual //Object lighting (using masks)
plane_masters[VIS_EMISSIVE] = new /obj/screen/plane_master/emissive //Emissive overlays
+ plane_masters[VIS_OPENSPACE] = new /obj/screen/plane_master/openspace //Openspace drop shadows mostly
plane_masters[VIS_GHOSTS] = new /obj/screen/plane_master/ghosts //Ghosts!
plane_masters[VIS_AI_EYE] = new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye!
@@ -223,6 +224,20 @@
. = ..()
add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix))
+/////////////////
+//Openspace gets some magic filters for layers
+/obj/screen/plane_master/openspace
+ plane = OPENSPACE_BACKDROP_PLANE
+ blend_mode = BLEND_MULTIPLY
+ alpha = 255
+
+/obj/screen/plane_master/openspace/Initialize()
+ . = ..()
+ //add_filter("multiz_lighting_mask", 1, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)) // Makes fake planet lights not work right
+ add_filter("first_stage_openspace", 2, drop_shadow_filter(color = "#04080FAA", size = -10))
+ add_filter("second_stage_openspace", 3, drop_shadow_filter(color = "#04080FAA", size = -15))
+ //add_filter("third_stage_openspace", 4, drop_shadow_filter(color = "#04080FAA", size = -20)) // TOO dark
+
/////////////////
//Ghosts has a special alpha level
/obj/screen/plane_master/ghosts
diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm
index bf4a770f54..80cace290a 100644
--- a/code/modules/mob/typing_indicator.dm
+++ b/code/modules/mob/typing_indicator.dm
@@ -33,9 +33,6 @@
cut_overlay(typing_indicator, TRUE)
typing = FALSE
- if(shadow) //Multi-Z above-me shadows
- shadow.set_typing_indicator(state)
-
return state
/mob/verb/say_wrapper()
diff --git a/code/modules/multiz/_stubs.dm b/code/modules/multiz/_stubs.dm
index a9d1d456b1..2b8fe09e0d 100644
--- a/code/modules/multiz/_stubs.dm
+++ b/code/modules/multiz/_stubs.dm
@@ -5,12 +5,3 @@
var/height = 1 ///< The number of Z-Levels in the map.
var/turf/edge_type ///< What the map edge should be formed with. (null = world.turf)
-
-// FOR THE LOVE OF GOD USE THESE. DO NOT FUCKING SPAGHETTIFY THIS.
-// Use the Has*() functions if you ONLY need to check.
-// If you need to do something, use Get*().
-/HasAbove(var/z)
-/HasBelow(var/z)
-// These give either the turf or null.
-/GetAbove(var/atom/atom)
-/GetBelow(var/atom/atom)
\ No newline at end of file
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index 15c000cdc5..ab2bcf6e3d 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -1,3 +1,4 @@
+/// Multiz support override for CanZPass
/turf/proc/CanZPass(atom/A, direction)
if(z == A.z) //moving FROM this turf
return direction == UP //can't go below
@@ -7,84 +8,81 @@
if(direction == DOWN) //on a turf above, trying to enter
return !density && isopenspace(GetAbove(src)) // VOREStation Edit
+/// Multiz support override for CanZPass
/turf/simulated/open/CanZPass(atom, direction)
return 1
+/// Multiz support override for CanZPass
/turf/space/CanZPass(atom, direction)
return 1
+/// WARNING WARNING
+/// Turfs DO NOT lose their signals when they get replaced, REMEMBER THIS
+/// It's possible because turfs are fucked, and if you have one in a list and it's replaced with another one, the list ref points to the new turf
+/// We do it because moving signals over was needlessly expensive, and bloated a very commonly used bit of code
+/turf/proc/multiz_turf_del(turf/T, dir)
+ SEND_SIGNAL(src, COMSIG_TURF_MULTIZ_DEL, T, dir)
+
+/turf/proc/multiz_turf_new(turf/T, dir)
+ SEND_SIGNAL(src, COMSIG_TURF_MULTIZ_NEW, T, dir)
+
//
// Open Space - "empty" turf that lets stuff fall thru it to the layer below
//
+GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdrop, new)
+
+/atom/movable/openspace_backdrop
+ name = "openspace_backdrop"
+
+ anchored = TRUE
+
+ icon = 'icons/turf/floors.dmi'
+ icon_state = "grey"
+ plane = OPENSPACE_BACKDROP_PLANE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ vis_flags = VIS_INHERIT_ID
+
/turf/simulated/open
name = "open space"
- icon = 'icons/turf/space.dmi'
- icon_state = ""
- desc = "\..."
+ icon = 'icons/turf/floors.dmi'
+ icon_state = "invisible"
+ desc = "Watch your step!"
density = 0
- plane = OPENSPACE_PLANE_START
+ plane = OPENSPACE_PLANE
pathweight = 100000 //Seriously, don't try and path over this one numbnuts
dynamic_lighting = 0 // Someday lets do proper lighting z-transfer. Until then we are leaving this off so it looks nicer.
can_build_into_floor = TRUE
- var/turf/below
-
/turf/simulated/open/vacuum
oxygen = 0
nitrogen = 0
temperature = TCMB
-/turf/simulated/open/post_change()
- ..()
- update()
-
-/turf/simulated/open/ChangeTurf(var/turf/N, var/tell_universe, var/force_lighting_update, var/preserve_outdoors)
- var/turf/T = GetBelow(src)
- if(T)
- GLOB.turf_entered_event.unregister(T, src, .proc/BelowOpenUpdated)
- GLOB.turf_exited_event.unregister(T, src, .proc/BelowOpenUpdated)
- . = ..()
-
/turf/simulated/open/Initialize()
. = ..()
ASSERT(HasBelow(z))
- update()
- var/turf/T = GetBelow(src)
- if(T)
- GLOB.turf_entered_event.register(T, src, .proc/BelowOpenUpdated)
- GLOB.turf_exited_event.register(T, src, .proc/BelowOpenUpdated)
+ add_overlay(GLOB.openspace_backdrop_one_for_all, TRUE) //Special grey square for projecting backdrop darkness filter on it.
+ return INITIALIZE_HINT_LATELOAD
+/turf/simulated/open/LateInitialize()
+ . = ..()
+ AddElement(/datum/element/turf_z_transparency, FALSE)
+ update_icon()
/turf/simulated/open/Entered(var/atom/movable/mover, var/atom/oldloc)
..()
mover.fall()
-/turf/simulated/open/proc/BelowOpenUpdated(turf/T, atom/movable/AM, old_loc)
- if(isobj(AM) && GLOB.open_space_initialised && !AM.invisibility)
- SSopen_space.add_turf(src, 1)
+/turf/simulated/open/proc/update()
+ for(var/atom/movable/A in src)
+ A.fall()
// Called when thrown object lands on this turf.
/turf/simulated/open/hitby(var/atom/movable/AM, var/speed)
. = ..()
AM.fall()
-/turf/simulated/open/proc/update()
- plane = OPENSPACE_PLANE + src.z
- below = GetBelow(src)
- turf_changed_event.register(below, src, /atom/proc/update_icon)
- levelupdate()
- below.update_icon() // So the 'ceiling-less' overlay gets added.
- for(var/atom/movable/A in src)
- A.fall()
- if(GLOB.open_space_initialised)
- SSopen_space.add_turf(src, TRUE)
-
-// override to make sure nothing is hidden
-/turf/simulated/open/levelupdate()
- for(var/obj/O in src)
- O.hide(0)
-
/turf/simulated/open/examine(mob/user, distance, infix, suffix)
. = ..()
if(Adjacent(user))
@@ -93,50 +91,9 @@
depth += 1
. += "It is about [depth] levels deep."
-/**
-* Update icon and overlays of open space to be that of the turf below, plus any visible objects on that turf.
-*/
/turf/simulated/open/update_icon()
- cut_overlays() // Edit - Overlays are being crashy when modified.
- update_icon_edge()// Add - Get grass into open spaces and whatnot.
- if(below)
- // Skybox lives on its own plane, if we don't set it to see that, then open space tiles over true space tiles see white nothingness below
- if(is_space())
- plane = SPACE_PLANE
- else
- plane = OPENSPACE_PLANE + src.z
-
- var/below_is_open = isopenspace(below)
-
- if(below_is_open)
- underlays = below.underlays
- else
- var/image/bottom_turf = image(icon = below.icon, icon_state = below.icon_state, dir=below.dir, layer=below.layer)
- bottom_turf.plane = src.plane
- bottom_turf.color = below.color
- underlays = list(bottom_turf)
- copy_overlays(below)
-
- // get objects (not mobs, they are handled by /obj/zshadow)
- var/list/o_img = list()
- for(var/obj/O in below)
- if(O.invisibility) continue // Ignore objects that have any form of invisibility
- if(O.loc != below) continue // Ignore multi-turf objects not directly below
- var/image/temp2 = image(O, dir = O.dir, layer = O.layer)
- if(temp2.icon == null)
- temp2.icon_state = null
- temp2.plane = src.plane
- temp2.color = O.color
- temp2.overlays = get_overlays(O, TRUE)
- // TODO Is pixelx/y needed?
- o_img += temp2
- add_overlay(o_img)
-
- if(!below_is_open)
- add_overlay(SSopen_space.over_OS_darkness)
-
- return 0
- return PROCESS_KILL
+ cut_overlays()
+ update_icon_edge()
// Straight copy from space.
/turf/simulated/open/attackby(obj/item/C as obj, mob/user as mob)
@@ -189,3 +146,84 @@
if(!O.CanFallThru(L, GetBelow(src)))
return TRUE // Can't fall through this, like lattice or catwalk.
return ..()
+
+
+/turf/simulated/floor/glass
+ name = "glass floor"
+ desc = "Dont jump on it, or do, I'm not your mom."
+ icon = 'icons/turf/flooring/glass.dmi'
+ icon_state = "glass-0"
+ base_icon_state = "glass"
+ /*
+ baseturfs = /turf/simulated/openspace
+ intact = FALSE //this means wires go on top
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = list(SMOOTH_GROUP_TURF_OPEN, SMOOTH_GROUP_FLOOR_TRANSPARENT_GLASS)
+ canSmoothWith = list(SMOOTH_GROUP_FLOOR_TRANSPARENT_GLASS)
+ footstep = FOOTSTEP_PLATING
+ barefootstep = FOOTSTEP_HARD_BAREFOOT
+ clawfootstep = FOOTSTEP_HARD_CLAW
+ heavyfootstep = FOOTSTEP_GENERIC_HEAVY
+ */
+
+// /turf/simulated/floor/glass/setup_broken_states()
+// return list("glass-damaged1", "glass-damaged2", "glass-damaged3")
+
+/turf/simulated/floor/glass/Initialize()
+ icon_state = "" //Prevent the normal icon from appearing behind the smooth overlays
+ ..()
+ return INITIALIZE_HINT_LATELOAD
+
+/turf/simulated/floor/glass/LateInitialize()
+ . = ..()
+ AddElement(/datum/element/turf_z_transparency, TRUE)
+ blend_icons()
+
+// TG's icon blending method because I don't want to redo all the icon states AAA
+
+//Redefinitions of the diagonal directions so they can be stored in one var without conflicts
+/turf/simulated/floor/glass/proc/blend_icons()
+ var/new_junction = NONE
+
+ for(var/direction in cardinal) //Cardinal case first.
+ var/turf/T = get_step(src, direction)
+ if(istype(T, type))
+ new_junction |= direction
+
+ if(!(new_junction & (NORTH|SOUTH)) || !(new_junction & (EAST|WEST)))
+ icon_state = "[base_icon_state]-[new_junction]"
+ return
+
+ if(new_junction & NORTH)
+ if(new_junction & WEST)
+ var/turf/T = get_step(src, NORTHWEST)
+ if(istype(T, type))
+ new_junction |= (1<<7)
+
+ if(new_junction & EAST)
+ var/turf/T = get_step(src, NORTHEAST)
+ if(istype(T, type))
+ new_junction |= (1<<4)
+
+ if(new_junction & SOUTH)
+ if(new_junction & WEST)
+ var/turf/T = get_step(src, SOUTHWEST)
+ if(istype(T, type))
+ new_junction |= (1<<6)
+
+ if(new_junction & EAST)
+ var/turf/T = get_step(src, SOUTHEAST)
+ if(istype(T, type))
+ new_junction |= (1<<5)
+
+ icon_state = "[base_icon_state]-[new_junction]"
+
+/turf/simulated/floor/glass/reinforced
+ name = "reinforced glass floor"
+ desc = "Do jump on it, it can take it."
+ icon = 'icons/turf/flooring/reinf_glass.dmi'
+ icon_state = "reinf_glass-0"
+ base_icon_state = "reinf_glass"
+
+// /turf/simulated/floor/glass/reinforced/setup_broken_states()
+// return list("reinf_glass-damaged1", "reinf_glass-damaged2", "reinf_glass-damaged3")
diff --git a/code/modules/multiz/zshadow.dm b/code/modules/multiz/zshadow.dm
deleted file mode 100644
index 3b6efa34d0..0000000000
--- a/code/modules/multiz/zshadow.dm
+++ /dev/null
@@ -1,126 +0,0 @@
-/mob // TODO: rewrite as obj.
- var/mob/zshadow/shadow
-
-/mob/zshadow
- plane = OVER_OPENSPACE_PLANE
- name = "shadow"
- desc = "Z-level shadow"
- status_flags = GODMODE
- anchored = 1
- unacidable = 1
- density = 0
- opacity = 0 // Don't trigger lighting recalcs gah! TODO - consider multi-z lighting.
- //auto_init = FALSE // We do not need to be initialize()d
- var/mob/owner = null // What we are a shadow of.
-
-/mob/zshadow/can_fall()
- return FALSE
-
-/mob/zshadow/New(var/mob/L)
- if(!istype(L))
- qdel(src)
- return
- owner = L
- sync_icon(L)
-
-/mob/zshadow/Destroy()
- owner.shadow = null
- owner = null
- ..() //But we don't return because the hint is wrong
- return QDEL_HINT_QUEUE
-
-/mob/Destroy()
- QDEL_NULL(shadow)
- . = ..()
-
-/mob/zshadow/examine(mob/user, distance, infix, suffix)
- if(!owner)
- // The only time we should have a null owner is if we are in nullspace. Help figure out why we were examined.
- crash_with("[src] ([type]) @ [log_info_line()] was examined by [user] @ [global.log_info_line(user)]")
- return list()
- return owner.examine(user, distance, infix, suffix)
-
-// Relay some stuff they hear
-/mob/zshadow/hear_say(var/list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
- if(speaker && speaker.z != src.z)
- return // Only relay speech on our acutal z, otherwise we might relay sounds that were themselves relayed up!
- if(isliving(owner))
- verb += " from above"
- return owner.hear_say(message_pieces, verb, italics, speaker, speech_sound, sound_vol)
-
-/mob/zshadow/proc/sync_icon(var/mob/M)
- name = M.name
- icon = M.icon
- icon_state = M.icon_state
- //color = M.color
- color = "#848484"
- overlays = M.overlays
- transform = M.transform
- dir = M.dir
- invisibility = M.invisibility
- if(shadow)
- shadow.sync_icon(src)
-
-/mob/living/Moved()
- . = ..()
- check_shadow()
-
-/mob/living/forceMove()
- . = ..()
- check_shadow()
-
-/mob/living/on_mob_jump()
- // We're about to be admin-jumped.
- // Unfortuantely loc isn't set until after this proc is called. So we must spawn() so check_shadow executes with the new loc.
- . = ..()
- if(shadow)
- spawn(0)
- check_shadow()
-
-/mob/living/proc/check_shadow()
- var/mob/M = src
- if(isturf(M.loc))
- var/turf/simulated/open/OS = GetAbove(src)
- while(OS && istype(OS))
- if(!M.shadow)
- M.shadow = new /mob/zshadow(M)
- M.shadow.forceMove(OS)
- M = M.shadow
- OS = GetAbove(M)
- // The topmost level does not need a shadow!
- if(M.shadow)
- qdel(M.shadow)
- M.shadow = null
-
-//
-// Handle cases where the owner mob might have changed its icon or overlays.
-//
-
-/mob/living/update_icons()
- . = ..()
- if(shadow)
- shadow.sync_icon(src)
-
-// WARNING - the true carbon/human/update_icons does not call ..(), therefore we must sideways override this.
-// But be careful, we don't want to screw with that proc. So lets be cautious about what we do here.
-/mob/living/carbon/human/update_icons()
- . = ..()
- if(shadow)
- shadow.sync_icon(src)
-
-/mob/set_dir(new_dir)
- . = ..()
- if(shadow)
- shadow.set_dir(new_dir)
-
-/mob/zshadow/set_typing_indicator(var/state)
- if(!typing_indicator)
- init_typing_indicator("typing")
- if(state && !typing)
- add_overlay(typing_indicator)
- typing = 1
- else if(!state && typing)
- cut_overlay(typing_indicator)
- typing = 0
- if(shadow)
- shadow.set_typing_indicator(state)
diff --git a/code/modules/persistence/graffiti.dm b/code/modules/persistence/graffiti.dm
index 9f0a7c3a32..d50a24a370 100644
--- a/code/modules/persistence/graffiti.dm
+++ b/code/modules/persistence/graffiti.dm
@@ -4,6 +4,7 @@
icon = 'icons/effects/writing.dmi'
desc = "It looks like someone has scratched something here."
plane = DIRTY_PLANE
+ layer = DIRTY_LAYER
gender = PLURAL
blend_mode = BLEND_MULTIPLY
color = "#000000"
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index eb26ea848e..0d16617feb 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -86,6 +86,7 @@ GLOBAL_LIST_EMPTY(apcs)
clicksound = "switch"
req_access = list(access_engine_equip)
blocks_emissive = FALSE
+ vis_flags = VIS_HIDE // They have an emissive that looks bad in openspace due to their wall-mounted nature
var/area/area
var/areastring = null
var/obj/item/weapon/cell/cell
diff --git a/icons/turf/flooring/glass.dmi b/icons/turf/flooring/glass.dmi
new file mode 100644
index 0000000000..e28bb13e23
Binary files /dev/null and b/icons/turf/flooring/glass.dmi differ
diff --git a/icons/turf/flooring/reinf_glass.dmi b/icons/turf/flooring/reinf_glass.dmi
new file mode 100644
index 0000000000..97614f510f
Binary files /dev/null and b/icons/turf/flooring/reinf_glass.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index f95702fa27..978eb5d9c7 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/maps/offmap_vr/om_ships/itglight.dmm b/maps/offmap_vr/om_ships/itglight.dmm
index 1bb19ea182..6c8a11d2aa 100644
--- a/maps/offmap_vr/om_ships/itglight.dmm
+++ b/maps/offmap_vr/om_ships/itglight.dmm
@@ -27,6 +27,13 @@
pixel_x = -26
},
/mob/living/simple_mob/vore/woof/cass,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"ac" = (
@@ -3355,6 +3362,19 @@
/obj/machinery/smartfridge/chemistry,
/turf/simulated/floor/tiled/eris/white/cargo,
/area/itglight/medbay)
+"wc" = (
+/obj/structure/bed/chair/comfy/brown{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
+/turf/simulated/floor/tiled/eris/steel/brown_platform,
+/area/itglight/common)
"wg" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -3545,10 +3565,7 @@
/obj/structure/bed/chair/comfy/brown{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 8
- },
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"wX" = (
/obj/structure/cable/pink{
@@ -3855,7 +3872,7 @@
icon_state = "frame";
pixel_y = 62
},
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"yN" = (
/obj/machinery/seed_extractor,
@@ -4973,18 +4990,6 @@
},
/turf/simulated/floor,
/area/itglight/starboarddocking)
-"EN" = (
-/obj/structure/cable/pink{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 8
- },
-/turf/simulated/floor/carpet/sblucarpet,
-/area/itglight/common)
"EP" = (
/obj/structure/cable/pink{
d1 = 4;
@@ -5736,6 +5741,17 @@
/area/itglight/shuttlebay)
"IN" = (
/obj/structure/coatrack,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/pink{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"IQ" = (
@@ -5796,6 +5812,13 @@
/turf/simulated/floor/tiled/steel_ridged,
/area/itglight/starboardengi)
"Ji" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Jk" = (
@@ -5812,14 +5835,16 @@
/turf/simulated/floor/tiled/techfloor/grid,
/area/itglight/starboarddocking)
"Jm" = (
-/obj/structure/cable/pink{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 8
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 10
+ },
+/obj/structure/cable/pink{
+ d1 = 2;
+ d2 = 8;
+ icon_state = "2-8"
},
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
@@ -6203,13 +6228,18 @@
/turf/simulated/floor/tiled/dark,
/area/itglight/passengersleeping)
"LZ" = (
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply,
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
/obj/structure/cable/pink{
d1 = 1;
- d2 = 2;
- icon_state = "1-2"
+ d2 = 4;
+ icon_state = "1-4"
+ },
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 8;
+ icon_state = "1-8"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Mg" = (
@@ -6217,6 +6247,17 @@
/obj/machinery/computer/ship/navigation/telescreen{
pixel_y = 30
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/pink{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Mh" = (
@@ -6243,6 +6284,17 @@
/obj/structure/bed/chair/comfy/brown{
dir = 8
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 10
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 10
+ },
+/obj/structure/cable/pink{
+ d1 = 2;
+ d2 = 8;
+ icon_state = "2-8"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Mm" = (
@@ -6316,27 +6368,19 @@
/obj/machinery/light{
dir = 8
},
-/turf/simulated/floor/tiled/eris/steel/brown_platform,
-/area/itglight/common)
-"ME" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/structure/cable/pink{
d1 = 1;
d2 = 2;
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 8
- },
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"MF" = (
/obj/structure/table/wooden_reinforced,
/obj/item/device/paicard,
-/obj/machinery/atmospherics/unary/vent_pump/on{
- dir = 8
- },
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"MG" = (
/obj/structure/cable{
@@ -6372,30 +6416,17 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/turf/simulated/floor/tiled/monotile,
/area/itglight/lockers)
-"MU" = (
+"MY" = (
+/obj/structure/bed/chair/sofa/brown/right{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/structure/cable/pink{
d1 = 1;
d2 = 2;
icon_state = "1-2"
},
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers,
-/obj/structure/cable/pink{
- d1 = 2;
- d2 = 4;
- icon_state = "2-4"
- },
-/obj/structure/cable/pink{
- d1 = 2;
- d2 = 8;
- icon_state = "2-8"
- },
-/turf/simulated/floor/carpet/sblucarpet,
-/area/itglight/common)
-"MY" = (
-/obj/structure/bed/chair/sofa/brown/right{
- dir = 4
- },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Na" = (
@@ -6447,11 +6478,8 @@
/area/itglight/starboardcargo)
"Nn" = (
/obj/structure/table/wooden_reinforced,
-/obj/machinery/atmospherics/unary/vent_scrubber/on{
- dir = 4
- },
/obj/random/coin,
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"No" = (
/obj/effect/floor_decal/industrial/warning{
@@ -6473,18 +6501,6 @@
},
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/shuttlebay)
-"Ns" = (
-/obj/structure/cable/pink{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
- dir = 4
- },
-/turf/simulated/floor/carpet/sblucarpet,
-/area/itglight/common)
"Nv" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
@@ -6634,6 +6650,17 @@
/obj/structure/bed/chair/sofa/brown/corner{
dir = 1
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 6
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 6
+ },
+/obj/structure/cable/pink{
+ d1 = 2;
+ d2 = 4;
+ icon_state = "2-4"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Om" = (
@@ -6658,12 +6685,34 @@
/area/itglight/kitchen)
"Or" = (
/obj/structure/bed/chair/sofa/brown,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/pink{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Ot" = (
/obj/structure/bed/chair/comfy/brown{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/pink{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Ov" = (
@@ -6679,16 +6728,21 @@
/turf/simulated/floor/tiled/dark,
/area/itglight/passengersleeping)
"Ow" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
dir = 4
},
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 8
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
+ dir = 4
},
/obj/structure/cable/pink{
- d1 = 4;
+ d1 = 1;
d2 = 8;
- icon_state = "4-8"
+ icon_state = "1-8"
+ },
+/obj/structure/cable/pink{
+ d1 = 2;
+ d2 = 8;
+ icon_state = "2-8"
},
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
@@ -6910,6 +6964,13 @@
/obj/structure/handrail{
dir = 4
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Qh" = (
@@ -6934,16 +6995,6 @@
/obj/machinery/atmospherics/pipe/tank/phoron/full,
/turf/simulated/floor,
/area/itglight/portengi)
-"Qp" = (
-/obj/structure/cable/pink{
- d1 = 1;
- d2 = 2;
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/turf/simulated/floor/carpet/sblucarpet,
-/area/itglight/common)
"Qq" = (
/obj/structure/grille,
/obj/structure/window/reinforced/full,
@@ -7010,7 +7061,7 @@
/area/itglight/medbay)
"QI" = (
/obj/structure/table/wooden_reinforced,
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"QN" = (
/obj/structure/handrail{
@@ -7021,6 +7072,7 @@
d2 = 2;
icon_state = "1-2"
},
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"QO" = (
@@ -7086,7 +7138,7 @@
/area/itglight/medbay)
"Rb" = (
/obj/structure/flora/pottedplant/orientaltree,
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"Rd" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
@@ -7124,9 +7176,6 @@
/area/itglight/portengi)
"Rp" = (
/obj/structure/table/wooden_reinforced,
-/obj/machinery/atmospherics/unary/vent_scrubber/on{
- dir = 8
- },
/obj/structure/cable/pink{
d1 = 1;
d2 = 2;
@@ -7135,6 +7184,9 @@
/obj/machinery/light{
dir = 4
},
+/obj/machinery/atmospherics/unary/vent_scrubber/on{
+ dir = 1
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Rq" = (
@@ -7227,42 +7279,23 @@
},
/turf/simulated/floor/tiled/eris/white/cargo,
/area/itglight/medbay)
-"Sh" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 8
- },
-/obj/structure/cable/pink{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/turf/simulated/floor/carpet/sblucarpet,
-/area/itglight/common)
"Sw" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 8
- },
-/obj/structure/cable/pink{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/structure/cable/pink{
- d1 = 2;
- d2 = 8;
- icon_state = "2-8"
- },
/obj/structure/cable/pink{
d1 = 2;
d2 = 4;
icon_state = "2-4"
},
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{
+ dir = 8
+ },
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Sz" = (
@@ -7569,9 +7602,6 @@
"Uw" = (
/turf/simulated/wall/shull,
/area/itglight/medbay)
-"UF" = (
-/turf/simulated/floor/carpet/sblucarpet,
-/area/itglight/common)
"UH" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -7649,10 +7679,7 @@
/turf/simulated/floor/tiled/eris/white/cargo,
/area/itglight/medbay)
"UZ" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/turf/simulated/floor/carpet/sblucarpet,
+/turf/simulated/floor/glass/reinforced,
/area/itglight/common)
"Vd" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
@@ -7709,6 +7736,35 @@
},
/turf/simulated/floor,
/area/itglight/starboardengi)
+<<<<<<< HEAD
+||||||| parent of b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
+"Vz" = (
+/obj/machinery/newscaster{
+ pixel_x = -12;
+ pixel_y = -26
+ },
+/turf/simulated/floor/tiled/eris/steel/brown_platform,
+/area/itglight/common)
+=======
+"Vz" = (
+/obj/machinery/newscaster{
+ pixel_x = -12;
+ pixel_y = -26
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/pink{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/tiled/eris/steel/brown_platform,
+/area/itglight/common)
+>>>>>>> b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
"VB" = (
/obj/machinery/light{
dir = 1
@@ -7883,6 +7939,17 @@
/area/itglight/portsolars)
"WE" = (
/obj/structure/flora/pottedplant/minitree,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 5
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 5
+ },
+/obj/structure/cable/pink{
+ d1 = 1;
+ d2 = 4;
+ icon_state = "1-4"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"WG" = (
@@ -8446,6 +8513,17 @@
/area/itglight/shuttlebay)
"Zs" = (
/obj/structure/bed/chair/sofa/brown/left,
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 8
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/pink{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
/turf/simulated/floor/tiled/eris/steel/brown_platform,
/area/itglight/common)
"Zw" = (
@@ -18148,9 +18226,9 @@ Xu
Or
yK
QI
-Sh
-UF
-UF
+UZ
+UZ
+UZ
IN
Xu
ZG
@@ -18290,10 +18368,22 @@ Xu
Zs
QI
Nn
+<<<<<<< HEAD
Sh
UF
UF
Ji
+||||||| parent of b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
+Sh
+UF
+UF
+Vz
+=======
+UZ
+UZ
+UZ
+Vz
+>>>>>>> b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
Xu
Ud
YT
@@ -18430,11 +18520,11 @@ LG
bk
wL
LZ
-ME
-Ns
-MU
-Qp
-EN
+UZ
+UZ
+UZ
+UZ
+UZ
Jm
SO
Oe
@@ -18573,9 +18663,9 @@ Ng
Xu
Ot
wW
-UF
-Sh
-UF
+UZ
+UZ
+UZ
UZ
Jt
Xu
@@ -18716,8 +18806,8 @@ Xu
Mg
MF
Rb
-Sh
-UF
+UZ
+UZ
UZ
SH
Xu
@@ -18856,7 +18946,7 @@ kR
Ek
Xu
Ml
-Ml
+wc
Ji
Sw
QN
diff --git a/vorestation.dme b/vorestation.dme
index 3ae53923aa..e1fa4cabfc 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -289,7 +289,6 @@
#include "code\controllers\subsystems\mobs.dm"
#include "code\controllers\subsystems\nanoui.dm"
#include "code\controllers\subsystems\nightshift.dm"
-#include "code\controllers\subsystems\open_space.dm"
#include "code\controllers\subsystems\orbits.dm"
#include "code\controllers\subsystems\overlays.dm"
#include "code\controllers\subsystems\persist_vr.dm"
@@ -373,6 +372,7 @@
#include "code\datums\components\crafting\tool_quality.dm"
#include "code\datums\elements\_element.dm"
#include "code\datums\elements\light_blocking.dm"
+#include "code\datums\elements\turf_transparency.dm"
#include "code\datums\game_masters\_common.dm"
#include "code\datums\helper_datums\construction_datum.dm"
#include "code\datums\helper_datums\events.dm"
@@ -3416,6 +3416,7 @@
#include "code\modules\multiz\pipes.dm"
#include "code\modules\multiz\stairs.dm"
#include "code\modules\multiz\turf.dm"
+<<<<<<< HEAD
#include "code\modules\multiz\turf_yw.dm"
#include "code\modules\multiz\zshadow.dm"
#include "code\modules\nano\nanoexternal.dm"
@@ -3437,6 +3438,10 @@
#include "code\modules\nano\interaction\remote.dm"
#include "code\modules\nano\interaction\self.dm"
#include "code\modules\nano\interaction\zlevel.dm"
+||||||| parent of b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
+#include "code\modules\multiz\zshadow.dm"
+=======
+>>>>>>> b9e47f102b... Merge pull request #10764 from VOREStation/Arokha/multiviz
#include "code\modules\news\news_init.dm"
#include "code\modules\news\newspaper.dm"
#include "code\modules\news\newspaper_layout.dm"