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--------------------------------------//