Files
Bubberstation/code/datums/components/omen.dm
SkyratBot 0391d4b7b2 [MIRROR] Cursed quirk doesn't go away after triggering a single time [MDB IGNORE] (#21271)
* Cursed quirk doesn't go away after triggering a single time (#75477)

## About The Pull Request

Fixes #75471
Someone added some optional initialise arguments and forgot to make an
important one optional, leading to it always setting the "permanent"
value to "null", which of course evaluates falsily to FALSE.

## Why It's Good For The Game

If you take this quirk you _want_ to be repeatedly pulverised by vending
machines until your skull pops. We shouldn't deny people their agency.

## Changelog

🆑
fix: The Cursed quirk will once more plague you with bad luck for your
entire shift rather than just once.
/🆑

* Cursed quirk doesn't go away after triggering a single time

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>
Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com>
2023-05-20 22:22:58 +01:00

233 lines
8.0 KiB
Plaintext

/**
* omen.dm: For when you want someone to have a really bad day
*
* When you attach an omen component to someone, they start running the risk of all sorts of bad environmental injuries, like nearby vending machines randomly falling on you,
* or hitting your head really hard when you slip and fall, or you get shocked by the tram rails at an unfortunate moment.
*
* Omens are removed once the victim is either maimed by one of the possible injuries, or if they receive a blessing (read: bashing with a bible) from the chaplain.
*/
/datum/component/omen
dupe_mode = COMPONENT_DUPE_UNIQUE
/// Whatever's causing the omen, if there is one. Destroying the vessel won't stop the omen, but we destroy the vessel (if one exists) upon the omen ending
var/obj/vessel
/// If the omen is permanent, it will never go away
var/permanent = FALSE
/// Base probability of negative events. Cursed are half as unlucky.
var/luck_mod = 1
/// Base damage from negative events. Cursed take 25% less damage.
var/damage_mod = 1
/datum/component/omen/Initialize(obj/vessel, permanent, luck_mod, damage_mod)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
if(istype(vessel))
src.vessel = vessel
RegisterSignal(vessel, COMSIG_PARENT_QDELETING, PROC_REF(vessel_qdeleting))
if(!isnull(permanent))
src.permanent = permanent
if(!isnull(luck_mod))
src.luck_mod = luck_mod
if(!isnull(damage_mod))
src.damage_mod = damage_mod
/datum/component/omen/Destroy(force)
var/mob/living/person = parent
to_chat(person, span_nicegreen("You feel a horrible omen lifted off your shoulders!"))
if(vessel)
vessel.visible_message(span_warning("[vessel] burns up in a sinister flash, taking an evil energy with it..."))
UnregisterSignal(vessel, COMSIG_PARENT_QDELETING)
vessel.burn()
vessel = null
return ..()
/datum/component/omen/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(check_accident))
RegisterSignal(parent, COMSIG_ON_CARBON_SLIP, PROC_REF(check_slip))
RegisterSignal(parent, COMSIG_CARBON_MOOD_UPDATE, PROC_REF(check_bless))
RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(check_death))
/datum/component/omen/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ON_CARBON_SLIP, COMSIG_MOVABLE_MOVED, COMSIG_CARBON_MOOD_UPDATE, COMSIG_LIVING_DEATH))
/**
* check_accident() is called each step we take
*
* While we're walking around, roll to see if there's any environmental hazards on one of the adjacent tiles we can trigger.
* We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time
*/
/datum/component/omen/proc/check_accident(atom/movable/our_guy)
SIGNAL_HANDLER
if(!isliving(our_guy))
return
var/mob/living/living_guy = our_guy
if(!prob(15 * luck_mod))
return
var/our_guy_pos = get_turf(living_guy)
for(var/obj/machinery/door/airlock/darth_airlock in our_guy_pos)
if(darth_airlock.locked || !darth_airlock.hasPower())
continue
to_chat(living_guy, span_warning("A malevolent force launches your body to the floor..."))
living_guy.Paralyze(1 SECONDS, ignore_canstun = TRUE)
INVOKE_ASYNC(src, PROC_REF(slam_airlock), darth_airlock)
return
if(istype(our_guy_pos, /turf/open/floor/noslip/tram_plate/energized))
var/turf/open/floor/noslip/tram_plate/energized/future_tram_victim = our_guy_pos
if(future_tram_victim.toast(living_guy))
if(!permanent)
qdel(src)
return
for(var/turf/the_turf as anything in get_adjacent_open_turfs(living_guy))
if(istype(the_turf, /turf/open/floor/glass/reinforced/tram)) // don't fall off the tram bridge, we want to hit you instead
return
if(the_turf.zPassOut(living_guy, DOWN) && living_guy.can_z_move(DOWN, the_turf, z_move_flags = ZMOVE_FALL_FLAGS))
to_chat(living_guy, span_warning("A malevolent force guides you towards the edge..."))
living_guy.throw_at(the_turf, 1, 10, force = MOVE_FORCE_EXTREMELY_STRONG)
if(!permanent)
qdel(src)
return
for(var/obj/machinery/vending/darth_vendor in the_turf)
if(!darth_vendor.tiltable || darth_vendor.tilted)
continue
to_chat(living_guy, span_warning("A malevolent force tugs at the [darth_vendor]..."))
INVOKE_ASYNC(darth_vendor, TYPE_PROC_REF(/obj/machinery/vending, tilt), living_guy)
if(!permanent)
qdel(src)
return
/datum/component/omen/proc/slam_airlock(obj/machinery/door/airlock/darth_airlock)
. = darth_airlock.close(force_crush = TRUE)
if(. && !permanent && !prob(66.6))
qdel(src)
/// If we get knocked down, see if we have a really bad slip and bash our head hard
/datum/component/omen/proc/check_slip(mob/living/our_guy, amount)
SIGNAL_HANDLER
if(prob(30)) // AAAA
INVOKE_ASYNC(our_guy, TYPE_PROC_REF(/mob, emote), "scream")
to_chat(our_guy, span_warning("What a horrible night... To have a curse!"))
if(prob(30 * luck_mod)) /// Bonk!
var/obj/item/bodypart/the_head = our_guy.get_bodypart(BODY_ZONE_HEAD)
if(!the_head)
return
playsound(get_turf(our_guy), 'sound/effects/tableheadsmash.ogg', 90, TRUE)
our_guy.visible_message(span_danger("[our_guy] hits [our_guy.p_their()] head really badly falling down!"), span_userdanger("You hit your head really badly falling down!"))
the_head.receive_damage(75 * damage_mod, damage_source = "slipping")
our_guy.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100 * damage_mod)
if(!permanent)
qdel(src)
return
/// Hijack the mood system to see if we get the blessing mood event to cancel the omen
/datum/component/omen/proc/check_bless(mob/living/our_guy, category)
SIGNAL_HANDLER
if(permanent)
return
if(!("blessing" in our_guy.mob_mood.mood_events))
return
qdel(src)
/// Severe deaths. Normally lifts the curse.
/datum/component/omen/proc/check_death(mob/living/our_guy)
SIGNAL_HANDLER
if(permanent)
return
qdel(src)
/// Creates a localized explosion that shakes the camera
/datum/component/omen/proc/death_explode(mob/living/our_guy)
explosion(our_guy, explosion_cause = src)
for(var/mob/witness in view(2, our_guy))
shake_camera(witness, 1 SECONDS, 2)
/// Vessel got deleted, set it to null
/datum/component/omen/proc/vessel_qdeleting(atom/source)
SIGNAL_HANDLER
UnregisterSignal(vessel, COMSIG_PARENT_QDELETING)
vessel = null
/**
* The smite omen. Permanent.
*/
/datum/component/omen/smite
/datum/component/omen/smite/check_death(mob/living/our_guy)
if(!permanent)
return ..()
death_explode(our_guy)
our_guy.gib()
/**
* The quirk omen. Permanent.
* Has only a 50% chance of bad things happening, and takes only 25% of normal damage.
*/
/datum/component/omen/quirk
permanent = TRUE
luck_mod = 0.5 // 50% chance of bad things happening
damage_mod = 0.25 // 25% of normal damage
/datum/component/omen/quirk/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(check_accident))
RegisterSignal(parent, COMSIG_ON_CARBON_SLIP, PROC_REF(check_slip))
RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(check_death))
/datum/component/omen/quirk/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ON_CARBON_SLIP, COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH))
/datum/component/omen/quirk/check_death(mob/living/our_guy)
if(!iscarbon(our_guy))
our_guy.gib()
return
// Don't explode if buckled to a stasis bed
if(our_guy.buckled)
var/obj/machinery/stasis/stasis_bed = our_guy.buckled
if(istype(stasis_bed))
return
death_explode(our_guy)
var/mob/living/carbon/player = our_guy
player.spread_bodyparts(skip_head = TRUE)
player.spawn_gibs()
return
/**
* The bible omen.
* While it lasts, parent gets a cursed aura filter.
*/
/datum/component/omen/bible
/datum/component/omen/bible/RegisterWithParent()
. = ..()
var/mob/living/living_parent = parent
living_parent.add_filter("omen", 2, list("type" = "drop_shadow", "color" = COLOR_DARK_RED, "alpha" = 0, "size" = 2))
var/filter = living_parent.get_filter("omen")
animate(filter, alpha = 255, time = 2 SECONDS, loop = -1)
animate(alpha = 0, time = 2 SECONDS)
/datum/component/omen/bible/UnregisterFromParent()
. = ..()
var/mob/living/living_parent = parent
living_parent.remove_filter("omen")