diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 37087056663f..a883722879de 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -144,8 +144,6 @@ #define STATUS_EFFECT_BROKEN_WILL /datum/status_effect/broken_will //A 30-second sleep effect, ends instantly upon taking enough damage in a single hit. //Yogs -#define STATUS_EFFECT_DEVOURED_WILL /datum/status_effect/devoured_will //A 3 minute long status effect that prevents using devour will on the owner - #define STATUS_EFFECT_AMOK /datum/status_effect/amok //Makes the target automatically strike out at adjecent non-heretics. #define STATUS_EFFECT_CLOUDSTRUCK /datum/status_effect/cloudstruck //blinds and applies an overlay. diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index c156f6916ad9..1f1c5ae5b140 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -1084,13 +1084,6 @@ icon_state = "broken_will" alerttooltipstyle = "alien" -//used to prevent the use of devour will on the target -/datum/status_effect/devoured_will - id = "devoured_will" - status_type = STATUS_EFFECT_UNIQUE - duration = 3 MINUTES - alert_type = null - /datum/status_effect/eldritch duration = 15 SECONDS status_type = STATUS_EFFECT_REPLACE diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index a88e0b0c5527..3ab91da89c5b 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -170,8 +170,8 @@ H.leave_victim() return FALSE if(I && I.owner == target) - if(istype(I, /obj/item/organ/shadowtumor))//Thralls resist deconversion - var/obj/item/organ/shadowtumor/tumor = I + if(istype(I, /obj/item/organ/shadowtumor/thrall))//Thralls resist deconversion + var/obj/item/organ/shadowtumor/thrall/tumor = I if(tumor.resist(target)) return FALSE display_results(user, target, span_notice("You successfully extract [I] from [target]'s [parse_zone(target_zone)]."), diff --git a/yogstation/code/modules/antagonists/darkspawn/_psi_web.dm b/yogstation/code/modules/antagonists/darkspawn/_psi_web.dm index 1f349f1f4e8f..4a8aeebf2487 100644 --- a/yogstation/code/modules/antagonists/darkspawn/_psi_web.dm +++ b/yogstation/code/modules/antagonists/darkspawn/_psi_web.dm @@ -86,7 +86,7 @@ name = "darkspawn progression abilities" desc = "me no think so good" shadow_flags = ALL_DARKSPAWN_CLASSES - learned_abilities = list(/datum/action/cooldown/spell/sacrament, /datum/action/cooldown/spell/touch/restrain_body, /datum/action/cooldown/spell/touch/devour_will) + learned_abilities = list(/datum/action/cooldown/spell/sacrament, /datum/action/cooldown/spell/touch/devour_will) //////////////////////////////////////////////////////////////////////////////////// //----------------------Specialization innate Upgrades----------------------------// diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/core_abilities.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/core_abilities.dm index 37aa5cedd69e..8b3e9004d7c7 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/core_abilities.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/core_abilities.dm @@ -18,7 +18,8 @@ ////////////////////////////////////////////////////////////////////////// /datum/action/cooldown/spell/touch/devour_will name = "Devour Will" - desc = "Creates a dark bead that can be used on a human to begin draining the lucidity and willpower from a living target, knocking them unconscious for a time.
Being interrupted will knock you down for a time." + desc = "Creates a dark bead that can be used on a human to begin draining the lucidity and willpower from a living target, knocking them unconscious for a time.\ +
Being interrupted will knock you down for a time." panel = "Darkspawn" button_icon = 'yogstation/icons/mob/actions/actions_darkspawn.dmi' sound = null @@ -61,11 +62,16 @@ if(target.stat == DEAD) to_chat(caster, span_warning("[target] is too weak to drain.")) return - if(target.has_status_effect(STATUS_EFFECT_DEVOURED_WILL)) - to_chat(caster, span_warning("[target]'s mind has not yet recovered enough willpower to be worth devouring.")) - return + if(get_shadow_tumor(target)) + to_chat(owner, span_danger("[target] already has a dark bead lodged within their psyche.")) + return FALSE + + var/datum/team/darkspawn/team = darkspawn.get_team() + if(!team) + CRASH("darkspawn without a team is trying to thrall someone") caster.Immobilize(1 SECONDS) // So they don't accidentally move while beading + target.Immobilize(10 SECONDS) //we remove this if it's canceled early target.silent += 5 caster.balloon_alert(caster, "Cera ko...") @@ -76,134 +82,53 @@ eating = TRUE if(!do_after(caster, 5 SECONDS, target)) + to_chat(caster, span_danger("Being interrupted causes a backlash of psionic power.")) + caster.Immobilize(5 SECONDS) + caster.Knockdown(10 SECONDS) to_chat(target, span_boldwarning("All right... You're all right.")) - caster.Knockdown(5 SECONDS) + target.SetImmobilized(0) eating = FALSE return FALSE eating = FALSE - if(target.has_status_effect(STATUS_EFFECT_DEVOURED_WILL)) - to_chat(caster, span_warning("[target]'s mind has not yet recovered enough willpower to be worth devouring.")) - return + if(get_shadow_tumor(target)) + to_chat(owner, span_danger("[target] already has a dark bead lodged within their psyche.")) + return FALSE //put the victim to sleep before the visible_message proc so the victim doesn't see it to_chat(target, span_progenitor("You suddenly feel... empty. Thoughts try to form, but flit away. You slip into a deep, deep slumber...")) playsound(target, 'yogstation/sound/magic/devour_will_end.ogg', 75, FALSE) target.playsound_local(target, 'yogstation/sound/magic/devour_will_victim.ogg', 50, FALSE) - target.Unconscious(5 SECONDS) - - //get how much lucidity and willpower will be given - var/willpower_amount = 2 - var/lucidity_amount = 1 - if(HAS_TRAIT(target, TRAIT_DARKSPAWN_DEVOURED)) //change the numbers before text - lucidity_amount = 0 - willpower_amount *= 0.5 - willpower_amount = round(willpower_amount) //make sure it's a whole number still //format the text output to the darkspawn var/list/self_text = list() caster.balloon_alert(caster, "...akkraup'dej") - self_text += span_velvet("You devour [target]'s will.") - if(HAS_TRAIT(target, TRAIT_DARKSPAWN_DEVOURED)) - self_text += span_warning("[target]'s mind is already damaged by previous devouring and has granted less willpower and no lucidity.") - else - self_text += span_velvet("This individual's lucidity brings you one step closer to the sacrament...") - self_text += span_warning("After meddling with [target]'s mind, they will grant less willpower and no lucidity any future times their will is devoured.") - self_text += span_warning("[target] is now severely weakened and will take some time to recover.") - caster.visible_message(span_warning("[caster] gently lowers [target] to the ground..."), self_text.Join("
")) - - //pass out the willpower and lucidity to the darkspawns - var/datum/team/darkspawn/team = darkspawn.get_team() - if(team) - team.grant_willpower(willpower_amount) - team.grant_lucidity(lucidity_amount) - - //apply the long-term debuffs to the victim - target.apply_status_effect(STATUS_EFFECT_BROKEN_WILL) - target.apply_status_effect(STATUS_EFFECT_DEVOURED_WILL) - ADD_TRAIT(target, TRAIT_DARKSPAWN_DEVOURED, type) - return TRUE - -////////////////////////////////////////////////////////////////////////// -//--------------------------Glorified handcuffs-------------------------// -////////////////////////////////////////////////////////////////////////// -/datum/action/cooldown/spell/touch/restrain_body - name = "Restrain body" - desc = "Forms rudimentary restraints on a target's hands." - panel = "Darkspawn" - button_icon = 'yogstation/icons/mob/actions/actions_darkspawn.dmi' - sound = null - background_icon_state = "bg_alien" - overlay_icon_state = "bg_alien_border" - buttontooltipstyle = "alien" - button_icon_state = "restrain_body" - check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_IMMOBILE | AB_CHECK_LYING | AB_CHECK_CONSCIOUS - spell_requirements = SPELL_REQUIRES_HUMAN - invocation_type = INVOCATION_NONE - hand_path = /obj/item/melee/touch_attack/darkspawn - resource_costs = list(ANTAG_RESOURCE_DARKSPAWN = 5) - //Boolean on whether we're tying someone's hands - var/tying = FALSE - -/datum/action/cooldown/spell/touch/restrain_body/can_cast_spell(feedback) - if(tying) - return - return ..() - -/datum/action/cooldown/spell/touch/restrain_body/is_valid_target(atom/cast_on) - return iscarbon(cast_on) - -/datum/action/cooldown/spell/touch/restrain_body/cast_on_hand_hit(obj/item/melee/touch_attack/hand, mob/living/carbon/target, mob/living/carbon/caster) - var/datum/antagonist/darkspawn/darkspawn = isdarkspawn(caster) - if(!darkspawn || tying || target == caster) //no tying yourself - return - if(is_team_darkspawn(target)) - to_chat(caster, span_warning("You cannot restrain allies.")) - return - if(!istype(target)) - to_chat(caster, span_warning("[target]'s mind is too pitiful to be of any use.")) - return - if(target.handcuffed) - to_chat(caster, span_warning("[target] is already restrained.")) - return - caster.balloon_alert(caster, "Koce ra...") - to_chat(caster, span_velvet("You begin restraining [target]...")) - playsound(target, 'yogstation/sound/ambience/antag/veil_mind_gasp.ogg', 50, TRUE) - tying = TRUE - if(!do_after(caster, 1.5 SECONDS, target, progress = FALSE)) - tying = FALSE - return FALSE - tying = FALSE + var/obj/item/organ/shadowtumor/bead = target.getorganslot(ORGAN_SLOT_BRAIN_TUMOR) + if(!bead || !istype(bead)) + bead = new + bead.Insert(target, FALSE, FALSE) + bead.antag_team = team - target.silent += 5 - - if(target.handcuffed) - to_chat(caster, span_warning("[target] is already restrained.")) - return + //pass out the willpower and lucidity to the darkspawns + if(!HAS_TRAIT(target, TRAIT_DARKSPAWN_DEVOURED)) + ADD_TRAIT(target, TRAIT_DARKSPAWN_DEVOURED, type) + self_text += span_velvet("You place a dark bead deep within [target]'s psyche.") + self_text += span_velvet("This individual's lucidity brings you one step closer to the sacrament...") + self_text += span_velvet("You also feed off their will to fuel your growth, generating 2 willpower.") + self_text += span_velvet("No further attempts to drain this individual will provide willpower or lucidity.") + team.grant_willpower(2) + team.grant_lucidity(1) + else + self_text += span_velvet("You replace the dark bead deep within [target]'s psyche.") - playsound(target, 'yogstation/sound/magic/devour_will_form.ogg', 50, TRUE) - target.set_handcuffed(new /obj/item/restraints/handcuffs/darkspawn(target)) - target.update_handcuffed() + caster.visible_message(span_warning("[caster] gently lowers [target] to the ground..."), self_text.Join("
")) + //apply the long-term debuff to the victim + target.apply_status_effect(STATUS_EFFECT_BROKEN_WILL) return TRUE -//the restrains in question -/obj/item/restraints/handcuffs/darkspawn - name = "shadow stitched restraints" - desc = "Bindings created by stitching together shadows." - icon_state = "handcuffAlien" - lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' - breakouttime = 30 SECONDS - flags_1 = NONE - item_flags = DROPDEL - -/obj/item/restraints/handcuffs/darkspawn/Initialize(mapload) - . = ..() - add_atom_colour(COLOR_VELVET, FIXED_COLOUR_PRIORITY) - ////////////////////////////////////////////////////////////////////////// //-----------------------Recall shuttle ability-------------------------// ////////////////////////////////////////////////////////////////////////// diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/thrall_spells.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/thrall_spells.dm index 39791f140ca2..b226f874dd3a 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/thrall_spells.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/thrall_spells.dm @@ -51,12 +51,12 @@ var/datum/antagonist/darkspawn/master = isdarkspawn(caster) if(!isthrall(target)) - if(!target.has_status_effect(STATUS_EFFECT_DEVOURED_WILL)) - to_chat(owner, span_danger("[target]'s will is still too strong to thrall.")) - return FALSE if(master.willpower < willpower_cost) to_chat(owner, span_danger("You do not have enough will to thrall [target].")) return FALSE + if(!get_shadow_tumor(target)) + to_chat(owner, span_danger("[target] does not have a shadow bead for you to enhance.")) + return FALSE owner.balloon_alert(owner, "Krx'lna tyhx graha...") to_chat(owner, span_velvet("You begin to channel your psionic powers through [target]'s mind.")) diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/thrall_tumor.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/thrall_tumor.dm index 1502686552ae..0760bf134907 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/thrall_tumor.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/thrall_tumor.dm @@ -8,10 +8,10 @@ slot = ORGAN_SLOT_BRAIN_TUMOR ///How many process ticks the organ can be in light before it evaporates var/organ_health = 3 - ///adds a cooldown to the resist so a thrall ipc or preternis can't weaponize it - COOLDOWN_DECLARE(resist_cooldown) - ///How long the resist cooldown is - var/cooldown_length = 15 SECONDS + ///Cached darkspawn team that gets the willpower + var/datum/team/darkspawn/antag_team + ///How much willpower is granted by this tumor + var/willpower_amount = 1 /obj/item/organ/shadowtumor/New() ..() @@ -22,9 +22,6 @@ ..() /obj/item/organ/shadowtumor/process() - if(!isthrall(owner)) - qdel(src) - return if(isturf(loc)) var/turf/T = loc var/light_count = T.get_lumcount() @@ -37,12 +34,31 @@ qdel(src) else organ_health = min(organ_health+0.5, 3) + if(owner && owner.stat != DEAD && antag_team) + antag_team.willpower_progress(willpower_amount) /obj/item/organ/shadowtumor/on_find(mob/living/finder) . = ..() finder.visible_message(span_danger("[finder] opens up [owner]'s skull, revealing a pulsating black mass, with red tendrils attaching it to [owner.p_their()] brain.")) -/obj/item/organ/shadowtumor/proc/resist(mob/living/carbon/M) +//////////////////////////////////////////////////////////////////////////////////// +//------------------------------Thrall version------------------------------------// +//////////////////////////////////////////////////////////////////////////////////// +/obj/item/organ/shadowtumor/thrall + //provides extra willpower because willpower was spent to thrall someone + willpower_amount = 2 + ///adds a cooldown to the resist so a thrall ipc or preternis can't weaponize it + COOLDOWN_DECLARE(resist_cooldown) + ///How long the resist cooldown is + var/cooldown_length = 15 SECONDS + +/obj/item/organ/shadowtumor/thrall/process() + if(!isthrall(owner)) + qdel(src) + return + return ..() + +/obj/item/organ/shadowtumor/thrall/proc/resist(mob/living/carbon/M) if(QDELETED(src)) return FALSE if(!(M.stat == CONSCIOUS))//Thralls cannot be deconverted while awake diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_team.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_team.dm index 98fb7801763a..14880e8e6d66 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_team.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_team.dm @@ -8,6 +8,10 @@ var/list/datum/mind/thralls = list() ///The number of drains required to perform the sacrament var/required_succs = 10 //How many succs are needed (this is changed in pre_setup, so it scales based on pop) + ///How much progress towards generating a willpower via tumors + var/current_willpower_progress = 0 + ///How much progress until another willpower is awarded + var/max_willpower_progress = 100 ///How many drains have happened so far var/lucidity = 0 ///The max number of people that can be actively converted @@ -109,13 +113,19 @@ //////////////////////////////////////////////////////////////////////////////////// //-----------------------------Special antag procs--------------------------------// //////////////////////////////////////////////////////////////////////////////////// -/datum/team/darkspawn/proc/grant_willpower(amount = 1, silent = FALSE) +/datum/team/darkspawn/proc/willpower_progress(amount = 1) + current_willpower_progress += amount + if(current_willpower_progress >= max_willpower_progress) + current_willpower_progress -= max_willpower_progress + max_willpower_progress *= 1.1 //gets harder to get more willpower with every willpower granted to reduce snowballing + grant_willpower(1) + +//give a willpower to every darkspawn on the team +/datum/team/darkspawn/proc/grant_willpower(amount = 1) for(var/datum/mind/master in members) if(master.has_antag_datum(/datum/antagonist/darkspawn)) //sanity check var/datum/antagonist/darkspawn/antag = master.has_antag_datum(/datum/antagonist/darkspawn) antag.willpower += amount - if(!silent && master.current) - to_chat(master.current, span_velvet("You have gained [amount] willpower.")) /datum/team/darkspawn/proc/grant_lucidity(amount = 1) lucidity += amount diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_thrall.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_thrall.dm index b7fbecd6c2ce..117b5083bf9b 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_thrall.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_thrall.dm @@ -1,3 +1,15 @@ +/** + * Helper proc to check if someone has a shadow tumor + */ +/proc/get_shadow_tumor(mob/living/source) + if(!istype(source)) + return + var/obj/item/organ/tumor = source.getorganslot(ORGAN_SLOT_BRAIN_TUMOR) + if(!tumor || !istype(tumor, /obj/item/organ/shadowtumor)) //if they somehow lose their tumor in an unusual way + return + return tumor + + /datum/antagonist/thrall name = "Darkspawn Thrall" job_rank = ROLE_DARKSPAWN @@ -7,10 +19,6 @@ antag_moodlet = /datum/mood_event/thrall ///The abilities granted to the thrall var/list/abilities = list(/datum/action/cooldown/spell/toggle/nightvision, /datum/action/cooldown/spell/pointed/darkspawn_build/thrall_eye/thrall) - ///How many ticks towards willpower generation has happened so far - var/current_willpower_progress = 0 - ///Amount of progress required to generate willpower, increases every time - var/current_willpower_max = 80 ///The darkspawn team that the thrall is on var/datum/team/darkspawn/team @@ -70,10 +78,12 @@ new_spell.Grant(current_mob) if(isliving(current_mob)) - var/obj/item/organ/shadowtumor/ST = current_mob.getorganslot(ORGAN_SLOT_BRAIN_TUMOR) + var/obj/item/organ/shadowtumor/thrall/ST = current_mob.getorganslot(ORGAN_SLOT_BRAIN_TUMOR) if(!ST || !istype(ST)) ST = new ST.Insert(current_mob, FALSE, FALSE) + if(team) + ST.antag_team = team /datum/antagonist/thrall/remove_innate_effects(mob/living/mob_override) var/mob/living/current_mob = mob_override || owner.current @@ -94,8 +104,8 @@ if(spells.type in abilities)//no keeping your abilities spells.Remove(current_mob) qdel(spells) - var/obj/item/organ/tumor = current_mob.getorganslot(ORGAN_SLOT_BRAIN_TUMOR) - if(tumor && istype(tumor, /obj/item/organ/shadowtumor)) + var/obj/item/organ/tumor = get_shadow_tumor(current_mob) + if(tumor) qdel(tumor) current_mob.update_sight() @@ -132,33 +142,13 @@ overlays += overlay //////////////////////////////////////////////////////////////////////////////////// -//--------------------------Passive willpower gen---------------------------------// +//-----------Check if the thrall has a tumor, if not, dethrall them---------------// //////////////////////////////////////////////////////////////////////////////////// /datum/antagonist/thrall/proc/thrall_life(mob/living/source, seconds_per_tick, times_fired) if(!source || source.stat == DEAD) return - var/obj/item/organ/tumor = source.getorganslot(ORGAN_SLOT_BRAIN_TUMOR) - if(!tumor || !istype(tumor, /obj/item/organ/shadowtumor)) //if they somehow lose their tumor in an unusual way + if(!get_shadow_tumor(source)) //if they somehow lose their tumor in an unusual way source.remove_thrall() - return - - var/found_other = FALSE - for(var/mob/living/thing in range(10, source)) - if(!thing.client) //gotta be an actual player (hope no one goes afk) - continue - if(is_team_darkspawn(thing)) - continue - if(!can_see(source, thing, 10)) - continue - found_other = TRUE - - if(found_other) - current_willpower_progress += seconds_per_tick - - if(current_willpower_progress >= current_willpower_max) - current_willpower_max *= 2 - current_willpower_progress = 0 - team.grant_willpower(1, TRUE) //////////////////////////////////////////////////////////////////////////////////// //-------------------------------Antag greet--------------------------------------//