From 05011a57c5a38ea210f3c77cc1b4d0c95b08f70a Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Fri, 12 Apr 2024 19:08:10 -0400 Subject: [PATCH] [MIRROR] Blood cult: cleans up blood rites code, fixes a bug or two, & adds blackbox logging for spells, runes, and shades (#1951) * Blood cult: cleans up blood rites code, fixes a bug or two, & adds blackbox logging for spells, runes, and shades (#82444) * Blood cult: cleans up blood rites code, fixes a bug or two, & adds blackbox logging for spells, runes, and shades --------- Co-authored-by: wesoda25 <37246588+wesoda25@users.noreply.github.com> --- code/modules/antagonists/cult/blood_magic.dm | 430 +++++++++++------- code/modules/antagonists/cult/runes.dm | 1 + .../antagonists/wizard/equipment/soulstone.dm | 4 + code/modules/library/bibles.dm | 1 + code/modules/mob/living/basic/cult/shade.dm | 7 + 5 files changed, 271 insertions(+), 172 deletions(-) diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index cbccf1d9ff1..cf79872c947 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -1,3 +1,10 @@ +/// how many units of blood one charge of blood rites is worth +#define USES_TO_BLOOD 2 +/// blood rites charges gained from sapping blood from a victim +#define BLOOD_DRAIN_GAIN 50 +/// penalty for self healing, 1 point of damage * this # = charges required +#define SELF_HEAL_PENALTY 1.65 + /datum/action/innate/cult/blood_magic //Blood magic handles the creation of blood spells (formerly talismans) name = "Prepare Blood Magic" button_icon_state = "carve" @@ -103,6 +110,8 @@ var/health_cost = 0 /// Have we already been positioned into our starting location? var/positioned = FALSE + /// If false, the spell will not delete after running out of charges + var/deletes_on_empty = TRUE /datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM) if(health_cost) @@ -121,26 +130,25 @@ ..() /datum/action/innate/cult/blood_spell/IsAvailable(feedback = FALSE) - if(!IS_CULTIST(owner) || owner.incapacitated() || !charges) + if(!IS_CULTIST(owner) || owner.incapacitated() || (!charges && deletes_on_empty)) return FALSE return ..() /datum/action/innate/cult/blood_spell/Activate() - if(magic_path) //If this spell flows from the hand - if(!hand_magic) - hand_magic = new magic_path(owner, src) - if(!owner.put_in_hands(hand_magic)) - qdel(hand_magic) - hand_magic = null - to_chat(owner, span_warning("You have no empty hand for invoking blood magic!")) - return - to_chat(owner, span_notice("Your wounds glow as you invoke the [name].")) - return - if(hand_magic) - qdel(hand_magic) - hand_magic = null - to_chat(owner, span_warning("You snuff out the spell, saving it for later.")) - + if(!magic_path) // only concerned with spells that flow from the hand + return + if(hand_magic) + qdel(hand_magic) + hand_magic = null + to_chat(owner, span_warning("You snuff out the spell, saving it for later.")) + return + hand_magic = new magic_path(owner, src) + if(!owner.put_in_hands(hand_magic)) + qdel(hand_magic) + hand_magic = null + to_chat(owner, span_warning("You have no empty hand for invoking blood magic!")) + return + to_chat(owner, span_notice("Your wounds glow as you invoke the [name].")) //Cult Blood Spells /datum/action/innate/cult/blood_spell/stun @@ -170,6 +178,7 @@ span_cult_italic("You speak the cursed words, emitting an EMP blast from your hand.")) empulse(owner, 2, 5) charges-- + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) qdel(src) @@ -214,6 +223,7 @@ span_cult_italic("A [summoned_blade] materializes at your feet.")) SEND_SOUND(owner, sound('sound/effects/magic.ogg', FALSE, 0, 25)) charges-- + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) qdel(src) @@ -255,6 +265,7 @@ desc = base_desc desc += "
Has [charges] use\s remaining." build_all_button_icons() + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") if(charges <= 0) to_chat(caller, span_cult("You have exhausted the spell's power!")) qdel(src) @@ -308,6 +319,7 @@ revealing = FALSE name = "Conceal Runes" button_icon_state = "gone" + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "Conceal Runes") if(charges <= 0) qdel(src) desc = base_desc @@ -321,6 +333,7 @@ button_icon_state = "manip" charges = 5 magic_path = "/obj/item/melee/blood_magic/manipulator" + deletes_on_empty = FALSE // The "magic hand" items /obj/item/melee/blood_magic @@ -350,7 +363,7 @@ /obj/item/melee/blood_magic/Destroy() if(!QDELETED(source)) - if(uses <= 0) + if(uses <= 0 && source.deletes_on_empty) source.hand_magic = null qdel(source) source = null @@ -371,6 +384,7 @@ qdel(src) return log_combat(user, M, "used a cult spell on", source.name, "") + SSblackbox.record_feedback("tally", "cult_spell_invoke", 1, "[name]") M.lastattacker = user.real_name M.lastattackerckey = user.ckey @@ -681,167 +695,235 @@ . = ..() . += "Bloody halberd, blood bolt barrage, and blood beam cost [BLOOD_HALBERD_COST], [BLOOD_BARRAGE_COST], and [BLOOD_BEAM_COST] charges respectively." +/** + * handles inhand use of blood rites on constructs, humans, or non-living blood sources + * + * see '/obj/item/melee/blood_magic/manipulator/proc/heal_construct' for construct/shade behavior + * see '/obj/item/melee/blood_magic/manipulator/proc/heal_cultist' for human cultist behavior + * see '/obj/item/melee/blood_magic/manipulator/proc/drain_victim' for human non-cultist behavior + * if any of the above procs return FALSE, '/obj/item/melee/blood_magic/afterattack' will not be called + * + * '/obj/item/melee/blood_magic/manipulator/proc/blood_draw' handles blood pools/trails and does not affect parent proc + */ /obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity) - if(proximity) - if(ishuman(target)) - var/mob/living/carbon/human/human_bloodbag = target - if(HAS_TRAIT(human_bloodbag, TRAIT_NOBLOOD)) - to_chat(user,span_warning("Blood rites do not work on people with no blood!")) - return - if(IS_CULTIST(human_bloodbag)) - if(human_bloodbag.stat == DEAD) - to_chat(user,span_warning("Only a revive rune can bring back the dead!")) - return - if(human_bloodbag.blood_volume < BLOOD_VOLUME_SAFE) - var/restore_blood = BLOOD_VOLUME_SAFE - human_bloodbag.blood_volume - if(uses*2 < restore_blood) - human_bloodbag.blood_volume += uses*2 - to_chat(user,span_danger("You use the last of your blood rites to restore what blood you could!")) - uses = 0 - return ..() - else - human_bloodbag.blood_volume = BLOOD_VOLUME_SAFE - uses -= round(restore_blood/2) - to_chat(user,span_warning("Your blood rites have restored [human_bloodbag == user ? "your" : "[human_bloodbag.p_their()]"] blood to safe levels!")) - var/overall_damage = human_bloodbag.getBruteLoss() + human_bloodbag.getFireLoss() + human_bloodbag.getToxLoss() + human_bloodbag.getOxyLoss() - if(overall_damage == 0) - to_chat(user,span_cult("That cultist doesn't require healing!")) - else - var/ratio = uses/overall_damage - if(human_bloodbag == user) - to_chat(user,span_cult("Your blood healing is far less efficient when used on yourself!")) - ratio *= 0.35 // Healing is half as effective if you can't perform a full heal - uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal - if(ratio>1) - ratio = 1 - uses -= round(overall_damage) - human_bloodbag.visible_message(span_warning("[human_bloodbag] is fully healed by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic!")) - else - human_bloodbag.visible_message(span_warning("[human_bloodbag] is partially healed by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic.")) - uses = 0 - ratio *= -1 - var/need_mob_update = FALSE - need_mob_update += human_bloodbag.adjustOxyLoss((overall_damage*ratio) * (human_bloodbag.getOxyLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustToxLoss((overall_damage*ratio) * (human_bloodbag.getToxLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustFireLoss((overall_damage*ratio) * (human_bloodbag.getFireLoss() / overall_damage), updating_health = FALSE) - need_mob_update += human_bloodbag.adjustBruteLoss((overall_damage*ratio) * (human_bloodbag.getBruteLoss() / overall_damage), updating_health = FALSE) - if(need_mob_update) - human_bloodbag.updatehealth() - playsound(get_turf(human_bloodbag), 'sound/magic/staff_healing.ogg', 25) - new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) - user.Beam(human_bloodbag, icon_state="sendbeam", time = 15) - else - if(human_bloodbag.stat == DEAD) - to_chat(user,span_warning("[human_bloodbag.p_Their()] blood has stopped flowing, you'll have to find another way to extract it.")) - return - if(human_bloodbag.has_status_effect(/datum/status_effect/speech/slurring/cult)) - to_chat(user,span_danger("[human_bloodbag.p_Their()] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")) - return - if(human_bloodbag.blood_volume > BLOOD_VOLUME_SAFE) - human_bloodbag.blood_volume -= 100 - uses += 50 - user.Beam(human_bloodbag, icon_state="drainbeam", time = 1 SECONDS) - playsound(get_turf(human_bloodbag), 'sound/magic/enter_blood.ogg', 50) - human_bloodbag.visible_message(span_danger("[user] drains some of [human_bloodbag]'s blood!")) - to_chat(user,span_cult_italic("Your blood rite gains 50 charges from draining [human_bloodbag]'s blood.")) - new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) - else - to_chat(user,span_warning("[human_bloodbag.p_Theyre()] missing too much blood - you cannot drain [human_bloodbag.p_them()] further!")) - return - if(isconstruct(target)) - var/mob/living/basic/construct/construct_thing = target - var/missing_health = construct_thing.maxHealth - construct_thing.health - if(missing_health) - if(uses > missing_health) - construct_thing.adjust_health(-missing_health) - construct_thing.visible_message(span_warning("[construct_thing] is fully healed by [user]'s blood magic!")) - uses -= missing_health - else - construct_thing.adjust_health(-uses) - construct_thing.visible_message(span_warning("[construct_thing] is partially healed by [user]'s blood magic!")) - uses = 0 - playsound(get_turf(construct_thing), 'sound/magic/staff_healing.ogg', 25) - user.Beam(construct_thing, icon_state="sendbeam", time = 1 SECONDS) - if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target)) - blood_draw(target, user) - ..() + if(!proximity) + return + + if((isconstruct(target) || isshade(target)) && !heal_construct(target, user)) + return + if(istype(target, /obj/effect/decal/cleanable/blood) || istype(target, /obj/effect/decal/cleanable/trail_holder) || isturf(target)) + blood_draw(target, user) + if(ishuman(target)) + var/mob/living/carbon/human/human_bloodbag = target + if(HAS_TRAIT(human_bloodbag, TRAIT_NOBLOOD)) + human_bloodbag.balloon_alert(user, "no blood!") + return + if(human_bloodbag.stat == DEAD) + human_bloodbag.balloon_alert(user, "dead!") + return + + if(IS_CULTIST(human_bloodbag) && !heal_cultist(human_bloodbag, user)) + return + if(!IS_CULTIST(human_bloodbag) && !drain_victim(human_bloodbag, user)) + return + ..() + +/** + * handles blood rites usage on constructs + * + * will only return TRUE if some amount healing is done + */ +/obj/item/melee/blood_magic/manipulator/proc/heal_construct(atom/target, mob/living/carbon/human/user) + var/mob/living/basic/construct_thing = target + if(!IS_CULTIST(construct_thing)) + return FALSE + var/missing_health = construct_thing.maxHealth - construct_thing.health + if(!missing_health) + to_chat(user,span_cult("That cultist doesn't require healing!")) + return FALSE + if(uses <= 0) + construct_thing.balloon_alert(user, "out of blood!") + return FALSE + if(uses > missing_health) + construct_thing.adjust_health(-missing_health) + construct_thing.visible_message(span_warning("[construct_thing] is fully healed by [user]'s blood magic!")) + uses -= missing_health + else + construct_thing.adjust_health(-uses) + construct_thing.visible_message(span_warning("[construct_thing] is partially healed by [user]'s blood magic!")) + uses = 0 + playsound(get_turf(construct_thing), 'sound/magic/staff_healing.ogg', 25) + user.Beam(construct_thing, icon_state="sendbeam", time = 1 SECONDS) + return TRUE + +/** + * handles blood rites usage on human cultists + * + * first restores blood, then heals damage. healing damage is more expensive, especially if performed on oneself + * returns TRUE if some amount of blood is restored and/or damage is healed + */ +/obj/item/melee/blood_magic/manipulator/proc/heal_cultist(mob/living/carbon/human/human_bloodbag, mob/living/carbon/human/user) + if(uses <= 0) + human_bloodbag.balloon_alert(user, "out of blood!") + return FALSE + + /// used to ensure the proc returns TRUE if we completely restore an undamaged persons blood + var/blood_donor = FALSE + if(human_bloodbag.blood_volume < BLOOD_VOLUME_SAFE) + var/blood_needed = BLOOD_VOLUME_SAFE - human_bloodbag.blood_volume + /// how much blood we are capable of restoring, based on spell charges + var/blood_bank = USES_TO_BLOOD * uses + if(blood_bank < blood_needed) + human_bloodbag.blood_volume += blood_bank + to_chat(user,span_danger("You use the last of your blood rites to restore what blood you could!")) + uses = 0 + return TRUE + blood_donor = TRUE + human_bloodbag.blood_volume = BLOOD_VOLUME_SAFE + uses -= round(blood_needed / USES_TO_BLOOD) + to_chat(user,span_warning("Your blood rites have restored [human_bloodbag == user ? "your" : "[human_bloodbag.p_their()]"] blood to safe levels!")) + + var/overall_damage = human_bloodbag.getBruteLoss() + human_bloodbag.getFireLoss() + human_bloodbag.getToxLoss() + human_bloodbag.getOxyLoss() + if(overall_damage == 0) + if(blood_donor) + return TRUE + to_chat(user,span_cult("That cultist doesn't require healing!")) + return FALSE + /// how much damage we can/will heal + var/damage_healed = -1 * min(uses, overall_damage) + /// how many spell charges will be consumed to heal said damage + var/healing_cost = damage_healed + if(human_bloodbag == user) + to_chat(user,span_cult("Your blood healing is far less efficient when used on yourself!")) + damage_healed = -1 * min(uses * (1 / SELF_HEAL_PENALTY), overall_damage) + healing_cost = damage_healed * SELF_HEAL_PENALTY + uses += round(healing_cost) + human_bloodbag.visible_message(span_warning("[human_bloodbag] is [uses == 0 ? "partially healed":"fully healed"] by [human_bloodbag == user ? "[human_bloodbag.p_their()]":"[human_bloodbag]'s"] blood magic!")) + + var/need_mob_update = FALSE + need_mob_update += human_bloodbag.adjustOxyLoss(damage_healed * (human_bloodbag.getOxyLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustToxLoss(damage_healed * (human_bloodbag.getToxLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustFireLoss(damage_healed * (human_bloodbag.getFireLoss() / overall_damage), updating_health = FALSE) + need_mob_update += human_bloodbag.adjustBruteLoss(damage_healed * (human_bloodbag.getBruteLoss() / overall_damage), updating_health = FALSE) + if(need_mob_update) + human_bloodbag.updatehealth() + playsound(get_turf(human_bloodbag), 'sound/magic/staff_healing.ogg', 25) + new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) + user.Beam(human_bloodbag, icon_state="sendbeam", time = 15) + return TRUE + +/** + * handles blood rites use on a non-cultist human + * + * returns TRUE if blood is successfully drained from the victim + */ +/obj/item/melee/blood_magic/manipulator/proc/drain_victim(mob/living/carbon/human/human_bloodbag, mob/living/carbon/human/user) + if(human_bloodbag.has_status_effect(/datum/status_effect/speech/slurring/cult)) + to_chat(user,span_danger("[human_bloodbag.p_Their()] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")) + return FALSE + if(human_bloodbag.blood_volume <= BLOOD_VOLUME_SAFE) + to_chat(user,span_warning("[human_bloodbag.p_Theyre()] missing too much blood - you cannot drain [human_bloodbag.p_them()] further!")) + return FALSE + human_bloodbag.blood_volume -= BLOOD_DRAIN_GAIN * USES_TO_BLOOD + uses += BLOOD_DRAIN_GAIN + user.Beam(human_bloodbag, icon_state="drainbeam", time = 1 SECONDS) + playsound(get_turf(human_bloodbag), 'sound/magic/enter_blood.ogg', 50) + human_bloodbag.visible_message(span_danger("[user] drains some of [human_bloodbag]'s blood!")) + to_chat(user,span_cult_italic("Your blood rite gains 50 charges from draining [human_bloodbag]'s blood.")) + new /obj/effect/temp_visual/cult/sparks(get_turf(human_bloodbag)) + return TRUE +/** + * handles blood rites use on turfs, blood pools, and blood trails + */ /obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) var/blood_to_gain = 0 var/turf/our_turf = get_turf(target) - if(our_turf) - for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) - if(blood_around_us.blood_state == BLOOD_STATE_HUMAN) - if(blood_around_us.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam - blood_to_gain += 30 - else - blood_to_gain += max((blood_around_us.bloodiness**2)/800,1) - new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) - qdel(blood_around_us) - for(var/obj/effect/decal/cleanable/trail_holder/trail_around_us in range(our_turf, 2)) - if(trail_around_us.blood_state == BLOOD_STATE_HUMAN) - blood_to_gain += 5 //These don't get bloodiness, so we'll just increase this by a fixed value - new /obj/effect/temp_visual/cult/turf/floor(get_turf(trail_around_us)) - qdel(trail_around_us) - if(blood_to_gain) - user.Beam(our_turf,icon_state="drainbeam", time = 15) - new /obj/effect/temp_visual/cult/sparks(get_turf(user)) - playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) - to_chat(user, span_cult_italic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) - uses += max(1, round(blood_to_gain)) - + if(!our_turf) + return + for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) + if(blood_around_us.blood_state != BLOOD_STATE_HUMAN) + break + if(blood_around_us.bloodiness == 100) // Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam + blood_to_gain += 30 + else + blood_to_gain += max((blood_around_us.bloodiness**2)/800,1) + new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) + qdel(blood_around_us) + for(var/obj/effect/decal/cleanable/trail_holder/trail_around_us in range(our_turf, 2)) + if(trail_around_us.blood_state != BLOOD_STATE_HUMAN) + break + blood_to_gain += 5 //These don't get bloodiness, so we'll just increase this by a fixed value + new /obj/effect/temp_visual/cult/turf/floor(get_turf(trail_around_us)) + qdel(trail_around_us) + + if(!blood_to_gain) + return + user.Beam(our_turf,icon_state="drainbeam", time = 15) + new /obj/effect/temp_visual/cult/sparks(get_turf(user)) + playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) + to_chat(user, span_cult_italic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) + uses += max(1, round(blood_to_gain)) + +/** + * handles untargeted use of blood rites + * + * allows user to trade in spell uses for equipment or spells + */ /obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user) - if(IS_CULTIST(user)) - var/static/list/spells = list( - "Bloody Halberd (150)" = image(icon = 'icons/obj/weapons/spear.dmi', icon_state = "occultpoleaxe0"), - "Blood Bolt Barrage (300)" = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "arcane_barrage"), - "Blood Beam (500)" = image(icon = 'icons/obj/weapons/hand.dmi', icon_state = "disintegrate") - ) - var/choice = show_radial_menu(user, src, spells, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE) - if(!check_menu(user)) - to_chat(user, span_cult_italic("You decide against conducting a greater blood rite.")) - return - switch(choice) - if("Bloody Halberd (150)") - if(uses < BLOOD_HALBERD_COST) - to_chat(user, span_cult_italic("You need [BLOOD_HALBERD_COST] charges to perform this rite.")) - else - uses -= BLOOD_HALBERD_COST - var/turf/current_position = get_turf(user) - qdel(src) - var/datum/action/innate/cult/halberd/halberd_act_granted = new(user) - var/obj/item/melee/cultblade/halberd/rite = new(current_position) - halberd_act_granted.Grant(user, rite) - rite.halberd_act = halberd_act_granted - if(user.put_in_hands(rite)) - to_chat(user, span_cult_italic("A [rite.name] appears in your hand!")) - else - user.visible_message(span_warning("A [rite.name] appears at [user]'s feet!"), \ - span_cult_italic("A [rite.name] materializes at your feet.")) - if("Blood Bolt Barrage (300)") - if(uses < BLOOD_BARRAGE_COST) - to_chat(user, span_cult_italic("You need [BLOOD_BARRAGE_COST] charges to perform this rite.")) - else - var/obj/rite = new /obj/item/gun/magic/wand/arcane_barrage/blood() - uses -= BLOOD_BARRAGE_COST - qdel(src) - if(user.put_in_hands(rite)) - to_chat(user, span_cult("Your hands glow with power!")) - else - to_chat(user, span_cult_italic("You need a free hand for this rite!")) - qdel(rite) - if("Blood Beam (500)") - if(uses < BLOOD_BEAM_COST) - to_chat(user, span_cult_italic("You need [BLOOD_BEAM_COST] charges to perform this rite.")) - else - var/obj/rite = new /obj/item/blood_beam() - uses -= BLOOD_BEAM_COST - qdel(src) - if(user.put_in_hands(rite)) - to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!")) - else - to_chat(user, span_cult_italic("You need a free hand for this rite!")) - qdel(rite) + var/static/list/spells = list( + "Bloody Halberd (150)" = image(icon = 'icons/obj/weapons/spear.dmi', icon_state = "occultpoleaxe0"), + "Blood Bolt Barrage (300)" = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "arcane_barrage"), + "Blood Beam (500)" = image(icon = 'icons/obj/weapons/hand.dmi', icon_state = "disintegrate") + ) + var/choice = show_radial_menu(user, src, spells, custom_check = CALLBACK(src, PROC_REF(check_menu), user), require_near = TRUE) + if(!check_menu(user)) + to_chat(user, span_cult_italic("You decide against conducting a greater blood rite.")) + return + + switch(choice) + if("Bloody Halberd (150)") + if(uses < BLOOD_HALBERD_COST) + to_chat(user, span_cult_italic("You need [BLOOD_HALBERD_COST] charges to perform this rite.")) + return + uses -= BLOOD_HALBERD_COST + var/turf/current_position = get_turf(user) + qdel(src) + var/datum/action/innate/cult/halberd/halberd_act_granted = new(user) + var/obj/item/melee/cultblade/halberd/rite = new(current_position) + halberd_act_granted.Grant(user, rite) + rite.halberd_act = halberd_act_granted + if(user.put_in_hands(rite)) + to_chat(user, span_cult_italic("A [rite.name] appears in your hand!")) + else + user.visible_message(span_warning("A [rite.name] appears at [user]'s feet!"), \ + span_cult_italic("A [rite.name] materializes at your feet.")) + + if("Blood Bolt Barrage (300)") + if(uses < BLOOD_BARRAGE_COST) + to_chat(user, span_cult_italic("You need [BLOOD_BARRAGE_COST] charges to perform this rite.")) + return + var/obj/rite = new /obj/item/gun/magic/wand/arcane_barrage/blood() + uses -= BLOOD_BARRAGE_COST + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, span_cult("Your hands glow with power!")) + else + to_chat(user, span_cult_italic("You need a free hand for this rite!")) + qdel(rite) + + if("Blood Beam (500)") + if(uses < BLOOD_BEAM_COST) + to_chat(user, span_cult_italic("You need [BLOOD_BEAM_COST] charges to perform this rite.")) + return + var/obj/rite = new /obj/item/blood_beam() + uses -= BLOOD_BEAM_COST + qdel(src) + if(user.put_in_hands(rite)) + to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!")) + else + to_chat(user, span_cult_italic("You need a free hand for this rite!")) + qdel(rite) /obj/item/melee/blood_magic/manipulator/proc/check_menu(mob/living/user) if(!istype(user)) @@ -849,3 +931,7 @@ if(user.incapacitated() || !user.Adjacent(src)) return FALSE return TRUE + +#undef USES_TO_BLOOD +#undef BLOOD_DRAIN_GAIN +#undef SELF_HEAL_PENALTY diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index d42ace3f4cd..aa979ff7814 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -104,6 +104,7 @@ Runes can either be invoked by one's self or with many different cultists. Each var/list/invokers = can_invoke(user) if(length(invokers) >= req_cultists) invoke(invokers) + SSblackbox.record_feedback("tally", "cult_rune_invoke", 1, "[name]") else to_chat(user, span_danger("You need [req_cultists - length(invokers)] more adjacent cultists to use this rune in such a manner.")) fail_invoke() diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index abceef36f0c..13273d22f6e 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -399,6 +399,7 @@ soulstone_spirit.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation if(IS_CULTIST(user)) soulstone_spirit.mind.add_antag_datum(/datum/antagonist/cult) + SSblackbox.record_feedback("tally", "cult_shade_created", 1) soulstone_spirit.cancel_camera() update_appearance() @@ -459,6 +460,7 @@ if(CONSTRUCT_JUGGERNAUT) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_jugger", 1) return switch(theme) if(THEME_WIZARD) @@ -470,6 +472,7 @@ if(CONSTRUCT_WRAITH) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_wraith", 1) return switch(theme) if(THEME_WIZARD) @@ -481,6 +484,7 @@ if(CONSTRUCT_ARTIFICER) if(IS_CULTIST(creator)) make_new_construct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc + SSblackbox.record_feedback("tally", "cult_shade_to_arti", 1) return switch(theme) if(THEME_WIZARD) diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 656c90d77bb..31630c550a1 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -324,6 +324,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list( if(cultist) cultist.silent = TRUE cultist.on_removal() + SSblackbox.record_feedback("tally", "cult_shade_purified", 1) shade.theme = THEME_HOLY shade.name = "Purified [shade.real_name]" shade.update_appearance(UPDATE_ICON_STATE) diff --git a/code/modules/mob/living/basic/cult/shade.dm b/code/modules/mob/living/basic/cult/shade.dm index fac1d347665..bf6fbe13944 100644 --- a/code/modules/mob/living/basic/cult/shade.dm +++ b/code/modules/mob/living/basic/cult/shade.dm @@ -54,6 +54,8 @@ icon_living = icon_state /mob/living/basic/shade/death() + if(IS_CULTIST(src)) + SSblackbox.record_feedback("tally", "cult_shade_killed", 1) if(death_message == initial(death_message)) death_message = "lets out a contented sigh as [p_their()] form unwinds." ..() @@ -63,6 +65,11 @@ return FALSE return ..() +/mob/living/basic/shade/suicide_log(obj/item/suicide_tool) + if(IS_CULTIST(src)) + SSblackbox.record_feedback("tally", "cult_shade_suicided", 1) + ..() + /mob/living/basic/shade/attackby(obj/item/item, mob/user, params) if(istype(item, /obj/item/soulstone)) var/obj/item/soulstone/stone = item