diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 55fbbecd14d..9fcc10c7a52 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -378,3 +378,9 @@ // Default UI style applied to client prefs. #define DEFAULT_UI_STYLE /decl/ui_style/midnight + +// Indicates a status effect will never expire. +#define STATUS_EFFECT_INDEFINITE (-1) + +// Converts a real time in deciseconds into an approximate number of SSmobs (Life()) ticks. +#define DS_TO_LIFE_TICKS(X) (ceil(X / SSmobs.wait)) diff --git a/code/__defines/mob_status.dm b/code/__defines/mob_status.dm index 42bc8854a7a..238ac560411 100644 --- a/code/__defines/mob_status.dm +++ b/code/__defines/mob_status.dm @@ -1,5 +1,5 @@ #define PENDING_STATUS(MOB, COND) (LAZYACCESS(MOB.pending_status_counters, COND) || LAZYACCESS(MOB.status_counters, COND)) #define GET_STATUS(MOB, COND) (LAZYACCESS(MOB.status_counters, COND)) #define HAS_STATUS(MOB, COND) (GET_STATUS(MOB, COND) > 0) -#define ADJ_STATUS(MOB, COND, AMT) (MOB.set_status(COND, PENDING_STATUS(MOB, COND) + AMT)) -#define SET_STATUS_MAX(MOB, COND, AMT) (MOB.set_status(COND, max(PENDING_STATUS(MOB, COND), AMT))) \ No newline at end of file +#define ADJ_STATUS(MOB, COND, AMT) (MOB.set_status_condition(COND, PENDING_STATUS(MOB, COND) + AMT)) +#define SET_STATUS_MAX(MOB, COND, AMT) (MOB.set_status_condition(COND, max(PENDING_STATUS(MOB, COND), AMT))) \ No newline at end of file diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 022c6011a7a..820ce611c47 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -389,7 +389,8 @@ var/global/list/dexterity_levels = list( #define HO_HANDCUFF_LAYER 25 #define HO_INHAND_LAYER 26 #define HO_FIRE_LAYER 27 //If you're on fire -#define TOTAL_OVER_LAYERS 27 +#define HO_EFFECT_LAYER 28 +#define TOTAL_OVER_LAYERS 28 ////////////////////////////////// // Underlay defines; vestigal implementation currently. diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 48829da57dd..203f646702f 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -44,6 +44,9 @@ var/obj/screen/action_button/hide_toggle/hide_actions_toggle var/action_buttons_hidden = FALSE + var/obj/screen/status_effect_master/status_effects + + /datum/hud/New(mob/owner) mymob = owner instantiate() diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm index 86ddc55b91f..bf03370505e 100644 --- a/code/datums/cinematic.dm +++ b/code/datums/cinematic.dm @@ -27,7 +27,7 @@ var/global/datum/cinematic/cinematic = new if(M.client) M.client.screen += cinematic_screen //show every client the cinematic viewers[M.client] = GET_STATUS(M, STAT_STUN) - M.set_status(STAT_STUN, 8000) + M.set_status_condition(STAT_STUN, 8000) override.nuke_act(cinematic_screen, station_missed) //cinematic happens here, as does mob death. //If it's actually the end of the round, wait for it to end. @@ -36,6 +36,6 @@ var/global/datum/cinematic/cinematic = new for(var/client/C in viewers) if(C.mob) - C.mob.set_status(STAT_STUN, viewers[C]) + C.mob.set_status_condition(STAT_STUN, viewers[C]) C.screen -= cinematic_screen QDEL_NULL(cinematic_screen) \ No newline at end of file diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm index 09046ea83f1..94260cca9de 100644 --- a/code/datums/wires/camera.dm +++ b/code/datums/wires/camera.dm @@ -42,7 +42,7 @@ var/global/const/CAMERA_WIRE_ALARM = 8 if(CAMERA_WIRE_POWER) C.cut_power = !mended - C.set_status(mended, usr) + C.set_status_condition(mended, usr) if(CAMERA_WIRE_LIGHT) C.light_disabled = !mended diff --git a/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm b/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm index aed8aa4e95e..7e94d52d67e 100644 --- a/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm +++ b/code/game/gamemodes/endgame/ftl_jump/ftl_jump.dm @@ -53,14 +53,14 @@ if(M.client) to_chat(M,"You feel oddly light, and somewhat disoriented as everything around you shimmers and warps ever so slightly.") M.overlay_fullscreen("wormhole", /obj/screen/fullscreen/wormhole_overlay) - M.set_status(STAT_CONFUSE, 20) + M.set_status_condition(STAT_CONFUSE, 20) bluegoasts += new/obj/effect/bluegoast/(get_turf(M),M) /datum/universal_state/jump/proc/clear_duplicated(var/mob/living/M) if(M.client) to_chat(M,"You feel rooted in material world again.") M.clear_fullscreen("wormhole") - M.set_status(STAT_CONFUSE, 0) + M.set_status_condition(STAT_CONFUSE, 0) for(var/mob/goast in global.ghost_mob_list) goast.mouse_opacity = initial(goast.mouse_opacity) goast.set_invisibility(initial(goast.invisibility)) diff --git a/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm b/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm index 7ce4792bc9f..7e44ab9a6d5 100644 --- a/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm +++ b/code/game/machinery/_machines_base/stock_parts/_stock_parts.dm @@ -15,7 +15,7 @@ return FALSE // Can potentially add uninstall code here, but not currently supported. return ..() -/obj/item/stock_parts/proc/set_status(var/obj/machinery/machine, var/flag) +/obj/item/stock_parts/proc/set_status_condition(var/obj/machinery/machine, var/flag) var/old_stat = status status |= flag if(old_stat != status) @@ -34,7 +34,7 @@ machine.component_stat_change(src, old_stat, flag) /obj/item/stock_parts/proc/on_install(var/obj/machinery/machine) - set_status(machine, PART_STAT_INSTALLED) + set_status_condition(machine, PART_STAT_INSTALLED) /obj/item/stock_parts/proc/on_uninstall(var/obj/machinery/machine, var/temporary = FALSE) unset_status(machine, PART_STAT_INSTALLED) @@ -48,7 +48,7 @@ if(istype(machine)) LAZYDISTINCTADD(machine.processing_parts, src) START_PROCESSING_MACHINE(machine, MACHINERY_PROCESS_COMPONENTS) - set_status(machine, PART_STAT_PROCESSING) + set_status_condition(machine, PART_STAT_PROCESSING) /obj/item/stock_parts/proc/stop_processing(var/obj/machinery/machine) if(istype(machine)) diff --git a/code/game/machinery/_machines_base/stock_parts/power/battery.dm b/code/game/machinery/_machines_base/stock_parts/power/battery.dm index c78b358aea6..f4ccdd2c701 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/battery.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/battery.dm @@ -49,7 +49,7 @@ if(istype(machine)) machine.power_change() machine.queue_icon_update() - set_status(machine, PART_STAT_CONNECTED) + set_status_condition(machine, PART_STAT_CONNECTED) update_icon() return cell @@ -112,7 +112,7 @@ /obj/item/stock_parts/power/battery/can_provide_power(var/obj/machinery/machine) if(is_functional() && cell && cell.check_charge(CELLRATE * machine.get_power_usage())) machine.update_power_channel(LOCAL) - set_status(machine, PART_STAT_ACTIVE) + set_status_condition(machine, PART_STAT_ACTIVE) return TRUE return FALSE diff --git a/code/game/machinery/_machines_base/stock_parts/power/terminal.dm b/code/game/machinery/_machines_base/stock_parts/power/terminal.dm index 732d90839c9..c86c170eb97 100644 --- a/code/game/machinery/_machines_base/stock_parts/power/terminal.dm +++ b/code/game/machinery/_machines_base/stock_parts/power/terminal.dm @@ -48,7 +48,7 @@ //Is willing to provide power if the wired contribution is nonnegligible and there is enough total local power to run the machine. /obj/item/stock_parts/power/terminal/can_provide_power(var/obj/machinery/machine) if(is_functional() && terminal && terminal.surplus() && machine.can_use_power_oneoff(machine.get_power_usage(), LOCAL) <= 0) - set_status(machine, PART_STAT_ACTIVE) + set_status_condition(machine, PART_STAT_ACTIVE) machine.update_power_channel(LOCAL) return TRUE return FALSE @@ -76,7 +76,7 @@ terminal.queue_icon_update() set_extension(src, /datum/extension/event_registration/shuttle_stationary, GET_DECL(/decl/observ/moved), machine, PROC_REF(machine_moved), get_area(src)) - set_status(machine, PART_STAT_CONNECTED) + set_status_condition(machine, PART_STAT_CONNECTED) start_processing(machine) /obj/item/stock_parts/power/terminal/proc/machine_moved(var/obj/machinery/machine, var/turf/old_loc, var/turf/new_loc) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 3262bf5a423..54234e2b26a 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -86,7 +86,7 @@ set_extension(src, /datum/extension/network_device/camera, null, null, null, TRUE, preset_channels, c_tag, cameranet_enabled, requires_connection) /obj/machinery/camera/Destroy() - set_status(0) //kick anyone viewing out + set_status_condition(0) //kick anyone viewing out return ..() /obj/machinery/camera/Process() @@ -227,7 +227,7 @@ //sparks spark_at(loc, amount=5) -/obj/machinery/camera/proc/set_status(var/newstatus, var/mob/user) +/obj/machinery/camera/proc/set_status_condition(var/newstatus, var/mob/user) if (status != newstatus && (!cut_power || status == TRUE)) status = newstatus // The only way for AI to reactivate cameras are malf abilities, this gives them different messages. @@ -337,7 +337,7 @@ ) /obj/machinery/camera/proc/toggle_status() - set_status(!status) + set_status_condition(!status) /decl/public_access/public_method/toggle_camera name = "toggle camera" diff --git a/code/game/machinery/doors/airlock_interactions.dm b/code/game/machinery/doors/airlock_interactions.dm index 2ad96280a52..2406735f21a 100644 --- a/code/game/machinery/doors/airlock_interactions.dm +++ b/code/game/machinery/doors/airlock_interactions.dm @@ -59,8 +59,8 @@ for(var/i in 1 to round(crush_damage/AIRLOCK_CRUSH_INCREMENT, 1)) apply_damage(AIRLOCK_CRUSH_INCREMENT, BRUTE) - set_status(STAT_STUN, round(crush_damage / 8, 1)) - set_status(STAT_WEAK, round(crush_damage / 8, 1)) + set_status_condition(STAT_STUN, round(crush_damage / 8, 1)) + set_status_condition(STAT_WEAK, round(crush_damage / 8, 1)) var/turf/T = loc if(!istype(T)) diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm index 1fb6b7666b7..1f9777dfac9 100644 --- a/code/game/machinery/jukebox.dm +++ b/code/game/machinery/jukebox.dm @@ -126,7 +126,7 @@ var/mob/living/human/H = M if(H.get_sound_volume_multiplier() < 0.2) continue - M.set_status(STAT_ASLEEP, 0) + M.set_status_condition(STAT_ASLEEP, 0) ADJ_STATUS(M, STAT_STUTTER, 20) SET_STATUS_MAX(M, STAT_DEAF, 30) SET_STATUS_MAX(M, STAT_WEAK, 3) @@ -134,7 +134,7 @@ SET_STATUS_MAX(M, STAT_STUN, 10) SET_STATUS_MAX(M, STAT_PARA, 4) else - M.set_status(STAT_JITTER, 400) + M.set_status_condition(STAT_JITTER, 400) spawn(15) explode() diff --git a/code/game/objects/items/weapons/implants/implants/adrenaline.dm b/code/game/objects/items/weapons/implants/implants/adrenaline.dm index 7c3f0036fa7..55adb2cb11d 100644 --- a/code/game/objects/items/weapons/implants/implants/adrenaline.dm +++ b/code/game/objects/items/weapons/implants/implants/adrenaline.dm @@ -26,9 +26,9 @@ uses-- to_chat(imp_in, "You feel a sudden surge of energy!") - imp_in.set_status(STAT_STUN, 0) - imp_in.set_status(STAT_WEAK, 0) - imp_in.set_status(STAT_PARA, 0) + imp_in.set_status_condition(STAT_STUN, 0) + imp_in.set_status_condition(STAT_WEAK, 0) + imp_in.set_status_condition(STAT_PARA, 0) /obj/item/implant/adrenalin/implanted(mob/source) source.StoreMemory("A implant can be activated by using the pale emote, say *pale to attempt to activate.", /decl/memory_options/system) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index f1d555da4d0..546fa11da25 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -35,7 +35,7 @@ /obj/item/baton/infinite/Initialize(var/ml, var/material_key, var/loaded_cell_type) . = ..(ml, material_key, loaded_cell_type = /obj/item/cell/device/infinite) - set_status(1, null) + set_status_condition(1, null) /obj/item/baton/proc/update_status() var/obj/item/cell/cell = get_cell() @@ -66,10 +66,10 @@ set_light(0) /obj/item/baton/attack_self(mob/user) - set_status(!status, user) + set_status_condition(!status, user) add_fingerprint(user) -/obj/item/baton/proc/set_status(var/newstatus, mob/user) +/obj/item/baton/proc/set_status_condition(var/newstatus, mob/user) var/obj/item/cell/cell = get_cell() if(cell?.charge >= hitcost) if(status != newstatus) diff --git a/code/modules/abstract/follower.dm b/code/modules/abstract/follower.dm new file mode 100644 index 00000000000..226477471d4 --- /dev/null +++ b/code/modules/abstract/follower.dm @@ -0,0 +1,16 @@ +// Simple obj for following another obj around (for light effects or such that need a physical reference) +/obj/abstract/follower + anchored = TRUE + simulated = FALSE + invisibility = INVISIBILITY_ABSTRACT + +/obj/abstract/follower/Initialize() + . = ..() + name = "" + verbs.Cut() + +/obj/abstract/follower/proc/follow_owner(atom/movable/owner) + if(istype(owner) && !QDELETED(owner) && owner.loc) + forceMove(owner.loc) + else + forceMove(null) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index c211f274d60..9594f9dd3dd 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1415,10 +1415,10 @@ var/global/BSACooldown = 0 SPAN_OCCULT("OOC: \The [M] has been paralyzed by a staff member. Please hold all interactions with them until staff have finished with them."), SPAN_OCCULT("OOC: You have been paralyzed by a staff member. Please refer to your currently open admin help ticket or, if you don't have one, admin help for assistance.") ) - M.set_status(STAT_PARA, 8000) + M.set_status_condition(STAT_PARA, 8000) M.admin_paralyzed = TRUE else - M.set_status(STAT_PARA, 0) + M.set_status_condition(STAT_PARA, 0) M.admin_paralyzed = FALSE M.visible_message(SPAN_OCCULT("OOC: \The [M] has been released from paralysis by staff. You may resume interactions with them.")) to_chat(M, SPAN_OCCULT("OOC: You have been released from paralysis by staff and can return to your game.")) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index c9e2798773b..45976fa2381 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -992,7 +992,7 @@ M.take_damage(min(99, M.current_health - 1)) SET_STATUS_MAX(M, STAT_STUN, 20) SET_STATUS_MAX(M, STAT_WEAK, 20) - M.set_status(STAT_STUTTER, 20) + M.set_status_condition(STAT_STUTTER, 20) else if(href_list["CentcommReply"]) var/mob/living/L = locate(href_list["CentcommReply"]) diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index 7b7155b8391..adbd2a25ab5 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -64,6 +64,8 @@ return ..() + {" + + diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index 971e7a394bc..5298721b88b 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -658,7 +658,7 @@ return if(amt < 0) amt += GET_STATUS(victim, selected_condition.type) - victim.set_status(selected_condition.type, amt) + victim.set_status_condition(selected_condition.type, amt) log_and_message_admins("set [selected_condition.name] to [amt] on \the [victim].") else if(href_list["setmaterial"]) @@ -705,6 +705,35 @@ else to_chat(usr, SPAN_WARNING("Failed to remove [ability] from [target]!")) + else if (href_list["give_status_effect"]) + var/mob/living/target = locate(href_list["give_status_effect"]) + if(!istype(target) || QDELETED(target)) + to_chat(usr, SPAN_WARNING("Only /mob/living mobs can have status effects.")) + else + // Evil pyramid due to apparently not being able to return early in this Topic() + var/decl/status_effect/effect = input(usr, "Which effect do you wish to give?", "Add Status Effect") as null|anything in decls_repository.get_decls_of_type_unassociated(/decl/status_effect) + if(istype(effect) && !QDELETED(target)) + var/duration = input(usr, "How long do you wish this effect to last, in life ticks (roughly 2 seconds each)? Enter -1 for a permanent effect.", "Add Status Effect") as num|null + if(!isnull(duration)) + duration = clamp(duration, STATUS_EFFECT_INDEFINITE, 100) + if(duration != 0 && !QDELETED(target)) + if(target.set_status_effect(effect, duration)) + to_chat(usr, SPAN_NOTICE("Added [effect] to [target] for [duration] life ticks.")) + else + to_chat(usr, SPAN_WARNING("Failed to add [effect] to [target].")) + + else if (href_list["remove_status_effect"]) + var/mob/living/target = locate(href_list["remove_status_effect"]) + if(!istype(target) && !QDELETED(target)) + to_chat(usr, SPAN_WARNING("Only /mob/living mobs can have status effects.")) + else + var/decl/status_effect/effect = input(usr, "Which effect do you wish to remove?", "Remove Status Effect") as null|anything in target.status_effects + if(istype(effect)) + if(target.clear_status_effect(effect)) + to_chat(usr, SPAN_NOTICE("Removed [effect] from [target].")) + else + to_chat(usr, SPAN_WARNING("Failed to remove [effect] from [target].")) + if(href_list["datumrefresh"]) var/datum/datum_to_refresh = locate(href_list["datumrefresh"]) if(istype(datum_to_refresh, /datum) || istype(datum_to_refresh, /client)) diff --git a/code/modules/clothing/_clothing.dm b/code/modules/clothing/_clothing.dm index b6cc37b0ada..cf23ae5cd17 100644 --- a/code/modules/clothing/_clothing.dm +++ b/code/modules/clothing/_clothing.dm @@ -71,7 +71,7 @@ /obj/item/clothing/Destroy() if(is_accessory()) - on_removed() + on_accessory_removed() return ..() /obj/item/clothing/get_fallback_slot(slot) diff --git a/code/modules/clothing/_clothing_accessories.dm b/code/modules/clothing/_clothing_accessories.dm index 0469f605d01..d958fc571e7 100644 --- a/code/modules/clothing/_clothing_accessories.dm +++ b/code/modules/clothing/_clothing_accessories.dm @@ -91,7 +91,7 @@ /obj/item/clothing/proc/remove_accessory(mob/user, obj/item/clothing/accessory) if(!accessory || !(accessory in accessories) || !accessory.accessory_removable || !accessory.canremove) return - accessory.on_removed(user) + accessory.on_accessory_removed(user) update_icon() /obj/item/clothing/proc/removetie_verb() @@ -178,7 +178,7 @@ return TRUE return FALSE -/obj/item/clothing/proc/on_removed(var/mob/user) +/obj/item/clothing/proc/on_accessory_removed(var/mob/user) var/obj/item/clothing/holder = loc if(istype(holder)) if(user) diff --git a/code/modules/clothing/sensors/vitals_sensor.dm b/code/modules/clothing/sensors/vitals_sensor.dm index 8ed94b74013..d029f8b33e1 100644 --- a/code/modules/clothing/sensors/vitals_sensor.dm +++ b/code/modules/clothing/sensors/vitals_sensor.dm @@ -44,7 +44,7 @@ . = ..() update_removable() -/obj/item/clothing/sensor/vitals/on_removed(mob/user) +/obj/item/clothing/sensor/vitals/on_accessory_removed(mob/user) . = ..() update_removable() diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm index 896bd3db241..f822bd442c6 100644 --- a/code/modules/clothing/spacesuits/spacesuits.dm +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -60,10 +60,10 @@ if(ispath(camera)) camera = new camera(src) - camera.set_status(0) + camera.set_status_condition(0) if(camera) - camera.set_status(!camera.status) + camera.set_status_condition(!camera.status) if(camera.status) camera.c_tag = user.get_id_name() to_chat(user, "User scanned as [camera.c_tag]. Camera activated.") diff --git a/code/modules/clothing/webbing/holster.dm b/code/modules/clothing/webbing/holster.dm index 1d49eaabc2b..efb1d4881aa 100644 --- a/code/modules/clothing/webbing/holster.dm +++ b/code/modules/clothing/webbing/holster.dm @@ -36,7 +36,7 @@ if(istype(holder)) holder.verbs |= /atom/proc/holster_verb -/obj/item/clothing/webbing/holster/on_removed(mob/user) +/obj/item/clothing/webbing/holster/on_accessory_removed(mob/user) var/obj/item/clothing/holder = loc if(istype(holder)) var/remove_verb = TRUE diff --git a/code/modules/mechs/mech_damage_immunity.dm b/code/modules/mechs/mech_damage_immunity.dm index 067c613d56d..01a8ef4a0f1 100644 --- a/code/modules/mechs/mech_damage_immunity.dm +++ b/code/modules/mechs/mech_damage_immunity.dm @@ -5,7 +5,7 @@ STAT_PARA ) -/mob/living/exosuit/set_status(condition, amount) +/mob/living/exosuit/set_status_condition(condition, amount) . = !(condition in ignore_status_conditions) && ..() /mob/living/exosuit/getOxyLoss() diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 4986952e130..a88a887cac4 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -92,7 +92,7 @@ reset_plane_and_layer() update_posture() if(!gibbed) - clear_status_effects() + clear_status_conditions() set_sight(sight|SEE_TURFS|SEE_MOBS|SEE_OBJS) set_see_in_dark(8) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 9f3089994e6..339769eea84 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -56,9 +56,9 @@ /mob/living/bot/handle_regular_status_updates() . = ..() if(.) - set_status(STAT_WEAK, 0) - set_status(STAT_STUN, 0) - set_status(STAT_PARA, 0) + set_status_condition(STAT_WEAK, 0) + set_status_condition(STAT_STUN, 0) + set_status_condition(STAT_PARA, 0) /mob/living/bot/get_life_damage_types() var/static/list/life_damage_types = list( diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index faca3a286c2..8f650dfa637 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -51,11 +51,11 @@ /mob/living/bot/secbot/turn_on() ..() - stun_baton.set_status(on, null) + stun_baton.set_status_condition(on, null) /mob/living/bot/secbot/turn_off() ..() - stun_baton.set_status(on, null) + stun_baton.set_status_condition(on, null) /mob/living/bot/secbot/on_update_icon() ..() diff --git a/code/modules/mob/living/human/life.dm b/code/modules/mob/living/human/life.dm index ebc47ef1202..8028fcd2ba2 100644 --- a/code/modules/mob/living/human/life.dm +++ b/code/modules/mob/living/human/life.dm @@ -125,8 +125,8 @@ vision = GET_INTERNAL_ORGAN(src, vision_organ_tag) if(!vision_organ_tag) // Presumably if a species has no vision organs, they see via some other means. - set_status(STAT_BLIND, 0) - set_status(STAT_BLURRY, 0) + set_status_condition(STAT_BLIND, 0) + set_status_condition(STAT_BLURRY, 0) else if(!vision || (vision && !vision.is_usable())) // Vision organs cut out or broken? Permablind. SET_STATUS_MAX(src, STAT_BLIND, 2) SET_STATUS_MAX(src, STAT_BLURRY, 1) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 05d2002770b..e662a4ef866 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -42,6 +42,7 @@ handle_grasp() handle_stance() handle_regular_hud_updates() + handle_status_conditions() handle_status_effects() return 1 @@ -445,9 +446,21 @@ //this handles hud updates. Calls update_vision() and handle_hud_icons() /mob/living/proc/handle_regular_hud_updates() + SHOULD_CALL_PARENT(TRUE) if(!should_do_hud_updates()) return FALSE + + if(buckled || restrained()) + set_status_effect(/decl/status_effect/restrained) + else + clear_status_effect(/decl/status_effect/restrained) + + if(current_posture?.prone) + set_status_effect(/decl/status_effect/prone) + else + clear_status_effect(/decl/status_effect/prone) + handle_hud_icons() handle_vision() handle_low_light_vision() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index dcbc0d2917e..0fa8f528b8a 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -232,8 +232,8 @@ default behaviour is: if(stat != DEAD && should_be_dead()) death() if(!QDELETED(src)) // death() may delete or remove us - set_status(STAT_BLIND, 1) - set_status(STAT_SILENCE, 0) + set_status_condition(STAT_BLIND, 1) + set_status_condition(STAT_SILENCE, 0) return TRUE //This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually @@ -329,17 +329,17 @@ default behaviour is: set_damage(OXY, 0) set_damage(CLONE, 0) set_damage(BRAIN, 0) - set_status(STAT_PARA, 0) - set_status(STAT_STUN, 0) - set_status(STAT_WEAK, 0) + set_status_condition(STAT_PARA, 0) + set_status_condition(STAT_STUN, 0) + set_status_condition(STAT_WEAK, 0) // shut down ongoing problems radiation = 0 bodytemperature = get_species()?.body_temperature || initial(bodytemperature) reset_genetic_conditions() - // fix all status conditions including blind/deaf - clear_status_effects() + // clear all status effects and conditions including blind/deaf + clear_status_conditions() heal_overall_damage(get_damage(BRUTE), get_damage(BURN)) @@ -901,7 +901,7 @@ default behaviour is: if(!HAS_STATUS(src, STAT_PARA) && stat == CONSCIOUS) visible_message(SPAN_DANGER("\The [src] starts having a seizure!")) SET_STATUS_MAX(src, STAT_PARA, rand(8,16)) - set_status(STAT_JITTER, rand(150,200)) + set_status_condition(STAT_JITTER, rand(150,200)) take_damage(rand(50, 60), PAIN) /mob/living/proc/get_digestion_product() diff --git a/code/modules/mob/living/living_appearance.dm b/code/modules/mob/living/living_appearance.dm index ea2bb37147e..e3f4369ece7 100644 --- a/code/modules/mob/living/living_appearance.dm +++ b/code/modules/mob/living/living_appearance.dm @@ -77,3 +77,24 @@ /mob/living/get_current_mob_underlay(var/underlay_layer) return mob_underlays[underlay_layer] + +/mob/living/refresh_visible_overlays() + if((. = ..())) + var/list/status_effect_overlays + for(var/decl/status_effect/effect in status_effects) + var/image/status_overlay = effect.get_mob_overlay(src) + if(status_overlay) + LAZYADD(status_effect_overlays, status_overlay) + set_current_mob_overlay(HO_EFFECT_LAYER, status_effect_overlays, FALSE) + +/decl/status_effect/proc/get_mob_overlay(mob/living/owner) + if(!mob_overlay_icon || !mob_overlay_state || !istype(owner)) + return null + var/image/mob_overlay = overlay_image(mob_overlay_icon, mob_overlay_state, COLOR_WHITE, RESET_COLOR) + var/decl/bodytype/owner_bodytype = owner.get_bodytype() + if(owner_bodytype) + if(owner_bodytype.pixel_offset_x) + mob_overlay.pixel_x += -(owner_bodytype.pixel_offset_x) + if(owner_bodytype.pixel_offset_y) + mob_overlay.pixel_y += -(owner_bodytype.pixel_offset_y) + return mob_overlay diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index fc07b274edc..67c1a09ab5f 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -139,7 +139,7 @@ if(31 to INFINITY) SET_STATUS_MAX(src, STAT_WEAK, 10) //This should work for now, more is really silly and makes you lay there forever - set_status(STAT_JITTER, min(shock_damage*5, 200)) + set_status_condition(STAT_JITTER, min(shock_damage*5, 200)) spark_at(loc, amount=5, cardinal_only = TRUE) diff --git a/code/modules/mob/living/living_status.dm b/code/modules/mob/living/living_status.dm index 645b5323448..32024893a1d 100644 --- a/code/modules/mob/living/living_status.dm +++ b/code/modules/mob/living/living_status.dm @@ -1,9 +1,18 @@ -/mob // Defined on /mob to avoid having to pass args to every single attack_foo() proc. +// Defined on /mob to avoid having to pass args to every single attack_foo() proc. +/mob + // A STATUS CONDITION is a counter on an general incapacitating effect like sleep or blindness. + // STATUS CONDITION TRACKERS: var/list/status_counters var/list/pending_status_counters var/datum/status_marker_holder/status_markers -/mob/living/set_status(var/condition, var/amount) +/mob/living + // A STATUS EFFECT is a generalised effect on the mob, positive or negative, like buckling, healing or a curse. + // STATUS EFFECT TRACKERS: + var/list/status_effects + +// Status condition procs: +/mob/living/set_status_condition(var/condition, var/amount) if(QDELETED(src)) return FALSE if(!ispath(condition, /decl/status_condition)) @@ -57,7 +66,7 @@ var/decl/status_condition/status = GET_DECL(condition) status.handle_changed_amount(src, new_amount, last_amount) -/mob/living/handle_status_effects() +/mob/living/handle_status_conditions() . = ..() var/refresh_icon = FALSE for(var/condition in status_counters) @@ -69,12 +78,75 @@ if(refresh_icon) update_icon() -/mob/living/clear_status_effects() +/mob/living/clear_status_conditions() var/had_counters = !!LAZYLEN(status_counters) for(var/stype in status_counters) - set_status(stype, 0) + set_status_condition(stype, 0) status_counters = null pending_status_counters = null if(had_counters) rebuild_status_markers() update_icon() + +// Status effect procs: +/mob/living/proc/handle_status_effects() + SHOULD_CALL_PARENT(TRUE) + for(var/effect as anything in status_effects) + var/datum/status_effect/effect_data = status_effects[effect] + effect_data.on_effect_mob_life() + status_effect_indicators?.refresh_status_effects() + +/mob/living/proc/clear_status_effects() + for(var/effect as anything in status_effects) + var/datum/status_effect/effect_data = status_effects[effect] + effect_data.on_effect_expiry() + status_effects = null + +/mob/living/proc/clear_status_effect(var/decl/status_effect/effect, skip_update = FALSE) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect)) + return FALSE + var/datum/status_effect/existing_effect = LAZYACCESS(status_effects, effect) + if(!istype(existing_effect)) + return FALSE + existing_effect.on_effect_removed() + if(!skip_update) + status_effect_indicators?.refresh_status_effects() + try_refresh_visible_overlays() + return TRUE + +/mob/living/proc/has_status_effect(decl/status_effect/effect) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect)) + return FALSE + return !!LAZYACCESS(status_effects, effect) + +/mob/living/proc/set_status_effect(decl/status_effect/effect, duration = STATUS_EFFECT_INDEFINITE, skip_update = FALSE) + if(ispath(effect)) + effect = GET_DECL(effect) + if(!istype(effect)) + return FALSE + var/datum/status_effect/existing_effect = LAZYACCESS(status_effects, effect) + if(istype(existing_effect)) + // If the effect already exists, just update the timer. + existing_effect.lifetime = duration + else + // Otherwise, create a new datum. + existing_effect = new effect.status_effect_type(effect, src) + existing_effect.lifetime = duration + existing_effect.on_effect_added() + if(!skip_update) + status_effect_indicators?.refresh_status_effects() + try_refresh_visible_overlays() + return TRUE + +// DEBUG, REMOVE WHEN PROPERLY INTEGRATED +/mob/living + var/obj/screen/status_effect_master/status_effect_indicators + +/mob/living/Login() + ..() + status_effect_indicators ||= new(null, src) + client.screen |= status_effect_indicators diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm index 3ff4653c93d..9f5a88f6cd1 100644 --- a/code/modules/mob/living/silicon/login.dm +++ b/code/modules/mob/living/silicon/login.dm @@ -1,3 +1,3 @@ /mob/living/silicon/Login() ..() - set_status(STAT_ASLEEP, 0) + set_status_condition(STAT_ASLEEP, 0) diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index b53b8a9cfe2..bb0c5ebccab 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -39,7 +39,7 @@ var/global/list/default_pai_software = list() if(user != src || !istype(card)) if(ui) - ui.set_status(STATUS_CLOSE, 0) + ui.set_status_condition(STATUS_CLOSE, 0) return if(ui_key != "main") @@ -47,7 +47,7 @@ var/global/list/default_pai_software = list() if(S && !S.toggle) S.on_ui_interact(src, ui, force_open) else - if(ui) ui.set_status(STATUS_CLOSE, 0) + if(ui) ui.set_status_condition(STATUS_CLOSE, 0) return var/data[0] diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 4e2bc0fe3cf..d594285f78a 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -48,7 +48,7 @@ SHOULD_CALL_PARENT(FALSE) update_health() - set_status(STAT_PARA, min(GET_STATUS(src, STAT_PARA), 30)) + set_status_condition(STAT_PARA, min(GET_STATUS(src, STAT_PARA), 30)) if(HAS_STATUS(src, STAT_ASLEEP)) SET_STATUS_MAX(src, STAT_PARA, 3) @@ -68,7 +68,7 @@ SET_STATUS_MAX(src, STAT_BLIND, 2) if(has_genetic_condition(GENE_COND_DEAFENED)) - src.set_status(STAT_DEAF, 1) + src.set_status_condition(STAT_DEAF, 1) //update the state of modules and components here if (stat != CONSCIOUS) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index ad15792b151..48663b8a4ec 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1388,7 +1388,7 @@ /// THIS DOES NOT RELATE TO HELD ITEM SLOTS. It is very specifically a functional BP_L_HAND or BP_R_HAND organ, not necessarily a gripper. /mob/proc/get_usable_hand_slot_organ() var/obj/item/organ/external/paw = GET_EXTERNAL_ORGAN(src, BP_L_HAND) - if(!istype(paw) && !paw.is_usable()) + if(!istype(paw) || !paw.is_usable()) paw = GET_EXTERNAL_ORGAN(src, BP_R_HAND) if(istype(paw) && paw.is_usable()) return paw diff --git a/code/modules/mob/mob_status.dm b/code/modules/mob/mob_status.dm index 0e2c45822b9..726edf26264 100644 --- a/code/modules/mob/mob_status.dm +++ b/code/modules/mob/mob_status.dm @@ -1,9 +1,9 @@ // Stubs; see living_status.dm -/mob/proc/handle_status_effects() +/mob/proc/handle_status_conditions() SHOULD_CALL_PARENT(TRUE) -/mob/proc/clear_status_effects() +/mob/proc/clear_status_conditions() return -/mob/proc/set_status(var/condition, var/amount) +/mob/proc/set_status_condition(var/condition, var/amount) return diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 6ec207ea1b8..21e905f85a6 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -5,7 +5,7 @@ drop_from_inventory(W) try_refresh_visible_overlays() ADD_TRANSFORMATION_MOVEMENT_HANDLER(src) - set_status(STAT_STUN, 1) + set_status_condition(STAT_STUN, 1) icon = null set_invisibility(INVISIBILITY_ABSTRACT) for(var/t in get_external_organs()) @@ -18,7 +18,7 @@ //animation = null DEL_TRANSFORMATION_MOVEMENT_HANDLER(src) - set_status(STAT_STUN, 0) + set_status_condition(STAT_STUN, 0) update_posture() set_invisibility(initial(invisibility)) diff --git a/code/modules/modular_computers/hardware/lan_port.dm b/code/modules/modular_computers/hardware/lan_port.dm index 8ffecb3d26a..443ebe3a137 100644 --- a/code/modules/modular_computers/hardware/lan_port.dm +++ b/code/modules/modular_computers/hardware/lan_port.dm @@ -31,7 +31,7 @@ terminal = new(get_turf(parent)) set_extension(src, /datum/extension/event_registration/shuttle_stationary, GET_DECL(/decl/observ/moved), parent, PROC_REF(check_terminal_prox), get_area(src)) events_repository.register(/decl/observ/destroyed, terminal, src, PROC_REF(unset_terminal)) - set_status(parent, PART_STAT_CONNECTED) + set_status_condition(parent, PART_STAT_CONNECTED) /obj/item/stock_parts/computer/lan_port/proc/unset_terminal() remove_extension(src, /datum/extension/event_registration/shuttle_stationary) diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index e315b28c580..319be31eec5 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -134,7 +134,7 @@ nanoui is used to open and update nano browser uis * * @return nothing */ -/datum/nanoui/proc/set_status(state, push_update) +/datum/nanoui/proc/set_status_condition(state, push_update) if (state != status) // Only update if it is different if (status == STATUS_DISABLED) status = state @@ -164,7 +164,7 @@ nanoui is used to open and update nano browser uis if(new_status == STATUS_CLOSE) close() return 1 - set_status(new_status, push_update) + set_status_condition(new_status, push_update) /** * Set the ui to auto update (every master_controller tick) diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index c4980c3a303..966ecffc80b 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -210,7 +210,7 @@ owner.custom_pain("Your head feels numb and painful.",10) if(is_bruised() && prob(1) && !HAS_STATUS(owner, STAT_BLURRY)) to_chat(owner, "It becomes hard to see for some reason.") - owner.set_status(STAT_BLURRY, 10) + owner.set_status_condition(STAT_BLURRY, 10) var/held = owner.get_active_held_item() if(damage >= 0.5*max_damage && prob(1) && held) to_chat(owner, "Your hand won't respond properly, and you drop what you are holding!") diff --git a/code/modules/organs/internal/heart.dm b/code/modules/organs/internal/heart.dm index 2cc637a076c..ae158663cdc 100644 --- a/code/modules/organs/internal/heart.dm +++ b/code/modules/organs/internal/heart.dm @@ -173,7 +173,7 @@ FONT_HUGE(SPAN_DANGER("Blood sprays out from your [spray_organ]!")) ) SET_STATUS_MAX(owner, STAT_STUN, 1) - owner.set_status(STAT_BLURRY, 2) + owner.set_status_condition(STAT_BLURRY, 2) //AB occurs every heartbeat, this only throttles the visible effect next_blood_squirt = world.time + 80 diff --git a/code/modules/reagents/chems/chems_drinks.dm b/code/modules/reagents/chems/chems_drinks.dm index eca5276b785..ceb15af9a17 100644 --- a/code/modules/reagents/chems/chems_drinks.dm +++ b/code/modules/reagents/chems/chems_drinks.dm @@ -549,7 +549,7 @@ SET_STATUS_MAX(M, STAT_DIZZY, 20) ADJ_STATUS(M, STAT_DIZZY, 2) ADJ_STATUS(M, STAT_JITTER, 2) - M.set_status(STAT_DROWSY, 0) + M.set_status_condition(STAT_DROWSY, 0) /decl/material/liquid/drink/grenadine name = "grenadine syrup" diff --git a/code/modules/status_conditions/_status.dm b/code/modules/status_conditions/_status.dm index 49750b10a03..0c474cf9a7f 100644 --- a/code/modules/status_conditions/_status.dm +++ b/code/modules/status_conditions/_status.dm @@ -1,11 +1,15 @@ var/global/list/status_marker_holders = list() -// Check code/modules/mob/mob_status.dm code/modules/mob/living/living_status.dm -// for the procs that check/set/process these status conditions. +// Check code/modules/mob/mob_status.dm code/modules/mob/living/living_status.dm +// for the procs that check/set/process these status conditions. /decl/status_condition var/name var/check_flags = 0 var/list/victim_data + + var/hud_icon + var/hud_state + var/status_marker_icon = 'icons/effects/status.dmi' var/status_marker_state var/status_marker_private = FALSE diff --git a/code/modules/status_conditions/_status_markers.dm b/code/modules/status_conditions/_status_markers.dm index 9731e1881e6..c6e0f8ec8e5 100644 --- a/code/modules/status_conditions/_status_markers.dm +++ b/code/modules/status_conditions/_status_markers.dm @@ -1,3 +1,12 @@ +var/global/list/_status_marker_decls +/proc/get_status_marker_decls() + if(!global._status_marker_decls) + global._status_marker_decls = list() + for(var/decl/status_condition/cond as anything in decls_repository.get_decls_of_subtype_unassociated(/decl/status_condition)) + if(cond.status_marker_icon && cond.status_marker_state) + global._status_marker_decls += cond + return global._status_marker_decls + /obj/status_marker name = "" mouse_opacity = MOUSE_OPACITY_UNCLICKABLE @@ -58,18 +67,14 @@ mob_image_personal.layer = POINTER_LAYER animate(mob_image_personal, pixel_z = 1, time = 3, easing = (SINE_EASING | EASE_OUT), loop = -1) - animate( pixel_z = -1, time = 6, easing = SINE_EASING, loop = -1) - animate( pixel_z = 0, time = 3, easing = (SINE_EASING | EASE_IN), loop = -1) + animate( pixel_z = -1, time = 6, easing = SINE_EASING, loop = -1) + animate( pixel_z = 0, time = 3, easing = (SINE_EASING | EASE_IN), loop = -1) - var/list/all_status = decls_repository.get_decls_of_subtype(/decl/status_condition) - for(var/status_type in all_status) - var/decl/status_condition/status = all_status[status_type] + for(var/decl/status_condition/status in get_status_marker_decls()) if(status.status_marker_icon && status.status_marker_state) - var/obj/status_marker/marker = new(null, status) mob_image.add_vis_contents(marker) LAZYSET(markers, status, marker) - marker = new(null, status) mob_image_personal.add_vis_contents(marker) LAZYSET(markers_personal, status, marker) diff --git a/code/modules/status_conditions/definitions/status_effect_object.dm b/code/modules/status_conditions/definitions/status_effect_object.dm new file mode 100644 index 00000000000..665f9ae2e8b --- /dev/null +++ b/code/modules/status_conditions/definitions/status_effect_object.dm @@ -0,0 +1,20 @@ +/decl/status_effect/object + abstract_type = /decl/status_effect/object + status_effect_type = /decl/status_effect/object + +/datum/status_effect/object + var/obj/object = /obj/abstract/follower + var/owner_moved_callback = TYPE_PROC_REF(/obj/abstract/follower, follow_owner) + +/datum/status_effect/object/on_effect_added(mob/living/owner, datum/status_effect/effect) + . = ..() + if(ispath(object)) + object = new object(get_turf(owner)) + if(owner_moved_callback) + events_repository.register(/decl/observ/moved, owner, object, owner_moved_callback) + +/datum/status_effect/object/on_effect_removed(mob/living/owner, datum/status_effect/effect) + if(istype(object) && !QDELETED(object)) + qdel(object) + object = null + . = ..() diff --git a/code/modules/status_conditions/definitions/status_effect_prone.dm b/code/modules/status_conditions/definitions/status_effect_prone.dm new file mode 100644 index 00000000000..4f6b22e7289 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_effect_prone.dm @@ -0,0 +1,9 @@ +/decl/status_effect/prone + name = "Prone" + desc = "You are lying prone and may need to stand up before taking action." + hud_icon_state = "prone" + +/decl/status_effect/prone/on_effect_click(mob/living/owner, datum/status_effect/effect, params) + if(owner.current_posture?.prone) + owner.lay_down() + return TRUE diff --git a/code/modules/status_conditions/definitions/status_effect_restrained.dm b/code/modules/status_conditions/definitions/status_effect_restrained.dm new file mode 100644 index 00000000000..8a3cc14bc16 --- /dev/null +++ b/code/modules/status_conditions/definitions/status_effect_restrained.dm @@ -0,0 +1,8 @@ +/decl/status_effect/restrained + name = "Restrained" + desc = "You are restrained and need to resist to get out of your bindings." + hud_icon_state = "restrained" + +/decl/status_effect/restrained/on_effect_click(mob/living/owner, datum/status_effect/effect, params) + owner.resist() + return TRUE diff --git a/code/modules/status_conditions/status_effect.dm b/code/modules/status_conditions/status_effect.dm new file mode 100644 index 00000000000..c6848181b6c --- /dev/null +++ b/code/modules/status_conditions/status_effect.dm @@ -0,0 +1,106 @@ +/obj/screen/status_effect_master + screen_loc = "CENTER,TOP" + requires_ui_style = FALSE + // TODO: consider pooling these. + var/list/elements + +/obj/screen/status_effect_master/Destroy() + QDEL_NULL_LIST(elements) + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner) && owner.status_effect_indicators == src) + owner.status_effect_indicators = null + return ..() + +/obj/screen/status_effect_master/proc/refresh_status_effects() + + if(QDELETED(src)) + return + + var/mob/living/owner = owner_ref?.resolve() + if(!istype(owner)) + return + + var/list/seen_archetypes + var/list/elements_to_keep + var/list/elements_to_add + var/list/elements_to_remove + + // Track deltas for keeping/removing existing elements. + for(var/obj/screen/status_effect/element in elements) + var/effect = LAZYACCESS(owner.status_effects, element.archetype) + if(effect) + LAZYADD(elements_to_keep, element) + else + LAZYADD(elements_to_remove, element) + LAZYDISTINCTADD(seen_archetypes, element.archetype) + + // Create elements for new effects. + for(var/decl/status_effect/archetype in owner.status_effects) + if(archetype in seen_archetypes) + continue + var/obj/screen/status_effect/element = new(null, owner) + element.archetype = archetype + element.master = src + element.pixel_y = 32 + element.icon = archetype.hud_icon + element.icon_state = archetype.hud_icon_state + element.alpha = 0 + LAZYADD(elements_to_add, element) + + // Fade out and delete expired markers. + if(LAZYLEN(elements_to_remove)) + LAZYREMOVE(elements, elements_to_remove) + for(var/obj/screen/status_effect/element in elements_to_remove) + animate(element, alpha = 0, pixel_y = 32, time = 5) + QDEL_IN(element, 5) + + // Add our new records. + if(LAZYLEN(elements_to_add)) + LAZYADD(elements, elements_to_add) + add_vis_contents(elements_to_add) + + // Adjust positions and fade in new elements. + if(length(elements)) + var/offset_x = -(((length(elements)-1) * (world.icon_size + 2)) / 2) + for(var/obj/screen/element in elements) + if(element in elements_to_add) + pixel_x = offset_x + animate(element, alpha = 255, pixel_y = 0, time = 5) + else + animate(element, alpha = 255, pixel_x = offset_x, pixel_y = 0, time = 5) + offset_x += world.icon_size + 2 + +/obj/screen/status_effect + alpha = 0 + requires_ui_style = FALSE + screen_loc = null // not handled via screen loc, but via vis contents of the master object. + var/decl/status_effect/archetype + var/obj/screen/status_effect_master/master + +/obj/screen/status_effect/Destroy() + if(master) + LAZYREMOVE(master.elements, src) + master.remove_vis_contents(src) + master = null + return ..() + +/obj/screen/status_effect/handle_click(mob/user, params) + if((. = ..())) + var/mob/living/owner = owner_ref?.resolve() + if(istype(owner) && archetype) + var/datum/status_effect/effect = LAZYACCESS(owner.status_effects, archetype) + if(istype(effect)) + effect.on_effect_click(params) + +/obj/screen/status_effect/MouseEntered(location, control, params) + if(archetype && (archetype.name || archetype.desc)) + openToolTip(user = usr, tip_src = src, params = params, title = archetype.name, content = archetype.desc) + ..() + +/obj/screen/status_effect/MouseDown() + closeToolTip(usr) + ..() + +/obj/screen/status_effect/MouseExited() + closeToolTip(usr) + ..() diff --git a/code/modules/status_conditions/status_effect_archetype.dm b/code/modules/status_conditions/status_effect_archetype.dm new file mode 100644 index 00000000000..b2f6f27f865 --- /dev/null +++ b/code/modules/status_conditions/status_effect_archetype.dm @@ -0,0 +1,59 @@ +/// Instanced 'effects' that sit on top of a mob and can expire over time or linger until dispelled. +/// Some are purely visual, others have associated effects. +/decl/status_effect + abstract_type = /decl/status_effect + var/name + var/desc + var/hud_icon = 'icons/screen/status_effects.dmi' + var/hud_icon_state + var/mob_overlay_icon + var/mob_overlay_state + var/status_effect_type = /datum/status_effect + var/on_add_message_1p + var/on_add_message_3p + var/on_end_message_1p + var/on_end_message_3p + +/decl/status_effect/validate() + . = ..() + if(!hud_icon) + . += "no hud_icon set" + if(!istext(hud_icon_state)) + . += "null or invalid hud_icon_state" + if(hud_icon && hud_icon_state && !check_state_in_icon(hud_icon_state, hud_icon)) + . += "hud_icon '[hud_icon]' missing hud_icon_state '[hud_icon_state]'" + + if(mob_overlay_icon) + if(istext(mob_overlay_state)) + if(!check_state_in_icon(mob_overlay_state, mob_overlay_icon)) + . += "mob_overlay_icon '[mob_overlay_icon]' missing mob_overlay_state '[mob_overlay_state]'" + else + . += "null or invalid mob_overlay_state" + else if(mob_overlay_state) + . += "mob_overlay_state set but mob_overlay_icon not set" + +/decl/status_effect/proc/replace_tokens(message, mob/user) + return capitalize(emote_replace_user_tokens(message, user)) + +/decl/status_effect/proc/on_effect_added(mob/living/owner, datum/status_effect/effect) + if(on_add_message_3p) + owner.visible_message(replace_tokens(on_add_message_3p), replace_tokens(on_add_message_3p || on_add_message_1p)) + else if(on_add_message_1p) + to_chat(owner, replace_tokens(on_add_message_1p)) + return TRUE + +/decl/status_effect/proc/on_effect_removed(mob/living/owner, datum/status_effect/effect) + if(on_end_message_3p) + owner.visible_message(replace_tokens(on_end_message_3p), replace_tokens(on_end_message_3p || on_end_message_1p)) + else if(on_end_message_1p) + to_chat(owner, replace_tokens(on_end_message_1p)) + return TRUE + +/decl/status_effect/proc/on_effect_expiry(mob/living/owner, datum/status_effect/effect) + return TRUE + +/decl/status_effect/proc/on_effect_mob_life(mob/living/owner, datum/status_effect/effect) + return TRUE + +/decl/status_effect/proc/on_effect_click(mob/living/owner, datum/status_effect/effect, params) + return FALSE diff --git a/code/modules/status_conditions/status_effect_datum.dm b/code/modules/status_conditions/status_effect_datum.dm new file mode 100644 index 00000000000..fbb581bb3be --- /dev/null +++ b/code/modules/status_conditions/status_effect_datum.dm @@ -0,0 +1,63 @@ +// Subtype for tracking timer etc. No actual behavior associated with these. +/datum/status_effect + var/mob/living/owner + var/decl/status_effect/archetype + var/lifetime = STATUS_EFFECT_INDEFINITE + +/datum/status_effect/New(decl/status_effect/_archetype, mob/living/_owner) + archetype = istype(_archetype) ? _archetype : GET_DECL(_archetype) + owner = _owner + +/datum/status_effect/Destroy(force) + if(owner) + if(LAZYACCESS(owner.status_effects, archetype) == src) + LAZYREMOVE(owner.status_effects, archetype) + owner = null + return ..() + +/datum/status_effect/proc/on_effect_mob_life() + SHOULD_CALL_PARENT(TRUE) + + // We should not exist without an owner. + if(!istype(owner)) + qdel(src) + return PROCESS_KILL + + // Count down our timer, if necessary. + if(lifetime != STATUS_EFFECT_INDEFINITE) + lifetime-- + if(lifetime <= 0) + on_effect_expiry() + return PROCESS_KILL + + // Pass off to the general behavior thingy to handle our actual logic. + if(!archetype.on_effect_mob_life(owner, src)) + on_effect_expiry() + return PROCESS_KILL + +/datum/status_effect/proc/on_effect_removed() + SHOULD_CALL_PARENT(TRUE) + if(!istype(owner)) + return FALSE + LAZYREMOVE(owner.status_effects, archetype) + archetype.on_effect_removed(owner, src) + owner = null + qdel(src) + return TRUE + +/datum/status_effect/proc/on_effect_added() + SHOULD_CALL_PARENT(TRUE) + if(!istype(owner)) + return FALSE + LAZYSET(owner.status_effects, archetype, src) + archetype.on_effect_added(owner, src) + return TRUE + +/datum/status_effect/proc/on_effect_expiry() + SHOULD_CALL_PARENT(TRUE) + archetype.on_effect_expiry(owner, src) + return on_effect_removed() + +/datum/status_effect/proc/on_effect_click(params) + SHOULD_CALL_PARENT(TRUE) + archetype.on_effect_click(owner, src, params) diff --git a/code/modules/xenoarcheaology/artifacts/effects/sleepy.dm b/code/modules/xenoarcheaology/artifacts/effects/sleepy.dm index 6bb1478a0ba..77ac2a2bd89 100644 --- a/code/modules/xenoarcheaology/artifacts/effects/sleepy.dm +++ b/code/modules/xenoarcheaology/artifacts/effects/sleepy.dm @@ -40,5 +40,5 @@ return if(prob(message_prob)) to_chat(H, SPAN_NOTICE(pick(sleepy_messages))) - H.set_status(STAT_DROWSY, min(GET_STATUS(H, STAT_DROWSY) + speed * weakness, limit * weakness)) - H.set_status(STAT_BLURRY, min(GET_STATUS(H, STAT_BLURRY) + speed * weakness, limit * weakness)) \ No newline at end of file + H.set_status_condition(STAT_DROWSY, min(GET_STATUS(H, STAT_DROWSY) + speed * weakness, limit * weakness)) + H.set_status_condition(STAT_BLURRY, min(GET_STATUS(H, STAT_BLURRY) + speed * weakness, limit * weakness)) \ No newline at end of file diff --git a/icons/screen/status_effects.dmi b/icons/screen/status_effects.dmi new file mode 100644 index 00000000000..ceb8879815d Binary files /dev/null and b/icons/screen/status_effects.dmi differ diff --git a/mods/content/psionics/system/psionics/faculties/coercion.dm b/mods/content/psionics/system/psionics/faculties/coercion.dm index 8a92f058ad1..eca5436d631 100644 --- a/mods/content/psionics/system/psionics/faculties/coercion.dm +++ b/mods/content/psionics/system/psionics/faculties/coercion.dm @@ -242,7 +242,7 @@ var/coercion_rank = psi?.get_rank(PSI_COERCION) if(coercion_rank >= PSI_RANK_GRANDMASTER) ADJ_STATUS(target, STAT_PARA, -1) - target.set_status(STAT_DROWSY, 0) + target.set_status_condition(STAT_DROWSY, 0) if(isliving(target)) var/mob/living/M = target M.adjust_hallucination(-30) diff --git a/mods/gamemodes/cult/mobs/constructs/constructs.dm b/mods/gamemodes/cult/mobs/constructs/constructs.dm index 1eb37f6980b..c3536733e70 100644 --- a/mods/gamemodes/cult/mobs/constructs/constructs.dm +++ b/mods/gamemodes/cult/mobs/constructs/constructs.dm @@ -124,7 +124,7 @@ _base_attack_force = 30 /mob/living/simple_animal/construct/armoured/handle_regular_status_updates() - set_status(STAT_WEAK, 0) + set_status_condition(STAT_WEAK, 0) if ((. = ..())) return diff --git a/mods/mobs/borers/mob/borer/borer.dm b/mods/mobs/borers/mob/borer/borer.dm index f9dbbe2f6e1..ede49edb624 100644 --- a/mods/mobs/borers/mob/borer/borer.dm +++ b/mods/mobs/borers/mob/borer/borer.dm @@ -100,8 +100,8 @@ /mob/living/simple_animal/borer/handle_vision() . = ..() - set_status(STAT_BLIND, host ? GET_STATUS(host, STAT_BLIND) : 0) - set_status(STAT_BLURRY, host ? GET_STATUS(host, STAT_BLURRY) : 0) + set_status_condition(STAT_BLIND, host ? GET_STATUS(host, STAT_BLIND) : 0) + set_status_condition(STAT_BLURRY, host ? GET_STATUS(host, STAT_BLURRY) : 0) /mob/living/simple_animal/borer/handle_disabilities() . = ..() diff --git a/mods/species/drakes/drake_abilities_friendly.dm b/mods/species/drakes/drake_abilities_friendly.dm index a224540e988..823ecf13e89 100644 --- a/mods/species/drakes/drake_abilities_friendly.dm +++ b/mods/species/drakes/drake_abilities_friendly.dm @@ -49,7 +49,7 @@ var/global/list/_wounds_being_tended_by_drakes = list() return TRUE // Are we already regenerating? - if(friend.has_aura(/obj/aura/sifsap_salve)) + if(friend.has_status_effect(/decl/status_effect/sifsap_salve)) if(friend == user) to_chat(user, SPAN_WARNING("Your wounds have already been cleaned.")) else @@ -72,7 +72,7 @@ var/global/list/_wounds_being_tended_by_drakes = list() var/friend_ref = "\ref[friend]" global._wounds_being_tended_by_drakes[friend_ref] = world.time + (8 SECONDS) - if(!do_after(user, 8 SECONDS, friend) || QDELETED(friend) || friend.has_aura(/obj/aura/sifsap_salve) || user.incapacitated() || !drake_spend_sap(user, 10)) + if(!do_after(user, 8 SECONDS, friend) || QDELETED(friend) || friend.has_status_effect(/decl/status_effect/sifsap_salve) || user.incapacitated() || !drake_spend_sap(user, 10)) global._wounds_being_tended_by_drakes -= friend_ref return TRUE @@ -86,7 +86,7 @@ var/global/list/_wounds_being_tended_by_drakes = list() // Sivian animals get a heal buff from the modifier, others just // get it to stop friendly drakes constantly licking their wounds. // Organ wounds are closed, but the owners get sifsap injected via open wounds. - friend.add_aura(new /obj/aura/sifsap_salve(friend, 60 SECONDS)) + friend.set_status_effect(/decl/status_effect/sifsap_salve, DS_TO_LIFE_TICKS(60 SECONDS)) var/list/friend_organs = friend.get_external_organs() if(length(friend_organs)) for (var/obj/item/organ/external/E in friend_organs) diff --git a/mods/species/drakes/drake_modifiers.dm b/mods/species/drakes/drake_modifiers.dm index a540b0f0c3b..2c15c5e3f0a 100644 --- a/mods/species/drakes/drake_modifiers.dm +++ b/mods/species/drakes/drake_modifiers.dm @@ -1,46 +1,37 @@ -/obj/aura/sifsap_salve - name = "Sifsap Salve" - icon = 'icons/effects/sparkles.dmi' - icon_state = "cyan_sparkles" - var/expiry - var/descriptor = "glowing sap" - -/obj/aura/sifsap_salve/Initialize(ml, _lifetime) - expiry = world.time + _lifetime - return ..() - -/obj/aura/sifsap_salve/added_to(var/mob/living/L) - ..() - to_chat(user, SPAN_NOTICE("The [descriptor] seethes and bubbles in your wounds, tingling and stinging.")) - -/obj/aura/sifsap_salve/removed() - to_chat(user, SPAN_NOTICE("The last of the [descriptor] in your wounds fizzles away.")) - ..() - -/obj/aura/sifsap_salve/life_tick() - - if(!user || user.stat == DEAD || user.isSynthetic()) - return 0 - - if(world.time >= expiry) - if(user) - user.remove_aura(src) - return 0 - - if(!user.has_trait(/decl/trait/sivian_biochemistry)) - user.heal_damage(BRUTE, 1, do_update_health = FALSE) - user.heal_damage(BURN, 1, do_update_health = TRUE) - return 1 - - if(user.current_health >= user.get_max_health()) - return 0 - - if(user.current_posture?.prone) - user.heal_damage(BRUTE, 3, do_update_health = FALSE) - user.heal_damage(BURN, 3, do_update_health = FALSE) - user.heal_damage(TOX, 2, do_update_health = TRUE) +/decl/status_effect/sifsap_salve + name = "Sifsap Salve" + desc = "Your wounds have been cleaned with drake spittle, which is beneficial to drakes - and not great for anyone else." + hud_icon = 'mods/species/drakes/icons/sifsap.dmi' + hud_icon_state = "sifsap_hud" + mob_overlay_icon = 'icons/effects/sparkles.dmi' + mob_overlay_state = "cyan_sparkles" + /// Defined here to allow overriding in fantasy modpack. + var/descriptor = "glowing sap" + +/decl/status_effect/sifsap_salve/Initialize() + on_add_message_1p = SPAN_NOTICE("The [descriptor] seethes and bubbles in your wounds, tingling and stinging.") + on_end_message_1p = SPAN_NOTICE("The last of the [descriptor] in your wounds fizzles away.") + . = ..() + +/decl/status_effect/sifsap_salve/on_effect_mob_life(mob/living/owner, datum/status_effect/effect) + + if(!owner || owner.stat == DEAD || owner.isSynthetic()) + return FALSE + + if(!owner.has_trait(/decl/trait/sivian_biochemistry)) + owner.heal_damage(BRUTE, 1, do_update_health = FALSE) + owner.heal_damage(BURN, 1, do_update_health = TRUE) + return TRUE + + if(owner.current_health >= owner.get_max_health()) + return FALSE + + if(owner.current_posture?.prone) + owner.heal_damage(BRUTE, 3, do_update_health = FALSE) + owner.heal_damage(BURN, 3, do_update_health = FALSE) + owner.heal_damage(TOX, 2, do_update_health = TRUE) else - user.heal_damage(BRUTE, 2, do_update_health = FALSE) - user.heal_damage(BURN, 2, do_update_health = FALSE) - user.heal_damage(TOX, 1, do_update_health = TRUE) - return 1 + owner.heal_damage(BRUTE, 2, do_update_health = FALSE) + owner.heal_damage(BURN, 2, do_update_health = FALSE) + owner.heal_damage(TOX, 1, do_update_health = TRUE) + return TRUE diff --git a/mods/species/drakes/icons/sifsap.dmi b/mods/species/drakes/icons/sifsap.dmi new file mode 100644 index 00000000000..6942ef6d839 Binary files /dev/null and b/mods/species/drakes/icons/sifsap.dmi differ diff --git a/mods/~compatibility/patches/fantasy/drake_fantasy.dm b/mods/~compatibility/patches/fantasy/drake_fantasy.dm index 70ad5e628e7..694bebc1b4c 100644 --- a/mods/~compatibility/patches/fantasy/drake_fantasy.dm +++ b/mods/~compatibility/patches/fantasy/drake_fantasy.dm @@ -16,6 +16,6 @@ name = "drake spittle" lore_text = "A complex chemical slurry brewed up in the gullet of meredrakes." -/obj/aura/sifsap_salve +/decl/status_effect/sifsap_salve name = "Drakespittle Salve" - descriptor = "glowing spittle" + desc = "glowing spittle" diff --git a/nebula.dme b/nebula.dme index 399eb186d43..8f801dd3fc1 100644 --- a/nebula.dme +++ b/nebula.dme @@ -5,6 +5,584 @@ // END_INTERNALS // BEGIN_FILE_DIR #define FILE_DIR . +#define FILE_DIR "code" +#define FILE_DIR "code/modules" +#define FILE_DIR "code/modules/synthesized_instruments" +#define FILE_DIR "code/modules/synthesized_instruments/samples" +#define FILE_DIR "code/modules/synthesized_instruments/samples/brass" +#define FILE_DIR "code/modules/synthesized_instruments/samples/brass/crisis_brass" +#define FILE_DIR "code/modules/synthesized_instruments/samples/brass/crisis_trombone" +#define FILE_DIR "code/modules/synthesized_instruments/samples/brass/crisis_trumpet" +#define FILE_DIR "code/modules/synthesized_instruments/samples/chromatic" +#define FILE_DIR "code/modules/synthesized_instruments/samples/chromatic/fluid_celeste" +#define FILE_DIR "code/modules/synthesized_instruments/samples/chromatic/sgmbox" +#define FILE_DIR "code/modules/synthesized_instruments/samples/chromatic/vibraphone1" +#define FILE_DIR "code/modules/synthesized_instruments/samples/guitar" +#define FILE_DIR "code/modules/synthesized_instruments/samples/guitar/crisis_clean" +#define FILE_DIR "code/modules/synthesized_instruments/samples/guitar/crisis_muted" +#define FILE_DIR "code/modules/synthesized_instruments/samples/guitar/crisis_nylon" +#define FILE_DIR "code/modules/synthesized_instruments/samples/guitar/crisis_steel" +#define FILE_DIR "code/modules/synthesized_instruments/samples/obsolete" +#define FILE_DIR "code/modules/synthesized_instruments/samples/obsolete/piano" +#define FILE_DIR "code/modules/synthesized_instruments/samples/obsolete/violin" +#define FILE_DIR "code/modules/synthesized_instruments/samples/organ" +#define FILE_DIR "code/modules/synthesized_instruments/samples/organ/crisis_accordian" +#define FILE_DIR "code/modules/synthesized_instruments/samples/organ/crisis_church" +#define FILE_DIR "code/modules/synthesized_instruments/samples/organ/crisis_hammond" +#define FILE_DIR "code/modules/synthesized_instruments/samples/organ/crisis_harmonica" +#define FILE_DIR "code/modules/synthesized_instruments/samples/organ/crisis_tangaccordian" +#define FILE_DIR "code/modules/synthesized_instruments/samples/piano" +#define FILE_DIR "code/modules/synthesized_instruments/samples/piano/crisis_bright_piano" +#define FILE_DIR "code/modules/synthesized_instruments/samples/piano/crisis_grand_piano" +#define FILE_DIR "code/modules/synthesized_instruments/samples/piano/crisis_harpsichord" +#define FILE_DIR "code/modules/synthesized_instruments/samples/piano/fluid_harpsi" +#define FILE_DIR "code/modules/synthesized_instruments/samples/piano/fluid_piano" +#define FILE_DIR "code/modules/synthesized_instruments/samples/tones" +#define FILE_DIR "data" +#define FILE_DIR "data/secrets" +#define FILE_DIR "data/secrets/example" +#define FILE_DIR "html" +#define FILE_DIR "html/images" +#define FILE_DIR "icons" +#define FILE_DIR "icons/atmos" +#define FILE_DIR "icons/clothing" +#define FILE_DIR "icons/clothing/accessories" +#define FILE_DIR "icons/clothing/accessories/armbands" +#define FILE_DIR "icons/clothing/accessories/armor" +#define FILE_DIR "icons/clothing/accessories/badges" +#define FILE_DIR "icons/clothing/accessories/clothing" +#define FILE_DIR "icons/clothing/accessories/holsters" +#define FILE_DIR "icons/clothing/accessories/jewelry" +#define FILE_DIR "icons/clothing/accessories/jewelry/pendants" +#define FILE_DIR "icons/clothing/accessories/jewelry/religious" +#define FILE_DIR "icons/clothing/accessories/jewelry/rings" +#define FILE_DIR "icons/clothing/accessories/medals" +#define FILE_DIR "icons/clothing/accessories/pouches" +#define FILE_DIR "icons/clothing/accessories/storage" +#define FILE_DIR "icons/clothing/accessories/tags" +#define FILE_DIR "icons/clothing/accessories/ties" +#define FILE_DIR "icons/clothing/belt" +#define FILE_DIR "icons/clothing/costumes" +#define FILE_DIR "icons/clothing/dresses" +#define FILE_DIR "icons/clothing/ears" +#define FILE_DIR "icons/clothing/eyes" +#define FILE_DIR "icons/clothing/feet" +#define FILE_DIR "icons/clothing/hands" +#define FILE_DIR "icons/clothing/head" +#define FILE_DIR "icons/clothing/head/armor" +#define FILE_DIR "icons/clothing/head/bandana" +#define FILE_DIR "icons/clothing/head/biosuit" +#define FILE_DIR "icons/clothing/head/hairflower" +#define FILE_DIR "icons/clothing/head/hardhat" +#define FILE_DIR "icons/clothing/head/space" +#define FILE_DIR "icons/clothing/head/space/syndicate" +#define FILE_DIR "icons/clothing/head/welding" +#define FILE_DIR "icons/clothing/head/wizard" +#define FILE_DIR "icons/clothing/jumpsuits" +#define FILE_DIR "icons/clothing/mask" +#define FILE_DIR "icons/clothing/mask/chewables" +#define FILE_DIR "icons/clothing/mask/smokables" +#define FILE_DIR "icons/clothing/pants" +#define FILE_DIR "icons/clothing/pants/leggings" +#define FILE_DIR "icons/clothing/plate_armour" +#define FILE_DIR "icons/clothing/rigs" +#define FILE_DIR "icons/clothing/rigs/boots" +#define FILE_DIR "icons/clothing/rigs/chests" +#define FILE_DIR "icons/clothing/rigs/ert" +#define FILE_DIR "icons/clothing/rigs/ert/asset_protection" +#define FILE_DIR "icons/clothing/rigs/ert/commander" +#define FILE_DIR "icons/clothing/rigs/ert/engineer" +#define FILE_DIR "icons/clothing/rigs/ert/janitor" +#define FILE_DIR "icons/clothing/rigs/ert/medic" +#define FILE_DIR "icons/clothing/rigs/ert/security" +#define FILE_DIR "icons/clothing/rigs/gloves" +#define FILE_DIR "icons/clothing/rigs/helmets" +#define FILE_DIR "icons/clothing/shirts" +#define FILE_DIR "icons/clothing/shirts/tunics" +#define FILE_DIR "icons/clothing/skirts" +#define FILE_DIR "icons/clothing/spacesuit" +#define FILE_DIR "icons/clothing/spacesuit/cult" +#define FILE_DIR "icons/clothing/spacesuit/emergency" +#define FILE_DIR "icons/clothing/spacesuit/generic" +#define FILE_DIR "icons/clothing/spacesuit/void" +#define FILE_DIR "icons/clothing/spacesuit/void/atmos" +#define FILE_DIR "icons/clothing/spacesuit/void/atmos_alt" +#define FILE_DIR "icons/clothing/spacesuit/void/deathsquad" +#define FILE_DIR "icons/clothing/spacesuit/void/engineering" +#define FILE_DIR "icons/clothing/spacesuit/void/engineering_alt" +#define FILE_DIR "icons/clothing/spacesuit/void/excavation" +#define FILE_DIR "icons/clothing/spacesuit/void/medical" +#define FILE_DIR "icons/clothing/spacesuit/void/medical_alt" +#define FILE_DIR "icons/clothing/spacesuit/void/merc" +#define FILE_DIR "icons/clothing/spacesuit/void/mining" +#define FILE_DIR "icons/clothing/spacesuit/void/mining_alt" +#define FILE_DIR "icons/clothing/spacesuit/void/nasa" +#define FILE_DIR "icons/clothing/spacesuit/void/pilot" +#define FILE_DIR "icons/clothing/spacesuit/void/salvage" +#define FILE_DIR "icons/clothing/spacesuit/void/sec" +#define FILE_DIR "icons/clothing/spacesuit/void/sec_alt" +#define FILE_DIR "icons/clothing/spacesuit/void/wizard" +#define FILE_DIR "icons/clothing/suits" +#define FILE_DIR "icons/clothing/suits/armor" +#define FILE_DIR "icons/clothing/suits/biosuit" +#define FILE_DIR "icons/clothing/suits/cloaks" +#define FILE_DIR "icons/clothing/suits/dashiki" +#define FILE_DIR "icons/clothing/suits/deity" +#define FILE_DIR "icons/clothing/suits/hazard_vest" +#define FILE_DIR "icons/clothing/suits/jackets" +#define FILE_DIR "icons/clothing/suits/labcoat" +#define FILE_DIR "icons/clothing/suits/poncho" +#define FILE_DIR "icons/clothing/suits/space" +#define FILE_DIR "icons/clothing/suits/space/syndicate" +#define FILE_DIR "icons/clothing/suits/tracksuit" +#define FILE_DIR "icons/clothing/suits/wintercoat" +#define FILE_DIR "icons/clothing/suits/wizard" +#define FILE_DIR "icons/clothing/suits/wizard/servant" +#define FILE_DIR "icons/effects" +#define FILE_DIR "icons/effects/decals" +#define FILE_DIR "icons/effects/mouse_pointers" +#define FILE_DIR "icons/effects/projectiles" +#define FILE_DIR "icons/mecha" +#define FILE_DIR "icons/misc" +#define FILE_DIR "icons/mob" +#define FILE_DIR "icons/mob/bot" +#define FILE_DIR "icons/mob/footprints" +#define FILE_DIR "icons/mob/human_races" +#define FILE_DIR "icons/mob/human_races/cyberlimbs" +#define FILE_DIR "icons/mob/human_races/cyberlimbs/morgan" +#define FILE_DIR "icons/mob/human_races/species" +#define FILE_DIR "icons/mob/human_races/species/blueforged" +#define FILE_DIR "icons/mob/human_races/species/golem" +#define FILE_DIR "icons/mob/human_races/species/human" +#define FILE_DIR "icons/mob/human_races/species/humanoid" +#define FILE_DIR "icons/mob/human_races/species/monkey" +#define FILE_DIR "icons/mob/human_races/species/shadow" +#define FILE_DIR "icons/mob/human_races/species/starborn" +#define FILE_DIR "icons/mob/onmob" +#define FILE_DIR "icons/mob/onmob/items" +#define FILE_DIR "icons/mob/robots" +#define FILE_DIR "icons/mob/robots/drones" +#define FILE_DIR "icons/mob/robots/flying" +#define FILE_DIR "icons/mob/robots/pai" +#define FILE_DIR "icons/mob/screen" +#define FILE_DIR "icons/mob/screen/styles" +#define FILE_DIR "icons/mob/screen/styles/constructs" +#define FILE_DIR "icons/mob/screen/styles/constructs/artificer" +#define FILE_DIR "icons/mob/screen/styles/constructs/harvester" +#define FILE_DIR "icons/mob/screen/styles/constructs/juggernaut" +#define FILE_DIR "icons/mob/screen/styles/constructs/wraith" +#define FILE_DIR "icons/mob/screen/styles/midnight" +#define FILE_DIR "icons/mob/screen/styles/minimalist" +#define FILE_DIR "icons/mob/screen/styles/old" +#define FILE_DIR "icons/mob/screen/styles/old_noborder" +#define FILE_DIR "icons/mob/screen/styles/orange" +#define FILE_DIR "icons/mob/screen/styles/robot" +#define FILE_DIR "icons/mob/screen/styles/underworld" +#define FILE_DIR "icons/mob/screen/styles/white" +#define FILE_DIR "icons/mob/simple_animal" +#define FILE_DIR "icons/obj" +#define FILE_DIR "icons/obj/action_buttons" +#define FILE_DIR "icons/obj/ammo" +#define FILE_DIR "icons/obj/ammo/casings" +#define FILE_DIR "icons/obj/assemblies" +#define FILE_DIR "icons/obj/atmospherics" +#define FILE_DIR "icons/obj/bedsheets" +#define FILE_DIR "icons/obj/closets" +#define FILE_DIR "icons/obj/closets/bases" +#define FILE_DIR "icons/obj/closets/decals" +#define FILE_DIR "icons/obj/clothing" +#define FILE_DIR "icons/obj/doors" +#define FILE_DIR "icons/obj/doors/blast_doors" +#define FILE_DIR "icons/obj/doors/centcomm" +#define FILE_DIR "icons/obj/doors/double" +#define FILE_DIR "icons/obj/doors/elevator" +#define FILE_DIR "icons/obj/doors/external" +#define FILE_DIR "icons/obj/doors/hatch" +#define FILE_DIR "icons/obj/doors/hazard" +#define FILE_DIR "icons/obj/doors/secure" +#define FILE_DIR "icons/obj/doors/shutters" +#define FILE_DIR "icons/obj/doors/station" +#define FILE_DIR "icons/obj/doors/vault" +#define FILE_DIR "icons/obj/drink_glasses" +#define FILE_DIR "icons/obj/flora" +#define FILE_DIR "icons/obj/food" +#define FILE_DIR "icons/obj/food/baked" +#define FILE_DIR "icons/obj/food/baked/bread" +#define FILE_DIR "icons/obj/food/baked/bread/slices" +#define FILE_DIR "icons/obj/food/baked/cakes" +#define FILE_DIR "icons/obj/food/baked/cakes/slices" +#define FILE_DIR "icons/obj/food/baked/pies" +#define FILE_DIR "icons/obj/food/baked/waffles" +#define FILE_DIR "icons/obj/food/burgers" +#define FILE_DIR "icons/obj/food/butchery" +#define FILE_DIR "icons/obj/food/canned" +#define FILE_DIR "icons/obj/food/condiments" +#define FILE_DIR "icons/obj/food/condiments/packets" +#define FILE_DIR "icons/obj/food/containers" +#define FILE_DIR "icons/obj/food/cooking_vessels" +#define FILE_DIR "icons/obj/food/custom" +#define FILE_DIR "icons/obj/food/dairy" +#define FILE_DIR "icons/obj/food/donuts" +#define FILE_DIR "icons/obj/food/eggs" +#define FILE_DIR "icons/obj/food/fried" +#define FILE_DIR "icons/obj/food/junk" +#define FILE_DIR "icons/obj/food/mre" +#define FILE_DIR "icons/obj/food/nuggets" +#define FILE_DIR "icons/obj/food/old" +#define FILE_DIR "icons/obj/food/pasta" +#define FILE_DIR "icons/obj/food/pizzas" +#define FILE_DIR "icons/obj/food/plates" +#define FILE_DIR "icons/obj/food/pudding" +#define FILE_DIR "icons/obj/food/rice" +#define FILE_DIR "icons/obj/food/salads" +#define FILE_DIR "icons/obj/food/tofu" +#define FILE_DIR "icons/obj/food/utensils" +#define FILE_DIR "icons/obj/grown" +#define FILE_DIR "icons/obj/guns" +#define FILE_DIR "icons/obj/guns/foam" +#define FILE_DIR "icons/obj/guns/launcher" +#define FILE_DIR "icons/obj/guns/random_pistol" +#define FILE_DIR "icons/obj/guns/random_pistol/handle" +#define FILE_DIR "icons/obj/guns/random_pistol/looks" +#define FILE_DIR "icons/obj/guns/shotgun" +#define FILE_DIR "icons/obj/guns/xenoarch" +#define FILE_DIR "icons/obj/hydroponics" +#define FILE_DIR "icons/obj/id" +#define FILE_DIR "icons/obj/items" +#define FILE_DIR "icons/obj/items/banners" +#define FILE_DIR "icons/obj/items/bladed" +#define FILE_DIR "icons/obj/items/books" +#define FILE_DIR "icons/obj/items/borg_module" +#define FILE_DIR "icons/obj/items/chem" +#define FILE_DIR "icons/obj/items/chem/beakers" +#define FILE_DIR "icons/obj/items/cosmetics" +#define FILE_DIR "icons/obj/items/device" +#define FILE_DIR "icons/obj/items/device/radio" +#define FILE_DIR "icons/obj/items/device/radio/headsets" +#define FILE_DIR "icons/obj/items/device/scanner" +#define FILE_DIR "icons/obj/items/device/tape_recorder" +#define FILE_DIR "icons/obj/items/flame" +#define FILE_DIR "icons/obj/items/gemstones" +#define FILE_DIR "icons/obj/items/grenades" +#define FILE_DIR "icons/obj/items/grooming" +#define FILE_DIR "icons/obj/items/handmade" +#define FILE_DIR "icons/obj/items/implant" +#define FILE_DIR "icons/obj/items/paperwork" +#define FILE_DIR "icons/obj/items/pens" +#define FILE_DIR "icons/obj/items/shield" +#define FILE_DIR "icons/obj/items/stacks" +#define FILE_DIR "icons/obj/items/stamps" +#define FILE_DIR "icons/obj/items/stock_parts" +#define FILE_DIR "icons/obj/items/storage" +#define FILE_DIR "icons/obj/items/storage/backpack" +#define FILE_DIR "icons/obj/items/storage/baskets" +#define FILE_DIR "icons/obj/items/storage/cigpack" +#define FILE_DIR "icons/obj/items/storage/lunchboxes" +#define FILE_DIR "icons/obj/items/storage/toolboxes" +#define FILE_DIR "icons/obj/items/surgery" +#define FILE_DIR "icons/obj/items/tanks" +#define FILE_DIR "icons/obj/items/tool" +#define FILE_DIR "icons/obj/items/tool/axes" +#define FILE_DIR "icons/obj/items/tool/components" +#define FILE_DIR "icons/obj/items/tool/drills" +#define FILE_DIR "icons/obj/items/tool/hammers" +#define FILE_DIR "icons/obj/items/tool/hoes" +#define FILE_DIR "icons/obj/items/tool/shovels" +#define FILE_DIR "icons/obj/items/tool/welders" +#define FILE_DIR "icons/obj/items/training_dummies" +#define FILE_DIR "icons/obj/items/weapon" +#define FILE_DIR "icons/obj/items/weapon/knives" +#define FILE_DIR "icons/obj/items/weapon/knives/folding" +#define FILE_DIR "icons/obj/items/weapon/knives/xenoarch" +#define FILE_DIR "icons/obj/items/weapon/machetes" +#define FILE_DIR "icons/obj/items/weapon/swords" +#define FILE_DIR "icons/obj/items/weapon/swords/xenoarch" +#define FILE_DIR "icons/obj/lighting" +#define FILE_DIR "icons/obj/machines" +#define FILE_DIR "icons/obj/machines/chemistry" +#define FILE_DIR "icons/obj/machines/fabricators" +#define FILE_DIR "icons/obj/machines/power" +#define FILE_DIR "icons/obj/machines/smartfridges" +#define FILE_DIR "icons/obj/machines/tcomms" +#define FILE_DIR "icons/obj/machines/vending" +#define FILE_DIR "icons/obj/materials" +#define FILE_DIR "icons/obj/metalworking" +#define FILE_DIR "icons/obj/modular_computers" +#define FILE_DIR "icons/obj/modular_computers/holo" +#define FILE_DIR "icons/obj/modular_computers/pda" +#define FILE_DIR "icons/obj/modules" +#define FILE_DIR "icons/obj/pipes" +#define FILE_DIR "icons/obj/seeds" +#define FILE_DIR "icons/obj/signs" +#define FILE_DIR "icons/obj/structures" +#define FILE_DIR "icons/obj/structures/barrels" +#define FILE_DIR "icons/obj/structures/decorations" +#define FILE_DIR "icons/obj/structures/forging" +#define FILE_DIR "icons/obj/structures/pedestals" +#define FILE_DIR "icons/obj/structures/pillars" +#define FILE_DIR "icons/obj/structures/snowmen" +#define FILE_DIR "icons/obj/structures/target_stakes" +#define FILE_DIR "icons/obj/toy" +#define FILE_DIR "icons/screen" +#define FILE_DIR "icons/skybox" +#define FILE_DIR "icons/Testing" +#define FILE_DIR "icons/turf" +#define FILE_DIR "icons/turf/flooring" +#define FILE_DIR "icons/turf/walls" +#define FILE_DIR "maps" +#define FILE_DIR "maps/away" +#define FILE_DIR "maps/away/casino" +#define FILE_DIR "maps/away/errant_pisces" +#define FILE_DIR "maps/away/errant_pisces/icons" +#define FILE_DIR "maps/away/liberia" +#define FILE_DIR "maps/away/lost_supply_base" +#define FILE_DIR "maps/away/magshield" +#define FILE_DIR "maps/away/mobius_rift" +#define FILE_DIR "maps/away/smugglers" +#define FILE_DIR "maps/away/unishi" +#define FILE_DIR "maps/away/yacht" +#define FILE_DIR "maps/example" +#define FILE_DIR "maps/exodus" +#define FILE_DIR "maps/exodus/lobby" +#define FILE_DIR "maps/ministation" +#define FILE_DIR "maps/random_ruins" +#define FILE_DIR "maps/random_ruins/exoplanet_ruins" +#define FILE_DIR "maps/random_ruins/exoplanet_ruins/hydrobase" +#define FILE_DIR "maps/random_ruins/exoplanet_ruins/marooned" +#define FILE_DIR "maps/random_ruins/exoplanet_ruins/marooned/icons" +#define FILE_DIR "maps/random_ruins/exoplanet_ruins/playablecolony" +#define FILE_DIR "maps/shaded_hills" +#define FILE_DIR "maps/shaded_hills/areas" +#define FILE_DIR "maps/tradeship" +#define FILE_DIR "maps/tradeship/lobby" +#define FILE_DIR "mods" +#define FILE_DIR "mods/content" +#define FILE_DIR "mods/content/byond_membership" +#define FILE_DIR "mods/content/corporate" +#define FILE_DIR "mods/content/corporate/away_sites" +#define FILE_DIR "mods/content/corporate/away_sites/lar_maria" +#define FILE_DIR "mods/content/corporate/icons" +#define FILE_DIR "mods/content/corporate/icons/clothing" +#define FILE_DIR "mods/content/corporate/icons/clothing/accessories" +#define FILE_DIR "mods/content/corporate/icons/clothing/accessories/jackets" +#define FILE_DIR "mods/content/corporate/icons/clothing/accessories/ties" +#define FILE_DIR "mods/content/corporate/icons/clothing/accessories/tunic" +#define FILE_DIR "mods/content/corporate/icons/clothing/head" +#define FILE_DIR "mods/content/corporate/icons/clothing/head/beret" +#define FILE_DIR "mods/content/corporate/icons/clothing/head/ert" +#define FILE_DIR "mods/content/corporate/icons/clothing/mask" +#define FILE_DIR "mods/content/corporate/icons/clothing/suit" +#define FILE_DIR "mods/content/corporate/icons/clothing/suit/armor" +#define FILE_DIR "mods/content/corporate/icons/clothing/suit/navy" +#define FILE_DIR "mods/content/corporate/icons/clothing/under" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/bishop" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/hephaestus" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/morpheus" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/nanotrasen" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/shellguard" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/veymed" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/wardtakahashi" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/xion" +#define FILE_DIR "mods/content/corporate/icons/cyberlimbs/zenghu" +#define FILE_DIR "mods/content/corporate/icons/obj" +#define FILE_DIR "mods/content/dungeon_loot" +#define FILE_DIR "mods/content/dungeon_loot/icons" +#define FILE_DIR "mods/content/fantasy" +#define FILE_DIR "mods/content/fantasy/icons" +#define FILE_DIR "mods/content/fantasy/icons/clothing" +#define FILE_DIR "mods/content/fantasy/icons/hnoll" +#define FILE_DIR "mods/content/fantasy/icons/kobaloi" +#define FILE_DIR "mods/content/fantasy/icons/structures" +#define FILE_DIR "mods/content/government" +#define FILE_DIR "mods/content/government/away_sites" +#define FILE_DIR "mods/content/government/away_sites/icarus" +#define FILE_DIR "mods/content/government/icons" +#define FILE_DIR "mods/content/inertia" +#define FILE_DIR "mods/content/inertia/icons" +#define FILE_DIR "mods/content/item_sharpening" +#define FILE_DIR "mods/content/item_sharpening/icons" +#define FILE_DIR "mods/content/psionics" +#define FILE_DIR "mods/content/psionics/icons" +#define FILE_DIR "mods/content/standard_jobs" +#define FILE_DIR "mods/content/standard_jobs/icons" +#define FILE_DIR "mods/content/tabloids" +#define FILE_DIR "mods/content/tabloids/icons" +#define FILE_DIR "mods/content/xenobiology" +#define FILE_DIR "mods/content/xenobiology/icons" +#define FILE_DIR "mods/content/xenobiology/icons/slimes" +#define FILE_DIR "mods/gamemodes" +#define FILE_DIR "mods/gamemodes/cult" +#define FILE_DIR "mods/gamemodes/cult/icons" +#define FILE_DIR "mods/mobs" +#define FILE_DIR "mods/mobs/borers" +#define FILE_DIR "mods/mobs/borers/icons" +#define FILE_DIR "mods/mobs/dionaea" +#define FILE_DIR "mods/mobs/dionaea/icons" +#define FILE_DIR "mods/mobs/dionaea/sounds" +#define FILE_DIR "mods/species" +#define FILE_DIR "mods/species/ascent" +#define FILE_DIR "mods/species/ascent/icons" +#define FILE_DIR "mods/species/ascent/icons/alate_spacesuit" +#define FILE_DIR "mods/species/ascent/icons/clothing" +#define FILE_DIR "mods/species/ascent/icons/doors" +#define FILE_DIR "mods/species/ascent/icons/harness" +#define FILE_DIR "mods/species/ascent/icons/magboots" +#define FILE_DIR "mods/species/ascent/icons/particle_rifle" +#define FILE_DIR "mods/species/ascent/icons/rig" +#define FILE_DIR "mods/species/ascent/icons/species" +#define FILE_DIR "mods/species/ascent/icons/species/body" +#define FILE_DIR "mods/species/ascent/icons/species/body/alate" +#define FILE_DIR "mods/species/ascent/icons/species/body/gyne" +#define FILE_DIR "mods/species/ascent/icons/species/mantid" +#define FILE_DIR "mods/species/ascent/sounds" +#define FILE_DIR "mods/species/bayliens" +#define FILE_DIR "mods/species/bayliens/adherent" +#define FILE_DIR "mods/species/bayliens/adherent/icons" +#define FILE_DIR "mods/species/bayliens/adherent/sound" +#define FILE_DIR "mods/species/bayliens/skrell" +#define FILE_DIR "mods/species/bayliens/skrell/icons" +#define FILE_DIR "mods/species/bayliens/skrell/icons/body" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing/accessories" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing/ears" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing/head" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing/mask" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing/suit" +#define FILE_DIR "mods/species/bayliens/skrell/icons/clothing/under" +#define FILE_DIR "mods/species/bayliens/skrell/icons/gear" +#define FILE_DIR "mods/species/bayliens/skrell/icons/rigs" +#define FILE_DIR "mods/species/bayliens/skrell/icons/rigs/combat" +#define FILE_DIR "mods/species/bayliens/skrell/icons/rigs/command" +#define FILE_DIR "mods/species/bayliens/skrell/icons/rigs/engineering" +#define FILE_DIR "mods/species/bayliens/skrell/icons/rigs/medical" +#define FILE_DIR "mods/species/bayliens/skrell/icons/rigs/standard" +#define FILE_DIR "mods/species/bayliens/skrell/icons/turf" +#define FILE_DIR "mods/species/bayliens/skrell/sound" +#define FILE_DIR "mods/species/bayliens/skrell/sound/drop" +#define FILE_DIR "mods/species/bayliens/skrell/sound/pickup" +#define FILE_DIR "mods/species/bayliens/tajaran" +#define FILE_DIR "mods/species/bayliens/tajaran/icons" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/atmos" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/atmos_alt" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/deathsquad" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/engineering" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/engineering_alt" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/excavation" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/medical" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/medical_alt" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/merc" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/mining" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/mining_alt" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/nasa" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/pilot" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/salvage" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/sec" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/sec_alt" +#define FILE_DIR "mods/species/bayliens/tajaran/icons/clothing/wizard" +#define FILE_DIR "mods/species/bayliens/tajaran/sound" +#define FILE_DIR "mods/species/bayliens/tritonian" +#define FILE_DIR "mods/species/bayliens/tritonian/icons" +#define FILE_DIR "mods/species/bayliens/unathi" +#define FILE_DIR "mods/species/bayliens/unathi/icons" +#define FILE_DIR "mods/species/bayliens/unathi/sound" +#define FILE_DIR "mods/species/drakes" +#define FILE_DIR "mods/species/drakes/icons" +#define FILE_DIR "mods/species/drakes/icons/clothing" +#define FILE_DIR "mods/species/drakes/sounds" +#define FILE_DIR "mods/species/neoavians" +#define FILE_DIR "mods/species/neoavians/icons" +#define FILE_DIR "mods/species/neoavians/icons/clothing" +#define FILE_DIR "mods/species/neoavians/icons/clothing/accessory" +#define FILE_DIR "mods/species/neoavians/icons/clothing/feet" +#define FILE_DIR "mods/species/neoavians/icons/clothing/head" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/atmos" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/engineering" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/medical" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/medical_alt" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/merc" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/mining" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/pilot" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/salvage" +#define FILE_DIR "mods/species/neoavians/icons/clothing/spacesuit/void/sec" +#define FILE_DIR "mods/species/neoavians/icons/clothing/suit" +#define FILE_DIR "mods/species/neoavians/icons/clothing/under" +#define FILE_DIR "mods/species/neoavians/sound" +#define FILE_DIR "mods/species/serpentid" +#define FILE_DIR "mods/species/serpentid/icons" +#define FILE_DIR "mods/species/utility_frames" +#define FILE_DIR "mods/species/utility_frames/icons" +#define FILE_DIR "mods/species/vox" +#define FILE_DIR "mods/species/vox/icons" +#define FILE_DIR "mods/species/vox/icons/body" +#define FILE_DIR "mods/species/vox/icons/body/servitor" +#define FILE_DIR "mods/species/vox/icons/body/soldier" +#define FILE_DIR "mods/species/vox/icons/body/stanchion" +#define FILE_DIR "mods/species/vox/icons/clothing" +#define FILE_DIR "mods/species/vox/icons/gear" +#define FILE_DIR "mods/species/vox/icons/rig" +#define FILE_DIR "mods/species/vox/sounds" +#define FILE_DIR "nano" +#define FILE_DIR "nano/images" +#define FILE_DIR "nano/images/example" +#define FILE_DIR "nano/images/exodus" +#define FILE_DIR "nano/images/ministation" +#define FILE_DIR "nano/images/modular_computers" +#define FILE_DIR "nano/images/overmap_example" +#define FILE_DIR "nano/images/shaded_hills" +#define FILE_DIR "nano/images/status_icons" +#define FILE_DIR "nano/images/tradeship" +#define FILE_DIR "sound" +#define FILE_DIR "sound/AI" +#define FILE_DIR "sound/ambience" +#define FILE_DIR "sound/effects" +#define FILE_DIR "sound/effects/footstep" +#define FILE_DIR "sound/effects/holster" +#define FILE_DIR "sound/effects/plants" +#define FILE_DIR "sound/effects/projectile_impact" +#define FILE_DIR "sound/effects/psi" +#define FILE_DIR "sound/effects/storage" +#define FILE_DIR "sound/effects/thunder" +#define FILE_DIR "sound/effects/turret" +#define FILE_DIR "sound/effects/weather" +#define FILE_DIR "sound/effects/wind" +#define FILE_DIR "sound/foley" +#define FILE_DIR "sound/hallucinations" +#define FILE_DIR "sound/items" +#define FILE_DIR "sound/items/containers" +#define FILE_DIR "sound/items/drop" +#define FILE_DIR "sound/items/pickup" +#define FILE_DIR "sound/machines" +#define FILE_DIR "sound/machines/keyboard" +#define FILE_DIR "sound/machines/kitchen" +#define FILE_DIR "sound/machines/kitchen/grill" +#define FILE_DIR "sound/machines/microwave" +#define FILE_DIR "sound/machines/phone" +#define FILE_DIR "sound/machines/sensors" +#define FILE_DIR "sound/machines/sm" +#define FILE_DIR "sound/machines/sm/accent" +#define FILE_DIR "sound/machines/sm/accent/delam" +#define FILE_DIR "sound/machines/sm/accent/normal" +#define FILE_DIR "sound/machines/sm/loops" +#define FILE_DIR "sound/magic" +#define FILE_DIR "sound/mecha" +#define FILE_DIR "sound/misc" +#define FILE_DIR "sound/music" +#define FILE_DIR "sound/music/europa" +#define FILE_DIR "sound/piano" +#define FILE_DIR "sound/violin" +#define FILE_DIR "sound/voice" +#define FILE_DIR "sound/voice/eal" +#define FILE_DIR "sound/voice/emotes" +#define FILE_DIR "sound/voice/medbot" +#define FILE_DIR "sound/voice/Serithi" +#define FILE_DIR "sound/weapons" +#define FILE_DIR "sound/weapons/guns" +#define FILE_DIR "sound/weapons/guns/interaction" +#define FILE_DIR "sound/weapons/gunshot" // END_FILE_DIR // BEGIN_PREFERENCES #define DEBUG @@ -1656,6 +2234,7 @@ #include "code\modules\abstract\abstract_fluid_direction.dm" #include "code\modules\abstract\abstract_ramp_sculptor.dm" #include "code\modules\abstract\airlock_helper.dm" +#include "code\modules\abstract\follower.dm" #include "code\modules\acting\acting_items.dm" #include "code\modules\admin\admin.dm" #include "code\modules\admin\admin_attack_log.dm" @@ -3827,11 +4406,17 @@ #include "code\modules\status_conditions\_status_markers.dm" #include "code\modules\status_conditions\status_counters_simple.dm" #include "code\modules\status_conditions\status_dizzy.dm" +#include "code\modules\status_conditions\status_effect.dm" +#include "code\modules\status_conditions\status_effect_archetype.dm" +#include "code\modules\status_conditions\status_effect_datum.dm" #include "code\modules\status_conditions\status_jittery.dm" #include "code\modules\status_conditions\status_paralyzed.dm" #include "code\modules\status_conditions\status_sleeping.dm" #include "code\modules\status_conditions\status_stunned.dm" #include "code\modules\status_conditions\status_weakened.dm" +#include "code\modules\status_conditions\definitions\status_effect_object.dm" +#include "code\modules\status_conditions\definitions\status_effect_prone.dm" +#include "code\modules\status_conditions\definitions\status_effect_restrained.dm" #include "code\modules\stressors\_stressor.dm" #include "code\modules\stressors\stressor_definitions.dm" #include "code\modules\submaps\_submap.dm"