Skip to content

Commit

Permalink
Changes how Cultists obtain the bastard sword. Instead of sacrificing…
Browse files Browse the repository at this point in the history
… Heretics, you now sacrifice Null Rods, with a caveat. (#80583)

Merry Christmas, I bring Chaplain code.

This PR reworks how cultists obtain the bloody bastard sword.

Instead of sacrificing a Heretic, you gain the bastard sword by
sacrificing a Null Rod that has been used by a holy person to spill
cultist blood.

You can also sacrifice a Null Rod to turn it into a cult blade it if
hasn't spilled any blood, as a means of destroying it.

- Putting a Null Rod over an Offer rune with
   - 0 or 1 cultist crits / kills will transform it into ritual dagger.
   - 2 cultist crits / kills will transform it into longsword.
- 3 or more cultist crits / kills will transform it into the bastard
sword.

This effect does not apply to special null rod types like the Bow or
Scythe implant.

Heretics retain their innate cult stun resistance, and are still
un-convertable.

- Allowing the Cult to get multiple of these things is horrible.
   - This puts a soft-cap on it to 1 under most circumstances.
- This makes obtaining the sword less incredibly easy.
- Heretics require a lot more time and effort to get equipped to pose a
passing chance fighting cultists. As a consequence, it's dead easy to
obtain: `I try to convert a guy 10 minutes into the round, they glow
green, I stab them to death with my dagger. They can do nothing to
defend themself. Free sword.`
- Instead, we put it behind the chaplain, who more often than not is
protected by security.
- Additionally, we put it behind the requirements that the chaplain is
*robust*: a chaplain that has been killing cultists actively.
- This also serves as a "comeback" mechanic, as if a chaplain has been
ripping and tearing through your ranks, but you manage to take them
down, you are rewarded with a strong weapon.

Honestly I would prefer if we straight up removed the sword (or... maybe
nerfed it) but improve, don't remove etc.

:cl: Melbert
balance: Blood cultists can now convert a Null Rod into a cult weapon on
an offer rune. The strength of the weapon it is converted into depends
on how many cultists the Chaplain crit / killed with it. At five or
more, it will turn into a Bastard Sword. Note, sacrificing someone
holding a Null Rod will automatically convert it after they are gibbed.
balance: Heretics no longer produce a Bastard Sword upon cult
conversion. They are still immune to cult stun and cannot be converted
by blood cultists.
/:cl:
  • Loading branch information
MrMelbert authored and KnigTheThrasher committed Jan 15, 2024
1 parent 582cd05 commit c9e586b
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 58 deletions.
23 changes: 23 additions & 0 deletions code/game/objects/items/holy_weapons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
var/chaplain_spawnable = TRUE
/// Short description of what this item is capable of, for radial menu uses.
var/menu_description = "A standard chaplain's weapon. Fits in pockets. Can be worn on the belt."
/// Lazylist, tracks refs()s to all cultists which have been crit or killed by this nullrod.
var/list/cultists_slain

/obj/item/nullrod/Initialize(mapload)
. = ..()
Expand Down Expand Up @@ -59,6 +61,27 @@
user.visible_message(span_suicide("[user] is killing [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to get closer to god!"))
return (BRUTELOSS|FIRELOSS)

/obj/item/nullrod/attack(mob/living/target_mob, mob/living/user, params)
if(!user.mind?.holy_role)
return ..()
if(!IS_CULTIST(target_mob) || istype(target_mob, /mob/living/carbon/human/cult_ghost))
return ..()

var/old_stat = target_mob.stat
. = ..()
if(old_stat < target_mob.stat)
LAZYOR(cultists_slain, REF(target_mob))
return .

/obj/item/nullrod/examine(mob/user)
. = ..()
if(!IS_CULTIST(user) || !GET_ATOM_BLOOD_DNA_LENGTH(src))
return

var/num_slain = LAZYLEN(cultists_slain)
. += span_cultitalic("It has the blood of [num_slain] fallen cultist[num_slain == 1 ? "" : "s"] on it. \
<b>Offering</b> it to Nar'sie will transform it into a [num_slain >= 3 ? "powerful" : "standard"] cult weapon.")

/obj/item/nullrod/godhand
name = "god hand"
desc = "This hand of yours glows with an awesome power!"
Expand Down
136 changes: 89 additions & 47 deletions code/modules/antagonists/cult/runes.dm
Original file line number Diff line number Diff line change
Expand Up @@ -222,52 +222,58 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/convert/invoke(list/invokers)
if(rune_in_use)
return

var/list/myriad_targets = list()
var/turf/T = get_turf(src)
for(var/mob/living/M in T)
if(!IS_CULTIST(M))
myriad_targets |= M
if(!length(myriad_targets))
for(var/mob/living/non_cultist in loc)
if(!IS_CULTIST(non_cultist))
myriad_targets += non_cultist

if(!length(myriad_targets) && !try_spawn_sword())
fail_invoke()
log_game("Offer rune failed - no eligible targets.")
return

rune_in_use = TRUE
visible_message(span_warning("[src] pulses blood red!"))
var/oldcolor = color
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)

var/mob/living/F = invokers[1]
var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/datum/team/cult/Cult_team = C.cult_team
var/is_convertable = is_convertable_to_cult(L,C.cult_team)
if(L.stat != DEAD && is_convertable)
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
if(is_convertable)
do_convert(L, invokers, Cult_team)

if(length(myriad_targets))
var/mob/living/new_convertee = pick(myriad_targets)
var/mob/living/first_invoker = invokers[1]
var/datum/antagonist/cult/first_invoker_datum = first_invoker.mind.has_antag_datum(/datum/antagonist/cult)
var/datum/team/cult/cult_team = first_invoker_datum.get_team()

var/is_convertable = is_convertable_to_cult(new_convertee, cult_team)
if(new_convertee.stat != DEAD && is_convertable)
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
do_convert(new_convertee, invokers, cult_team)

else
invocation = "Barhah hra zar'garis!"
..()
do_sacrifice(new_convertee, invokers, cult_team)

cult_team.check_size() // Triggers the eye glow or aura effects if the cult has grown large enough relative to the crew

else
invocation = "Barhah hra zar'garis!"
..()
do_sacrifice(L, invokers)
animate(src, color = oldcolor, time = 5)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 5)
Cult_team.check_size() // Triggers the eye glow or aura effects if the cult has grown large enough relative to the crew
do_invoke_glow()

animate(src, color = oldcolor, time = 0.5 SECONDS)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.5 SECONDS)
rune_in_use = FALSE

/obj/effect/rune/convert/proc/do_convert(mob/living/convertee, list/invokers, datum/team/cult/cult_team)
ASSERT(convertee.mind)

if(length(invokers) < 2)
for(var/M in invokers)
to_chat(M, span_warning("You need at least two invokers to convert [convertee]!"))
log_game("Offer rune with [convertee] on it failed - tried conversion with one invoker.")
for(var/invoker in invokers)
to_chat(invoker, span_warning("You need at least two invokers to convert [convertee]!"))
return FALSE

if(convertee.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_HOLY, charge_cost = 0)) //No charge_cost because it can be spammed
for(var/M in invokers)
to_chat(M, span_warning("Something is shielding [convertee]'s mind!"))
log_game("Offer rune with [convertee] on it failed - convertee had anti-magic.")
for(var/invoker in invokers)
to_chat(invoker, span_warning("Something is shielding [convertee]'s mind!"))
return FALSE

var/brutedamage = convertee.getBruteLoss()
Expand Down Expand Up @@ -314,19 +320,11 @@ structure_check() searches for nearby cultist structures required for the invoca
convertee.name = convertee.real_name
return TRUE

/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
var/mob/living/first_invoker = invokers[1]
if(!first_invoker)
return FALSE
var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C)
return FALSE

/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers, datum/team/cult/cult_team)
var/big_sac = FALSE
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && length(invokers) < 3)
for(var/M in invokers)
to_chat(M, span_cultitalic("[sacrificial] is too greatly linked to the world! You need three acolytes!"))
log_game("Offer rune with [sacrificial] on it failed - not enough acolytes and target is living or sac target")
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || cult_team.is_sacrifice_target(sacrificial.mind)) && length(invokers) < 3)
for(var/invoker in invokers)
to_chat(invoker, span_cultitalic("[sacrificial] is too greatly linked to the world! You need three acolytes!"))
return FALSE

var/signal_result = SEND_SIGNAL(sacrificial, COMSIG_LIVING_CULT_SACRIFICED, invokers)
Expand All @@ -335,7 +333,7 @@ structure_check() searches for nearby cultist structures required for the invoca

if(sacrificial.mind)
LAZYADD(GLOB.sacrificed, WEAKREF(sacrificial.mind))
for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
for(var/datum/objective/sacrifice/sac_objective in cult_team.objectives)
if(sac_objective.target == sacrificial.mind)
sac_objective.sacced = TRUE
sac_objective.clear_sacrifice()
Expand All @@ -344,7 +342,7 @@ structure_check() searches for nearby cultist structures required for the invoca
else
LAZYADD(GLOB.sacrificed, WEAKREF(sacrificial))

new /obj/effect/temp_visual/cult/sac(get_turf(src))
new /obj/effect/temp_visual/cult/sac(loc)

if(!(signal_result & SILENCE_SACRIFICE_MESSAGE))
for(var/invoker in invokers)
Expand All @@ -357,26 +355,70 @@ structure_check() searches for nearby cultist structures required for the invoca
to_chat(invoker, span_cultlarge("\"I accept this meager sacrifice.\""))

if(iscyborg(sacrificial))
var/construct_class = show_radial_menu(first_invoker, sacrificial, GLOB.construct_radial_images, require_near = TRUE, tooltips = TRUE)
var/construct_class = show_radial_menu(invokers[1], sacrificial, GLOB.construct_radial_images, require_near = TRUE, tooltips = TRUE)
if(QDELETED(sacrificial) || !construct_class)
return FALSE
sacrificial.grab_ghost()
make_new_construct_from_class(construct_class, THEME_CULT, sacrificial, first_invoker, TRUE, get_turf(src))
make_new_construct_from_class(construct_class, THEME_CULT, sacrificial, invokers[1], TRUE, get_turf(src))
var/mob/living/silicon/robot/sacriborg = sacrificial
sacrificial.log_message("was sacrificed as a cyborg.", LOG_GAME)
sacriborg.mmi = null
qdel(sacrificial)
return TRUE
var/obj/item/soulstone/stone = new /obj/item/soulstone(get_turf(src))

var/obj/item/soulstone/stone = new(loc)
if(sacrificial.mind && !HAS_TRAIT(sacrificial, TRAIT_SUICIDED))
stone.capture_soul(sacrificial, first_invoker, TRUE)
stone.capture_soul(sacrificial, invokers[1], forced = TRUE)

if(sacrificial)
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, TRUE)
sacrificial.investigate_log("has been sacrificially gibbed by the cult.", INVESTIGATE_DEATHS)
sacrificial.gib()

try_spawn_sword() // after sharding and gibbing, which potentially dropped a null rod
return TRUE

/// Tries to convert a null rod over the rune to a cult sword
/obj/effect/rune/convert/proc/try_spawn_sword()
for(var/obj/item/nullrod/rod in loc)
if(rod.anchored || (rod.resistance_flags & INDESTRUCTIBLE))
continue

var/num_slain = LAZYLEN(rod.cultists_slain)
var/displayed_message = "[rod] glows an unholy red and begins to transform..."
if(GET_ATOM_BLOOD_DNA_LENGTH(rod))
displayed_message += " The blood of [num_slain] fallen cultist[num_slain == 1 ? "":"s"] is absorbed into [rod]!"

rod.visible_message(span_cultitalic(displayed_message))
switch(num_slain)
if(0, 1)
animate_spawn_sword(rod, /obj/item/melee/cultblade/dagger)
if(2)
animate_spawn_sword(rod, /obj/item/melee/cultblade)
else
animate_spawn_sword(rod, /obj/item/cult_bastard)
return TRUE

return FALSE

/// Does an animation of a null rod transforming into a cult sword
/obj/effect/rune/convert/proc/animate_spawn_sword(obj/item/nullrod/former_rod, new_blade_typepath)
playsound(src, 'sound/effects/magic.ogg', 33, vary = TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, frequency = 0.66)
former_rod.anchored = TRUE
former_rod.Shake()
animate(former_rod, alpha = 0, transform = matrix(former_rod.transform).Scale(0.01), time = 2 SECONDS, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
QDEL_IN(former_rod, 2 SECONDS)

var/obj/item/new_blade = new new_blade_typepath(loc)
var/matrix/blade_matrix_on_spawn = matrix(new_blade.transform)
new_blade.name = "converted [new_blade.name]"
new_blade.anchored = TRUE
new_blade.alpha = 0
new_blade.transform = matrix(new_blade.transform).Scale(0.01)
new_blade.Shake()
animate(new_blade, alpha = 255, transform = blade_matrix_on_spawn, time = 2 SECONDS, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
addtimer(VARSET_CALLBACK(new_blade, anchored, FALSE), 2 SECONDS)

/obj/effect/rune/empower
cultist_name = "Empower"
cultist_desc = "allows cultists to prepare greater amounts of blood magic at far less of a cost."
Expand Down
11 changes: 0 additions & 11 deletions code/modules/antagonists/heretic/heretic_antag.dm
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@
RegisterSignal(our_mob, COMSIG_MOB_ITEM_AFTERATTACK, PROC_REF(on_item_afterattack))
RegisterSignal(our_mob, COMSIG_MOB_LOGIN, PROC_REF(fix_influence_network))
RegisterSignal(our_mob, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(after_fully_healed))
RegisterSignal(our_mob, COMSIG_LIVING_CULT_SACRIFICED, PROC_REF(on_cult_sacrificed))

/datum/antagonist/heretic/remove_innate_effects(mob/living/mob_override)
var/mob/living/our_mob = mob_override || owner.current
Expand All @@ -237,7 +236,6 @@
COMSIG_MOB_ITEM_AFTERATTACK,
COMSIG_MOB_LOGIN,
COMSIG_LIVING_POST_FULLY_HEAL,
COMSIG_LIVING_CULT_SACRIFICED
))

/datum/antagonist/heretic/on_body_transfer(mob/living/old_body, mob/living/new_body)
Expand Down Expand Up @@ -382,15 +380,6 @@
var/datum/heretic_knowledge/living_heart/heart_knowledge = get_knowledge(/datum/heretic_knowledge/living_heart)
heart_knowledge.on_research(source, src)

/// Signal proc for [COMSIG_LIVING_CULT_SACRIFICED] to reward cultists for sacrificing a heretic
/datum/antagonist/heretic/proc/on_cult_sacrificed(mob/living/source, list/invokers)
SIGNAL_HANDLER

new /obj/item/cult_bastard(source.loc)
for(var/mob/living/cultist as anything in invokers)
to_chat(cultist, span_cultlarge("\"A follower of the forgotten gods! You must be rewarded for such a valuable sacrifice.\""))
return SILENCE_SACRIFICE_MESSAGE

/**
* Create our objectives for our heretic.
*/
Expand Down

0 comments on commit c9e586b

Please sign in to comment.