diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index 912d2970674..bddba819a9d 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -130,17 +130,12 @@ //Layering order of these is not particularly meaningful. //Important part is the seperation of the planes for control via plane_master -///This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas +/// This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas. #define EMISSIVE_PLANE 150 +/// The render target used by the emissive layer. #define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE" - -///This plane masks the emissive plane to "block" it. Byond is wacky, this is the only way to get things to look like they're actually blocking said glowing lights. -#define EMISSIVE_BLOCKER_PLANE 160 -#define EMISSIVE_BLOCKER_RENDER_TARGET "*EMISSIVE_BLOCKER_PLANE" - -///This plane is "unblockable" emissives. It does the same thing as the emissive plane but isn't masked by the emissive blocker plane. Use for on-mob and movable emissives. -#define EMISSIVE_UNBLOCKABLE_PLANE 170 -#define EMISSIVE_UNBLOCKABLE_RENDER_TARGET "*EMISSIVE_UNBLOCKABLE_PLANE" +/// The layer you should use if you _really_ don't want an emissive overlay to be blocked. +#define EMISSIVE_LAYER_UNBLOCKABLE 9999 ///---------------- MISC ----------------------- diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index d23ce875b67..9336ac5f789 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -75,11 +75,25 @@ #define FLASH_LIGHT_POWER 3 #define FLASH_LIGHT_RANGE 3.8 +// Emissive blocking. /// Uses vis_overlays to leverage caching so that very few new items need to be made for the overlay. For anything that doesn't change outline or opaque area much or at all. #define EMISSIVE_BLOCK_GENERIC 1 /// Uses a dedicated render_target object to copy the entire appearance in real time to the blocking layer. For things that can change in appearance a lot from the base state, like humans. #define EMISSIVE_BLOCK_UNIQUE 2 +/// The color matrix applied to all emissive overlays. Should be solely dependent on alpha and not have RGB overlap with [EM_BLOCK_COLOR]. +#define EMISSIVE_COLOR list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,1,0) +/// A globaly cached version of [EMISSIVE_COLOR] for quick access. +GLOBAL_LIST_INIT(emissive_color, EMISSIVE_COLOR) +/// The color matrix applied to all emissive blockers. Should be solely dependent on alpha and not have RGB overlap with [EMISSIVE_COLOR]. +#define EM_BLOCK_COLOR list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) +/// A globaly cached version of [EM_BLOCK_COLOR] for quick access. +GLOBAL_LIST_INIT(em_block_color, EM_BLOCK_COLOR) +/// The color matrix used to mask out emissive blockers on the emissive plane. Alpha should default to zero, be solely dependent on the RGB value of [EMISSIVE_COLOR], and be independant of the RGB value of [EM_BLOCK_COLOR]. +#define EM_MASK_MATRIX list(0,0,0,1/3, 0,0,0,1/3, 0,0,0,1/3, 0,0,0,0, 1,1,1,0) +/// A globaly cached version of [EM_MASK_MATRIX] for quick access. +GLOBAL_LIST_INIT(em_mask_matrix, EM_MASK_MATRIX) + /// Returns the red part of a #RRGGBB hex sequence as number #define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4)) diff --git a/code/__HELPERS/lighting.dm b/code/__HELPERS/lighting.dm new file mode 100644 index 00000000000..685958b015f --- /dev/null +++ b/code/__HELPERS/lighting.dm @@ -0,0 +1,5 @@ +/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR]. +/proc/emissive_appearance(icon, icon_state = "", layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE) + var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, EMISSIVE_PLANE, alpha, appearance_flags) + appearance.color = GLOB.emissive_color + return appearance diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index 9006a746db4..16970064226 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -115,17 +115,25 @@ mymob.overlay_fullscreen("lighting_backdrop_lit", /atom/movable/screen/fullscreen/lighting_backdrop/lit) mymob.overlay_fullscreen("lighting_backdrop_unlit", /atom/movable/screen/fullscreen/lighting_backdrop/unlit) +/*! + * This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers. + * + * Emissive overlays are pasted with an atom color that converts them to be entirely some specific color. + * Emissive blockers are pasted with an atom color that converts them to be entirely some different color. + * Emissive overlays and emissive blockers are put onto the same plane. + * The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects. + * A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is. + * This is then used to alpha mask the lighting plane. + */ + /atom/movable/screen/plane_master/lighting/Initialize() . = ..() add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE)) - add_filter("unblockable_emissives", 2, alpha_mask_filter(render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE)) - add_filter("object_lighting", 3, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)) + add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)) + /** - * Things placed on this mask the lighting plane. Doesn't render directly. - * - * Gets masked by blocking plane. Use for things that you want blocked by - * mobs, items, etc. + * Handles emissive overlays and emissive blockers. */ /atom/movable/screen/plane_master/emissive name = "emissive plane master" @@ -135,30 +143,7 @@ /atom/movable/screen/plane_master/emissive/Initialize() . = ..() - add_filter("emissive_block", 1, alpha_mask_filter(render_source = EMISSIVE_BLOCKER_RENDER_TARGET, flags = MASK_INVERSE)) - -/** - * Things placed on this always mask the lighting plane. Doesn't render directly. - * - * Always masks the light plane, isn't blocked by anything. Use for on mob glows, - * magic stuff, etc. - */ -/atom/movable/screen/plane_master/emissive_unblockable - name = "unblockable emissive plane master" - plane = EMISSIVE_UNBLOCKABLE_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_target = EMISSIVE_UNBLOCKABLE_RENDER_TARGET - -/** - * Things placed on this layer mask the emissive layer. Doesn't render directly - * - * You really shouldn't be directly using this, use atom helpers instead - */ -/atom/movable/screen/plane_master/emissive_blocker - name = "emissive blocker plane master" - plane = EMISSIVE_BLOCKER_PLANE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - render_target = EMISSIVE_BLOCKER_RENDER_TARGET + add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix)) ///Contains space parallax /atom/movable/screen/plane_master/parallax diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 94873398849..3436ff17fc3 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -77,9 +77,9 @@ . = ..() switch(blocks_emissive) if(EMISSIVE_BLOCK_GENERIC) - var/mutable_appearance/gen_emissive_blocker = mutable_appearance(icon, icon_state, 0, EMISSIVE_BLOCKER_PLANE) + var/mutable_appearance/gen_emissive_blocker = mutable_appearance(icon, icon_state, plane = EMISSIVE_PLANE, alpha = src.alpha) + gen_emissive_blocker.color = GLOB.em_block_color gen_emissive_blocker.dir = dir - gen_emissive_blocker.alpha = alpha gen_emissive_blocker.appearance_flags |= appearance_flags add_overlay(list(gen_emissive_blocker)) if(EMISSIVE_BLOCK_UNIQUE) @@ -139,9 +139,9 @@ if(!blocks_emissive) return else if (blocks_emissive == EMISSIVE_BLOCK_GENERIC) - var/mutable_appearance/gen_emissive_blocker = mutable_appearance(icon, icon_state, 0, EMISSIVE_BLOCKER_PLANE) + var/mutable_appearance/gen_emissive_blocker = mutable_appearance(icon, icon_state, plane = EMISSIVE_PLANE, alpha = src.alpha) + gen_emissive_blocker.color = GLOB.em_block_color gen_emissive_blocker.dir = dir - gen_emissive_blocker.alpha = alpha gen_emissive_blocker.appearance_flags |= appearance_flags return gen_emissive_blocker else if(blocks_emissive == EMISSIVE_BLOCK_UNIQUE) diff --git a/code/game/machinery/accounting.dm b/code/game/machinery/accounting.dm index 0cf85a07a80..98d2769dc59 100644 --- a/code/game/machinery/accounting.dm +++ b/code/game/machinery/accounting.dm @@ -58,15 +58,15 @@ if(machine_stat & (NOPOWER|BROKEN) || !anchored) return if(panel_open) - . += mutable_appearance(icon, "recharger-open", layer, plane, alpha) + . += mutable_appearance(icon, "recharger-open", alpha = src.alpha) return if(inserted_id) - . += mutable_appearance(icon, "recharger-full", layer, plane, alpha) - . += mutable_appearance(icon, "recharger-full", 0, EMISSIVE_PLANE, alpha) + . += mutable_appearance(icon, "recharger-full", alpha = src.alpha) + . += emissive_appearance(icon, "recharger-full", alpha = src.alpha) return - . += mutable_appearance(icon, "recharger-empty", layer, plane, alpha) - . += mutable_appearance(icon, "recharger-empty", 0, EMISSIVE_PLANE, alpha) + . += mutable_appearance(icon, "recharger-empty", alpha = src.alpha) + . += emissive_appearance(icon, "recharger-empty", alpha = src.alpha) /obj/machinery/accounting/update_appearance(updates) . = ..() diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 810cb72f3cf..95379125be6 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -39,8 +39,8 @@ var/overlay_state = icon_screen if(machine_stat & BROKEN) overlay_state = "[icon_state]_broken" - . += mutable_appearance(icon, overlay_state, layer, plane) - . += mutable_appearance(icon, overlay_state, layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, overlay_state) + . += emissive_appearance(icon, overlay_state) /obj/machinery/computer/power_change() . = ..() diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index bbf32901c87..6379461204c 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -80,32 +80,32 @@ . += "fire_overlay" if(is_station_level(z)) . += "fire_[SSsecurity_level.current_level]" - . += mutable_appearance(icon, "fire_[SSsecurity_level.current_level]", layer, plane) - . += mutable_appearance(icon, "fire_[SSsecurity_level.current_level]", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "fire_[SSsecurity_level.current_level]") + . += emissive_appearance(icon, "fire_[SSsecurity_level.current_level]") else . += "fire_[SEC_LEVEL_GREEN]" - . += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]", layer, plane) - . += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]") + . += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]") var/area/A = get_area(src) if(!detecting || !A.fire) . += "fire_off" - . += mutable_appearance(icon, "fire_off", layer, plane) - . += mutable_appearance(icon, "fire_off", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "fire_off") + . += emissive_appearance(icon, "fire_off") else if(obj_flags & EMAGGED) . += "fire_emagged" - . += mutable_appearance(icon, "fire_emagged", layer, plane) - . += mutable_appearance(icon, "fire_emagged", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "fire_emagged") + . += emissive_appearance(icon, "fire_emagged") else . += "fire_on" - . += mutable_appearance(icon, "fire_on", layer, plane) - . += mutable_appearance(icon, "fire_on", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "fire_on") + . += emissive_appearance(icon, "fire_on") if(!panel_open && detecting && triggered) //It just looks horrible with the panel open . += "fire_detected" - . += mutable_appearance(icon, "fire_detected", layer, plane) - . += mutable_appearance(icon, "fire_detected", layer, EMISSIVE_PLANE) //Pain + . += mutable_appearance(icon, "fire_detected") + . += emissive_appearance(icon, "fire_detected") //Pain /obj/machinery/firealarm/emp_act(severity) . = ..() diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 31efa556d53..10e7f854c1c 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -38,7 +38,7 @@ /obj/machinery/light_switch/update_overlays() . = ..() if(!(machine_stat & NOPOWER)) - . += mutable_appearance(icon, "[base_icon_state]-glow", 0, EMISSIVE_PLANE, alpha) + . += emissive_appearance(icon, "[base_icon_state]-glow", alpha = src.alpha) /obj/machinery/light_switch/examine(mob/user) . = ..() diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index e634d2392cb..bc84b0f03c2 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -176,17 +176,17 @@ if(machine_stat & (NOPOWER|BROKEN) || !anchored) return if(panel_open) - . += mutable_appearance(icon, "[base_icon_state]-open", layer, plane, alpha) + . += mutable_appearance(icon, "[base_icon_state]-open", alpha = src.alpha) return if(!charging) - . += mutable_appearance(icon, "[base_icon_state]-empty", layer, plane, alpha) - . += mutable_appearance(icon, "[base_icon_state]-empty", 0, EMISSIVE_PLANE, alpha) + . += mutable_appearance(icon, "[base_icon_state]-empty", alpha = src.alpha) + . += emissive_appearance(icon, "[base_icon_state]-empty", alpha = src.alpha) return if(using_power) - . += mutable_appearance(icon, "[base_icon_state]-charging", layer, plane, alpha) - . += mutable_appearance(icon, "[base_icon_state]-charging", 0, EMISSIVE_PLANE, alpha) + . += mutable_appearance(icon, "[base_icon_state]-charging", alpha = src.alpha) + . += emissive_appearance(icon, "[base_icon_state]-charging", alpha = src.alpha) return - . += mutable_appearance(icon, "[base_icon_state]-full", layer, plane, alpha) - . += mutable_appearance(icon, "[base_icon_state]-full", 0, EMISSIVE_PLANE, alpha) + . += mutable_appearance(icon, "[base_icon_state]-full", alpha = src.alpha) + . += emissive_appearance(icon, "[base_icon_state]-full", alpha = src.alpha) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 78514a6f3ad..8710d58440c 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -88,7 +88,7 @@ if(broken || !secure) return //Overlay is similar enough for both that we can use the same mask for both - . += mutable_appearance(icon, "locked", 0, EMISSIVE_PLANE, alpha) + . += emissive_appearance(icon, "locked", alpha = src.alpha) . += locked ? "locked" : "unlocked" /obj/structure/closet/examine(mob/user) diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 3be8dbb5453..69ff657394f 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -63,7 +63,7 @@ /obj/machinery/smartfridge/update_overlays() . = ..() if(!machine_stat) - . += mutable_appearance(icon, "smartfridge-light-mask", 0, EMISSIVE_PLANE, alpha) + . += emissive_appearance(icon, "smartfridge-light-mask", alpha = src.alpha) diff --git a/code/modules/lighting/emissive_blocker.dm b/code/modules/lighting/emissive_blocker.dm index 2da767abc84..396c59e971e 100644 --- a/code/modules/lighting/emissive_blocker.dm +++ b/code/modules/lighting/emissive_blocker.dm @@ -7,8 +7,9 @@ * almost guaranteed to be doing something wrong. */ /atom/movable/emissive_blocker - name = "" - plane = EMISSIVE_BLOCKER_PLANE + name = "emissive blocker" + plane = EMISSIVE_PLANE + layer = FLOAT_LAYER mouse_opacity = MOUSE_OPACITY_TRANSPARENT //Why? //render_targets copy the transform of the target as well, but vis_contents also applies the transform @@ -21,6 +22,8 @@ verbs.Cut() //Cargo culting from lighting object, this maybe affects memory usage? render_source = source + color = GLOB.em_block_color + /atom/movable/emissive_blocker/ex_act(severity) return FALSE diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 599eeecc848..2e92c3570c9 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -402,19 +402,19 @@ if((machine_stat & (BROKEN|MAINT)) || update_state) return - . += mutable_appearance(icon, "apcox-[locked]", layer, plane) - . += mutable_appearance(icon, "apcox-[locked]", layer, EMISSIVE_PLANE) - . += mutable_appearance(icon, "apco3-[charging]", layer, plane) - . += mutable_appearance(icon, "apco3-[charging]", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "apcox-[locked]") + . += emissive_appearance(icon, "apcox-[locked]") + . += mutable_appearance(icon, "apco3-[charging]") + . += emissive_appearance(icon, "apco3-[charging]") if(!operating) return - . += mutable_appearance(icon, "apco0-[equipment]", layer, plane) - . += mutable_appearance(icon, "apco0-[equipment]", layer, EMISSIVE_PLANE) - . += mutable_appearance(icon, "apco1-[lighting]", layer, plane) - . += mutable_appearance(icon, "apco1-[lighting]", layer, EMISSIVE_PLANE) - . += mutable_appearance(icon, "apco2-[environ]", layer, plane) - . += mutable_appearance(icon, "apco2-[environ]", layer, EMISSIVE_PLANE) + . += mutable_appearance(icon, "apco0-[equipment]") + . += emissive_appearance(icon, "apco0-[equipment]") + . += mutable_appearance(icon, "apco1-[lighting]") + . += emissive_appearance(icon, "apco1-[lighting]") + . += mutable_appearance(icon, "apco2-[environ]") + . += emissive_appearance(icon, "apco2-[environ]") /// Checks for what icon updates we will need to handle /obj/machinery/power/apc/proc/check_updates() diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index c8e79a27def..041a3951890 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -387,15 +387,15 @@ //check for items in disposal - occupied light if(contents.len > 0) . += "dispover-full" - . += mutable_appearance(icon, "dispover-full", 0, EMISSIVE_PLANE, alpha) + . += emissive_appearance(icon, "dispover-full", alpha = src.alpha) //charging and ready light if(pressure_charging) . += "dispover-charge" - . += mutable_appearance(icon, "dispover-charge-glow", 0, EMISSIVE_PLANE, alpha) + . += emissive_appearance(icon, "dispover-charge-glow", alpha = src.alpha) else if(full_pressure) . += "dispover-ready" - . += mutable_appearance(icon, "dispover-ready-glow", 0, EMISSIVE_PLANE, alpha) + . += emissive_appearance(icon, "dispover-ready-glow", alpha = src.alpha) /obj/machinery/disposal/bin/proc/do_flush() set waitfor = FALSE diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm index f8ad95c498f..9ff2e9ab5bd 100644 --- a/code/modules/research/nanites/nanite_program_hub.dm +++ b/code/modules/research/nanites/nanite_program_hub.dm @@ -30,8 +30,8 @@ . = ..() if((machine_stat & (NOPOWER|MAINT|BROKEN)) || panel_open) return - . += mutable_appearance(icon, "nanite_program_hub_on", layer, plane) - . += mutable_appearance(icon, "nanite_program_hub_on", 0, EMISSIVE_PLANE) + . += mutable_appearance(icon, "nanite_program_hub_on") + . += emissive_appearance(icon, "nanite_program_hub_on") /obj/machinery/nanite_program_hub/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/disk/nanite_program)) diff --git a/code/modules/research/nanites/nanite_programmer.dm b/code/modules/research/nanites/nanite_programmer.dm index cbc572d5fcd..6bc2b020a1c 100644 --- a/code/modules/research/nanites/nanite_programmer.dm +++ b/code/modules/research/nanites/nanite_programmer.dm @@ -15,8 +15,8 @@ . = ..() if((machine_stat & (NOPOWER|MAINT|BROKEN)) || panel_open) return - . += mutable_appearance(icon, "nanite_programmer_on", layer, plane) - . += mutable_appearance(icon, "nanite_programmer_on", 0, EMISSIVE_PLANE) + . += mutable_appearance(icon, "nanite_programmer_on") + . += emissive_appearance(icon, "nanite_programmer_on") /obj/machinery/nanite_programmer/attackby(obj/item/I, mob/user) if(istype(I, /obj/item/disk/nanite_program)) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index a1ef7369bde..966d59978c9 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -263,7 +263,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C if(!light_mask) return if(!(machine_stat & BROKEN) && powered()) - . += mutable_appearance(icon, light_mask, 0, EMISSIVE_PLANE) + . += emissive_appearance(icon, light_mask) /obj/machinery/vending/obj_break(damage_flag) . = ..() diff --git a/tgstation.dme b/tgstation.dme index 2d01a9f6f38..d21976789a2 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -204,6 +204,7 @@ #include "code\__HELPERS\icons.dm" #include "code\__HELPERS\jatum.dm" #include "code\__HELPERS\level_traits.dm" +#include "code\__HELPERS\lighting.dm" #include "code\__HELPERS\matrices.dm" #include "code\__HELPERS\mobs.dm" #include "code\__HELPERS\mouse_control.dm"