mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
## About The Pull Request One line change, max(variable,0) means if the variable is negative then it is 0 instead cooldown_remaining can be negative, whether its due to how spell.next_use_time and world.time is measured, or due to something else. This makes sure no blood spell will ever give you free blood back, touch spells are still broken, this PR doesn't change that, they simply do not interact with splattercasting period as of now, which is not intended. Sanguine spells not interacting IS intended. ## Why It's Good For The Game No infinite time stop (via this method, anyway) ## Changelog 🆑 fix: Splattercasting touch spells no longer give infinite blood /🆑
102 lines
4.1 KiB
Plaintext
102 lines
4.1 KiB
Plaintext
///how much we multiply cooldown (deciseconds) by to get the amount of blood to remove.
|
|
///BLOOD_VOLUME_NORMAL is 560, expensive spells max out at around 60 seconds which is 600 deciseconds
|
|
///removing 9/10ths of the cooldown from that puts us at 540 deciseconds, mult by 0.5 gives 270 blood taken
|
|
///one second is worth 5 blood, roughly half of your normal amount of blood taken for a huge spell, seems fair
|
|
#define COOLDOWN_TO_BLOOD_RATIO 0.5
|
|
|
|
/**
|
|
* # splattercasting component!
|
|
*
|
|
* Component that makes casted spells cost blood from the user and dramatically lowers their cooldown.
|
|
*/
|
|
/datum/component/splattercasting
|
|
|
|
/datum/component/splattercasting/Initialize()
|
|
if(!iscarbon(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
/datum/component/splattercasting/RegisterWithParent()
|
|
. = ..()
|
|
RegisterSignal(parent, COMSIG_SPECIES_LOSS, PROC_REF(on_species_change))
|
|
RegisterSignal(parent, COMSIG_MOB_SPELL_PROJECTILE, PROC_REF(on_spell_projectile))
|
|
RegisterSignal(parent, COMSIG_MOB_BEFORE_SPELL_CAST, PROC_REF(on_before_spell_cast))
|
|
RegisterSignal(parent, COMSIG_MOB_AFTER_SPELL_CAST, PROC_REF(on_after_spell_cast))
|
|
ADD_TRAIT(parent, TRAIT_SPLATTERCASTER, REF(src))
|
|
|
|
/datum/component/splattercasting/UnregisterFromParent()
|
|
. = ..()
|
|
UnregisterSignal(parent, list(COMSIG_SPECIES_LOSS, COMSIG_MOB_SPELL_PROJECTILE, COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_AFTER_SPELL_CAST))
|
|
REMOVE_TRAIT(parent, TRAIT_SPLATTERCASTER, REF(src))
|
|
|
|
///signal sent when a spell casts a projectile
|
|
/datum/component/splattercasting/proc/on_species_change(mob/living/carbon/source, datum/species/lost_species)
|
|
SIGNAL_HANDLER
|
|
qdel(src)
|
|
|
|
///signal sent when the parent casts a spell that has a projectile
|
|
/datum/component/splattercasting/proc/on_spell_projectile(mob/living/carbon/source, datum/action/cooldown/spell/spell, atom/cast_on, obj/projectile/to_fire)
|
|
SIGNAL_HANDLER
|
|
|
|
if(spell.school == SCHOOL_SANGUINE)
|
|
//already has blood themed projectiles
|
|
return
|
|
|
|
playsound(source, 'sound/effects/wounds/splatter.ogg', 60, TRUE, -1)
|
|
to_fire.color = "#ff7070"
|
|
to_fire.name = "blood-[to_fire.name]"
|
|
to_fire.set_light(2, 2, LIGHT_COLOR_BLOOD_MAGIC, l_on = TRUE)
|
|
|
|
///signal sent before parent casts a spell
|
|
/datum/component/splattercasting/proc/on_before_spell_cast(mob/living/carbon/source, datum/action/cooldown/spell/spell, atom/cast_on)
|
|
SIGNAL_HANDLER
|
|
|
|
var/changed_spell = FALSE
|
|
if(!(spell.spell_requirements & SPELL_REQUIRES_NO_ANTIMAGIC))
|
|
spell.spell_requirements |= SPELL_REQUIRES_NO_ANTIMAGIC
|
|
changed_spell = TRUE
|
|
if(!(spell.antimagic_flags & MAGIC_RESISTANCE_HOLY))
|
|
spell.antimagic_flags |= MAGIC_RESISTANCE_HOLY
|
|
changed_spell = TRUE
|
|
|
|
if(changed_spell)
|
|
//we changed some kind of antimagic so we should check if the new version of the spell is still valid.
|
|
//since can_cast_spell has already been checked before "before spell cast" only antimagic check should fail
|
|
if(!spell.can_cast_spell(feedback = TRUE))
|
|
return SPELL_CANCEL_CAST
|
|
|
|
///signal sent after parent casts a spell
|
|
/datum/component/splattercasting/proc/on_after_spell_cast(mob/living/carbon/source, datum/action/cooldown/spell/spell, atom/cast_on)
|
|
SIGNAL_HANDLER
|
|
|
|
if(spell.school == SCHOOL_SANGUINE)
|
|
//allows for sanguine spells that work specially with blood to not interact with splattercasting.
|
|
//might sound weird, but maybe in the future we'll have a spell that adds blood to the user when it hits a target
|
|
//we wouldn't want that to cost blood.
|
|
return
|
|
|
|
//normal cooldown spell has
|
|
var/cooldown_remaining = max(spell.next_use_time - world.time,0)
|
|
//how much we discount, we make the spell cost 1/10th of its actual cooldown
|
|
var/new_cooldown = cooldown_remaining / 10
|
|
//convert how much cooldown that spell saved into blood cost
|
|
var/blood_cost = (cooldown_remaining - new_cooldown ) * COOLDOWN_TO_BLOOD_RATIO
|
|
|
|
spell.StartCooldown(new_cooldown)
|
|
source.blood_volume -= blood_cost
|
|
|
|
var/cost_desc
|
|
|
|
switch(blood_cost)
|
|
if(1 to 50)
|
|
cost_desc = "trickle"
|
|
if(51 to 100)
|
|
cost_desc = "stream"
|
|
if(101 to 200)
|
|
cost_desc = "river"
|
|
if(201 to INFINITY)
|
|
cost_desc = "torrent"
|
|
|
|
to_chat(source, span_danger("You feel a [cost_desc] of your blood drained into the spell you just cast."))
|
|
|
|
#undef COOLDOWN_TO_BLOOD_RATIO
|