Buffs Heretic Curses, Living Heart, Leeching Walk, and technically Entropic Plume by fixing some bugs (#69181)

About The Pull Request

    Heretic curses have been buffed / reworked.
        Curses can be cast on any crewmember, not just those who you have fingerprints to.
        Having an item present in the ritual that contains fingerprints OR blood dna of a crewmember who you are cursing will boost the curse, causing it to last longer (and be stronger? Still undecided, but there's support for it)
        Curses have a max range (64 by default) and don't work on people on a different z-level (Do not BTFO miners so easily)
        Corrosion curse's numbers have been tweaked due to this, and it can no longer cause vital organ failure

    Living Heart has been buffed
        Cooldown cut in half, and it provides a bit more thorough instructions
        Closes 

    Living heart targets who are located in non-turf locs and are off z-level will show as on the same z #67256

Leeching Walk has been buffed

    Rust will also restore lost blood.

Technically buffs Entropic Plume by fixing some bugs

    "Cloudstruck" has always meant to blind, but they used the wrong method, so I fixed that.
    Also it was meant to inject multiple units of poison, but used "min" instead of "max" so it always did the lowest.
    I also fixed the stink cloud lasting forever on people.
    Amok also makes people holding guns to shoot people further away.

Closes

    Admin healing removes heretic living heart #69167 while I'm here

Why It's Good For The Game

    Heretic curses have pretty much always been bad, getting fingerprints is damn near impossible considering everyone uses gloves. Not only that but their requirements were very high. This should hopefully bring curses to the limelight, as they can be applied to any potential targets. It also rewards heretics who go out of their way to collect fingerprints and blood samples with even stronger curses.

    The Living Heart was often hard to pinpoint people exactly, partially cause of an oversight. I improved the text to be clearer about potential locations of your targets.

    Leeching Walk's healing was nice, but blood wounds were still a major threat. Some blood restoration should help.

    Entropic Plume I think has never worked correctly, so that was a bummer. Fixes that.

Changelog

cl Melbert
balance: Heretic: Curses have been reworked. You can now curse any member of the crew, granted they're not too far away. If you additionally provide an item in the ritual containing a sample of the target's blood or fingerprints, the curse's duration will be increased and have its range uncapped.
balance: Heretic: The Curse of Corrosion has been nerfed slightly due to this rework, and can no longer cause vital organs to fail.
balance: Heretic: The Living Heart should now provide better directions, and had its cooldown halved to 4 seconds.
balance: Heretic: Leeching Walk (rust healing) now restores lost blood.
balance: Heretic: If you apply Amok (Entropic Plume) to someone holding a gun, they'll try to shoot it at people nearby.
fix: Entropic Plume's effect now blinds, as it should.
fix: Entropic Plume no longer sometimes applies the stink effect forever.
fix: Entropic Plume no longer always applies the lowest amount of poison, and properly scales on distance.
fix: Fixed an exploit which allowed people to figure out if a Heretic's heart was a previously a Living Heart after being removed.
fix: If a heretic is fully healed by something (such as ahealed), they'll not lose their living heart
/cl
This commit is contained in:
MrMelbert
2022-09-02 09:47:25 +12:00
committed by GitHub
parent 0cb66b3c16
commit bc90ded5b8
11 changed files with 320 additions and 166 deletions
+8 -2
View File
@@ -1,11 +1,17 @@
//Prevents calling anything in update_icon() like update_icon_state() or update_overlays()
/// Prevents calling anything in update_icon() like update_icon_state() or update_overlays()
/datum/element/update_icon_blocker
/datum/element/update_icon_blocker/Attach(datum/target)
. = ..()
if(!istype(target, /atom))
if(!isatom(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_ATOM_UPDATE_ICON, .proc/block_update_icon)
/datum/element/update_icon_blocker/Detach(datum/source, ...)
UnregisterSignal(source, COMSIG_ATOM_UPDATE_ICON)
return ..()
/datum/element/update_icon_blocker/proc/block_update_icon()
SIGNAL_HANDLER
@@ -770,78 +770,6 @@
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_userdanger("Your body starts to break apart!"))
/datum/status_effect/corrosion_curse/tick()
. = ..()
if(!ishuman(owner))
return
var/mob/living/carbon/human/human_owner = owner
var/chance = rand(0, 100)
switch(chance)
if(0 to 10)
human_owner.vomit()
if(20 to 30)
human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE)
human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE)
if(30 to 40)
human_owner.adjustOrganLoss(ORGAN_SLOT_LIVER, 5)
if(40 to 50)
human_owner.adjustOrganLoss(ORGAN_SLOT_HEART, 5, 90)
if(50 to 60)
human_owner.adjustOrganLoss(ORGAN_SLOT_STOMACH, 5)
if(60 to 70)
human_owner.adjustOrganLoss(ORGAN_SLOT_EYES, 10)
if(70 to 80)
human_owner.adjustOrganLoss(ORGAN_SLOT_EARS, 10)
if(80 to 90)
human_owner.adjustOrganLoss(ORGAN_SLOT_LUNGS, 10)
if(90 to 95)
human_owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20, 190)
if(95 to 100)
human_owner.adjust_timed_status_effect(12 SECONDS, /datum/status_effect/confusion)
/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"
@@ -29,7 +29,7 @@
var/ascended = FALSE
/// The path our heretic has chosen. Mostly used for flavor.
var/heretic_path = PATH_START
/// A list of how many knowledge points this heretic CURRENTLY has. Used to research.
/// A sum of how many knowledge points this heretic CURRENTLY has. Used to research.
var/knowledge_points = 1
/// The time between gaining influence passively. The heretic gain +1 knowledge points every this duration of time.
var/passive_gain_timer = 20 MINUTES
@@ -39,9 +39,9 @@
var/living_heart_organ_slot = ORGAN_SLOT_HEART
/// A list of TOTAL how many sacrifices completed. (Includes high value sacrifices)
var/total_sacrifices = 0
/// A list of TOTAL how many high value sacrifices completed.
/// A list of TOTAL how many high value sacrifices completed. (Heads of staff)
var/high_value_sacrifices = 0
/// Lazy assoc list of [weakrefs to humans] to [image previews of the human]. Humans that we have as sacrifice targets.
/// Lazy assoc list of [refs to humans] to [image previews of the human]. Humans that we have as sacrifice targets.
var/list/mob/living/carbon/human/sac_targets
/// Whether we're drawing a rune or not
var/drawing_rune = FALSE
@@ -181,7 +181,6 @@
return ..()
/datum/antagonist/heretic/on_removal()
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
knowledge.on_lose(owner.current)
@@ -194,15 +193,24 @@
var/mob/living/our_mob = mob_override || owner.current
handle_clown_mutation(our_mob, "Ancient knowledge described to you has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
our_mob.faction |= FACTION_HERETIC
RegisterSignal(our_mob, list(COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED), .proc/on_spell_cast)
RegisterSignal(our_mob, COMSIG_MOB_ITEM_AFTERATTACK, .proc/on_item_afterattack)
RegisterSignal(our_mob, COMSIG_MOB_LOGIN, .proc/fix_influence_network)
RegisterSignal(our_mob, COMSIG_LIVING_POST_FULLY_HEAL, .proc/after_fully_healed)
/datum/antagonist/heretic/remove_innate_effects(mob/living/mob_override)
var/mob/living/our_mob = mob_override || owner.current
handle_clown_mutation(our_mob, removing = FALSE)
our_mob.faction -= FACTION_HERETIC
UnregisterSignal(our_mob, list(COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED, COMSIG_MOB_ITEM_AFTERATTACK, COMSIG_MOB_LOGIN))
UnregisterSignal(our_mob, list(
COMSIG_MOB_BEFORE_SPELL_CAST,
COMSIG_MOB_SPELL_ACTIVATED,
COMSIG_MOB_ITEM_AFTERATTACK,
COMSIG_MOB_LOGIN,
COMSIG_LIVING_POST_FULLY_HEAL,
))
/datum/antagonist/heretic/on_body_transfer(mob/living/old_body, mob/living/new_body)
. = ..()
@@ -327,6 +335,17 @@
GLOB.reality_smash_track.rework_network()
/// Signal proc for [COMSIG_LIVING_POST_FULLY_HEAL], when we get fullhealed / ahealed,
/// all of our organs are "deleted" and regenerated (cause it's a full heal)
/// which unfortunately means we lose our living heart.
/// So, we'll give them some lee-way and give them back the living heart afterwards
/// (Maybe put this behind only admin_revives only? Not sure.)
/datum/antagonist/heretic/proc/after_fully_healed(mob/living/source, admin_revive)
SIGNAL_HANDLER
var/datum/heretic_knowledge/living_heart/heart_knowledge = get_knowledge(/datum/heretic_knowledge/living_heart)
heart_knowledge.on_research(source)
/**
* Create our objectives for our heretic.
*/
@@ -374,64 +374,123 @@
*/
/datum/heretic_knowledge/curse
abstract_parent_type = /datum/heretic_knowledge/curse
/// How far can we curse people?
var/max_range = 64
/// The duration of the curse
var/duration = 5 MINUTES
/// Cache list of fingerprints (actual fingerprint strings) we have from our current ritual
var/duration = 1 MINUTES
/// The duration of the curse on people which have a fingerprint or blood sample present
var/duration_modifier = 2
/// What color do we outline cursed folk with?
var/curse_color = "#dadada"
/// A list of all the fingerprints that were found on our atoms, in our last go at the ritual
var/list/fingerprints
/// A list of all the blood samples that were found on our atoms, in our last go at the ritual
var/list/blood_samples
/datum/heretic_knowledge/curse/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
fingerprints = list()
for(var/atom/requirements as anything in atoms)
fingerprints |= GET_ATOM_FINGERPRINTS(requirements)
list_clear_nulls(fingerprints)
blood_samples = list()
for(var/atom/requirement as anything in atoms)
for(var/print in GET_ATOM_FINGERPRINTS(requirement))
fingerprints[print] = 1
// No fingerprints? No ritual
if(!length(fingerprints))
loc.balloon_alert(user, "ritual failed, no fingerprints!")
return FALSE
for(var/blood in GET_ATOM_BLOOD_DNA(requirement))
blood_samples[blood] = 1
return TRUE
/datum/heretic_knowledge/curse/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
var/list/compiled_list = list()
// Potential targets is an assoc list of [names] to [human mob ref].
var/list/potential_targets = list()
// Boosted targets is a list of human mob references.
var/list/boosted_targets = list()
for(var/mob/living/carbon/human/human_to_check as anything in GLOB.human_list)
if(fingerprints[md5(human_to_check.dna.unique_identity)])
compiled_list |= human_to_check.real_name
compiled_list[human_to_check.real_name] = human_to_check
for(var/datum/mind/crewmember as anything in get_crewmember_minds())
var/mob/living/carbon/human/human_to_check = crewmember.current
if(!istype(human_to_check) || human_to_check.stat == DEAD || !human_to_check.dna)
continue
var/their_prints = md5(human_to_check.dna.unique_identity)
var/their_blood = human_to_check.dna.unique_enzymes
// Having their fingerprints or blood present will boost the curse
// and also not run any z or dist checks, as a bonus for those going beyond
if(fingerprints[their_prints] || blood_samples[their_blood])
boosted_targets += human_to_check
potential_targets["[human_to_check.real_name] (Boosted)"] = human_to_check
continue
if(!length(compiled_list))
loc.balloon_alert(user, "ritual failed, no fingerprints!")
return FALSE
// No boost present, so we should be a little stricter moving forward
var/turf/check_turf = get_turf(human_to_check)
// We have to match z-levels.
// Otherwise, you could probably hard own miners, which is funny but mean.
// Multi-z stations technically work though.
if(!is_valid_z_level(check_turf, loc))
continue
// Also has to abide by our max range.
if(get_dist(check_turf, loc) > max_range)
continue
var/chosen_mob = tgui_input_list(user, "Select the person you wish to curse", "Eldritch Curse", sort_list(compiled_list))
potential_targets[human_to_check.real_name] = human_to_check
var/chosen_mob = tgui_input_list(user, "Select the victim you wish to curse.", name, sort_list(potential_targets, /proc/cmp_text_asc))
if(isnull(chosen_mob))
return FALSE
var/mob/living/carbon/human/to_curse = compiled_list[chosen_mob]
var/mob/living/carbon/human/to_curse = potential_targets[chosen_mob]
if(QDELETED(to_curse))
loc.balloon_alert(user, "ritual failed, invalid choice!")
return FALSE
log_combat(user, to_curse, "cursed via heretic ritual", addition = "([name])")
curse(to_curse)
addtimer(CALLBACK(src, .proc/uncurse, to_curse), duration)
// Yes, you COULD curse yourself, not sure why but you could
if(to_curse == user)
var/are_you_sure = tgui_alert(user, "Are you sure you want to curse yourself?", name, list("Yes", "No"))
if(are_you_sure != "Yes")
return FALSE
var/boosted = (to_curse in boosted_targets)
var/turf/curse_turf = get_turf(to_curse)
if(!boosted && (!is_valid_z_level(curse_turf, loc) || get_dist(curse_turf, loc) > max_range * 1.5)) // Give a bit of leeway on max range for people moving around
loc.balloon_alert(user, "ritual failed, too far!")
return FALSE
if(to_curse.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY, charge_cost = 0))
to_chat(to_curse, span_warning("You feel a ghastly chill, but the feeling passes shortly."))
return TRUE
log_combat(user, to_curse, "cursed via heretic ritual", addition = "([boosted ? "Boosted" : ""] [name])")
curse(to_curse, boosted)
to_chat(user, span_hierophant("You cast a[boosted ? "n empowered":""] [name] upon [to_curse.real_name]."))
fingerprints = null
blood_samples = null
return TRUE
/**
* Calls a curse onto [chosen_mob].
*/
/datum/heretic_knowledge/curse/proc/curse(mob/living/carbon/human/chosen_mob)
SHOULD_CALL_PARENT(FALSE)
CRASH("[type] did not implement curse()!")
/datum/heretic_knowledge/curse/proc/curse(mob/living/carbon/human/chosen_mob, boosted = FALSE)
SHOULD_CALL_PARENT(TRUE)
addtimer(CALLBACK(src, .proc/uncurse, chosen_mob, boosted), duration * (boosted ? duration_modifier : 1))
if(!curse_color)
return
chosen_mob.add_filter(name, 2, list("type" = "outline", "color" = curse_color, "size" = 1))
/**
* Removes a curse from [chosen_mob]. Used in timers / callbacks.
*/
/datum/heretic_knowledge/curse/proc/uncurse(mob/living/carbon/human/chosen_mob)
SHOULD_CALL_PARENT(FALSE)
CRASH("[type] did not implement uncurse()!")
/datum/heretic_knowledge/curse/proc/uncurse(mob/living/carbon/human/chosen_mob, boosted = FALSE)
SHOULD_CALL_PARENT(TRUE)
if(QDELETED(chosen_mob))
return
if(!curse_color)
return
chosen_mob.remove_filter(name)
/*
* A knowledge subtype lets the heretic summon a monster with the ritual.
@@ -14,14 +14,13 @@
var/datum/action/item_action/organ_action/track_target/action
/// The icon of the heart before we made it a living heart.
var/old_icon
/// The icon_state of the heart before we made it a living heart.
var/old_icon_state
/datum/component/living_heart/Initialize()
if(!isorgan(parent))
return COMPONENT_INCOMPATIBLE
var/obj/item/organ/organ_parent = parent
// These are incompatible for "balance" reasons, not due to code limitations.
if(organ_parent.status != ORGAN_ORGANIC || (organ_parent.organ_flags & ORGAN_SYNTHETIC))
return COMPONENT_INCOMPATIBLE
@@ -34,12 +33,10 @@
ADD_TRAIT(parent, TRAIT_LIVING_HEART, REF(src))
RegisterSignal(parent, COMSIG_ORGAN_REMOVED, .proc/on_organ_removed)
// It's not technically visible,
// but the organ sprite shows up in the action
// So we'll do this anyways
// The heart's not technically visible (and is never visible to anyone besides the heretic),
// but the organ sprite shows up in the organ action - so we'll do this anyways
parent.AddElement(/datum/element/update_icon_blocker)
old_icon = organ_parent.icon
old_icon_state = organ_parent.icon_state
organ_parent.icon = 'icons/obj/eldritch.dmi'
organ_parent.icon_state = "living_heart"
@@ -50,10 +47,14 @@
REMOVE_TRAIT(parent, TRAIT_LIVING_HEART, REF(src))
UnregisterSignal(parent, COMSIG_ORGAN_REMOVED)
// Restore the heart to look normal
parent.RemoveElement(/datum/element/update_icon_blocker)
var/obj/item/organ/organ_parent = parent
organ_parent.icon = old_icon
organ_parent.icon_state = old_icon_state
organ_parent.icon_state = initial(organ_parent.icon_state)
// Sets the icon state to be the correct state
organ_parent.update_appearance(UPDATE_ICON_STATE)
return ..()
@@ -82,7 +83,7 @@
/// Whether the target radial is currently opened.
var/radial_open = FALSE
/// How long we have to wait between tracking uses.
var/track_cooldown_lenth = 8 SECONDS
var/track_cooldown_lenth = 4 SECONDS
/// The cooldown between button uses.
COOLDOWN_DECLARE(track_cooldown)
@@ -106,12 +107,15 @@
if(radial_open)
return FALSE
return TRUE
/datum/action/item_action/organ_action/track_target/Trigger(trigger_flags)
. = ..()
if(!.)
return
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(owner)
var/datum/heretic_knowledge/sac_knowledge = heretic_datum.get_knowledge(/datum/heretic_knowledge/hunt_and_sacrifice)
if(!LAZYLEN(heretic_datum.sac_targets))
owner.balloon_alert(owner, "no targets, visit a rune!")
return TRUE
@@ -147,14 +151,71 @@
return FALSE
COOLDOWN_START(src, track_cooldown, track_cooldown_lenth)
var/balloon_message = "error text!"
UpdateButtons()
addtimer(CALLBACK(src, .proc/UpdateButtons), track_cooldown_lenth + 1)
playsound(owner, 'sound/effects/singlebeat.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE)
if(isturf(tracked_mob.loc) && owner.z != tracked_mob.z)
owner.balloon_alert(owner, get_balloon_message(tracked_mob))
// Let them know how to sacrifice people if they're able to be sac'd
if(tracked_mob.stat == DEAD)
to_chat(owner, span_hierophant("[tracked_mob] is dead. Bring them to a transmutation rune \
and invoke \"[sac_knowledge.name]\" to sacrifice them!"))
return TRUE
/// Callback for the radial to ensure it's closed when not allowed.
/datum/action/item_action/organ_action/track_target/proc/check_menu()
if(QDELETED(src))
return FALSE
if(!IS_HERETIC(owner))
return FALSE
if(!HAS_TRAIT(target, TRAIT_LIVING_HEART))
return FALSE
return TRUE
/// Gets the balloon message for who we're tracking.
/datum/action/item_action/organ_action/track_target/proc/get_balloon_message(mob/living/carbon/human/tracked_mob)
var/balloon_message = "error text!"
var/turf/their_turf = get_turf(tracked_mob)
var/turf/our_turf = get_turf(owner)
var/their_z = their_turf?.z
var/our_z = our_turf?.z
// One of us is in somewhere we shouldn't be
if(!our_z || !their_z)
// "Hell if I know"
balloon_message = "on another plane!"
// They're not on the same z-level as us
else if(our_z != their_z)
// They're on the station
if(is_station_level(their_z))
// We're on a multi-z station
if(is_station_level(our_z))
if(our_z > their_z)
balloon_message = "below you!"
else
balloon_message = "above you!"
// We're off station, they're not
else
balloon_message = "on station!"
// Mining
else if(is_mining_level(their_z))
balloon_message = "on lavaland!"
// In the gateway
else if(is_away_level(their_z) || is_secret_level(their_z))
balloon_message = "beyond the gateway!"
// They're somewhere we probably can't get too - sacrifice z-level, centcom, etc
else
balloon_message = "on another plane!"
// They're on the same z-level as us!
else
var/dist = get_dist(get_turf(owner), get_turf(tracked_mob))
var/dir = get_dir(get_turf(owner), get_turf(tracked_mob))
var/dist = get_dist(our_turf, their_turf)
var/dir = get_dir(our_turf, their_turf)
switch(dist)
if(0 to 15)
@@ -169,15 +230,4 @@
if(tracked_mob.stat == DEAD)
balloon_message = "they're dead, " + balloon_message
owner.balloon_alert(owner, balloon_message)
return TRUE
/// Callback for the radial to ensure it's closed when not allowed.
/datum/action/item_action/organ_action/track_target/proc/check_menu()
if(QDELETED(src))
return FALSE
if(!IS_HERETIC(owner))
return FALSE
if(!HAS_TRAIT(target, TRAIT_LIVING_HEART))
return FALSE
return TRUE
return balloon_message
@@ -122,12 +122,17 @@
if(!HAS_TRAIT(our_turf, TRAIT_RUSTY))
return
// Heals all damage + Stamina
source.adjustBruteLoss(-2, FALSE)
source.adjustFireLoss(-2, FALSE)
source.adjustToxLoss(-2, FALSE, forced = TRUE)
source.adjustToxLoss(-2, FALSE, forced = TRUE) // Slimes are people to
source.adjustOxyLoss(-0.5, FALSE)
source.adjustStaminaLoss(-2)
source.AdjustAllImmobility(-5)
// Reduces duration of stuns/etc
source.AdjustAllImmobility(-0.5 SECONDS)
// Heals blood loss
if(source.blood_volume < BLOOD_VOLUME_NORMAL)
source.blood_volume += 2.5 * delta_time
/datum/heretic_knowledge/mark/rust_mark
name = "Mark of Rust"
@@ -19,10 +19,9 @@
/datum/heretic_knowledge/curse/paralysis
name = "Curse of Paralysis"
desc = "Allows you to transmute a hatchet, a left and right leg, \
and an item containing fingerprints to cast a curse of immobility \
on one of the fingerprint's owners for five minutes. While cursed, \
the victim will be unable to walk."
desc = "Allows you to transmute a hatchet and both a left and right leg to cast a curse of immobility on a crew member. \
While cursed, the victim will be unable to walk. You can additionally supply an item that a victim has touched \
or is covered in the victim's blood to empower the curse."
gain_text = "The flesh of humanity is weak. Make them bleed. Show them their fragility."
next_knowledge = list(
/datum/heretic_knowledge/mad_mask,
@@ -33,27 +32,31 @@
/obj/item/bodypart/r_leg = 1,
/obj/item/hatchet = 1,
)
duration = 5 MINUTES
duration = 3 MINUTES
duration_modifier = 2
curse_color = "#f19a9a"
cost = 1
route = PATH_SIDE
/datum/heretic_knowledge/curse/paralysis/curse(mob/living/carbon/human/chosen_mob)
/datum/heretic_knowledge/curse/paralysis/curse(mob/living/carbon/human/chosen_mob, boosted = FALSE)
if(chosen_mob.usable_legs <= 0) // What're you gonna do, curse someone who already can't walk?
to_chat(chosen_mob, span_notice("You feel a slight pain for a moment, but it passes shortly. Odd."))
else
to_chat(chosen_mob, span_danger("You suddenly lose feeling in your leg[chosen_mob.usable_legs == 1 ? "":"s"]!"))
return
to_chat(chosen_mob, span_danger("You suddenly lose feeling in your leg[chosen_mob.usable_legs == 1 ? "":"s"]!"))
ADD_TRAIT(chosen_mob, TRAIT_PARALYSIS_L_LEG, type)
ADD_TRAIT(chosen_mob, TRAIT_PARALYSIS_R_LEG, type)
return ..()
/datum/heretic_knowledge/curse/paralysis/uncurse(mob/living/carbon/human/chosen_mob, boosted = FALSE)
if(QDELETED(chosen_mob))
return
/datum/heretic_knowledge/curse/paralysis/uncurse(mob/living/carbon/human/chosen_mob)
REMOVE_TRAIT(chosen_mob, TRAIT_PARALYSIS_L_LEG, type)
REMOVE_TRAIT(chosen_mob, TRAIT_PARALYSIS_R_LEG, type)
if(chosen_mob.usable_legs <= 0) // What're you gonna do, curse someone who already can't walk?
to_chat(chosen_mob, span_notice("The slight pain returns, but disperses shortly."))
else
to_chat(chosen_mob, span_notice("You regain feeling in your leg[chosen_mob.usable_legs == 1 ? "":"s"]!"))
if(chosen_mob.usable_legs > 1)
to_chat(chosen_mob, span_green("You regain feeling in your leg[chosen_mob.usable_legs == 1 ? "":"s"]!"))
return ..()
/datum/heretic_knowledge/summon/ashy
name = "Ashen Ritual"
@@ -20,10 +20,9 @@
/datum/heretic_knowledge/curse/corrosion
name = "Curse of Corrosion"
desc = "Allows you to transmute wirecutters, a pool of vomit, a heart, \
and an item containing fingerprints to cast a curse of plague \
on one of the fingerprint's owners for two minutes. While cursed, \
the victim will repeatedly vomit while their organs will take constant damage."
desc = "Allows you to transmute wirecutters, a pool of vomit, and a heart to cast a curse of sickness on a crew member.\
While cursed, the victim will repeatedly vomit while their organs will take constant damage. You can additionally supply an item \
that a victim has touched or is covered in the victim's blood to empower the curse."
gain_text = "The body of humanity is temporary. Their weaknesses cannot be stopped, like iron falling to rust. Show them all."
next_knowledge = list(
/datum/heretic_knowledge/mad_mask,
@@ -34,17 +33,24 @@
/obj/effect/decal/cleanable/vomit = 1,
/obj/item/organ/internal/heart = 1,
)
duration = 2 MINUTES
duration = 0.5 MINUTES
duration_modifier = 4
curse_color = "#c1ffc9"
cost = 1
route = PATH_SIDE
/datum/heretic_knowledge/curse/corrosion/curse(mob/living/carbon/human/chosen_mob)
to_chat(chosen_mob, span_danger("You feel very ill."))
/datum/heretic_knowledge/curse/corrosion/curse(mob/living/carbon/human/chosen_mob, boosted = FALSE)
to_chat(chosen_mob, span_danger("You feel very ill..."))
chosen_mob.apply_status_effect(/datum/status_effect/corrosion_curse)
return ..()
/datum/heretic_knowledge/curse/corrosion/uncurse(mob/living/carbon/human/chosen_mob, boosted = FALSE)
if(QDELETED(chosen_mob))
return
/datum/heretic_knowledge/curse/corrosion/uncurse(mob/living/carbon/human/chosen_mob)
chosen_mob.remove_status_effect(/datum/status_effect/corrosion_curse)
to_chat(chosen_mob, span_notice("You start to feel better."))
to_chat(chosen_mob, span_green("You start to feel better."))
return ..()
/datum/heretic_knowledge/summon/rusty
name = "Rusted Ritual"
@@ -5,6 +5,7 @@
background_icon_state = "bg_ecult"
icon_icon = 'icons/mob/actions/actions_ecult.dmi'
button_icon_state = "entropic_plume"
sound = 'sound/magic/forcewall.ogg'
school = SCHOOL_FORBIDDEN
cooldown_time = 30 SECONDS
@@ -27,10 +28,8 @@
if(victim.can_block_magic(antimagic_flags) || IS_HERETIC_OR_MONSTER(victim))
return
victim.apply_status_effect(/datum/status_effect/amok)
victim.apply_status_effect(/datum/status_effect/cloudstruck, (level * 1 SECONDS))
if(iscarbon(victim))
var/mob/living/carbon/carbon_victim = victim
carbon_victim.reagents?.add_reagent(/datum/reagent/eldritch, min(1, 6 - level))
victim.apply_status_effect(/datum/status_effect/cloudstruck, level * 1 SECONDS)
victim.reagents?.add_reagent(/datum/reagent/eldritch, max(1, 6 - level))
/datum/action/cooldown/spell/cone/staggered/entropic_plume/calculate_cone_shape(current_level)
if(current_level == cone_levels)
@@ -39,20 +39,99 @@
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!"))
return TRUE
/datum/status_effect/amok/tick()
. = ..()
var/prev_combat_mode = owner.combat_mode
owner.set_combat_mode(TRUE)
// If we're holding a gun, expand the range a bit.
// Otherwise, just look for adjacent targets
var/search_radius = isgun(owner.get_active_held_item()) ? 3 : 1
var/list/mob/living/targets = list()
for(var/mob/living/potential_target in oview(owner, 1))
for(var/mob/living/potential_target in oview(owner, search_radius))
if(IS_HERETIC_OR_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
alert_type = null
duration = 3 SECONDS
on_remove_on_mob_delete = TRUE
///This overlay is applied to the owner for the duration of the effect.
var/static/mutable_appearance/mob_overlay
/datum/status_effect/cloudstruck/on_creation(mob/living/new_owner, duration = 10 SECONDS)
src.duration = duration
if(!mob_overlay)
mob_overlay = mutable_appearance('icons/effects/eldritch.dmi', "cloud_swirl", ABOVE_MOB_LAYER)
return ..()
/datum/status_effect/cloudstruck/on_apply()
owner.add_overlay(mob_overlay)
owner.become_blind(STATUS_EFFECT_TRAIT)
owner.update_blindness() // become_blind is supposed to call this but it doesn't work for some reason because blindness is a fuck
return TRUE
/datum/status_effect/cloudstruck/on_remove()
if(QDELETED(owner))
return
owner.cure_blind(STATUS_EFFECT_TRAIT)
owner.update_blindness()
owner.cut_overlay(mob_overlay)
/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_apply()
to_chat(owner, span_userdanger("Your body starts to break apart!"))
return TRUE
/datum/status_effect/corrosion_curse/tick()
. = ..()
if(!ishuman(owner))
return
var/mob/living/carbon/human/human_owner = owner
var/chance = rand(0, 100)
switch(chance)
if(0 to 10)
human_owner.vomit()
if(20 to 30)
human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/dizziness, only_if_higher = TRUE)
human_owner.set_timed_status_effect(100 SECONDS, /datum/status_effect/jitter, only_if_higher = TRUE)
if(30 to 40)
// Don't fully kill liver that's important
human_owner.adjustOrganLoss(ORGAN_SLOT_LIVER, 10, 90)
if(40 to 50)
// Don't fully kill heart that's important
human_owner.adjustOrganLoss(ORGAN_SLOT_HEART, 10, 90)
if(50 to 60)
// You can fully kill the stomach that's not crucial
human_owner.adjustOrganLoss(ORGAN_SLOT_STOMACH, 10)
if(60 to 70)
// Same with eyes
human_owner.adjustOrganLoss(ORGAN_SLOT_EYES, 5)
if(70 to 80)
// And same with ears
human_owner.adjustOrganLoss(ORGAN_SLOT_EARS, 10)
if(80 to 90)
// But don't fully kill lungs that's usually important
human_owner.adjustOrganLoss(ORGAN_SLOT_LUNGS, 10, 90)
if(90 to 95)
// And definitely don't fully kil brains
human_owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, 20, 190)
if(95 to 100)
human_owner.adjust_timed_status_effect(12 SECONDS, /datum/status_effect/confusion, max_duration = 24 SECONDS)
@@ -32,9 +32,9 @@
for(var/atom/movable/movable_content as anything in target_turf)
if(isobj(movable_content))
do_obj_cone_effect(movable_content, level)
do_obj_cone_effect(movable_content, caster, level)
else if(isliving(movable_content))
do_mob_cone_effect(movable_content, level)
do_mob_cone_effect(movable_content, caster, level)
///This proc deterimines how the spell will affect turfs.
/datum/action/cooldown/spell/cone/proc/do_turf_cone_effect(turf/target_turf, atom/caster, level)