diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index f4732eea7e8..801076af58f 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -402,6 +402,13 @@ id = "sleeping" tick_interval = 2 SECONDS needs_update_stat = TRUE + /// Whether we decided to take a nap on our own. + /// As opposed to being hard knocked out with N2O or similar. + var/voluntary = FALSE + +/datum/status_effect/incapacitating/sleeping/on_creation(mob/living/new_owner, set_duration, voluntary = FALSE) + ..() + src.voluntary = voluntary /datum/status_effect/incapacitating/sleeping/tick() if(!iscarbon(owner)) diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index 17c3be0fcaa..590888b2c43 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -105,8 +105,9 @@ // HELPER PROCS // ////////////////// -/mob/living/proc/apply_status_effect(effect, ...) //applies a given status effect to this mob, returning the effect if it was successful - . = FALSE +/// Applies a given status effect to this mob, returning the effect if it was successful or null otherwise +/mob/living/proc/apply_status_effect(effect, ...) + . = null var/datum/status_effect/S1 = effect LAZYINITLIST(status_effects) for(var/datum/status_effect/S in status_effects) @@ -123,7 +124,8 @@ S1 = new effect(arguments) . = S1 -/mob/living/proc/remove_status_effect(effect, ...) //removes all of a given status effect from this mob, returning TRUE if at least one was removed +/// Removes all of a given status effect from this mob, returning TRUE if at least one was removed +/mob/living/proc/remove_status_effect(effect, ...) . = FALSE var/list/arguments = args.Copy(2) if(status_effects) @@ -133,15 +135,17 @@ qdel(S) . = TRUE -/mob/living/proc/has_status_effect(effect) //returns the effect if the mob calling the proc owns the given status effect - . = FALSE +/// Returns the effect if the mob calling the proc owns the given status effect, or null otherwise +/mob/living/proc/has_status_effect(effect) + . = null if(status_effects) var/datum/status_effect/S1 = effect for(var/datum/status_effect/S in status_effects) if(initial(S1.id) == S.id) return S -/mob/living/proc/has_status_effect_list(effect) //returns a list of effects with matching IDs that the mod owns; use for effects there can be multiple of +/// Returns a list of effects with matching IDs that the mod owns; use for effects there can be multiple of +/mob/living/proc/has_status_effect_list(effect) . = list() if(status_effects) var/datum/status_effect/S1 = effect diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 92ed8060f4b..eb1c71b1e3d 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -382,7 +382,7 @@ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount) return S -/mob/living/proc/SetSleeping(amount, ignore_canstun = FALSE) +/mob/living/proc/SetSleeping(amount, ignore_canstun = FALSE, voluntary = FALSE) if(frozen) // If the mob has been admin frozen, sleeping should not be changeable return if(status_flags & GODMODE) @@ -393,13 +393,19 @@ if(S) S.duration = amount + world.time else if(amount > 0) - S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount) + S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, voluntary) + if(!voluntary && S) + // Only set it one way (true => false) + // Otherwise if we are hard knocked out, and then try to nap, we'd be + // treated as "just lightly napping" and woken up by trivial stuff. + S.voluntary = FALSE return S /mob/living/proc/PermaSleeping() /// used for admin freezing. var/datum/status_effect/incapacitating/sleeping/S = IsSleeping() if(S) S.duration = -1 + S.voluntary = FALSE else S = apply_status_effect(STATUS_EFFECT_SLEEPING, -1) return S diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 51586346048..edf0d40520b 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -460,9 +460,8 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM if(IsSleeping()) to_chat(src, "You are already sleeping.") return - else - if(alert(src, "You sure you want to sleep for a while?", "Sleep", "Yes", "No") == "Yes") - SetSleeping(40 SECONDS) //Short nap + if(alert(src, "You sure you want to sleep for a while?", "Sleep", "Yes", "No") == "Yes") + SetSleeping(40 SECONDS, voluntary = TRUE) //Short nap /mob/living/verb/lay_down() set name = "Rest" diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index d3feb46ebc1..1e030409d61 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -118,7 +118,13 @@ /proc/get_pain_modifier(mob/living/carbon/human/M) //returns modfier to make surgery harder if patient is conscious and feels pain - if(M.stat) //stat=0 if CONSCIOUS, 1=UNCONSCIOUS and 2=DEAD. Operating on dead people is easy, too. Just sleeping won't work, though. + if(M.stat == DEAD) // Operating on dead people is easy + return 1 + var/datum/status_effect/incapacitating/sleeping/S = M.IsSleeping() + if(M.stat == UNCONSCIOUS && !(S?.voluntary)) + // Either unconscious due to something other than sleep, + // or "sleeping" due to being hard knocked out (N2O or similar), rather than just napping. + // Either way, not easily woken up. return 1 if(HAS_TRAIT(M, TRAIT_NOPAIN))//if you don't feel pain, you can hold still return 1 diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 1acef049678..57c0cb64285 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -114,7 +114,16 @@ if(!ispath(surgery.steps[surgery.status], /datum/surgery_step/robotics))//Repairing robotic limbs doesn't hurt, and neither does cutting someone out of a rig if(ishuman(target)) var/mob/living/carbon/human/H = target //typecast to human - prob_chance *= get_pain_modifier(H)//operating on conscious people is hard. + var/pain_mod = get_pain_modifier(H) + var/datum/status_effect/incapacitating/sleeping/S = H.IsSleeping() + if(S?.voluntary) + H.SetSleeping(0) // wake up people who are napping through the surgery + if(pain_mod < 0.95) + to_chat(H, "The surgery on your [target_zone] is agonizingly painful, and wrecks you out of your shallow slumber!") + else + // Still wake people up, but they shouldn't be as alarmed. + to_chat(H, "The surgery being performed on your [target_zone] wakes you up.") + prob_chance *= pain_mod //operating on conscious people is hard. if(prob(prob_chance) || isrobot(user)) if(end_step(user, target, target_zone, tool, surgery))