diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 8eceebe02b7..89a210acf37 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -74,6 +74,7 @@ #define ADMIN_PUNISHMENT_SUPPLYPOD_QUICK "Supply Pod (Quick)" #define ADMIN_PUNISHMENT_SUPPLYPOD "Supply Pod" #define ADMIN_PUNISHMENT_MAZING "Puzzle" +#define ADMIN_PUNISHMENT_IMMERSE "Fully Immerse" #define AHELP_ACTIVE 1 #define AHELP_CLOSED 2 diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 75022a9987b..48a94c388b6 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -220,6 +220,8 @@ #define SPEECH_FORCED 7 */ #define COMSIG_MOB_DEADSAY "mob_deadsay" // from /mob/say_dead(): (mob/speaker, message) #define MOB_DEADSAY_SIGNAL_INTERCEPT 1 +#define COMSIG_MOB_EMOTE "mob_emote" // from /mob/living/emote(): () + // /mob/living signals #define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living) #define COMSIG_LIVING_IGNITED "living_ignite" //from base of mob/living/IgniteMob() (/mob/living) @@ -244,6 +246,8 @@ // /mob/living/carbon signals #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity)) +#define COMSIG_CARBON_GAIN_ORGAN "carbon_gain_organ" //from /item/organ/proc/Insert() (/obj/item/organ/) +#define COMSIG_CARBON_LOSE_ORGAN "carbon_lose_organ" //from /item/organ/proc/Remove() (/obj/item/organ/) // /mob/living/simple_animal/hostile signals #define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget" diff --git a/code/datums/components/manual_blinking.dm b/code/datums/components/manual_blinking.dm new file mode 100644 index 00000000000..2459ec438f1 --- /dev/null +++ b/code/datums/components/manual_blinking.dm @@ -0,0 +1,83 @@ +/datum/component/manual_blinking + dupe_mode = COMPONENT_DUPE_UNIQUE + + var/obj/item/organ/eyes/E + var/warn_grace = FALSE + var/warn_dying = FALSE + var/last_blink + var/check_every = 20 SECONDS + var/grace_period = 6 SECONDS + var/damage_rate = 1 // organ damage taken per tick + var/list/valid_emotes = list(/datum/emote/living/carbon/blink, /datum/emote/living/carbon/blink_r) + +/datum/component/manual_blinking/Initialize() + if(!iscarbon(parent)) + return COMPONENT_INCOMPATIBLE + + var/mob/living/carbon/C = parent + E = C.getorganslot(ORGAN_SLOT_EYES) + + if(E) + START_PROCESSING(SSdcs, src) + last_blink = world.time + to_chat(C, "You suddenly realize you're blinking manually.") + +/datum/component/manual_blinking/Destroy(force, silent) + E = null + STOP_PROCESSING(SSdcs, src) + to_chat(parent, "You revert back to automatic blinking.") + return ..() + +/datum/component/manual_blinking/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOB_EMOTE, .proc/check_emote) + RegisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN, .proc/check_added_organ) + RegisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN, .proc/check_removed_organ) + RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/restart) + RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/pause) + +/datum/component/manual_blinking/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_MOB_EMOTE) + UnregisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN) + UnregisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN) + UnregisterSignal(parent, COMSIG_LIVING_REVIVE) + UnregisterSignal(parent, COMSIG_MOB_DEATH) + +/datum/component/manual_blinking/proc/restart() + START_PROCESSING(SSdcs, src) + +/datum/component/manual_blinking/proc/pause() + STOP_PROCESSING(SSdcs, src) + +/datum/component/manual_blinking/process() + var/mob/living/carbon/C = parent + + if(world.time > (last_blink + check_every + grace_period)) + if(!warn_dying) + to_chat(C, "Your eyes begin to wither, you need to blink!") + warn_dying = TRUE + + E.applyOrganDamage(damage_rate) + else if(world.time > (last_blink + check_every)) + if(!warn_grace) + to_chat(C, "You feel a need to blink!") + warn_grace = TRUE + +/datum/component/manual_blinking/proc/check_added_organ(mob/who_cares, obj/item/organ/O) + var/obj/item/organ/eyes/new_eyes = O + + if(istype(new_eyes,/obj/item/organ/eyes)) + E = new_eyes + START_PROCESSING(SSdcs, src) + +/datum/component/manual_blinking/proc/check_removed_organ(mob/who_cares, obj/item/organ/O) + var/obj/item/organ/eyes/bye_beyes = O // oh come on, that's pretty good + + if(istype(bye_beyes, /obj/item/organ/eyes)) + E = null + STOP_PROCESSING(SSdcs, src) + +/datum/component/manual_blinking/proc/check_emote(mob/living/carbon/user, datum/emote/emote) + if(emote.type in valid_emotes) + warn_grace = FALSE + warn_dying = FALSE + last_blink = world.time diff --git a/code/datums/components/manual_breathing.dm b/code/datums/components/manual_breathing.dm new file mode 100644 index 00000000000..da1c6cffc47 --- /dev/null +++ b/code/datums/components/manual_breathing.dm @@ -0,0 +1,93 @@ +/datum/component/manual_breathing + dupe_mode = COMPONENT_DUPE_UNIQUE + + var/obj/item/organ/lungs/L + var/warn_grace = FALSE + var/warn_dying = FALSE + var/last_breath + var/check_every = 12 SECONDS + var/grace_period = 6 SECONDS + var/damage_rate = 1 // organ damage taken per tick + var/datum/emote/next_breath_type = /datum/emote/inhale + +/datum/component/manual_breathing/Initialize() + if(!iscarbon(parent)) + return COMPONENT_INCOMPATIBLE + + var/mob/living/carbon/C = parent + L = C.getorganslot(ORGAN_SLOT_LUNGS) + + if(L) + START_PROCESSING(SSdcs, src) + last_breath = world.time + to_chat(C, "You suddenly realize you're breathing manually.") + +/datum/component/manual_breathing/Destroy(force, silent) + L = null + STOP_PROCESSING(SSdcs, src) + to_chat(parent, "You revert back to automatic breathing.") + return ..() + +/datum/component/manual_breathing/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOB_EMOTE, .proc/check_emote) + RegisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN, .proc/check_added_organ) + RegisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN, .proc/check_removed_organ) + RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/restart) + RegisterSignal(parent, COMSIG_MOB_DEATH, .proc/pause) + +/datum/component/manual_breathing/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_MOB_EMOTE) + UnregisterSignal(parent, COMSIG_CARBON_GAIN_ORGAN) + UnregisterSignal(parent, COMSIG_CARBON_LOSE_ORGAN) + UnregisterSignal(parent, COMSIG_LIVING_REVIVE) + UnregisterSignal(parent, COMSIG_MOB_DEATH) + +/datum/component/manual_breathing/proc/restart() + START_PROCESSING(SSdcs, src) + +/datum/component/manual_breathing/proc/pause() + STOP_PROCESSING(SSdcs, src) + +/datum/component/manual_breathing/process() + var/mob/living/carbon/C = parent + + var/next_text = initial(next_breath_type.key) + if(world.time > (last_breath + check_every + grace_period)) + if(!warn_dying) + to_chat(C, "You begin to suffocate, you need to [next_text]!") + warn_dying = TRUE + + L.applyOrganDamage(damage_rate) + C.losebreath += 0.8 + else if(world.time > (last_breath + check_every)) + if(!warn_grace) + to_chat(C, "You feel a need to [next_text]!") + warn_grace = TRUE + +/datum/component/manual_breathing/proc/check_added_organ(mob/who_cares, obj/item/organ/O) + var/obj/item/organ/eyes/new_lungs = O + + if(istype(new_lungs,/obj/item/organ/lungs)) + L = new_lungs + START_PROCESSING(SSdcs, src) + +/datum/component/manual_breathing/proc/check_removed_organ(mob/who_cares, obj/item/organ/O) + var/obj/item/organ/lungs/old_lungs = O + + if(istype(old_lungs, /obj/item/organ/lungs)) + L = null + STOP_PROCESSING(SSdcs, src) + +/datum/component/manual_breathing/proc/check_emote(mob/living/carbon/user, datum/emote/emote) + if(emote.type == next_breath_type) + if(next_breath_type == /datum/emote/inhale) + next_breath_type = /datum/emote/exhale + else + next_breath_type = /datum/emote/inhale + + warn_grace = FALSE + warn_dying = FALSE + last_breath = world.time + + var/mob/living/carbon/C = parent + C.losebreath = max(0, C.losebreath - 0.4) diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 825b0844f22..57e866c8249 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -69,6 +69,8 @@ Change bomb cap
Mass Purrbation
Mass Remove Purrbation
+ Fully Immerse Everyone
+ Un-Fully Immerse Everyone
"} dat += "
" @@ -595,6 +597,22 @@ purrbation.") log_admin("[key_name(usr)] has removed everyone from purrbation.") + if("massimmerse") + if(!check_rights(R_FUN)) + return + mass_immerse() + message_admins("[key_name_admin(usr)] has Fully Immersed \ + everyone!") + log_admin("[key_name(usr)] has Fully Immersed everyone.") + + if("unmassimmerse") + if(!check_rights(R_FUN)) + return + mass_immerse(remove=TRUE) + message_admins("[key_name_admin(usr)] has Un-Fully Immersed \ + everyone!") + log_admin("[key_name(usr)] has Un-Fully Immersed everyone.") + if("customportal") if(!check_rights(R_FUN)) return diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index b1830ba3873..dc5e9ef4839 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -1020,6 +1020,20 @@ Traitors and the like can also be revived with the previous role mostly intact. dat += "
Add New Goal" usr << browse(dat, "window=goals;size=400x400") +/proc/immerse_player(mob/living/carbon/target, toggle=TRUE, remove=FALSE) + var/list/immersion_components = list(/datum/component/manual_breathing, /datum/component/manual_blinking) + + for(var/immersies in immersion_components) + var/has_component = target.GetComponent(immersies) + + if(has_component && (toggle || remove)) + qdel(has_component) + else if(toggle || !remove) + target.AddComponent(immersies) + +/proc/mass_immerse(remove=FALSE) + for(var/mob/living/carbon/M in GLOB.mob_list) + immerse_player(M, toggle=FALSE, remove=remove) /client/proc/toggle_hub() set category = "Server" @@ -1040,7 +1054,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!check_rights(R_ADMIN) || !check_rights(R_FUN)) return - var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING) + var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING, ADMIN_PUNISHMENT_IMMERSE) var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in sortList(punishment_list) @@ -1100,11 +1114,12 @@ Traitors and the like can also be revived with the previous role mostly intact. plaunch.temp_pod.effectStun = TRUE plaunch.ui_interact(usr) return //We return here because punish_log() is handled by the centcom_podlauncher datum - if(ADMIN_PUNISHMENT_MAZING) if(!puzzle_imprison(target)) to_chat(usr,"Imprisonment failed!") return + if(ADMIN_PUNISHMENT_IMMERSE) + immerse_player(target) punish_log(target, punishment) diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index b7dc2425107..7577bcca357 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -19,6 +19,7 @@ silenced = TRUE continue if(P.run_emote(src, param, m_type, intentional)) + SEND_SIGNAL(src, COMSIG_MOB_EMOTE, P, act, m_type, message, intentional) return TRUE if(intentional && !silenced) to_chat(src, "Unusable emote '[act]'. Say *help for a list.") diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 158267a60c1..784dcf86bff 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -520,3 +520,13 @@ to_chat(user, "You ready your slapping hand.") else to_chat(user, "You're incapable of slapping in your current state.") + +/datum/emote/inhale + key = "inhale" + key_third_person = "inhales" + message = "breathes in." + +/datum/emote/exhale + key = "exhale" + key_third_person = "exhales" + message = "breathes out." diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 271c7895163..89f658e6168 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -38,6 +38,8 @@ else qdel(replaced) + SEND_SIGNAL(M, COMSIG_CARBON_GAIN_ORGAN, src) + owner = M M.internal_organs |= src M.internal_organs_slot[slot] = src @@ -59,6 +61,9 @@ for(var/X in actions) var/datum/action/A = X A.Remove(M) + + SEND_SIGNAL(M, COMSIG_CARBON_LOSE_ORGAN, src) + START_PROCESSING(SSobj, src) diff --git a/tgstation.dme b/tgstation.dme index 503a81f55a1..06580ae52ba 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -394,6 +394,8 @@ #include "code\datums\components\lifesteal.dm" #include "code\datums\components\lockon_aiming.dm" #include "code\datums\components\magnetic_catch.dm" +#include "code\datums\components\manual_blinking.dm" +#include "code\datums\components\manual_breathing.dm" #include "code\datums\components\material_container.dm" #include "code\datums\components\mirage_border.dm" #include "code\datums\components\mood.dm"