Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit ea2ea4f

Browse files
authored
Refactors spell resource costs (#22015)
* wow, that was easy * vampires * fix * Update airlock.dm * Update umbral_tendrils.dm * bruh, 1 second cooldown dodge!?!?!?! you crazy!?!?!?!
1 parent 993a277 commit ea2ea4f

16 files changed

Lines changed: 146 additions & 159 deletions

File tree

code/__DEFINES/antagonists.dm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,7 @@
190190

191191
/// Checks if the given mob is a malf ai.
192192
#define IS_MALF_AI(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/malf_ai))
193+
194+
// Antag resource defines
195+
#define ANTAG_RESOURCE_DARKSPAWN "psi"
196+
#define ANTAG_RESOURCE_VAMPIRE "blood"

code/__DEFINES/dcs/signals/signals_spell.dm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@
9898
#define COMPONENT_ITEM_CHARGED (1 << 0)
9999
/// Return if the item had a negative side effect occur while recharging
100100
#define COMPONENT_ITEM_BURNT_OUT (1 << 1)
101+
102+
/// Sent from /datum/action/cooldown/spell/proc/can_cast_spell(), to the mind of the mob casting the spell: (datum/mind, resource_flag, resource_amount)
103+
#define COMSIG_MIND_CHECK_ANTAG_RESOURCE "check_antag_resource"
104+
/// Sent from /datum/action/cooldown/spell/proc/consume_resource(), to the mind of the mob casting the spell: (datum/mind, list/resource_costs)
105+
#define COMSIG_MIND_SPEND_ANTAG_RESOURCE "spend_antag_resource"

code/game/machinery/doors/airlock.dm

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@
11371137
open(2)
11381138
var/obj/item/umbral_tendrils/T = C
11391139
var/list/modifiers = params2list(params)
1140-
if(!T.darkspawn)
1140+
if(!isdarkspawn(user))
11411141
return ..()
11421142
else if((!user.combat_mode || (modifiers && modifiers[RIGHT_CLICK])) && density)
11431143
// we dont want Duality double-hitting the airlock when we're trying to pry it open
@@ -1147,9 +1147,9 @@
11471147
if(!hasPower()) // a crowbar can do this and you're telling me tentacles struggle?
11481148
open(2)
11491149
return
1150-
if(!T.darkspawn.has_psi(15))
1150+
if(!(user.mind && SEND_SIGNAL(user.mind, COMSIG_MIND_CHECK_ANTAG_RESOURCE, ANTAG_RESOURCE_DARKSPAWN, 15)))
11511151
to_chat(user, span_warning("You need at least 15 Psi to force open an airlock!"))
1152-
return
1152+
return
11531153
user.visible_message(span_warning("[user] starts forcing open [src]!"), span_velvet("<b>ueahz</b><br>You begin forcing open [src]..."))
11541154
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE)
11551155
if(!T.twin)
@@ -1161,28 +1161,28 @@
11611161
open(2)
11621162
if(density && !open(2))
11631163
to_chat(user, span_warning("Despite your attempts, [src] refuses to open!"))
1164-
T.darkspawn.use_psi(15)
1164+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_DARKSPAWN = 15))
11651165
else
1166-
if(!T.darkspawn.has_psi(30))
1166+
if(!(user.mind && SEND_SIGNAL(user.mind, COMSIG_MIND_CHECK_ANTAG_RESOURCE, ANTAG_RESOURCE_DARKSPAWN, 30)))
11671167
to_chat(user, span_warning("You need at least 30 Psi to smash down an airlock!"))
1168-
return
1168+
return
11691169
user.visible_message(span_boldwarning("[user] starts slamming [T] into [src]!"), \
11701170
"<span class='velvet italics'>You loudly begin smashing down [src].</span>")
11711171
while(atom_integrity > max_integrity * 0.25)
11721172
if(T.twin)
11731173
if(!do_after(user, rand(4, 6), src))
1174-
T.darkspawn.use_psi(30)
1174+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_DARKSPAWN = 30))
11751175
return
11761176
else
11771177
if(!do_after(user, rand(8, 10), src))
1178-
T.darkspawn.use_psi(30)
1178+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_DARKSPAWN = 30))
11791179
return
11801180
playsound(src, 'yogstation/sound/magic/pass_smash_door.ogg', 50, TRUE)
11811181
take_damage(max_integrity / rand(8, 15))
11821182
to_chat(user, "<span class='velvet bold'>klaj.</span>")
11831183
ex_act(EXPLODE_DEVASTATE)
11841184
user.visible_message(span_boldwarning("[user] slams down [src]!"), "<span class='velvet bold'>KLAJ.</span>")
1185-
T.darkspawn.use_psi(30)
1185+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_DARKSPAWN = 30))
11861186
else
11871187
return ..()
11881188
else

code/modules/admin/admin_verbs.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ GLOBAL_PROTECT(admin_verbs_hideable)
628628

629629
if(robeless)
630630
new_spell.spell_requirements &= ~SPELL_REQUIRES_WIZARD_GARB
631-
new_spell.psi_cost = 0 //breaks balance, but allows non darkspawns to use darkspawn abilities
631+
new_spell.bypass_cost = TRUE //breaks balance, but allows non antags to use antag specific abilities
632632

633633
new_spell.Grant(spell_recipient)
634634

code/modules/spells/spell.dm

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@
8585
/// The amount of smoke to create on cast. This is a range, so a value of 5 will create enough smoke to cover everything within 5 steps.
8686
var/smoke_amt = 0
8787

88-
///used for darkspawn, if there is a psi cost, it will try to check for a darkspawn datum
89-
var/psi_cost = 0 //can var edit psi_cost to 0 to make darkspawn abilities usable by non-darkspawns
88+
/// An associative list of all resource costs
89+
var/list/resource_costs
90+
/// Boolean, if true, resource costs will be ignored
91+
var/bypass_cost = FALSE
9092

9193
/datum/action/cooldown/spell/Grant(mob/grant_to)
9294
// If our spell is mind-bound, we only wanna grant it to our mind
@@ -175,17 +177,13 @@
175177
return FALSE
176178

177179
//used for darkspawn spells
178-
if(psi_cost)
179-
if(isdarkspawn(owner))
180-
var/datum/antagonist/darkspawn/darkspawn = isdarkspawn(owner)
181-
if(!darkspawn.has_psi(psi_cost))
180+
if(owner.mind && !bypass_cost && LAZYLEN(resource_costs))
181+
for(var/i in resource_costs)
182+
var/has_cost = SEND_SIGNAL(owner.mind, COMSIG_MIND_CHECK_ANTAG_RESOURCE, i, resource_costs[i])
183+
if(!has_cost)
182184
if(feedback)
183-
owner.balloon_alert(owner, span_warning("Not enough psi!"))
185+
to_chat(owner, span_warning("You don't have enough [i]!"))
184186
return FALSE
185-
else
186-
if(feedback)
187-
to_chat(owner, span_warning("Your mind is incapable of comprehending this ability!"))
188-
return FALSE
189187

190188
// If the spell requires the user has no antimagic equipped, and they're holding antimagic
191189
// that corresponds with the spell's antimagic, then they can't actually cast the spell
@@ -348,10 +346,8 @@
348346

349347
/// Called after the effect happens, whether that's after the button press or after hitting someone with a touch ability
350348
/datum/action/cooldown/spell/proc/consume_resource() //to-do: rework vampire blood use into using this proc
351-
if(psi_cost && isdarkspawn(owner))
352-
var/datum/antagonist/darkspawn/darkspawn = isdarkspawn(owner)
353-
darkspawn.use_psi(psi_cost)
354-
349+
if(!bypass_cost && owner.mind && LAZYLEN(resource_costs))
350+
SEND_SIGNAL(owner.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, resource_costs)
355351

356352
/// Provides feedback after a spell cast occurs, in the form of a cast sound and/or invocation
357353
/datum/action/cooldown/spell/proc/spell_feedback()

yogstation/code/datums/antagonists/vampire.dm

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,24 @@
7979
check_vampire_upgrade()
8080
owner.special_role = "vampire"
8181
owner.current.faction += "vampire"
82+
RegisterSignal(owner, COMSIG_MIND_CHECK_ANTAG_RESOURCE, PROC_REF(has_blood))
83+
RegisterSignal(owner, COMSIG_MIND_SPEND_ANTAG_RESOURCE, PROC_REF(use_blood))
8284
if(ishuman(owner.current))
8385
var/mob/living/carbon/human/H = owner.current
8486
RegisterSignal(H, COMSIG_HUMAN_BURNING, PROC_REF(handle_fire))
8587
var/obj/item/organ/brain/B = H.getorganslot(ORGAN_SLOT_BRAIN)
8688
if(B)
8789
B.organ_flags &= ~ORGAN_VITAL
8890
B.decoy_override = TRUE
89-
..()
91+
return ..()
9092

9193
/datum/antagonist/vampire/on_removal()
9294
remove_vampire_powers()
9395
owner.current.faction -= "vampire"
9496
SSticker.mode.vampires -= owner
9597
owner.special_role = null
98+
UnregisterSignal(owner, COMSIG_MIND_CHECK_ANTAG_RESOURCE)
99+
UnregisterSignal(owner, COMSIG_MIND_SPEND_ANTAG_RESOURCE)
96100
if(ishuman(owner.current))
97101
var/mob/living/carbon/human/H = owner.current
98102
UnregisterSignal(H, COMSIG_HUMAN_BURNING)
@@ -110,7 +114,7 @@
110114
if(B && (B.decoy_override != initial(B.decoy_override)))
111115
B.organ_flags |= ORGAN_VITAL
112116
B.decoy_override = FALSE
113-
..()
117+
return ..()
114118

115119
/datum/antagonist/vampire/greet()
116120
to_chat(owner, span_userdanger("You are a Vampire!"))
@@ -187,6 +191,24 @@
187191
steal_objective.find_target()
188192
add_objective(steal_objective)
189193

194+
/datum/antagonist/vampire/proc/has_blood(datum/mind, flag = ANTAG_RESOURCE_VAMPIRE, amt)
195+
SIGNAL_HANDLER
196+
if(flag != ANTAG_RESOURCE_VAMPIRE)
197+
return FALSE
198+
return usable_blood >= amt
199+
200+
/datum/antagonist/vampire/proc/use_blood(datum/mind, list/resource_costs)
201+
SIGNAL_HANDLER
202+
if(!LAZYLEN(resource_costs))
203+
return
204+
var/amount = resource_costs[ANTAG_RESOURCE_VAMPIRE]
205+
if(!amount)
206+
return
207+
if(!has_blood(amt = amount))
208+
return
209+
usable_blood -= amount
210+
to_chat(owner.current, span_notice("<b>You have [usable_blood] left to use.</b>"))
211+
190212
/datum/antagonist/vampire/proc/vamp_burn(severe_burn = FALSE)
191213
var/mob/living/L = owner.current
192214
if(!L)

yogstation/code/game/gamemodes/vampire/vampire_powers.dm

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
/datum/action/cooldown/spell
22
var/gain_desc
3-
var/blood_used = 0
43
var/vamp_req = FALSE
54

65
/datum/action/cooldown/spell/can_cast_spell(feedback = TRUE)
76
if(vamp_req)
87
if(!is_vampire(owner))
98
return FALSE
10-
var/datum/antagonist/vampire/V = owner.mind.has_antag_datum(/datum/antagonist/vampire)
11-
if(!V)
12-
return FALSE
13-
if(V.usable_blood < blood_used)
14-
if(feedback)
15-
to_chat(owner, span_warning("You do not have enough blood to cast this!"))
16-
return FALSE
179
return ..()
1810

1911
/datum/action/cooldown/spell/New()
@@ -26,19 +18,6 @@
2618
// sanity check before we cast
2719
if(!is_vampire(owner))
2820
return
29-
30-
if(!blood_used)
31-
return
32-
33-
// enforce blood
34-
var/datum/antagonist/vampire/vampire = owner.mind.has_antag_datum(/datum/antagonist/vampire)
35-
36-
if(blood_used <= vampire.usable_blood)
37-
vampire.usable_blood -= blood_used
38-
39-
if(cast_on)
40-
to_chat(owner, span_notice("<b>You have [vampire.usable_blood] left to use.</b>"))
41-
4221
return ..()
4322

4423
/datum/action/cooldown/spell/is_valid_target(mob/living/target)
@@ -84,7 +63,7 @@
8463

8564
check_flags = NONE
8665
cooldown_time = 20 SECONDS
87-
blood_used = 20
66+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 20)
8867
vamp_req = TRUE
8968

9069
/datum/action/cooldown/spell/rejuvenate/cast(mob/living/user)
@@ -180,7 +159,7 @@
180159
school = SCHOOL_SANGUINE
181160

182161
cooldown_time = 30 SECONDS
183-
blood_used = 20
162+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 20)
184163
active_msg = span_warning("You prepare your hypnosis technique.")
185164
deactive_msg = span_warning("You stop preparing your hypnosis.")
186165
vamp_req = TRUE
@@ -342,7 +321,7 @@
342321
school = SCHOOL_SANGUINE
343322

344323
aoe_radius = 4
345-
blood_used = 20
324+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 20)
346325
vamp_req = TRUE
347326

348327
/datum/action/cooldown/spell/aoe/screech/get_things_to_cast_on(atom/center)
@@ -389,7 +368,7 @@
389368

390369
cooldown_time = 2 MINUTES
391370
vamp_req = TRUE
392-
blood_used = 30
371+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 30)
393372
var/num_bats = 2
394373

395374
/datum/action/cooldown/spell/bats/cast(mob/living/user)
@@ -415,7 +394,7 @@
415394
background_icon_state = "bg_vampire"
416395
overlay_icon_state = "bg_vampire_border"
417396

418-
blood_used = 30
397+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 30)
419398
vamp_req = TRUE
420399

421400
/datum/action/cooldown/spell/pointed/vampirize
@@ -430,7 +409,7 @@
430409

431410
school = SCHOOL_SANGUINE
432411

433-
blood_used = 300
412+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 300)
434413
vamp_req = TRUE
435414

436415
/datum/action/cooldown/spell/pointed/vampirize/InterceptClickOn(mob/living/user, params, atom/target_atom)
@@ -443,11 +422,11 @@
443422
var/datum/antagonist/vampire/vamp = user.mind.has_antag_datum(/datum/antagonist/vampire)
444423
if(is_vampire(target))
445424
to_chat(user, span_warning("They're already a vampire!"))
446-
vamp.usable_blood += blood_used // Refund cost
425+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_VAMPIRE = -300)) // Refund cost
447426
return FALSE
448427
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
449428
to_chat(user, span_warning("[target]'s mind is too strong!"))
450-
vamp.usable_blood += blood_used // Refund cost
429+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_VAMPIRE = -300)) // Refund cost
451430
return FALSE
452431
user.visible_message(span_warning("[user] latches onto [target]'s neck, pure dread eminating from them."), span_warning("You latch onto [target]'s neck, preparing to transfer your unholy blood to them."), span_warning("A dreadful feeling overcomes you"))
453432
target.reagents.add_reagent(/datum/reagent/medicine/salbutamol, 10) //incase you're choking the victim
@@ -464,7 +443,7 @@
464443
if(!do_after(user, 7 SECONDS, target))
465444
to_chat(user, span_danger("The pact has failed! [target] has not became a vampire."))
466445
to_chat(target, span_notice("The visions stop, and you relax."))
467-
vamp.usable_blood += blood_used // Refund the cost
446+
SEND_SIGNAL(user.mind, COMSIG_MIND_SPEND_ANTAG_RESOURCE, list(ANTAG_RESOURCE_VAMPIRE = -300)) // Refund cost
468447
return FALSE
469448
if(!QDELETED(user) && !QDELETED(target))
470449
to_chat(user, span_notice(". . ."))
@@ -494,7 +473,7 @@
494473

495474
school = SCHOOL_CONJURATION
496475

497-
blood_used = 100
476+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 100)
498477
vamp_req = TRUE
499478

500479
/datum/action/cooldown/spell/summon_coat/cast(mob/living/user)
@@ -525,14 +504,14 @@
525504
cooldown_time = 20 SECONDS
526505
die_with_shapeshifted_form = FALSE
527506
convert_damage_type = STAMINA
528-
blood_used = 15
507+
resource_costs = list(ANTAG_RESOURCE_VAMPIRE = 15)
529508
vamp_req = TRUE
530509
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED
531510
possible_shapes = list(/mob/living/simple_animal/hostile/vampire_bat)
532511

533512
/datum/action/cooldown/spell/shapeshift/vampire/can_cast_spell()
534513
if(ishuman(owner))
535-
blood_used = 15
514+
bypass_cost = FALSE
536515
else
537-
blood_used = 0
516+
bypass_cost = TRUE
538517
return ..()

yogstation/code/modules/antagonists/darkspawn/darkspawn_abilities/core_abilities.dm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_IMMOBILE | AB_CHECK_LYING | AB_CHECK_CONSCIOUS
3131
spell_requirements = SPELL_REQUIRES_HUMAN
3232
invocation_type = INVOCATION_NONE
33-
psi_cost = 5
33+
resource_costs = list(ANTAG_RESOURCE_DARKSPAWN = 5)
3434
hand_path = /obj/item/melee/touch_attack/devour_will
3535
var/eating = FALSE //If we're devouring someone's will
3636

@@ -143,7 +143,7 @@
143143
spell_requirements = SPELL_REQUIRES_HUMAN
144144
invocation_type = INVOCATION_NONE
145145
hand_path = /obj/item/melee/touch_attack/darkspawn
146-
psi_cost = 5
146+
resource_costs = list(ANTAG_RESOURCE_DARKSPAWN = 5)
147147
//Boolean on whether we're tying someone's hands
148148
var/tying = FALSE
149149

@@ -221,7 +221,7 @@
221221
panel = "Darkspawn"
222222
check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_IMMOBILE
223223
spell_requirements = SPELL_REQUIRES_HUMAN
224-
psi_cost = 60
224+
resource_costs = list(ANTAG_RESOURCE_DARKSPAWN = 60)
225225
hand_path = /obj/item/melee/touch_attack/darkspawn
226226
///Boolean on whether this is in use.
227227
var/in_use = FALSE
@@ -300,7 +300,7 @@
300300
check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_CONSCIOUS | AB_CHECK_LYING
301301
spell_requirements = SPELL_REQUIRES_HUMAN
302302
ranged_mousepointer = 'icons/effects/mouse_pointers/visor_reticule.dmi'
303-
psi_cost = 35
303+
resource_costs = list(ANTAG_RESOURCE_DARKSPAWN = 35)
304304
cooldown_time = 15 SECONDS
305305
cast_range = 2
306306
///Whether or not the user is in the process of "building"

0 commit comments

Comments
 (0)