Files
Bubberstation/code/datums/status_effects/debuffs.dm
SkyratBot 94c42253b2 [MIRROR] Felinids don't like getting sprayed with water. [MDB IGNORE] (#9399)
* Felinids don't like getting sprayed with water. (#59506)

This PR is an ode to @ Ryll-Ryll, who inspired me to try and find fun, silly things to PR to try and make people smile.
About The Pull Request

Felinids now get a SMALL and SHORT mood debuff when getting sprayed with water. The intent of this PR is not to provide content to grief felinid (flashback to the "Felinids hate water" pr), but rather to provide a funny interaction.

Bonus point (Suggested by Ninja) : Getting sprayed with water interrupts do_after. Felinid climbing on your table ? Pssshttt. Straight in the face.

PR with permission from @ ninjanomnom
Why It's Good For The Game

Light-hearted fun and a bit of flavour to felinids.
Changelog

cl
add: Felinids don't like getting sprayed with water.
code: Adds a new status effect, incapacitated, which causes your do_afters to stop.
/cl

* Felinids don't like getting sprayed with water.

* Yes

Co-authored-by: Cimika/Lessie/KathyRyals <65850818+KathyRyals@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
2021-11-11 19:09:20 -05:00

1132 lines
38 KiB
Plaintext

#define TRAIT_STATUS_EFFECT(effect_id) "[effect_id]-trait"
//Largely negative status effects go here, even if they have small benificial effects
//STUN EFFECTS
/datum/status_effect/incapacitating
tick_interval = 0
status_type = STATUS_EFFECT_REPLACE
alert_type = null
var/needs_update_stat = FALSE
/datum/status_effect/incapacitating/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
. = ..()
if(. && (needs_update_stat || issilicon(owner)))
owner.update_stat()
/datum/status_effect/incapacitating/on_remove()
if(needs_update_stat || issilicon(owner)) //silicons need stat updates in addition to normal canmove updates
owner.update_stat()
return ..()
//STUN
/datum/status_effect/incapacitating/stun
id = "stun"
/datum/status_effect/incapacitating/stun/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id))
ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
ADD_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id))
/datum/status_effect/incapacitating/stun/on_remove()
REMOVE_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id))
REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
REMOVE_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id))
return ..()
//KNOCKDOWN
/datum/status_effect/incapacitating/knockdown
id = "knockdown"
/datum/status_effect/incapacitating/knockdown/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_FLOORED, TRAIT_STATUS_EFFECT(id))
/datum/status_effect/incapacitating/knockdown/on_remove()
REMOVE_TRAIT(owner, TRAIT_FLOORED, TRAIT_STATUS_EFFECT(id))
return ..()
//IMMOBILIZED
/datum/status_effect/incapacitating/immobilized
id = "immobilized"
/datum/status_effect/incapacitating/immobilized/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
/datum/status_effect/incapacitating/immobilized/on_remove()
REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
return ..()
//PARALYZED
/datum/status_effect/incapacitating/paralyzed
id = "paralyzed"
/datum/status_effect/incapacitating/paralyzed/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id))
ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
ADD_TRAIT(owner, TRAIT_FLOORED, TRAIT_STATUS_EFFECT(id))
ADD_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id))
/datum/status_effect/incapacitating/paralyzed/on_remove()
REMOVE_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id))
REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
REMOVE_TRAIT(owner, TRAIT_FLOORED, TRAIT_STATUS_EFFECT(id))
REMOVE_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id))
return ..()
//INCAPACITATED
/// This status effect represents anything that leaves a character unable to perform basic tasks (interrupting do-afters, for example), but doesn't incapacitate them further than that (no stuns etc..)
/datum/status_effect/incapacitating/incapacitated
id = "incapacitated"
// What happens when you get the incapacitated status. You get TRAIT_INCAPACITATED added to you for the duration of the status effect.
/datum/status_effect/incapacitating/incapacitated/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id))
// When the status effect runs out, your TRAIT_INCAPACITATED is removed.
/datum/status_effect/incapacitating/incapacitated/on_remove()
REMOVE_TRAIT(owner, TRAIT_INCAPACITATED, TRAIT_STATUS_EFFECT(id))
return ..()
//UNCONSCIOUS
/datum/status_effect/incapacitating/unconscious
id = "unconscious"
needs_update_stat = TRUE
/datum/status_effect/incapacitating/unconscious/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
/datum/status_effect/incapacitating/unconscious/on_remove()
REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
return ..()
/datum/status_effect/incapacitating/unconscious/tick()
if(owner.getStaminaLoss())
owner.adjustStaminaLoss(-0.3) //reduce stamina loss by 0.3 per tick, 6 per 2 seconds
//SLEEPING
/datum/status_effect/incapacitating/sleeping
id = "sleeping"
alert_type = /atom/movable/screen/alert/status_effect/asleep
needs_update_stat = TRUE
tick_interval = 2 SECONDS
var/mob/living/carbon/carbon_owner
var/mob/living/carbon/human/human_owner
/datum/status_effect/incapacitating/sleeping/on_creation(mob/living/new_owner)
. = ..()
if(.)
if(iscarbon(owner)) //to avoid repeated istypes
carbon_owner = owner
if(ishuman(owner))
human_owner = owner
/datum/status_effect/incapacitating/sleeping/Destroy()
carbon_owner = null
human_owner = null
return ..()
/datum/status_effect/incapacitating/sleeping/on_apply()
. = ..()
if(!.)
return
if(!HAS_TRAIT(owner, TRAIT_SLEEPIMMUNE))
ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
tick_interval = -1
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_SLEEPIMMUNE), .proc/on_owner_insomniac)
RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_SLEEPIMMUNE), .proc/on_owner_sleepy)
/datum/status_effect/incapacitating/sleeping/on_remove()
UnregisterSignal(owner, list(SIGNAL_ADDTRAIT(TRAIT_SLEEPIMMUNE), SIGNAL_REMOVETRAIT(TRAIT_SLEEPIMMUNE)))
if(!HAS_TRAIT(owner, TRAIT_SLEEPIMMUNE))
REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
tick_interval = initial(tick_interval)
return ..()
///If the mob is sleeping and gain the TRAIT_SLEEPIMMUNE we remove the TRAIT_KNOCKEDOUT and stop the tick() from happening
/datum/status_effect/incapacitating/sleeping/proc/on_owner_insomniac(mob/living/source)
SIGNAL_HANDLER
REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
tick_interval = -1
///If the mob has the TRAIT_SLEEPIMMUNE but somehow looses it we make him sleep and restart the tick()
/datum/status_effect/incapacitating/sleeping/proc/on_owner_sleepy(mob/living/source)
SIGNAL_HANDLER
ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
tick_interval = initial(tick_interval)
/datum/status_effect/incapacitating/sleeping/tick()
if(owner.maxHealth)
var/health_ratio = owner.health / owner.maxHealth
var/healing = -0.2
if((locate(/obj/structure/bed) in owner.loc))
healing -= 0.3
else if((locate(/obj/structure/table) in owner.loc))
healing -= 0.1
for(var/obj/item/bedsheet/bedsheet in range(owner.loc,0))
if(bedsheet.loc != owner.loc) //bedsheets in your backpack/neck don't give you comfort
continue
healing -= 0.1
break //Only count the first bedsheet
if(health_ratio > 0.8)
owner.adjustBruteLoss(healing)
owner.adjustFireLoss(healing)
owner.adjustToxLoss(healing * 0.5, TRUE, TRUE)
owner.adjustStaminaLoss(healing)
if(human_owner?.drunkenness)
human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds
if(carbon_owner)
carbon_owner.handle_dreams()
if(prob(2) && owner.health > owner.crit_threshold)
owner.emote("snore")
/atom/movable/screen/alert/status_effect/asleep
name = "Asleep"
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
icon_state = "asleep"
//STASIS
/datum/status_effect/grouped/stasis
id = "stasis"
duration = -1
tick_interval = 10
alert_type = /atom/movable/screen/alert/status_effect/stasis
var/last_dead_time
/datum/status_effect/grouped/stasis/proc/update_time_of_death()
if(last_dead_time)
var/delta = world.time - last_dead_time
var/new_timeofdeath = owner.timeofdeath + delta
owner.timeofdeath = new_timeofdeath
owner.tod = station_time_timestamp(wtime=new_timeofdeath)
last_dead_time = null
if(owner.stat == DEAD)
last_dead_time = world.time
/datum/status_effect/grouped/stasis/on_creation(mob/living/new_owner, set_duration)
. = ..()
if(.)
update_time_of_death()
owner.reagents?.end_metabolization(owner, FALSE)
/datum/status_effect/grouped/stasis/on_apply()
. = ..()
if(!.)
return
ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
ADD_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id))
owner.add_filter("stasis_status_ripple", 2, list("type" = "ripple", "flags" = WAVE_BOUNDED, "radius" = 0, "size" = 2))
var/filter = owner.get_filter("stasis_status_ripple")
animate(filter, radius = 32, time = 15, size = 0, loop = -1)
/datum/status_effect/grouped/stasis/tick()
update_time_of_death()
/datum/status_effect/grouped/stasis/on_remove()
REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
REMOVE_TRAIT(owner, TRAIT_HANDS_BLOCKED, TRAIT_STATUS_EFFECT(id))
owner.remove_filter("stasis_status_ripple")
update_time_of_death()
return ..()
/atom/movable/screen/alert/status_effect/stasis
name = "Stasis"
desc = "Your biological functions have halted. You could live forever this way, but it's pretty boring."
icon_state = "stasis"
//GOLEM GANG
//OTHER DEBUFFS
/datum/status_effect/strandling //get it, strand as in durathread strand + strangling = strandling hahahahahahahahahahhahahaha i want to die
id = "strandling"
examine_text = "SUBJECTPRONOUN seems to be being choked by some durathread strands. You may be able to <b>cut</b> them off."
status_type = STATUS_EFFECT_UNIQUE
alert_type = /atom/movable/screen/alert/status_effect/strandling
/datum/status_effect/strandling/on_apply()
ADD_TRAIT(owner, TRAIT_MAGIC_CHOKE, STATUS_EFFECT_TRAIT)
return ..()
/datum/status_effect/strandling/on_remove()
REMOVE_TRAIT(owner, TRAIT_MAGIC_CHOKE, STATUS_EFFECT_TRAIT)
return ..()
/atom/movable/screen/alert/status_effect/strandling
name = "Choking strand"
desc = "A magical strand of Durathread is wrapped around your neck, preventing you from breathing! Click this icon to remove the strand."
icon_state = "his_grace"
alerttooltipstyle = "hisgrace"
/atom/movable/screen/alert/status_effect/strandling/Click(location, control, params)
. = ..()
if(!.)
return
to_chat(owner, span_notice("You attempt to remove the durathread strand from around your neck."))
if(do_after(owner, 3.5 SECONDS, owner))
if(isliving(owner))
var/mob/living/living_owner = owner
to_chat(living_owner, span_notice("You succesfuly remove the durathread strand."))
living_owner.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND)
//OTHER DEBUFFS
/datum/status_effect/pacify
id = "pacify"
status_type = STATUS_EFFECT_REPLACE
tick_interval = 1
duration = 100
alert_type = null
/datum/status_effect/pacify/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
. = ..()
/datum/status_effect/pacify/on_apply()
ADD_TRAIT(owner, TRAIT_PACIFISM, STATUS_EFFECT_TRAIT)
return ..()
/datum/status_effect/pacify/on_remove()
REMOVE_TRAIT(owner, TRAIT_PACIFISM, STATUS_EFFECT_TRAIT)
/datum/status_effect/his_wrath //does minor damage over time unless holding His Grace
id = "his_wrath"
duration = -1
tick_interval = 4
alert_type = /atom/movable/screen/alert/status_effect/his_wrath
/atom/movable/screen/alert/status_effect/his_wrath
name = "His Wrath"
desc = "You fled from His Grace instead of feeding Him, and now you suffer."
icon_state = "his_grace"
alerttooltipstyle = "hisgrace"
/datum/status_effect/his_wrath/tick()
for(var/obj/item/his_grace/HG in owner.held_items)
qdel(src)
return
owner.adjustBruteLoss(0.1)
owner.adjustFireLoss(0.1)
owner.adjustToxLoss(0.2, TRUE, TRUE)
/datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
id = "cult_ghost"
duration = -1
alert_type = null
/datum/status_effect/cultghost/on_apply()
owner.see_invisible = SEE_INVISIBLE_OBSERVER
owner.see_in_dark = 2
/datum/status_effect/cultghost/tick()
if(owner.reagents)
owner.reagents.del_reagent(/datum/reagent/water/holywater) //can't be deconverted
/datum/status_effect/crusher_mark
id = "crusher_mark"
duration = 300 //if you leave for 30 seconds you lose the mark, deal with it
status_type = STATUS_EFFECT_REPLACE
alert_type = null
var/mutable_appearance/marked_underlay
var/obj/item/kinetic_crusher/hammer_synced
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/kinetic_crusher/new_hammer_synced)
. = ..()
if(.)
hammer_synced = new_hammer_synced
/datum/status_effect/crusher_mark/on_apply()
if(owner.mob_size >= MOB_SIZE_LARGE)
marked_underlay = mutable_appearance('icons/effects/effects.dmi', "shield2")
marked_underlay.pixel_x = -owner.pixel_x
marked_underlay.pixel_y = -owner.pixel_y
owner.underlays += marked_underlay
return TRUE
return FALSE
/datum/status_effect/crusher_mark/Destroy()
hammer_synced = null
if(owner)
owner.underlays -= marked_underlay
QDEL_NULL(marked_underlay)
return ..()
/datum/status_effect/crusher_mark/be_replaced()
owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point.
..()
/datum/status_effect/eldritch
duration = 15 SECONDS
status_type = STATUS_EFFECT_REPLACE
alert_type = null
on_remove_on_mob_delete = TRUE
///underlay used to indicate that someone is marked
var/mutable_appearance/marked_underlay
///path for the underlay
var/effect_sprite = ""
/datum/status_effect/eldritch/on_creation(mob/living/new_owner, ...)
marked_underlay = mutable_appearance('icons/effects/effects.dmi', effect_sprite,BELOW_MOB_LAYER)
return ..()
/datum/status_effect/eldritch/on_apply()
if(owner.mob_size >= MOB_SIZE_HUMAN)
RegisterSignal(owner,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/update_owner_underlay)
owner.update_appearance()
return TRUE
return FALSE
/datum/status_effect/eldritch/on_remove()
UnregisterSignal(owner,COMSIG_ATOM_UPDATE_OVERLAYS)
owner.update_appearance()
return ..()
/datum/status_effect/eldritch/proc/update_owner_underlay(atom/source, list/overlays)
SIGNAL_HANDLER
overlays += marked_underlay
/datum/status_effect/eldritch/Destroy()
QDEL_NULL(marked_underlay)
return ..()
/**
* What happens when this mark gets poppedd
*
* Adds actual functionality to each mark
*/
/datum/status_effect/eldritch/proc/on_effect()
playsound(owner, 'sound/magic/repulse.ogg', 75, TRUE)
qdel(src) //what happens when this is procced.
//Each mark has diffrent effects when it is destroyed that combine with the mansus grasp effect.
/datum/status_effect/eldritch/flesh
id = "flesh_mark"
effect_sprite = "emark1"
/datum/status_effect/eldritch/flesh/on_effect()
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
var/obj/item/bodypart/bodypart = pick(H.bodyparts)
var/datum/wound/slash/severe/crit_wound = new
crit_wound.apply_wound(bodypart)
return ..()
/datum/status_effect/eldritch/ash
id = "ash_mark"
effect_sprite = "emark2"
///Dictates how much damage and stamina loss this mark will cause.
var/repetitions = 1
/datum/status_effect/eldritch/ash/on_creation(mob/living/new_owner, _repetition = 5)
. = ..()
repetitions = min(1,_repetition)
/datum/status_effect/eldritch/ash/on_effect()
if(iscarbon(owner))
var/mob/living/carbon/carbon_owner = owner
carbon_owner.adjustStaminaLoss(10 * repetitions)
carbon_owner.adjustFireLoss(5 * repetitions)
for(var/mob/living/carbon/victim in range(1,carbon_owner))
if(IS_HERETIC(victim) || victim == carbon_owner)
continue
victim.apply_status_effect(type,repetitions-1)
break
return ..()
/datum/status_effect/eldritch/rust
id = "rust_mark"
effect_sprite = "emark3"
/datum/status_effect/eldritch/rust/on_effect()
if(!iscarbon(owner))
return
var/mob/living/carbon/carbon_owner = owner
for(var/obj/item/I in carbon_owner.get_all_gear())
//Affects roughly 75% of items
if(!QDELETED(I) && prob(75)) //Just in case
I.take_damage(100)
return ..()
/datum/status_effect/eldritch/void
id = "void_mark"
effect_sprite = "emark4"
/datum/status_effect/eldritch/void/on_effect()
var/turf/open/turfie = get_turf(owner)
turfie.TakeTemperature(-40)
owner.adjust_bodytemperature(-20)
return ..()
/// A status effect used for specifying confusion on a living mob.
/// Created automatically with /mob/living/set_confusion.
/datum/status_effect/confusion
id = "confusion"
alert_type = null
var/strength
/datum/status_effect/confusion/tick()
strength -= 1
if (strength <= 0)
owner.remove_status_effect(STATUS_EFFECT_CONFUSION)
return
/datum/status_effect/confusion/proc/set_strength(new_strength)
strength = new_strength
/datum/status_effect/stacking/saw_bleed
id = "saw_bleed"
tick_interval = 6
delay_before_decay = 5
stack_threshold = 10
max_stacks = 10
overlay_file = 'icons/effects/bleed.dmi'
underlay_file = 'icons/effects/bleed.dmi'
overlay_state = "bleed"
underlay_state = "bleed"
var/bleed_damage = 200
/datum/status_effect/stacking/saw_bleed/fadeout_effect()
new /obj/effect/temp_visual/bleed(get_turf(owner))
/datum/status_effect/stacking/saw_bleed/threshold_cross_effect()
owner.adjustBruteLoss(bleed_damage)
var/turf/T = get_turf(owner)
new /obj/effect/temp_visual/bleed/explode(T)
for(var/d in GLOB.alldirs)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
playsound(T, "desecration", 100, TRUE, -1)
/datum/status_effect/stacking/saw_bleed/bloodletting
id = "bloodletting"
stack_threshold = 7
max_stacks = 7
bleed_damage = 20
/datum/status_effect/neck_slice
id = "neck_slice"
status_type = STATUS_EFFECT_UNIQUE
alert_type = null
duration = -1
/datum/status_effect/neck_slice/tick()
var/mob/living/carbon/human/H = owner
var/obj/item/bodypart/throat = H.get_bodypart(BODY_ZONE_HEAD)
if(H.stat == DEAD || !throat)
H.remove_status_effect(/datum/status_effect/neck_slice)
var/still_bleeding = FALSE
for(var/thing in throat.wounds)
var/datum/wound/W = thing
if(W.wound_type == WOUND_SLASH && W.severity > WOUND_SEVERITY_MODERATE)
still_bleeding = TRUE
break
if(!still_bleeding)
H.remove_status_effect(/datum/status_effect/neck_slice)
if(prob(10))
H.emote(pick("gasp", "gag", "choke"))
/mob/living/proc/apply_necropolis_curse(set_curse)
var/datum/status_effect/necropolis_curse/C = has_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE)
if(!set_curse)
set_curse = pick(CURSE_BLINDING, CURSE_SPAWNING, CURSE_WASTING, CURSE_GRASPING)
if(QDELETED(C))
apply_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE, set_curse)
else
C.apply_curse(set_curse)
C.duration += 3000 //time added by additional curses
return C
/datum/status_effect/necropolis_curse
id = "necrocurse"
duration = 6000 //you're cursed for 10 minutes have fun
tick_interval = 50
alert_type = null
var/curse_flags = NONE
var/effect_last_activation = 0
var/effect_cooldown = 100
var/obj/effect/temp_visual/curse/wasting_effect = new
/datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse)
. = ..()
if(.)
apply_curse(set_curse)
/datum/status_effect/necropolis_curse/Destroy()
if(!QDELETED(wasting_effect))
qdel(wasting_effect)
wasting_effect = null
return ..()
/datum/status_effect/necropolis_curse/on_remove()
remove_curse(curse_flags)
/datum/status_effect/necropolis_curse/proc/apply_curse(set_curse)
curse_flags |= set_curse
if(curse_flags & CURSE_BLINDING)
owner.overlay_fullscreen("curse", /atom/movable/screen/fullscreen/curse, 1)
/datum/status_effect/necropolis_curse/proc/remove_curse(remove_curse)
if(remove_curse & CURSE_BLINDING)
owner.clear_fullscreen("curse", 50)
curse_flags &= ~remove_curse
/datum/status_effect/necropolis_curse/tick()
if(owner.stat == DEAD)
return
if(curse_flags & CURSE_WASTING)
wasting_effect.forceMove(owner.loc)
wasting_effect.setDir(owner.dir)
wasting_effect.transform = owner.transform //if the owner has been stunned the overlay should inherit that position
wasting_effect.alpha = 255
animate(wasting_effect, alpha = 0, time = 32)
playsound(owner, 'sound/effects/curse5.ogg', 20, TRUE, -1)
owner.adjustFireLoss(0.75)
if(effect_last_activation <= world.time)
effect_last_activation = world.time + effect_cooldown
if(curse_flags & CURSE_SPAWNING)
var/turf/spawn_turf
var/sanity = 10
while(!spawn_turf && sanity)
spawn_turf = locate(owner.x + pick(rand(10, 15), rand(-10, -15)), owner.y + pick(rand(10, 15), rand(-10, -15)), owner.z)
sanity--
if(spawn_turf)
var/mob/living/simple_animal/hostile/asteroid/curseblob/C = new (spawn_turf)
C.set_target = owner
C.GiveTarget()
if(curse_flags & CURSE_GRASPING)
var/grab_dir = turn(owner.dir, pick(-90, 90, 180, 180)) //grab them from a random direction other than the one faced, favoring grabbing from behind
var/turf/spawn_turf = get_ranged_target_turf(owner, grab_dir, 5)
if(spawn_turf)
grasp(spawn_turf)
/datum/status_effect/necropolis_curse/proc/grasp(turf/spawn_turf)
set waitfor = FALSE
new/obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, owner.dir)
playsound(spawn_turf, 'sound/effects/curse2.ogg', 80, TRUE, -1)
var/obj/projectile/curse_hand/C = new (spawn_turf)
C.preparePixelProjectile(owner, spawn_turf)
C.fire()
/obj/effect/temp_visual/curse
icon_state = "curse"
/obj/effect/temp_visual/curse/Initialize(mapload)
. = ..()
deltimer(timerid)
/datum/status_effect/gonbola_pacify
id = "gonbolaPacify"
status_type = STATUS_EFFECT_MULTIPLE
tick_interval = -1
alert_type = null
/datum/status_effect/gonbola_pacify/on_apply()
. = ..()
ADD_TRAIT(owner, TRAIT_PACIFISM, CLOTHING_TRAIT)
ADD_TRAIT(owner, TRAIT_MUTE, CLOTHING_TRAIT)
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, type, /datum/mood_event/gondola)
to_chat(owner, span_notice("You suddenly feel at peace and feel no need to make any sudden or rash actions..."))
/datum/status_effect/gonbola_pacify/on_remove()
REMOVE_TRAIT(owner, TRAIT_PACIFISM, CLOTHING_TRAIT)
REMOVE_TRAIT(owner, TRAIT_MUTE, CLOTHING_TRAIT)
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, type)
return ..()
/datum/status_effect/trance
id = "trance"
status_type = STATUS_EFFECT_UNIQUE
duration = 300
tick_interval = 10
examine_text = "<span class='warning'>SUBJECTPRONOUN seems slow and unfocused.</span>"
var/stun = TRUE
alert_type = /atom/movable/screen/alert/status_effect/trance
/atom/movable/screen/alert/status_effect/trance
name = "Trance"
desc = "Everything feels so distant, and you can feel your thoughts forming loops inside your head..."
icon_state = "high"
/datum/status_effect/trance/tick()
if(stun)
owner.Stun(60, TRUE)
owner.dizziness = 20
/datum/status_effect/trance/on_apply()
if(!iscarbon(owner))
return FALSE
RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/hypnotize)
ADD_TRAIT(owner, TRAIT_MUTE, STATUS_EFFECT_TRAIT)
owner.add_client_colour(/datum/client_colour/monochrome/trance)
owner.visible_message("[stun ? span_warning("[owner] stands still as [owner.p_their()] eyes seem to focus on a distant point.") : ""]", \
span_warning("[pick("You feel your thoughts slow down...", "You suddenly feel extremely dizzy...", "You feel like you're in the middle of a dream...","You feel incredibly relaxed...")]"))
return TRUE
/datum/status_effect/trance/on_creation(mob/living/new_owner, _duration, _stun = TRUE)
duration = _duration
stun = _stun
return ..()
/datum/status_effect/trance/on_remove()
UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
REMOVE_TRAIT(owner, TRAIT_MUTE, STATUS_EFFECT_TRAIT)
owner.dizziness = 0
owner.remove_client_colour(/datum/client_colour/monochrome/trance)
to_chat(owner, span_warning("You snap out of your trance!"))
/datum/status_effect/trance/proc/hypnotize(datum/source, list/hearing_args)
SIGNAL_HANDLER
if(!owner.can_hear())
return
var/mob/hearing_speaker = hearing_args[HEARING_SPEAKER]
if(hearing_speaker == owner)
return
var/mob/living/carbon/C = owner
C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis
// The brain trauma itself does its own set of logging, but this is the only place the source of the hypnosis phrase can be found.
hearing_speaker.log_message("has hypnotised [key_name(C)] with the phrase '[hearing_args[HEARING_RAW_MESSAGE]]'", LOG_ATTACK)
C.log_message("has been hypnotised by the phrase '[hearing_args[HEARING_RAW_MESSAGE]]' spoken by [key_name(hearing_speaker)]", LOG_VICTIM, log_globally = FALSE)
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10)
addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it
qdel(src)
/datum/status_effect/spasms
id = "spasms"
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
/datum/status_effect/spasms/tick()
if(prob(15))
switch(rand(1,5))
if(1)
if((owner.mobility_flags & MOBILITY_MOVE) && isturf(owner.loc))
to_chat(owner, span_warning("Your leg spasms!"))
step(owner, pick(GLOB.cardinals))
if(2)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
if(I)
to_chat(owner, span_warning("Your fingers spasm!"))
owner.log_message("used [I] due to a Muscle Spasm", LOG_ATTACK)
I.attack_self(owner)
if(3)
owner.set_combat_mode(TRUE)
var/range = 1
if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
range = 7
var/list/mob/living/targets = list()
for(var/mob/M in oview(owner, range))
if(isliving(M))
targets += M
if(LAZYLEN(targets))
to_chat(owner, span_warning("Your arm spasms!"))
owner.log_message(" attacked someone due to a Muscle Spasm", LOG_ATTACK) //the following attack will log itself
owner.ClickOn(pick(targets))
owner.set_combat_mode(FALSE)
if(4)
owner.set_combat_mode(TRUE)
to_chat(owner, span_warning("Your arm spasms!"))
owner.log_message("attacked [owner.p_them()]self to a Muscle Spasm", LOG_ATTACK)
owner.ClickOn(owner)
owner.set_combat_mode(FALSE)
if(5)
if(owner.incapacitated())
return
var/obj/item/I = owner.get_active_held_item()
var/list/turf/targets = list()
for(var/turf/T in oview(owner, 3))
targets += T
if(LAZYLEN(targets) && I)
to_chat(owner, span_warning("Your arm spasms!"))
owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK)
owner.throw_item(pick(targets))
/datum/status_effect/convulsing
id = "convulsing"
duration = 150
status_type = STATUS_EFFECT_REFRESH
alert_type = /atom/movable/screen/alert/status_effect/convulsing
/datum/status_effect/convulsing/on_creation(mob/living/zappy_boy)
. = ..()
to_chat(zappy_boy, span_boldwarning("You feel a shock moving through your body! Your hands start shaking!"))
/datum/status_effect/convulsing/tick()
var/mob/living/carbon/H = owner
if(prob(40))
var/obj/item/I = H.get_active_held_item()
if(I && H.dropItemToGround(I))
H.visible_message(span_notice("[H]'s hand convulses, and they drop their [I.name]!"),span_userdanger("Your hand convulses violently, and you drop what you were holding!"))
H.jitteriness += 5
/atom/movable/screen/alert/status_effect/convulsing
name = "Shaky Hands"
desc = "You've been zapped with something and your hands can't stop shaking! You can't seem to hold on to anything."
icon_state = "convulsing"
/datum/status_effect/dna_melt
id = "dna_melt"
duration = 600
status_type = STATUS_EFFECT_REPLACE
alert_type = /atom/movable/screen/alert/status_effect/dna_melt
var/kill_either_way = FALSE //no amount of removing mutations is gonna save you now
/datum/status_effect/dna_melt/on_creation(mob/living/new_owner, set_duration)
. = ..()
to_chat(new_owner, span_boldwarning("My body can't handle the mutations! I need to get my mutations removed fast!"))
/datum/status_effect/dna_melt/on_remove()
if(!ishuman(owner))
owner.gib() //fuck you in particular
return
var/mob/living/carbon/human/H = owner
H.something_horrible(kill_either_way)
/atom/movable/screen/alert/status_effect/dna_melt
name = "Genetic Breakdown"
desc = "I don't feel so good. Your body can't handle the mutations! You have one minute to remove your mutations, or you will be met with a horrible fate."
icon_state = "dna_melt"
/datum/status_effect/go_away
id = "go_away"
duration = 100
status_type = STATUS_EFFECT_REPLACE
tick_interval = 1
alert_type = /atom/movable/screen/alert/status_effect/go_away
var/direction
/datum/status_effect/go_away/on_creation(mob/living/new_owner, set_duration)
. = ..()
direction = pick(NORTH, SOUTH, EAST, WEST)
new_owner.setDir(direction)
/datum/status_effect/go_away/tick()
owner.AdjustStun(1, ignore_canstun = TRUE)
var/turf/T = get_step(owner, direction)
owner.forceMove(T)
/atom/movable/screen/alert/status_effect/go_away
name = "TO THE STARS AND BEYOND!"
desc = "I must go, my people need me!"
icon_state = "high"
/datum/status_effect/fake_virus
id = "fake_virus"
duration = 1800//3 minutes
status_type = STATUS_EFFECT_REPLACE
tick_interval = 1
alert_type = null
var/msg_stage = 0//so you dont get the most intense messages immediately
/datum/status_effect/fake_virus/tick()
var/fake_msg = ""
var/fake_emote = ""
switch(msg_stage)
if(0 to 300)
if(prob(1))
fake_msg = pick(span_warning("[pick("Your head hurts.", "Your head pounds.")]"),
span_warning("[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]"),
span_warning("[pick("You feel dizzy.", "Your head spins.")]"),
"<span notice='warning'>[pick("You swallow excess mucus.", "You lightly cough.")]</span>",
span_warning("[pick("Your head hurts.", "Your mind blanks for a moment.")]"),
span_warning("[pick("Your throat hurts.", "You clear your throat.")]"))
if(301 to 600)
if(prob(2))
fake_msg = pick(span_warning("[pick("Your head hurts a lot.", "Your head pounds incessantly.")]"),
span_warning("[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]"),
span_warning("You feel very [pick("dizzy","woozy","faint")]."),
span_warning("[pick("You hear a ringing in your ear.", "Your ears pop.")]"),
span_warning("You nod off for a moment."))
else
if(prob(3))
if(prob(50))// coin flip to throw a message or an emote
fake_msg = pick(span_userdanger("[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]"),
span_userdanger("[pick("Your lungs hurt!", "It hurts to breathe!")]"),
span_warning("[pick("You feel nauseated.", "You feel like you're going to throw up!")]"))
else
fake_emote = pick("cough", "sniff", "sneeze")
if(fake_emote)
owner.emote(fake_emote)
else if(fake_msg)
to_chat(owner, fake_msg)
msg_stage++
/datum/status_effect/corrosion_curse
id = "corrosion_curse"
status_type = STATUS_EFFECT_REPLACE
alert_type = null
tick_interval = 1 SECONDS
/datum/status_effect/corrosion_curse/on_creation(mob/living/new_owner, ...)
. = ..()
to_chat(owner, span_danger("Your feel your body starting to break apart..."))
/datum/status_effect/corrosion_curse/tick()
. = ..()
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
var/chance = rand(0,100)
switch(chance)
if(0 to 19)
H.vomit()
if(20 to 29)
H.Dizzy(10)
if(30 to 39)
H.adjustOrganLoss(ORGAN_SLOT_LIVER,5)
if(40 to 49)
H.adjustOrganLoss(ORGAN_SLOT_HEART,5)
if(50 to 59)
H.adjustOrganLoss(ORGAN_SLOT_STOMACH,5)
if(60 to 69)
H.adjustOrganLoss(ORGAN_SLOT_EYES,10)
if(70 to 79)
H.adjustOrganLoss(ORGAN_SLOT_EARS,10)
if(80 to 89)
H.adjustOrganLoss(ORGAN_SLOT_LUNGS,10)
if(90 to 99)
H.adjustOrganLoss(ORGAN_SLOT_TONGUE,10)
if(100)
H.adjustOrganLoss(ORGAN_SLOT_BRAIN,20)
/datum/status_effect/amok
id = "amok"
status_type = STATUS_EFFECT_REPLACE
alert_type = null
duration = 10 SECONDS
tick_interval = 1 SECONDS
/datum/status_effect/amok/on_apply(mob/living/afflicted)
. = ..()
to_chat(owner, span_boldwarning("You feel filled with a rage that is not your own!"))
/datum/status_effect/amok/tick()
. = ..()
var/prev_combat_mode = owner.combat_mode
owner.set_combat_mode(TRUE)
var/list/mob/living/targets = list()
for(var/mob/living/potential_target in oview(owner, 1))
if(IS_HERETIC(potential_target) || IS_HERETIC_MONSTER(potential_target))
continue
targets += potential_target
if(LAZYLEN(targets))
owner.log_message(" attacked someone due to the amok debuff.", LOG_ATTACK) //the following attack will log itself
owner.ClickOn(pick(targets))
owner.set_combat_mode(prev_combat_mode)
/datum/status_effect/cloudstruck
id = "cloudstruck"
status_type = STATUS_EFFECT_REPLACE
duration = 3 SECONDS
on_remove_on_mob_delete = TRUE
///This overlay is applied to the owner for the duration of the effect.
var/mutable_appearance/mob_overlay
/datum/status_effect/cloudstruck/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
. = ..()
/datum/status_effect/cloudstruck/on_apply()
mob_overlay = mutable_appearance('icons/effects/eldritch.dmi', "cloud_swirl", ABOVE_MOB_LAYER)
owner.overlays += mob_overlay
owner.update_appearance()
ADD_TRAIT(owner, TRAIT_BLIND, STATUS_EFFECT_TRAIT)
return TRUE
/datum/status_effect/cloudstruck/on_remove()
. = ..()
if(QDELETED(owner))
return
REMOVE_TRAIT(owner, TRAIT_BLIND, STATUS_EFFECT_TRAIT)
if(owner)
owner.overlays -= mob_overlay
owner.update_appearance()
/datum/status_effect/cloudstruck/Destroy()
. = ..()
QDEL_NULL(mob_overlay)
//Deals with ants covering someone.
/datum/status_effect/ants
id = "ants"
status_type = STATUS_EFFECT_REFRESH
alert_type = /atom/movable/screen/alert/status_effect/ants
duration = 2 MINUTES //Keeping the normal timer makes sure people can't somehow dump 300+ ants on someone at once so they stay there for like 30 minutes. Max w/ 1 dump is 57.6 brute.
examine_text = "<span class='warning'>SUBJECTPRONOUN is covered in ants!</span>"
processing_speed = STATUS_EFFECT_NORMAL_PROCESS
/// Will act as the main timer as well as changing how much damage the ants do.
var/ants_remaining = 0
/datum/status_effect/ants/on_creation(mob/living/new_owner, amount_left)
if(isnum(amount_left) && new_owner.stat < HARD_CRIT)
if(new_owner.stat < UNCONSCIOUS) // Unconcious people won't get messages
to_chat(new_owner, "<span class='userdanger'>You're covered in ants!</span>")
ants_remaining += amount_left
RegisterSignal(new_owner, COMSIG_COMPONENT_CLEAN_ACT, .proc/ants_washed)
. = ..()
/datum/status_effect/ants/refresh(effect, amount_left)
var/mob/living/carbon/human/victim = owner
if(isnum(amount_left) && ants_remaining >= 1 && victim.stat < HARD_CRIT)
if(victim.stat < UNCONSCIOUS) // Unconcious people won't get messages
if(!prob(1)) // 99%
to_chat(victim, "<span class='userdanger'>You're covered in MORE ants!</span>")
else // 1%
victim.say("AAHH! THIS SITUATION HAS ONLY BEEN MADE WORSE WITH THE ADDITION OF YET MORE ANTS!!", forced = /datum/status_effect/ants)
ants_remaining += amount_left
. = ..()
/datum/status_effect/ants/on_remove()
ants_remaining = 0
to_chat(owner, "<span class='notice'>All of the ants are off of your body!</span>")
UnregisterSignal(owner, COMSIG_COMPONENT_CLEAN_ACT, .proc/ants_washed)
. = ..()
/datum/status_effect/ants/proc/ants_washed()
SIGNAL_HANDLER
owner.remove_status_effect(STATUS_EFFECT_ANTS)
return COMPONENT_CLEANED
/datum/status_effect/ants/tick()
var/mob/living/carbon/human/victim = owner
victim.adjustBruteLoss(max(0.1, round((ants_remaining * 0.004),0.1))) //Scales with # of ants (lowers with time). Roughly 10 brute over 50 seconds.
if(victim.stat <= SOFT_CRIT) //Makes sure people don't scratch at themselves while they're in a critical condition
if(prob(15))
switch(rand(1,2))
if(1)
victim.say(pick("GET THEM OFF ME!!", "OH GOD THE ANTS!!", "MAKE IT END!!", "THEY'RE EVERYWHERE!!", "GET THEM OFF!!", "SOMEBODY HELP ME!!"), forced = /datum/status_effect/ants)
if(2)
victim.emote("scream")
if(prob(50)) // Most of the damage is done through random chance. When tested yielded an average 100 brute with 200u ants.
switch(rand(1,50))
if (1 to 8) //16% Chance
var/obj/item/bodypart/head/hed = victim.get_bodypart(BODY_ZONE_HEAD)
to_chat(victim, "<span class='danger'>You scratch at the ants on your scalp!.</span>")
hed.receive_damage(1,0)
if (9 to 29) //40% chance
var/obj/item/bodypart/arm = victim.get_bodypart(pick(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM))
to_chat(victim, "<span class='danger'>You scratch at the ants on your arms!</span>")
arm.receive_damage(3,0)
if (30 to 49) //38% chance
var/obj/item/bodypart/leg = victim.get_bodypart(pick(BODY_ZONE_L_LEG,BODY_ZONE_R_LEG))
to_chat(victim, "<span class='danger'>You scratch at the ants on your leg!</span>")
leg.receive_damage(3,0)
if(50) // 2% chance
to_chat(victim, "<span class='danger'>You rub some ants away from your eyes!</span>")
victim.blur_eyes(3)
ants_remaining -= 5 // To balance out the blindness, it'll be a little shorter.
ants_remaining--
if(ants_remaining <= 0 || victim.stat >= HARD_CRIT)
victim.remove_status_effect(STATUS_EFFECT_ANTS) //If this person has no more ants on them or are dead, they are no longer affected.
/atom/movable/screen/alert/status_effect/ants
name = "Ants!"
desc = "<span class='warning'>JESUS FUCKING CHRIST! CLICK TO GET THOSE THINGS OFF!</span>"
icon_state = "antalert"
/atom/movable/screen/alert/status_effect/ants/Click()
var/mob/living/living = owner
if(!istype(living) || !living.can_resist() || living != owner)
return
to_chat(living, "<span class='notice'>You start to shake the ants off!</span>")
if(!do_after(living, 2 SECONDS, target = living))
return
for (var/datum/status_effect/ants/ant_covered in living.status_effects)
to_chat(living, "<span class='notice'>You manage to get some of the ants off!</span>")
ant_covered.ants_remaining -= 10 // 5 Times more ants removed per second than just waiting in place
/datum/status_effect/ghoul
id = "ghoul"
status_type = STATUS_EFFECT_UNIQUE
duration = -1
alert_type = /atom/movable/screen/alert/status_effect/ghoul
/atom/movable/screen/alert/status_effect/ghoul
name = "Flesh Servant"
desc = "You are a Ghoul! A eldritch monster reanimated to serve its master."
icon_state = "mind_control"
/datum/status_effect/stagger
id = "stagger"
status_type = STATUS_EFFECT_REFRESH
duration = 30 SECONDS
tick_interval = 1 SECONDS
alert_type = null
/datum/status_effect/stagger/on_apply()
owner.next_move_modifier *= 1.5
if(ishostile(owner))
var/mob/living/simple_animal/hostile/simple_owner = owner
simple_owner.ranged_cooldown_time *= 2.5
return TRUE
/datum/status_effect/stagger/on_remove()
. = ..()
if(QDELETED(owner))
return
owner.next_move_modifier /= 1.5
if(ishostile(owner))
var/mob/living/simple_animal/hostile/simple_owner = owner
simple_owner.ranged_cooldown_time /= 2.5
/datum/status_effect/freezing_blast
id = "freezing_blast"
alert_type = /atom/movable/screen/alert/status_effect/freezing_blast
duration = 5 SECONDS
status_type = STATUS_EFFECT_REPLACE
/atom/movable/screen/alert/status_effect/freezing_blast
name = "Freezing Blast"
desc = "You've been struck by a freezing blast! Your body moves more slowly!"
icon_state = "frozen"
/datum/status_effect/freezing_blast/on_apply()
owner.add_movespeed_modifier(/datum/movespeed_modifier/freezing_blast, update = TRUE)
return ..()
/datum/status_effect/freezing_blast/on_remove()
owner.remove_movespeed_modifier(/datum/movespeed_modifier/freezing_blast, update = TRUE)
/datum/movespeed_modifier/freezing_blast
multiplicative_slowdown = 1