From b4387f251d614469e64c503566457d8dddcb79d6 Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Wed, 30 Jun 2021 15:39:07 -0400 Subject: [PATCH] /tg/ vis openspace --- code/__defines/_planes+layers.dm | 12 +- code/__defines/dcs/signals.dm | 4 +- code/__defines/mobs.dm | 47 +-- code/__defines/mobs_vr.dm | 12 +- code/__defines/subsystems.dm | 1 - code/_helpers/game.dm | 17 +- code/_helpers/turfs.dm | 4 - code/_helpers/unsorted.dm | 4 - code/controllers/subsystems/open_space.dm | 107 ------ code/datums/elements/turf_transparency.dm | 82 +++++ code/game/atoms_movable.dm | 4 - code/game/machinery/air_alarm.dm | 1 + code/game/machinery/computer/guestpass.dm | 1 + code/game/machinery/fire_alarm.dm | 1 + code/game/machinery/holoposter.dm | 1 + code/game/machinery/lightswitch.dm | 1 + .../objects/effects/decals/Cleanable/fuel.dm | 1 + .../effects/decals/Cleanable/humans.dm | 1 + code/game/objects/effects/decals/cleanable.dm | 1 + code/game/objects/effects/decals/crayon.dm | 1 + .../objects/items/weapons/storage/storage.dm | 313 +++++++----------- code/game/objects/objs.dm | 1 + code/game/objects/structures/catwalk.dm | 4 +- code/game/objects/structures/flora/flora.dm | 2 +- code/game/turfs/flooring/flooring_decals.dm | 2 +- code/game/turfs/turf.dm | 8 + code/game/turfs/turf_changing.dm | 9 +- code/modules/holomap/station_holomap.dm | 1 + code/modules/lighting/emissive_blocker.dm | 1 + code/modules/mob/dead/observer/observer.dm | 1 + code/modules/mob/inventory.dm | 4 +- .../mob/living/carbon/human/inventory.dm | 31 +- .../species/station/traits_vr/weaver_objs.dm | 1 + code/modules/mob/living/inventory.dm | 16 +- code/modules/mob/living/say.dm | 14 - code/modules/mob/mob.dm | 3 - code/modules/mob/mob_defines.dm | 2 + code/modules/mob/mob_planes.dm | 15 + code/modules/mob/typing_indicator.dm | 3 - code/modules/multiz/_stubs.dm | 9 - code/modules/multiz/turf.dm | 206 +++++++----- code/modules/multiz/zshadow.dm | 126 ------- code/modules/persistence/graffiti.dm | 1 + code/modules/power/apc.dm | 1 + icons/turf/flooring/glass.dmi | Bin 0 -> 9535 bytes icons/turf/flooring/reinf_glass.dmi | Bin 0 -> 6051 bytes icons/turf/floors.dmi | Bin 108162 -> 108202 bytes vorestation.dme | 3 +- 48 files changed, 440 insertions(+), 640 deletions(-) delete mode 100644 code/controllers/subsystems/open_space.dm create mode 100644 code/datums/elements/turf_transparency.dm delete mode 100644 code/modules/multiz/zshadow.dm create mode 100644 icons/turf/flooring/glass.dmi create mode 100644 icons/turf/flooring/reinf_glass.dmi 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 b70001cbd6..19ff35c86b 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 9ad2af0504..2c9e6ee6a6 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -78,7 +78,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 c7631479f8..2f172d198e 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -273,9 +273,24 @@ 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 ee5899fbe8..5540fe8e08 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -852,10 +852,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/atoms_movable.dm b/code/game/atoms_movable.dm index 983e0ea56e..728859eee7 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -63,10 +63,6 @@ moveToNullspace() - vis_contents.Cut() - for(var/atom/movable/A as anything in vis_locs) - A.vis_contents -= src - if(pulledby) pulledby.stop_pulling() diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index 9e700f9904..8f223ed549 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' //VOREStation Edit - Other icons 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 30182cbd8b..e23aa459be 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 d52e10b57a..7a71d9fc64 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/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index c0414036b5..9f3f4335c8 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -15,32 +15,20 @@ w_class = ITEMSIZE_NORMAL show_messages = 1 - /// List of objects which this item can store (if set, it can't store anything else) - var/list/can_hold - /// List of objects which this item can't store (in effect only if can_hold isn't set) - var/list/cant_hold - /// List of mobs which are currently seeing the contents of this item's storage - var/list/is_seeing - + var/list/can_hold = new/list() //List of objects which this item can store (if set, it can't store anything else) + var/list/cant_hold = new/list() //List of objects which this item can't store (in effect only if can_hold isn't set) + var/list/is_seeing = new/list() //List of mobs which are currently seeing the contents of this item's storage var/max_w_class = ITEMSIZE_SMALL //Max size of objects that this object can store (in effect only if can_hold isn't set) var/max_storage_space = ITEMSIZE_COST_SMALL * 4 //The sum of the storage costs of all the items in this storage item. var/storage_slots = null //The number of storage slots in this container. If null, it uses the volume-based storage instead. - - /// Boxes screen object for fixed-size storage (belts, etc) var/obj/screen/storage/boxes = null - /// List of 'click catchers' for boxes for fixed-size storage - var/list/box_catchers = null - - /// For dynamic storage, the leftmost pixel column for the whole storage display. Most of the interesting effects are hung on this in vis_contents. - var/obj/screen/storage/storage_start = null - /// For dynamic storage, the majority of the width of the whole storage display. Decorative, but sized to the width appropriate to represent how much storage there is. + var/obj/screen/storage/storage_start = null //storage UI var/obj/screen/storage/storage_continue = null - /// For dynamic storage, the rightmost pixel column for the whole storage display. Decorative. var/obj/screen/storage/storage_end = null - - /// The "X" button at the far right of the storage + var/obj/screen/storage/stored_start = null + var/obj/screen/storage/stored_continue = null + var/obj/screen/storage/stored_end = null var/obj/screen/close/closer = null - var/use_to_pickup //Set this to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up. var/display_contents_with_number //Set this to make the storage item group contents of the same type and display them as a number. var/allow_quick_empty //Set this variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor. @@ -50,67 +38,15 @@ var/list/starts_with //Things to spawn on the box on spawn var/empty //Mapper override to spawn an empty version of a container that usually has stuff -/obj/item/weapon/storage/Initialize() - . = ..() - - if(allow_quick_empty) - verbs += /obj/item/weapon/storage/verb/quick_empty - else - verbs -= /obj/item/weapon/storage/verb/quick_empty - - if(allow_quick_gather) - verbs += /obj/item/weapon/storage/verb/toggle_gathering_mode - else - verbs -= /obj/item/weapon/storage/verb/toggle_gathering_mode - - if(storage_slots) - src.boxes = new /obj/screen/storage( ) - src.boxes.name = "storage" - src.boxes.master = src - src.boxes.icon_state = "block" - src.boxes.screen_loc = "7,7 to 10,8" - else - src.storage_start = new /obj/screen/storage( ) - src.storage_start.name = "storage" - src.storage_start.master = src - src.storage_start.icon_state = "storage_start" - src.storage_start.screen_loc = "7,7 to 10,8" - - src.storage_continue = new /obj/screen/storage( ) - src.storage_continue.name = "storage" - src.storage_continue.master = src - src.storage_continue.icon_state = "storage_continue" - src.storage_continue.screen_loc = "7,7 to 10,8" - - src.storage_end = new /obj/screen/storage( ) - src.storage_end.name = "storage" - src.storage_end.master = src - src.storage_end.icon_state = "storage_end" - src.storage_end.screen_loc = "7,7 to 10,8" - - src.closer = new /obj/screen/close( ) - src.closer.master = src - src.closer.icon_state = "storage_close" - src.closer.hud_layerise() - orient2hud() - - if(LAZYLEN(starts_with) && !empty) - for(var/newtype in starts_with) - var/count = starts_with[newtype] || 1 //Could have left it blank. - while(count) - count-- - new newtype(src) - starts_with = null //Reduce list count. - - calibrate_size() - /obj/item/weapon/storage/Destroy() close_all() - clear_slot_catchers() QDEL_NULL(boxes) QDEL_NULL(storage_start) QDEL_NULL(storage_continue) QDEL_NULL(storage_end) + QDEL_NULL(stored_start) + QDEL_NULL(stored_continue) + QDEL_NULL(stored_end) QDEL_NULL(closer) if(ismob(loc)) @@ -177,58 +113,44 @@ return if(user.s_active) user.s_active.hide_from(user) - - var/client/C = user.client - if(!C) - return - - if(storage_slots) - C.screen += src.boxes - create_slot_catchers() - C.screen += src.box_catchers + user.client.screen -= src.boxes + user.client.screen -= src.storage_start + user.client.screen -= src.storage_continue + user.client.screen -= src.storage_end + user.client.screen -= src.closer + user.client.screen -= src.contents + user.client.screen += src.closer + user.client.screen += src.contents + if(storage_slots) + user.client.screen += src.boxes else - C.screen += src.storage_start - C.screen += src.storage_continue - C.screen += src.storage_end - - C.screen += src.closer - C.screen += src.contents - + user.client.screen += src.storage_start + user.client.screen += src.storage_continue + user.client.screen += src.storage_end user.s_active = src - LAZYDISTINCTADD(is_seeing,user) + is_seeing |= user + return /obj/item/weapon/storage/proc/hide_from(mob/user as mob) - var/client/C = user.client - LAZYREMOVE(is_seeing,user) - - if(!C) - if(!LAZYLEN(is_seeing)) - clear_slot_catchers() + + if(!user.client) return - - if(storage_slots) - C.screen -= src.boxes - C.screen -= src.box_catchers - else - C.screen -= src.storage_start - C.screen -= src.storage_continue - C.screen -= src.storage_end - - C.screen -= src.closer - C.screen -= src.contents - + user.client.screen -= src.boxes + user.client.screen -= src.storage_start + user.client.screen -= src.storage_continue + user.client.screen -= src.storage_end + user.client.screen -= src.closer + user.client.screen -= src.contents if(user.s_active == src) user.s_active = null - - if(!LAZYLEN(is_seeing)) - clear_slot_catchers() + is_seeing -= user /obj/item/weapon/storage/proc/open(mob/user as mob) if (use_sound) playsound(src, src.use_sound, 50, 0, -5) orient2hud(user) - if(user.s_active) + if (user.s_active) user.s_active.close(user) show_to(user) @@ -248,25 +170,9 @@ if(M.s_active == src && M.client) cansee |= M else - LAZYREMOVE(is_seeing,M) + is_seeing -= M return cansee -/obj/item/weapon/storage/proc/create_slot_catchers() - clear_slot_catchers() - var/list/new_catchers = list() - for(var/obj/item/I in contents) - var/atom/movable/storage_slot/SS = new(null, I) - SS.screen_loc = I.screen_loc - SS.mouse_opacity = MOUSE_OPACITY_OPAQUE - new_catchers += SS - box_catchers = new_catchers - -/obj/item/weapon/storage/proc/clear_slot_catchers() - if(box_catchers) - for(var/mob/M in is_seeing) - M.client?.screen -= box_catchers - QDEL_LIST_NULL(box_catchers) - //This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. //The numbers are calculated from the bottom-left The bottom-left slot being 1,1. /obj/item/weapon/storage/proc/orient_objs(tx, ty, mx, my) @@ -294,9 +200,6 @@ ND.sample_object.screen_loc = "[cx]:16,[cy]:16" ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" ND.sample_object.hud_layerise() - var/atom/movable/storage_slot/SS = new(null, ND.sample_object) - SS.screen_loc = ND.sample_object.screen_loc - SS.mouse_opacity = MOUSE_OPACITY_OPAQUE cx++ if (cx > (4+cols)) cx = 4 @@ -306,9 +209,6 @@ O.screen_loc = "[cx]:16,[cy]:16" O.maptext = "" O.hud_layerise() - var/atom/movable/storage_slot/SS = new(null, O) - SS.screen_loc = O.screen_loc - SS.mouse_opacity = MOUSE_OPACITY_OPAQUE cx++ if (cx > (4+cols)) cx = 4 @@ -317,20 +217,6 @@ return /obj/item/weapon/storage/proc/space_orient_objs(var/list/obj/item/display_contents) - SHOULD_NOT_SLEEP(TRUE) - - /// A prototype for drawing the leftmost border behind each item in storage - var/static/mutable_appearance/stored_start - /// A prototype for drawing the wide backing space behind each item in storage - var/static/mutable_appearance/stored_continue - /// A prototype for drawing the rightmost border behind each item in storage - var/static/mutable_appearance/stored_end - - if(!stored_start) - // Because these are static and manipulated all the time by different storages, you'd better make 100000% sure this proc never sleeps - stored_start = mutable_appearance(icon = 'icons/mob/screen1.dmi', icon_state = "stored_start", layer = 0.1, plane = PLANE_PLAYER_HUD_ITEMS) - stored_continue = mutable_appearance(icon = 'icons/mob/screen1.dmi', icon_state = "stored_continue", layer = 0.1, plane = PLANE_PLAYER_HUD_ITEMS) - stored_end = mutable_appearance(icon = 'icons/mob/screen1.dmi', icon_state = "stored_end", layer = 0.1, plane = PLANE_PLAYER_HUD_ITEMS) var/baseline_max_storage_space = INVENTORY_STANDARD_SPACE / 2 //should be equal to default backpack capacity // This is a lie. // Above var is misleading, what it does upon changing is makes smaller inventory sizes have smaller space on the UI. @@ -340,7 +226,7 @@ var/stored_cap_width = 4 //length of sprite for start and end of the box representing the stored item var/storage_width = min( round( 224 * max_storage_space/baseline_max_storage_space ,1) ,274) //length of sprite for the box representing total storage space - QDEL_LIST_NULL(storage_start.vis_contents) + storage_start.cut_overlays() var/matrix/M = matrix() M.Scale((storage_width-storage_cap_width*2+3)/32,1) @@ -354,7 +240,6 @@ var/endpoint = 1 for(var/obj/item/O in contents) - var/atom/movable/storage_slot/SS = new(null, O) startpoint = endpoint + 1 endpoint += storage_width * O.get_storage_cost()/max_storage_space @@ -365,19 +250,21 @@ M_continue.Scale((endpoint-startpoint-stored_cap_width*2)/32,1) M_continue.Translate(startpoint+stored_cap_width+(endpoint-startpoint-stored_cap_width*2)/2 - 16,0) M_end.Translate(endpoint-stored_cap_width,0) - stored_start.transform = M_start - stored_continue.transform = M_continue - stored_end.transform = M_end - SS.add_overlay(list(stored_start, stored_continue, stored_end)) + src.stored_start.transform = M_start + src.stored_continue.transform = M_continue + src.stored_end.transform = M_end + storage_start.add_overlay(stored_start) + storage_start.add_overlay(stored_continue) + storage_start.add_overlay(stored_end) O.screen_loc = "4:[round((startpoint+endpoint)/2)+2],2:16" O.maptext = "" O.hud_layerise() - storage_start.vis_contents += SS src.closer.screen_loc = "4:[storage_width+19],2:16" return + /datum/numbered_display var/obj/item/sample_object var/number @@ -434,14 +321,14 @@ to_chat(usr, "[src] is full, make some space.") return 0 //Storage item is full - if(LAZYLEN(can_hold) && !is_type_in_list(W, can_hold)) + if(can_hold.len && !is_type_in_list(W, can_hold)) if(!stop_messages) if (istype(W, /obj/item/weapon/hand_labeler)) return 0 to_chat(usr, "[src] cannot hold [W].") return 0 - if(LAZYLEN(cant_hold) && is_type_in_list(W, cant_hold)) + if(cant_hold.len && is_type_in_list(W, cant_hold)) if(!stop_messages) to_chat(usr, "[src] cannot hold [W].") return 0 @@ -510,8 +397,10 @@ var/obj/item/weapon/storage/fancy/F = src F.update_icon(1) - for(var/mob/M in is_seeing) - M?.client.screen -= W + for(var/mob/M in range(1, src.loc)) + if (M.s_active == src) + if (M.client) + M.client.screen -= W if(new_location) if(ismob(loc)) @@ -524,10 +413,10 @@ else W.forceMove(get_turf(src)) - for(var/mob/M in is_seeing) - if(M.s_active == src) - orient2hud(M) - show_to(M) + if(usr) + src.orient2hud(usr) + if(usr.s_active) + usr.s_active.show_to(usr) if(W.maptext) W.maptext = "" W.on_exit_storage(src) @@ -647,6 +536,68 @@ for(var/obj/item/I in contents) remove_from_storage(I, T) +/obj/item/weapon/storage/Initialize() + . = ..() + + if(allow_quick_empty) + verbs += /obj/item/weapon/storage/verb/quick_empty + else + verbs -= /obj/item/weapon/storage/verb/quick_empty + + if(allow_quick_gather) + verbs += /obj/item/weapon/storage/verb/toggle_gathering_mode + else + verbs -= /obj/item/weapon/storage/verb/toggle_gathering_mode + + src.boxes = new /obj/screen/storage( ) + src.boxes.name = "storage" + src.boxes.master = src + src.boxes.icon_state = "block" + src.boxes.screen_loc = "7,7 to 10,8" + + src.storage_start = new /obj/screen/storage( ) + src.storage_start.name = "storage" + src.storage_start.master = src + src.storage_start.icon_state = "storage_start" + src.storage_start.screen_loc = "7,7 to 10,8" + + src.storage_continue = new /obj/screen/storage( ) + src.storage_continue.name = "storage" + src.storage_continue.master = src + src.storage_continue.icon_state = "storage_continue" + src.storage_continue.screen_loc = "7,7 to 10,8" + + src.storage_end = new /obj/screen/storage( ) + src.storage_end.name = "storage" + src.storage_end.master = src + src.storage_end.icon_state = "storage_end" + src.storage_end.screen_loc = "7,7 to 10,8" + + src.stored_start = new /obj //we just need these to hold the icon + src.stored_start.icon_state = "stored_start" + + src.stored_continue = new /obj + src.stored_continue.icon_state = "stored_continue" + + src.stored_end = new /obj + src.stored_end.icon_state = "stored_end" + + src.closer = new /obj/screen/close( ) + src.closer.master = src + src.closer.icon_state = "storage_close" + src.closer.hud_layerise() + orient2hud() + + if(LAZYLEN(starts_with) && !empty) + for(var/newtype in starts_with) + var/count = starts_with[newtype] || 1 //Could have left it blank. + while(count) + count-- + new newtype(src) + starts_with = null //Reduce list count. + + calibrate_size() + /obj/item/weapon/storage/proc/calibrate_size() var/total_storage_space = 0 for(var/obj/item/I in contents) @@ -723,8 +674,7 @@ /obj/item/weapon/storage/proc/make_exact_fit() storage_slots = contents.len - LAZYCLEARLIST(can_hold) - can_hold = list() + can_hold.Cut() max_w_class = 0 max_storage_space = 0 for(var/obj/item/I in src) @@ -797,32 +747,3 @@ for (var/obj/O in contents) remove_from_storage(O, T) O.tumble(2) - -/// Hangar for storage backdrops, so that we can redirect clicks from them to our item for QOL -/atom/movable/storage_slot - name = "stored - " - icon = 'icons/effects/effects.dmi' - icon_state = "nothing" - plane = PLANE_PLAYER_HUD_ITEMS - layer = 0.1 - alpha = 200 - var/weakref/held_item - -/atom/movable/storage_slot/New(newloc, obj/item/held_item) - ASSERT(held_item) - name += held_item.name - src.held_item = weakref(held_item) - -/atom/movable/storage_slot/Destroy() - held_item = null - -/// Has to be this way. The fact that the overlays will be constantly mutated by other storage means we can't wait. -/atom/movable/storage_slot/add_overlay(list/somethings) - ASSERT(islist(somethings)) - overlays = somethings - -/atom/movable/storage_slot/Click() - var/obj/item/I = held_item?.resolve() - if(I) - usr.ClickOn(I) - return 1 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 578fb80f54..1fd1d6e6ed 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 8b3bee6f9e..bd7df8d280 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 @@ -49,6 +50,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 74b3e6dc0e..06c538b041 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -2,6 +2,7 @@ name = "observer" desc = "This shouldn't appear" density = 0 + vis_flags = NONE /mob/observer/dead name = "ghost" diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 13bc02dda4..35df5ef8a1 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -50,7 +50,7 @@ var/list/slot_equipment_priority = list( \ /mob/proc/equip_to_slot_if_possible(obj/item/W as obj, slot, del_on_fail = 0, disable_warning = 0, redraw_mob = 1) if(!W) return 0 - if(!W.mob_can_equip(src, slot, disable_warning)) + if(!W.mob_can_equip(src, slot)) if(del_on_fail) qdel(W) @@ -93,7 +93,7 @@ var/list/slot_equipment_priority = list( \ return 0 -/mob/proc/equip_to_storage(obj/item/newitem, user_initiated = FALSE) +/mob/proc/equip_to_storage(obj/item/newitem) return 0 /* Hands */ diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 7aa1dee24f..d756271286 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -16,40 +16,13 @@ This saves us from having to call add_fingerprint() any time something is put in if(!I) to_chat(H, "You are not holding anything to equip.") return - - var/moved = FALSE - - // Try an equipment slot if(H.equip_to_appropriate_slot(I)) - moved = TRUE - - // No? Try a storage item. - else if(H.equip_to_storage(I, TRUE)) - moved = TRUE - - // No?! Well, give up. - if(!moved) - to_chat(H, "You are unable to equip that.") - - // Update hand icons - else if(hand) update_inv_l_hand(0) else update_inv_r_hand(0) - -/mob/living/carbon/human/equip_to_storage(obj/item/newitem, user_initiated = FALSE) - // Try put it in their belt first - if(istype(src.belt,/obj/item/weapon/storage)) - var/obj/item/weapon/storage/wornbelt = src.belt - if(wornbelt.can_be_inserted(newitem, 1)) - if(user_initiated) - wornbelt.handle_item_insertion(newitem) - else - newitem.forceMove(wornbelt) - return wornbelt - - return ..() + else + to_chat(H, "You are unable to equip that.") /mob/living/carbon/human/proc/equip_in_one_of_slots(obj/item/W, list/slots, del_on_fail = 1) for (var/slot in slots) diff --git a/code/modules/mob/living/carbon/human/species/station/traits_vr/weaver_objs.dm b/code/modules/mob/living/carbon/human/species/station/traits_vr/weaver_objs.dm index 72d53be19b..b3ddc26ed3 100644 --- a/code/modules/mob/living/carbon/human/species/station/traits_vr/weaver_objs.dm +++ b/code/modules/mob/living/carbon/human/species/station/traits_vr/weaver_objs.dm @@ -39,6 +39,7 @@ /obj/effect/weaversilk/floor var/possible_icon_states = list("floorweb1", "floorweb2", "floorweb3", "floorweb4", "floorweb5", "floorweb6", "floorweb7", "floorweb8") plane = DIRTY_PLANE + layer = DIRTY_LAYER /obj/effect/weaversilk/floor/Initialize() ..() diff --git a/code/modules/mob/living/inventory.dm b/code/modules/mob/living/inventory.dm index c2ea298683..8d4a66def3 100644 --- a/code/modules/mob/living/inventory.dm +++ b/code/modules/mob/living/inventory.dm @@ -6,25 +6,19 @@ var/obj/item/weapon/tank/internal = null//Human/Monkey var/obj/item/clothing/mask/wear_mask = null//Carbon -/mob/living/equip_to_storage(obj/item/newitem, user_initiated = FALSE) +/mob/living/equip_to_storage(obj/item/newitem) // Try put it in their backpack if(istype(src.back,/obj/item/weapon/storage)) var/obj/item/weapon/storage/backpack = src.back if(backpack.can_be_inserted(newitem, 1)) - if(user_initiated) - backpack.handle_item_insertion(newitem) - else - newitem.forceMove(src.back) - return src.back + newitem.forceMove(src.back) + return 1 // Try to place it in any item that can store stuff, on the mob. for(var/obj/item/weapon/storage/S in src.contents) if (S.can_be_inserted(newitem, 1)) - if(user_initiated) - S.handle_item_insertion(newitem) - else - newitem.forceMove(S) - return S + newitem.forceMove(S) + return 1 return 0 //Returns the thing in our active hand diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 6db59df65b..139397aa29 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -342,20 +342,6 @@ var/list/channel_to_radio_key = new speech_bubble.alpha = CLAMP(sb_alpha, 0, 255) images_to_clients[speech_bubble] = list() - // Attempt Multi-Z Talking - var/mob/above = src.shadow - while(!QDELETED(above)) - var/turf/ST = get_turf(above) - if(ST) - var/list/results = get_mobs_and_objs_in_view_fast(ST, world.view) - var/image/z_speech_bubble = generate_speech_bubble(above, "h[speech_bubble_test]") - images_to_clients[z_speech_bubble] = list() - for(var/item in results["mobs"]) - if(item != above && !(item in listening)) - listening[item] = z_speech_bubble - listening_obj |= results["objs"] - above = above.shadow - //Main 'say' and 'whisper' message delivery for(var/mob/M in listening) spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d8040cdc0b..9b623bec93 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -84,9 +84,6 @@ else exclude_mobs = list(src) src.show_message(self_message, 1, blind_message, 2) - // Transfer messages about what we are doing to upstairs - if(shadow) - shadow.visible_message(message, self_message, blind_message, exclude_mobs, range) if(isnull(runemessage)) runemessage = -1 . = ..(message, blind_message, exclude_mobs, range, runemessage) // Really not ideal that atom/visible_message has different arg numbering :( 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 c3c5a1450d..e9715834c8 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 e0b7fa05ee..2259186c71 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 4f7ac688d7..c9ecf3d8fb 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 0000000000000000000000000000000000000000..e28bb13e233a02fdc00a429004cb778a172dce8e GIT binary patch literal 9535 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 literal 0 HcmV?d00001 diff --git a/icons/turf/flooring/reinf_glass.dmi b/icons/turf/flooring/reinf_glass.dmi new file mode 100644 index 0000000000000000000000000000000000000000..97614f510f745a8aee2f0ca3f48f20ca5a3ab3b4 GIT binary patch literal 6051 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 literal 0 HcmV?d00001 diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index f95702fa27c611a41edadaf97f9c876166bcc366..978eb5d9c77458f52c89fc07c6f9929b7b3933b1 100644 GIT binary patch delta 22032 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 delta 21843 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 z z)VGns^u}sjf4fAbp|u+<7<2Bw*S)XpP~N=$MX(i;}S zrPT}B$L?P)$bPD<5^i~bt3Ik-4(Wpj-o%gQ>cvvt_A$gIIeaM2DgbAflfZS>I-I zt|Z4y3*RSS2Nmy?vsjsyJg&6HuDS$$rO*Ze(#-T?{u&q7awP7=VX+}X_&xM9;NLl= zN7v-|soS(J`X`AT>LZ8^L@!6fx@>1x|0pZ%Qu z`sd4%{VK1CLZmn-Dd9!!cgYM|h-r3cJ+>6N^|~sd7Qi zI6zX2R7!@lO;p3~2|S~@|ClClR>TlSRC96uUS)asyF=8K`6l81e}rWFn3*ss6D)IO zug&DYnaG<&FRQ)|$kde}6@{Ar5HvYj-JngjqQ8JQb){0VaC(`eaCk<6^_8_tb+Cdo zjw~vT*a>6i7MfKYMf%0UEgWibtSI!WFJW*K&bGPrJQEc8Nu#(-ofxu5%@DBEP5aRP dUou`B<-v3_jwGeoDsuqvgR(qrQDN>L`#)k8