Skip to content

Commit

Permalink
/tg/ Status effects part 1 - fluid status updates (#4828)
Browse files Browse the repository at this point in the history
![image](https://github.com/cmss13-devs/cmss13/assets/604624/38cdd1a0-e13c-4d69-b893-49cea2a8113f)
CM Dev figured it out 9 years ago and nobody listened and kept tacking
illogical conditions

<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->

# About the pull request

<!-- Remove this text and explain what the purpose of your PR is.

Mention if you have tested your changes. If you changed a map, make sure
you used the mapmerge tool.
If this is an Issue Correction, you can type "Fixes Issue #169420" to
link the PR to the corresponding Issue number #169420.

Remember: something that is self-evident to you might not be to others.
Explain your rationale fully, even if you feel it goes without saying.
-->

Builds on previous "prelude" PRs in the following steps:
 * Ports /tg/ body_position and mobility_flags
* Fixes some interaction requirements to use stun/mobility rather than
lying/knocked_down
* Ports /tg/ granular status updates, ie. status propagating through
handlers and signals. This includes changes to resting, buckling, and
lying down human transforms.
 * Wires our status effect system to it directly
* Removes `update_canmove` from existence completely as not needed
anymore

Because step 1 and 2 require updating all the gameplay logic using them,
this PR modifies a lot of files.

Part 2 will move the actual status effects to /tg/ status_effects,
resolving our timing problems.

# Testing Photographs and Procedure
<!-- Include any screenshots/videos/debugging steps of the modified code
functioning successfully, ideally including edge cases. -->
<details>
<summary>Testing Checklist!</summary>

- [x] Basic Movement
- [x] Admin Freeze Prevents Movement
- [x] Resting, Getting Up
- [x] Xenos change icon when resting
- [x] Buckling, including bed rotation and propelled chairs
- [x] Crawling Movement including sprite movement
- [x] Aggressive, Choke Grabbing, and Fireman carry apply rotation
- [x] Xeno Pounce and Abduct properly freeze both target and caster 
- [x] Double dropship seats density update
- [x] Explosive knockout on Humans
- [x] Xeno burrow density and movement interactions
- [x] Xeno nest interactions, specifically confirm density changes work
- [ ] Xeno nest bullet hits doublecheck with snowflake trait check
- [x] Combat Xeno ~~knockouts~~ knockdown and sprite updates
- [x] ~~Sleeping, Waking up, Usage of items while sleeping~~ - Can't
really test this we have almost no sleep code
- [x] Arbitrary buckling rotations
- [x] Admin-set transforms work with buckling/lying
- [ ] All the broken objects that will only be found out in Testmerge

</details>


# Changelog

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Be sure to properly
label your changes in the changelog. Please note that maintainers freely
reserve the right to remove and add tags should they deem it
appropriate. You can attempt to finagle the system all you want, but
it's best to shoot for clear communication right off the bat. -->
<!-- If you add a name after the ':cl', that name will be used in the
changelog. You must add your CKEY after the CL if your GitHub name
doesn't match. Maintainers freely reserve the right to remove and add
tags should they deem it appropriate. -->

:cl:
code: Ported basic /tg/ Status Backend.
add: Human transform changes such as lying down, knock down, buckling,
are now animated.
fix: Some statuses will now take effect immediately instead of waiting
for a life tick, notably Resting.
balance: Many interaction requirements were changed to eg. fail upon
stuns rather than if lying down.
/:cl:

<!-- Both :cl:'s are required for the changelog to work! -->
  • Loading branch information
fira authored Nov 27, 2023
1 parent 77a9f06 commit a955791
Show file tree
Hide file tree
Showing 219 changed files with 1,052 additions and 819 deletions.
5 changes: 5 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@
/// From /mob/living/Collide(): (atom/A)
#define COMSIG_LIVING_PRE_COLLIDE "living_pre_collide"
#define COMPONENT_LIVING_COLLIDE_HANDLED (1<<0)

///from base of mob/living/set_buckled(): (new_buckled)
#define COMSIG_LIVING_SET_BUCKLED "living_set_buckled"
///from base of mob/living/set_body_position()
#define COMSIG_LIVING_SET_BODY_POSITION "living_set_body_position"
6 changes: 0 additions & 6 deletions code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@
#define COMSIG_MOB_FIRED_GUN_ATTACHMENT "mob_fired_gun_attachment"
/// From /mob/proc/death
#define COMSIG_MOB_DEATH "mob_death"
/// From /mob/proc/update_canmove()
#define COMSIG_MOB_GETTING_UP "mob_getting_up"
/// From /mob/proc/update_canmove()
#define COMSIG_MOB_KNOCKED_DOWN "mob_knocked_down"
/// For when a mob is dragged
#define COMSIG_MOB_DRAGGED "mob_dragged"
/// From /obj/item/proc/unequipped()
Expand Down Expand Up @@ -86,8 +82,6 @@
//from /mob/proc/on_deafness_loss()
#define COMSIG_MOB_REGAINED_HEARING "mob_regained_hearing"

#define COMSIG_MOB_POST_UPDATE_CANMOVE "mob_can_move"

#define COMSIG_ATTEMPT_MOB_PULL "attempt_mob_pull"
#define COMPONENT_CANCEL_MOB_PULL (1<<0)

Expand Down
28 changes: 28 additions & 0 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,31 @@ GLOBAL_LIST_INIT(default_xeno_onmob_icons, list(
#define CORE_LIMBS list("chest","head","groin")

#define SYMPTOM_ACTIVATION_PROB 3

// Body position defines.
/// Mob is standing up, usually associated with lying_angle value of 0.
#define STANDING_UP 0
/// Mob is lying down, usually associated with lying_angle values of 90 or 270.
#define LYING_DOWN 1

/// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled.
#define NO_BUCKLE_LYING -1

// ====================================
// /mob/living /tg/ mobility_flags
// These represent in what capacity the mob is capable of moving
// Because porting this is underway, NOT ALL FLAGS ARE CURRENTLY IN.

/// can move
#define MOBILITY_MOVE (1<<0)
/// can, and is, standing up
#define MOBILITY_STAND (1<<1)
/// can rest
#define MOBILITY_REST (1<<7)
/// can lie down
#define MOBILITY_LIEDOWN (1<<8)

#define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND)
#define MOBILITY_FLAGS_CARBON_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN)
#define MOBILITY_FLAGS_REST_CAPABLE_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN)

45 changes: 41 additions & 4 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,18 @@
// #define TRAIT_X "t_x"

//-- mob traits --
/// Prevents voluntary movement.
#define TRAIT_IMMOBILIZED "immobilized"
/// Apply this to make a mob not dense, and remove it when you want it to no longer make them undense, other sorces of undesity will still apply. Always define a unique source when adding a new instance of this!
#define TRAIT_UNDENSE "undense"
/// Forces the user to stay unconscious.
#define TRAIT_KNOCKEDOUT "knockedout"
/// Prevents voluntary movement.
#define TRAIT_IMMOBILIZED "immobilized"
/// Prevents voluntary standing or staying up on its own.
#define TRAIT_FLOORED "floored"
/// Forces user to stay standing
#define TRAIT_FORCED_STANDING "forcedstanding"
/// Stuns preventing movement and using objects but without further impairement
#define TRAIT_INCAPACITATED "incapacitated"
/// Apply this to identify a mob as merged with weeds
#define TRAIT_MERGED_WITH_WEEDS "merged_with_weeds"

Expand Down Expand Up @@ -298,7 +306,10 @@ GLOBAL_LIST_INIT(mob_traits, list(
*/
GLOBAL_LIST_INIT(traits_by_type, list(
/mob = list(
"TRAIT_KNOCKEDOUT" = TRAIT_KNOCKEDOUT,
"TRAIT_IMMOBILIZED" = TRAIT_IMMOBILIZED,
"TRAIT_INCAPACITATED" = TRAIT_INCAPACITATED,
"TRAIT_FLOORED" = TRAIT_FLOORED,
"TRAIT_UNDENSE" = TRAIT_UNDENSE,
"TRAIT_YAUTJA_TECH" = TRAIT_YAUTJA_TECH,
"TRAIT_SUPER_STRONG" = TRAIT_SUPER_STRONG,
Expand Down Expand Up @@ -416,13 +427,39 @@ GLOBAL_LIST(trait_name_map)
//Status trait coming from clothing.
#define TRAIT_SOURCE_CLOTHING "t_s_clothing"

/// traits associated with actively interacted machinery
#define INTERACTION_TRAIT "interaction"
/// trait associated to being buckled
#define BUCKLED_TRAIT "buckled" // Yes the name doesn't conform. /tg/ appears to have changed naming style inbetween
/// trait source when an effect is coming from a fakedeath effect (refactor this)
#define FAKEDEATH_TRAIT "fakedeath"
/// trait source where a condition comes from body state
#define BODY_TRAIT "body"
/// Trait associated to lying down (having a [lying_angle] of a different value than zero).
#define LYING_DOWN_TRAIT "lying-down"
/// trait associated to a stat value or range of
#define STAT_TRAIT "stat"
/// trait effect related to the queen ovipositor
#define OVIPOSITOR_TRAIT "ovipositor"
/// trait associated to being held in a chokehold
#define CHOKEHOLD_TRAIT "chokehold"
/// trait effect related to active specialist gear
#define SPECIALIST_GEAR_TRAIT "specialist_gear"
/// traits associated with usage of snowflake dropship double seats
#define DOUBLE_SEATS_TRAIT "double_seats"
/// traits associated with xeno on-ground weeds
#define XENO_WEED_TRAIT "xeno_weed"
/// traits associated with actively interacted machinery
#define INTERACTION_TRAIT "interaction"
/// traits bound by stunned status effects
#define STUNNED_TRAIT "stunned"
/// traits bound by knocked_down status effect
#define KNOCKEDDOWN_TRAIT "knockeddown"
/// traits bound by knocked_out status effect
#define KNOCKEDOUT_TRAIT "knockedout"
/// traits from being pounced
#define POUNCED_TRAIT "pounced"
/// traits from step_triggers on the map
#define STEP_TRIGGER_TRAIT "step_trigger"
/// traits from hacked machine interactions
#define HACKED_TRAIT "hacked"
/// traits from chloroform usage
#define CHLOROFORM_TRAIT "chloroform"
2 changes: 2 additions & 0 deletions code/__HELPERS/animations.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// The duration of the animate call in mob/living/update_transform
#define UPDATE_TRANSFORM_ANIMATION_TIME (0.2 SECONDS)
1 change: 1 addition & 0 deletions code/__HELPERS/status_effects.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#define TRAIT_STATUS_EFFECT(effect_id) "[effect_id]-trait"
16 changes: 8 additions & 8 deletions code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1089,15 +1089,15 @@ GLOBAL_DATUM(action_purple_power_up, /image)
target_orig_turf = get_turf(target)
var/obj/user_holding = busy_user.get_active_hand()
var/obj/target_holding
var/cur_user_lying = busy_user.lying
var/cur_user_lying = busy_user.body_position
var/cur_target_lying
var/expected_total_time = delayfraction*numticks
var/time_remaining = expected_total_time

if(has_target && istype(T))
cur_target_zone_sel = T.zone_selected
target_holding = T.get_active_hand()
cur_target_lying = T.lying
cur_target_lying = T.body_position

. = TRUE
for(var/i in 1 to numticks)
Expand All @@ -1121,13 +1121,13 @@ GLOBAL_DATUM(action_purple_power_up, /image)
)
. = FALSE
break
if(user_flags & INTERRUPT_KNOCKED_DOWN && busy_user.knocked_down || \
target_is_mob && (target_flags & INTERRUPT_KNOCKED_DOWN && T.knocked_down)
if(user_flags & INTERRUPT_KNOCKED_DOWN && HAS_TRAIT(busy_user, TRAIT_FLOORED) || \
target_is_mob && (target_flags & INTERRUPT_KNOCKED_DOWN && HAS_TRAIT(T, TRAIT_FLOORED))
)
. = FALSE
break
if(user_flags & INTERRUPT_STUNNED && busy_user.stunned || \
target_is_mob && (target_flags & INTERRUPT_STUNNED && T.stunned)
if(user_flags & INTERRUPT_STUNNED && HAS_TRAIT(busy_user, TRAIT_INCAPACITATED)|| \
target_is_mob && (target_flags & INTERRUPT_STUNNED && HAS_TRAIT(T, TRAIT_INCAPACITATED))
)
. = FALSE
break
Expand Down Expand Up @@ -1201,8 +1201,8 @@ GLOBAL_DATUM(action_purple_power_up, /image)
)
. = FALSE
break
if(user_flags & INTERRUPT_CHANGED_LYING && busy_user.lying != cur_user_lying || \
target_is_mob && (target_flags & INTERRUPT_CHANGED_LYING && T.lying != cur_target_lying)
if(user_flags & INTERRUPT_CHANGED_LYING && busy_user.body_position != cur_user_lying || \
target_is_mob && (target_flags & INTERRUPT_CHANGED_LYING && T.body_position != cur_target_lying)
)
. = FALSE
break
Expand Down
7 changes: 7 additions & 0 deletions code/_globalvars/bitfields.dm
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,13 @@ DEFINE_BITFIELD(mob_flags, list(
"NOBIOSCAN" = NOBIOSCAN,
))

DEFINE_BITFIELD(mobility_flags, list(
"MOVE" = MOBILITY_MOVE,
"STAND" = MOBILITY_STAND,
"REST" = MOBILITY_REST,
"LIEDOWN" = MOBILITY_LIEDOWN
))

DEFINE_BITFIELD(flags, list(
"NO_BLOOD" = NO_BLOOD,
"NO_BREATHE" = NO_BREATHE,
Expand Down
6 changes: 2 additions & 4 deletions code/_onclick/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, click_parameters)

if(lying) //No attacks while laying down
if(body_position == LYING_DOWN) //No attacks while laying down
return 0

var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines
Expand All @@ -88,7 +88,7 @@
/atom/proc/attack_hand(mob/user)
return

/mob/living/carbon/human/MouseDrop_T(atom/dropping, mob/user)
/mob/living/carbon/human/MouseDrop_T(atom/dropping, mob/living/user)
if(user != src)
return . = ..()

Expand Down Expand Up @@ -153,6 +153,4 @@
target.Move(user.loc, get_dir(target.loc, user.loc))
target.update_transform(TRUE)

target.update_canmove()


4 changes: 2 additions & 2 deletions code/_onclick/ventcrawl.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
to_chat(src, SPAN_WARNING("You must be conscious to do this!"))
return

if(lying)
if(is_mob_incapacitated())
to_chat(src, SPAN_WARNING("You can't vent crawl while you're stunned!"))
return

Expand Down Expand Up @@ -88,7 +88,7 @@
return

updatehealth()
if(stat || stunned || dazed || knocked_down || lying || health < 0 || !client || !ventcrawl_carry())
if(is_mob_incapacitated(src) || health < 0 || !client || !ventcrawl_carry())
vent_found.animate_ventcrawl_reset()
return

Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/xeno.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/

/mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE, ignores_resin = FALSE)
if(lying || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //No attacks while laying down
if(body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //No attacks while laying down
return FALSE
var/mob/alt

Expand All @@ -21,7 +21,7 @@

if (!L.is_xeno_grabbable() || L == src) //Xenos never attack themselves.
continue
if (L.lying)
if (L.body_position == LYING_DOWN)
alt = L
continue
target = L
Expand Down
6 changes: 4 additions & 2 deletions code/datums/action.dm
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,10 @@
I.ui_action_click(owner, holder_item)

/datum/action/item_action/can_use_action()
if(ishuman(owner) && !owner.is_mob_incapacitated() && !owner.lying)
return TRUE
if(ishuman(owner) && !owner.is_mob_incapacitated())
var/mob/living/carbon/human/human = owner
if(human.body_position == STANDING_UP)
return TRUE

/datum/action/item_action/update_button_icon()
button.overlays.Cut()
Expand Down
2 changes: 0 additions & 2 deletions code/datums/agents/tools/chloroform.dm
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
ADD_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT)
ADD_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT)
M.able_to_speak = FALSE
M.update_canmove()

M.drop_inv_item_on_ground(M.wear_mask, force = TRUE)

Expand Down Expand Up @@ -79,7 +78,6 @@
/obj/item/weapon/chloroform/proc/remove_stun(mob/living/M)
animate(M, pixel_x = 0, pixel_y = 0, time = 0.2 SECONDS, easing = QUAD_EASING)
M.anchored = FALSE
M.density = TRUE
M.able_to_speak = TRUE
M.layer = MOB_LAYER
REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT)
Expand Down
6 changes: 3 additions & 3 deletions code/datums/ammo/ammo.dm
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
/datum/ammo/proc/knockback(mob/living/living_mob, obj/projectile/fired_projectile, max_range = 2)
if(!living_mob || living_mob == fired_projectile.firer)
return
if(fired_projectile.distance_travelled > max_range || living_mob.lying)
if(fired_projectile.distance_travelled > max_range || living_mob.body_position == LYING_DOWN)
return //Two tiles away or more, basically.

if(living_mob.mob_size >= MOB_SIZE_BIG)
Expand Down Expand Up @@ -180,8 +180,8 @@
else
living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)

/datum/ammo/proc/pushback(mob/target_mob, obj/projectile/fired_projectile, max_range = 2)
if(!target_mob || target_mob == fired_projectile.firer || fired_projectile.distance_travelled > max_range || target_mob.lying)
/datum/ammo/proc/pushback(mob/living/target_mob, obj/projectile/fired_projectile, max_range = 2)
if(!target_mob || target_mob == fired_projectile.firer || fired_projectile.distance_travelled > max_range || target_mob.body_position == LYING_DOWN)
return

if(target_mob.mob_size >= MOB_SIZE_BIG)
Expand Down
2 changes: 1 addition & 1 deletion code/datums/ammo/bullet/shotgun.dm
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@
if(P.distance_travelled > 8)
knockback(M, P, 12)

else if(!M || M == P.firer || M.lying) //These checks are included in knockback and would be redundant above.
else if(!M || M == P.firer || M.body_position == LYING_DOWN) //These checks are included in knockback and would be redundant above.
return

shake_camera(M, 3, 4)
Expand Down
8 changes: 4 additions & 4 deletions code/datums/ammo/xeno.dm
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@

if(!isxeno(M))
if(insta_neuro)
if(M.knocked_down < 3)
if(M.GetKnockDownValueNotADurationDoNotUse() < 3) // If they have less than somewhere random between 4 and 6 seconds KD left and assuming it doesnt get refreshed itnernally
M.adjust_effect(1 * power, WEAKEN)
return
return

if(ishuman(M))
M.apply_effect(2.5, SUPERSLOW)
Expand All @@ -65,7 +65,7 @@
no_clothes_neuro = TRUE

if(no_clothes_neuro)
if(M.knocked_down < 5)
if(M.GetKnockDownValueNotADurationDoNotUse() < 5) // If they have less than somewhere random between 8 and 10 seconds KD left and assuming it doesnt get refreshed itnernally
M.adjust_effect(1 * power, WEAKEN) // KD them a bit more
M.visible_message(SPAN_DANGER("[M] falls prone."))

Expand All @@ -79,7 +79,7 @@
H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!"))
return

if(M.knocked_down < 0.7) // apply knockdown only if current knockdown is less than 0.7 second
if(M.GetKnockDownValueNotADurationDoNotUse() < 0.7) // basically (knocked_down && prob(90))
M.apply_effect(0.7, WEAKEN)
M.visible_message(SPAN_DANGER("[M] falls prone."))

Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/footstep.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
if(!T)
return
var/mob/living/parent_mob = parent
if(parent_mob.lying && (isfile(drag_sounds) || istext(drag_sounds)))
if(parent_mob.body_position == LYING_DOWN && (isfile(drag_sounds) || istext(drag_sounds)))
playsound(T, drag_sounds, volume, rand(20000, 25000), range, falloff = falloff)
else if(isfile(footstep_sounds) || istext(footstep_sounds))
playsound(T, footstep_sounds, volume, rand(20000, 25000), range, falloff = falloff)
4 changes: 2 additions & 2 deletions code/datums/diseases/cold.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
cure()
return
*/
if(affected_mob.lying && prob(40)) //changed FROM prob(10) until sleeping is fixed
if(affected_mob.body_position == LYING_DOWN && prob(40)) //changed FROM prob(10) until sleeping is fixed
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
cure()
return
Expand All @@ -43,7 +43,7 @@
cure()
return
*/
if(affected_mob.lying && prob(25)) //changed FROM prob(5) until sleeping is fixed
if(affected_mob.body_position == LYING_DOWN && prob(25)) //changed FROM prob(5) until sleeping is fixed
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
cure()
return
Expand Down
4 changes: 2 additions & 2 deletions code/datums/diseases/flu.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
stage--
return
*/
if(affected_mob.lying && prob(20)) //added until sleeping is fixed --Blaank
if(affected_mob.body_position == LYING_DOWN && prob(20)) //added until sleeping is fixed --Blaank
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
stage--
return
Expand All @@ -46,7 +46,7 @@
stage--
return
*/
if(affected_mob.lying && prob(15)) //added until sleeping is fixed
if(affected_mob.body_position == LYING_DOWN && prob(15)) //added until sleeping is fixed
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
stage--
return
Expand Down
Loading

0 comments on commit a955791

Please sign in to comment.