diff --git a/code/__DEFINES/ai/pets.dm b/code/__DEFINES/ai/pets.dm
index c7383f56a00..48d4f2d67d0 100644
--- a/code/__DEFINES/ai/pets.dm
+++ b/code/__DEFINES/ai/pets.dm
@@ -51,6 +51,20 @@
/// key that holds items we arent interested in hoarding
#define BB_IGNORE_ITEMS "ignore_items"
+// Cultist pet keys
+///our ability to summon runes
+#define BB_RUNE_ABILITY "rune_ability"
+///the cult team we serve
+#define BB_CULT_TEAM "cult_team"
+///our dead cultist we revive
+#define BB_DEAD_CULTIST "dead_cultist"
+///nearby runes
+#define BB_NEARBY_RUNE "nearby_rune"
+///occupied runes
+#define BB_OCCUPIED_RUNE "occupied_rune"
+///friendly cultists we befriend
+#define BB_FRIENDLY_CULTIST "friendly_cultist"
+
//virtual pet keys
///the last PDA message we must relay
#define BB_LAST_RECIEVED_MESSAGE "last_recieved_message"
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index d5533dcac54..7a510c9cdee 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -219,6 +219,8 @@ GLOBAL_LIST_INIT(ai_employers, list(
/// Checks if the given mob is a blood cultist
#define IS_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/cult))
+/// Checks if the mob is a sentient or non-sentient cultist
+#define IS_CULTIST_OR_CULTIST_MOB(mob) ((IS_CULTIST(mob)) || (mob.faction.Find(FACTION_CULT)))
/// Checks if the given mob is a changeling
#define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling))
diff --git a/code/__DEFINES/cult.dm b/code/__DEFINES/cult.dm
index 3e0395eab4e..06393d145f8 100644
--- a/code/__DEFINES/cult.dm
+++ b/code/__DEFINES/cult.dm
@@ -36,6 +36,12 @@
/// The global Nar'sie that the cult's summoned
GLOBAL_DATUM(cult_narsie, /obj/narsie)
+///how many sacrifices we have used, cultists get 1 free revive at the start
+GLOBAL_VAR_INIT(sacrifices_used, -SOULS_TO_REVIVE)
+
+/// list of weakrefs to mobs OR minds that have been sacrificed
+GLOBAL_LIST(sacrificed)
+
// Used in determining which cinematic to play when cult ends
#define CULT_VICTORY_MASS_CONVERSION 2
#define CULT_FAILURE_NARSIE_KILLED 1
diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm
index bf918b55efc..0447e87f532 100644
--- a/code/__DEFINES/span.dm
+++ b/code/__DEFINES/span.dm
@@ -38,10 +38,10 @@
#define span_command_headset(str) ("" + str + "")
#define span_comradio(str) ("" + str + "")
#define span_cult(str) ("" + str + "")
-#define span_cultbold(str) ("" + str + "")
-#define span_cultboldtalic(str) ("" + str + "")
-#define span_cultitalic(str) ("" + str + "")
-#define span_cultlarge(str) ("" + str + "")
+#define span_cult_bold(str) ("" + str + "")
+#define span_cult_bold_italic(str) ("" + str + "")
+#define span_cult_italic(str) ("" + str + "")
+#define span_cult_large(str) ("" + str + "")
#define span_danger(str) ("" + str + "")
#define span_deadsay(str) ("" + str + "")
#define span_deconversion_message(str) ("" + str + "")
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 9767173dfdc..348fafebdb4 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -1090,6 +1090,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait which self-identifies as an enemy of the law
#define TRAIT_ALWAYS_WANTED "always_wanted"
+/// Trait given to mobs that have the basic eating element
+#define TRAIT_MOB_EATER "mob_eater"
/// Trait which means whatever has this is dancing by a dance machine
#define TRAIT_DISCO_DANCER "disco_dancer"
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 5ee84733964..358a4b55599 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -295,6 +295,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_MINDSHIELD" = TRAIT_MINDSHIELD,
"TRAIT_MIND_TEMPORARILY_GONE" = TRAIT_MIND_TEMPORARILY_GONE,
"TRAIT_MOB_BREEDER" = TRAIT_MOB_BREEDER,
+ "TRAIT_MOB_EATER" = TRAIT_MOB_EATER,
"TRAIT_MOB_TIPPED" = TRAIT_MOB_TIPPED,
"TRAIT_MORBID" = TRAIT_MORBID,
"TRAIT_MULTIZ_SUIT_SENSORS" = TRAIT_MULTIZ_SUIT_SENSORS,
diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm
new file mode 100644
index 00000000000..9bfc3f85d24
--- /dev/null
+++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm
@@ -0,0 +1,25 @@
+/datum/ai_behavior/pull_target
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION | AI_BEHAVIOR_REQUIRE_REACH
+
+/datum/ai_behavior/pull_target/setup(datum/ai_controller/controller, target_key)
+ . = ..()
+ var/atom/target = controller.blackboard[target_key]
+ if(QDELETED(target))
+ return FALSE
+ set_movement_target(controller, target)
+
+/datum/ai_behavior/pull_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
+ . = ..()
+
+ var/atom/movable/target = controller.blackboard[target_key]
+ if(QDELETED(target) || target.anchored || target.pulledby)
+ finish_action(controller, FALSE, target_key)
+ return
+ var/mob/living/our_mob = controller.pawn
+ our_mob.start_pulling(target)
+ finish_action(controller, TRUE, target_key)
+
+/datum/ai_behavior/pull_target/finish_action(datum/ai_controller/controller, succeeded, target_key)
+ . = ..()
+ if(!succeeded)
+ controller.clear_blackboard_key(target_key)
diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm
index c3acb0b9467..74bac463e32 100644
--- a/code/datums/components/cult_ritual_item.dm
+++ b/code/datums/components/cult_ritual_item.dm
@@ -283,13 +283,13 @@
return FALSE
if(ispath(rune_to_scribe, /obj/effect/rune/summon) && (!is_station_level(our_turf.z) || istype(get_area(cultist), /area/space)))
- to_chat(cultist, span_cultitalic("The veil is not weak enough here to summon a cultist, you must be on station!"))
+ to_chat(cultist, span_cult_italic("The veil is not weak enough here to summon a cultist, you must be on station!"))
return
if(ispath(rune_to_scribe, /obj/effect/rune/apocalypse))
if((world.time - SSticker.round_start_time) <= 6000)
var/wait = 6000 - (world.time - SSticker.round_start_time)
- to_chat(cultist, span_cultitalic("The veil is not yet weak enough for this rune - it will be available in [DisplayTimeText(wait)]."))
+ to_chat(cultist, span_cult_italic("The veil is not yet weak enough for this rune - it will be available in [DisplayTimeText(wait)]."))
return
if(!check_if_in_ritual_site(cultist, user_team, TRUE))
return
@@ -359,7 +359,7 @@
to_chat(cultist, span_warning("The sacrifice is not complete. The portal would lack the power to open if you tried!"))
return FALSE
if(summon_objective.check_completion())
- to_chat(cultist, span_cultlarge("\"I am already here. There is no need to try to summon me now.\""))
+ to_chat(cultist, span_cult_large("\"I am already here. There is no need to try to summon me now.\""))
return FALSE
var/confirm_final = tgui_alert(cultist, "This is the FINAL step to summon Nar'Sie; it is a long, painful ritual and the crew will be alerted to your presence.", "Are you prepared for the final battle?", list("My life for Nar'Sie!", "No"))
if(confirm_final == "No")
diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm
index 2a7a4b46598..757fd8b3519 100644
--- a/code/datums/elements/basic_eating.dm
+++ b/code/datums/elements/basic_eating.dm
@@ -23,6 +23,7 @@
if(!isliving(target))
return ELEMENT_INCOMPATIBLE
+ ADD_TRAIT(target, TRAIT_MOB_EATER, REF(src))
src.heal_amt = heal_amt
src.damage_amount = damage_amount
src.damage_type = damage_type
@@ -35,6 +36,7 @@
RegisterSignal(target, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_pre_attackingtarget))
/datum/element/basic_eating/Detach(datum/target)
+ REMOVE_TRAIT(target, TRAIT_MOB_EATER, REF(src))
UnregisterSignal(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET))
return ..()
diff --git a/code/game/objects/items/stacks/sheets/runed_metal.dm b/code/game/objects/items/stacks/sheets/runed_metal.dm
index a1febc091b7..b60cd67d389 100644
--- a/code/game/objects/items/stacks/sheets/runed_metal.dm
+++ b/code/game/objects/items/stacks/sheets/runed_metal.dm
@@ -8,7 +8,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_solid_ground = TRUE, \
- desc = span_cultbold("Pylon: Heals and regenerates the blood of nearby blood cultists and constructs, and also \
+ desc = span_cult_bold("Pylon: Heals and regenerates the blood of nearby blood cultists and constructs, and also \
converts nearby floor tiles into engraved flooring, which allows blood cultists to scribe runes faster."), \
required_noun = "runed metal sheet", \
category = CAT_CULT, \
@@ -20,7 +20,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_solid_ground = TRUE, \
- desc = span_cultbold("Altar: Can make Eldritch Whetstones, Construct Shells, and Flasks of Unholy Water."), \
+ desc = span_cult_bold("Altar: Can make Eldritch Whetstones, Construct Shells, and Flasks of Unholy Water."), \
required_noun = "runed metal sheet", \
category = CAT_CULT, \
), \
@@ -31,7 +31,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_solid_ground = TRUE, \
- desc = span_cultbold("Archives: Can make Zealot's Blindfolds, Shuttle Curse Orbs, \
+ desc = span_cult_bold("Archives: Can make Zealot's Blindfolds, Shuttle Curse Orbs, \
and Veil Walker equipment. Emits Light."), \
required_noun = "runed metal sheet", \
category = CAT_CULT, \
@@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \
time = 4 SECONDS, \
one_per_turf = TRUE, \
on_solid_ground = TRUE, \
- desc = span_cultbold("Daemon Forge: Can make Nar'Sien Hardened Armor, Flagellant's Robes, \
+ desc = span_cult_bold("Daemon Forge: Can make Nar'Sien Hardened Armor, Flagellant's Robes, \
and Eldritch Longswords. Emits Light."), \
required_noun = "runed metal sheet", \
category = CAT_CULT, \
@@ -54,7 +54,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \
time = 5 SECONDS, \
one_per_turf = TRUE, \
on_solid_ground = TRUE, \
- desc = span_cultbold("Runed Door: A weak door which stuns non-blood cultists who touch it."), \
+ desc = span_cult_bold("Runed Door: A weak door which stuns non-blood cultists who touch it."), \
required_noun = "runed metal sheet", \
category = CAT_CULT, \
), \
@@ -64,7 +64,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list( \
time = 5 SECONDS, \
one_per_turf = TRUE, \
on_solid_ground = TRUE, \
- desc = span_cultbold("Runed Girder: A weak girder that can be instantly destroyed by ritual daggers. Not a recommended usage of runed metal."), \
+ desc = span_cult_bold("Runed Girder: A weak girder that can be instantly destroyed by ritual daggers. Not a recommended usage of runed metal."), \
required_noun = "runed metal sheet", \
category = CAT_CULT, \
), \
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 015fed21360..3d3f2a31f58 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -46,9 +46,9 @@
limit = MAX_BLOODCHARGE
if(length(spells) >= limit)
if(rune)
- to_chat(owner, span_cultitalic("You cannot store more than [MAX_BLOODCHARGE] spells. Pick a spell to remove."))
+ to_chat(owner, span_cult_italic("You cannot store more than [MAX_BLOODCHARGE] spells. Pick a spell to remove."))
else
- to_chat(owner, span_cultitalic("You cannot store more than [RUNELESS_MAX_BLOODCHARGE] spells without an empowering rune! Pick a spell to remove."))
+ to_chat(owner, span_cult_bold_italic("You cannot store more than [RUNELESS_MAX_BLOODCHARGE] spells without an empowering rune! Pick a spell to remove."))
var/nullify_spell = tgui_input_list(owner, "Spell to remove", "Current Spells", spells)
if(isnull(nullify_spell))
return
@@ -77,7 +77,7 @@
if(!channeling)
channeling = TRUE
else
- to_chat(owner, span_cultitalic("You are already invoking blood magic!"))
+ to_chat(owner, span_cult_italic("You are already invoking blood magic!"))
return
if(do_after(owner, 100 - rune*60, target = owner))
if(ishuman(owner))
@@ -167,7 +167,7 @@
/datum/action/innate/cult/blood_spell/emp/Activate()
owner.whisper(invocation, language = /datum/language/common)
owner.visible_message(span_warning("[owner]'s hand flashes a bright blue!"), \
- span_cultitalic("You speak the cursed words, emitting an EMP blast from your hand."))
+ span_cult_italic("You speak the cursed words, emitting an EMP blast from your hand."))
empulse(owner, 2, 5)
charges--
if(charges <= 0)
@@ -205,13 +205,13 @@
var/turf/owner_turf = get_turf(owner)
owner.whisper(invocation, language = /datum/language/common)
owner.visible_message(span_warning("[owner]'s hand glows red for a moment."), \
- span_cultitalic("Your plea for aid is answered, and light begins to shimmer and take form within your hand!"))
+ span_cult_italic("Your plea for aid is answered, and light begins to shimmer and take form within your hand!"))
var/obj/item/summoned_blade = new summoned_type(owner_turf)
if(owner.put_in_hands(summoned_blade))
to_chat(owner, span_warning("A [summoned_blade] appears in your hand!"))
else
owner.visible_message(span_warning("A [summoned_blade] appears at [owner]'s feet!"), \
- span_cultitalic("A [summoned_blade] materializes at your feet."))
+ span_cult_italic("A [summoned_blade] materializes at your feet."))
SEND_SOUND(owner, sound('sound/effects/magic.ogg', FALSE, 0, 25))
charges--
if(charges <= 0)
@@ -249,7 +249,7 @@
clicked_on.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", sparkle_image, NONE)
addtimer(CALLBACK(clicked_on, TYPE_PROC_REF(/atom/, remove_alt_appearance), "cult_apoc", TRUE), 4 MINUTES, TIMER_OVERRIDE|TIMER_UNIQUE)
- to_chat(caller, span_cultbold("[clicked_on] has been cursed with living nightmares!"))
+ to_chat(caller, span_cult_bold("[clicked_on] has been cursed with living nightmares!"))
charges--
desc = base_desc
@@ -272,7 +272,7 @@
/datum/action/innate/cult/blood_spell/veiling/Activate()
if(!revealing)
owner.visible_message(span_warning("Thin grey dust falls from [owner]'s hand!"), \
- span_cultitalic("You invoke the veiling spell, hiding nearby runes."))
+ span_cult_italic("You invoke the veiling spell, hiding nearby runes."))
charges--
SEND_SOUND(owner, sound('sound/magic/smoke.ogg',0,1,25))
owner.whisper(invocation, language = /datum/language/common)
@@ -291,7 +291,7 @@
button_icon_state = "back"
else
owner.visible_message(span_warning("A flash of light shines from [owner]'s hand!"), \
- span_cultitalic("You invoke the counterspell, revealing nearby runes."))
+ span_cult_italic("You invoke the counterspell, revealing nearby runes."))
charges--
owner.whisper(invocation, language = /datum/language/common)
SEND_SOUND(owner, sound('sound/magic/enter_blood.ogg',0,1,25))
@@ -404,7 +404,7 @@
return
if(IS_CULTIST(user))
user.visible_message(span_warning("[user] holds up [user.p_their()] hand, which explodes in a flash of red light!"), \
- span_cultitalic("You attempt to stun [target] with the spell!"))
+ span_cult_italic("You attempt to stun [target] with the spell!"))
user.mob_light(range = 1.1, power = 2, color = LIGHT_COLOR_BLOOD_MAGIC, duration = 0.2 SECONDS)
if(IS_HERETIC(target))
to_chat(user, span_warning("Some force greater than you intervenes! [target] is protected by the Forgotten Gods!"))
@@ -425,7 +425,7 @@
else if(target.can_block_magic())
to_chat(user, span_warning("The spell had no effect!"))
else
- to_chat(user, span_cultitalic("In a brilliant flash of red, [target] falls to the ground!"))
+ to_chat(user, span_cult_italic("In a brilliant flash of red, [target] falls to the ground!"))
target.Paralyze(16 SECONDS)
target.flash_act(1, TRUE)
if(issilicon(target))
@@ -464,7 +464,7 @@
var/turf/T = get_turf(src)
if(is_away_level(T.z))
- to_chat(user, span_cultitalic("You are not in the right dimension!"))
+ to_chat(user, span_cult_italic("You are not in the right dimension!"))
return
var/input_rune_key = tgui_input_list(user, "Rune to teleport to", "Teleportation Target", potential_runes) //we know what key they picked
@@ -485,7 +485,7 @@
var/mob/living/L = target
if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
origin.visible_message(span_warning("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!"), \
- span_cultitalic("You speak the words of the talisman and find yourself somewhere else!"), "You hear a sharp crack.")
+ span_cult_italic("You speak the words of the talisman and find yourself somewhere else!"), "You hear a sharp crack.")
dest.visible_message(span_warning("There is a boom of outrushing air as something appears above the rune!"), null, "You hear a boom.")
..()
@@ -502,7 +502,7 @@
if(C.canBeHandcuffed())
CuffAttack(C, user)
else
- user.visible_message(span_cultitalic("This victim doesn't have enough arms to complete the restraint!"))
+ user.visible_message(span_cult_italic("This victim doesn't have enough arms to complete the restraint!"))
return
..()
@@ -560,7 +560,7 @@
/obj/item/melee/blood_magic/construction/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(proximity_flag && IS_CULTIST(user))
if(channeling)
- to_chat(user, span_cultitalic("You are already invoking twisted construction!"))
+ to_chat(user, span_cult_italic("You are already invoking twisted construction!"))
return
. |= AFTERATTACK_PROCESSED_ITEM
var/turf/T = get_turf(target)
@@ -743,7 +743,7 @@
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_cultitalic("Your blood rite gains 50 charges from draining [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!"))
@@ -787,7 +787,7 @@
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_cultitalic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!"))
+ 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))
/obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user)
@@ -799,12 +799,12 @@
)
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_cultitalic("You decide against conducting a greater blood rite."))
+ 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_cultitalic("You need [BLOOD_HALBERD_COST] charges to perform this rite."))
+ 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)
@@ -814,13 +814,13 @@
halberd_act_granted.Grant(user, rite)
rite.halberd_act = halberd_act_granted
if(user.put_in_hands(rite))
- to_chat(user, span_cultitalic("A [rite.name] appears in your hand!"))
+ 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_cultitalic("A [rite.name] materializes at your 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_cultitalic("You need [BLOOD_BARRAGE_COST] charges to perform this rite."))
+ 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
@@ -828,19 +828,19 @@
if(user.put_in_hands(rite))
to_chat(user, span_cult("Your hands glow with power!"))
else
- to_chat(user, span_cultitalic("You need a free hand for this rite!"))
+ 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_cultitalic("You need [BLOOD_BEAM_COST] charges to perform this rite."))
+ 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_cultlarge("Your hands glow with POWER OVERWHELMING!!!"))
+ to_chat(user, span_cult_large("Your hands glow with POWER OVERWHELMING!!!"))
else
- to_chat(user, span_cultitalic("You need a free hand for this rite!"))
+ 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)
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index d9418bb1010..e6faa911ee4 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -202,10 +202,10 @@
for(var/datum/mind/cult_mind as anything in cult_team.members)
var/datum/antagonist/cult/cult_datum = cult_mind.has_antag_datum(/datum/antagonist/cult)
cult_datum.vote_ability.Remove(cult_mind.current)
- to_chat(cult_mind.current, span_cultlarge("[owner.current] has won the cult's support and is now their master. \
+ to_chat(cult_mind.current, span_cult_large("[owner.current] has won the cult's support and is now their master. \
Follow [owner.current.p_their()] orders to the best of your ability!"))
- to_chat(owner.current, span_cultlarge("You are the cult's Master. \
+ to_chat(owner.current, span_cult_large("You are the cult's Master. \
As the cult's Master, you have a unique title and loud voice when communicating, are capable of marking \
targets, such as a location or a noncultist, to direct the cult to them, and, finally, you are capable of \
summoning the entire living cult to your location once. Use these abilities to direct the cult \
@@ -238,7 +238,7 @@
var/datum/antagonist/cult/cult_datum = cult_mind.has_antag_datum(/datum/antagonist/cult)
cult_datum.vote_ability.Grant(cult_mind.current)
- to_chat(owner.current, span_cultlarge("You have been demoted from being the cult's Master, you are now an acolyte once more!"))
+ to_chat(owner.current, span_cult_large("You have been demoted from being the cult's Master, you are now an acolyte once more!"))
return TRUE
@@ -256,7 +256,7 @@
var/area/current_area = get_area(owner.current)
for(var/datum/mind/cult_mind as anything in cult_team.members)
SEND_SOUND(cult_mind, sound('sound/hallucinations/veryfar_noise.ogg'))
- to_chat(cult_mind, span_cultlarge("The Cult's Master, [owner.current.name], has fallen in \the [current_area]!"))
+ to_chat(cult_mind, span_cult_large("The Cult's Master, [owner.current.name], has fallen in \the [current_area]!"))
/datum/antagonist/cult/get_preview_icon()
var/icon/icon = render_preview_outfit(preview_outfit)
diff --git a/code/modules/antagonists/cult/cult_bastard_sword.dm b/code/modules/antagonists/cult/cult_bastard_sword.dm
index 784eaedf636..0d70bd503fb 100644
--- a/code/modules/antagonists/cult/cult_bastard_sword.dm
+++ b/code/modules/antagonists/cult/cult_bastard_sword.dm
@@ -77,7 +77,7 @@
force = 5
return
else
- to_chat(user, span_cultlarge("\"You cling to the Forgotten Gods, as if you're more than their pawn.\""))
+ to_chat(user, span_cult_large("\"You cling to the Forgotten Gods, as if you're more than their pawn.\""))
to_chat(user, span_userdanger("A horrible force yanks at your arm!"))
user.emote("scream")
user.apply_damage(30, BRUTE, pick(GLOB.arm_zones))
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index 17dcdc37789..ff64cc86a2b 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -81,7 +81,7 @@
var/my_message
if(!message)
return
- my_message = span_cultboldtalic("The [user.name]: [message]")
+ my_message = span_cult_bold_italic("The [user.name]: [message]")
for(var/mob/player_list as anything in GLOB.player_list)
if(IS_CULTIST(player_list))
to_chat(player_list, my_message)
@@ -123,7 +123,7 @@
if(team_member.current.incapacitated())
continue
SEND_SOUND(team_member.current, 'sound/hallucinations/im_here1.ogg')
- to_chat(team_member.current, span_cultlarge("Acolyte [nominee] has asserted that [nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly."))
+ to_chat(team_member.current, span_cult_large("Acolyte [nominee] has asserted that [nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly."))
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(poll_cultists_for_leader), nominee, team), 10 SECONDS)
@@ -137,7 +137,7 @@
team_member.current.update_mob_action_buttons()
if(team_member.current.incapacitated())
continue
- to_chat(team_member.current,span_cultlarge("[nominee] has died in the process of attempting to start a vote!"))
+ to_chat(team_member.current,span_cult_large("[nominee] has died in the process of attempting to start a vote!"))
return FALSE
var/list/mob/living/asked_cultists = list()
for(var/datum/mind/team_member as anything in team.members)
@@ -169,7 +169,7 @@
team_member.current.update_mob_action_buttons()
if(team_member.current.incapacitated())
continue
- to_chat(team_member.current,span_cultlarge("[nominee] has died in the process of attempting to win the cult's support!"))
+ to_chat(team_member.current,span_cult_large("[nominee] has died in the process of attempting to win the cult's support!"))
return FALSE
if(!nominee.mind)
team.cult_vote_called = FALSE
@@ -179,7 +179,7 @@
team_member.current.update_mob_action_buttons()
if(team_member.current.incapacitated())
continue
- to_chat(team_member.current,span_cultlarge("[nominee] has gone catatonic in the process of attempting to win the cult's support!"))
+ to_chat(team_member.current,span_cult_large("[nominee] has gone catatonic in the process of attempting to win the cult's support!"))
return FALSE
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
team.cult_vote_called = FALSE
@@ -189,7 +189,7 @@
team_member.current.update_mob_action_buttons()
if(team_member.current.incapacitated())
continue
- to_chat(team_member.current, span_cultlarge("[nominee] could not win the cult's support and shall continue to serve as an acolyte."))
+ to_chat(team_member.current, span_cult_large("[nominee] could not win the cult's support and shall continue to serve as an acolyte."))
return FALSE
team.cult_vote_called = FALSE
@@ -218,7 +218,7 @@
var/place = get_area(owner)
var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
if(place in summon_objective.summon_spots)//cant do final reckoning in the summon area to prevent abuse, you'll need to get everyone to stand on the circle!
- to_chat(owner, span_cultlarge("The veil is too weak here! Move to an area where it is strong enough to support this magic."))
+ to_chat(owner, span_cult_large("The veil is too weak here! Move to an area where it is strong enough to support this magic."))
return
for(var/i in 1 to 4)
chant(i)
@@ -353,14 +353,14 @@
if(cult_team.blood_target)
if(!COOLDOWN_FINISHED(src, cult_mark_cooldown))
cult_team.unset_blood_target_and_timer()
- to_chat(owner, span_cultbold("You have cleared the cult's blood target!"))
+ to_chat(owner, span_cult_bold("You have cleared the cult's blood target!"))
return TRUE
- to_chat(owner, span_cultbold("The cult has already designated a target!"))
+ to_chat(owner, span_cult_bold("The cult has already designated a target!"))
return FALSE
if(!COOLDOWN_FINISHED(src, cult_mark_cooldown))
- to_chat(owner, span_cultbold("You aren't ready to place another blood mark yet!"))
+ to_chat(owner, span_cult_bold("You aren't ready to place another blood mark yet!"))
return FALSE
var/atom/mark_target = owner.orbiting?.parent || get_turf(owner)
@@ -368,7 +368,7 @@
return FALSE
if(cult_team.set_blood_target(mark_target, owner, 60 SECONDS))
- to_chat(owner, span_cultbold("You have marked [mark_target] for the cult! It will last for [DisplayTimeText(cult_mark_duration)]."))
+ to_chat(owner, span_cult_bold("You have marked [mark_target] for the cult! It will last for [DisplayTimeText(cult_mark_duration)]."))
COOLDOWN_START(src, cult_mark_cooldown, cult_mark_cooldown_duration)
build_all_button_icons(UPDATE_BUTTON_NAME|UPDATE_BUTTON_ICON)
addtimer(CALLBACK(src, PROC_REF(reset_button)), cult_mark_cooldown_duration + 1)
@@ -400,7 +400,7 @@
return
SEND_SOUND(owner, 'sound/magic/enter_blood.ogg')
- to_chat(owner, span_cultbold("Your previous mark is gone - you are now ready to create a new blood mark."))
+ to_chat(owner, span_cult_bold("Your previous mark is gone - you are now ready to create a new blood mark."))
build_all_button_icons(UPDATE_BUTTON_NAME|UPDATE_BUTTON_ICON)
//////// ELDRITCH PULSE /////////
@@ -489,12 +489,12 @@
if(!IS_CULTIST(living_clicked))
return FALSE
SEND_SOUND(caller, sound('sound/weapons/thudswoosh.ogg'))
- to_chat(caller, span_cultbold("You reach through the veil with your mind's eye and seize [clicked_on]! Click anywhere nearby to teleport [clicked_on.p_them()]!"))
+ to_chat(caller, span_cult_bold("You reach through the veil with your mind's eye and seize [clicked_on]! Click anywhere nearby to teleport [clicked_on.p_them()]!"))
throwee_ref = WEAKREF(clicked_on)
return TRUE
if(istype(clicked_on, /obj/structure/destructible/cult))
- to_chat(caller, span_cultbold("You reach through the veil with your mind's eye and lift [clicked_on]! Click anywhere nearby to teleport it!"))
+ to_chat(caller, span_cult_bold("You reach through the veil with your mind's eye and lift [clicked_on]! Click anywhere nearby to teleport it!"))
throwee_ref = WEAKREF(clicked_on)
return TRUE
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 5426b41805a..7877a3dd1cb 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -97,7 +97,7 @@ Striking a noncultist, however, will tear their flesh."}
user.Paralyze(100)
user.dropItemToGround(src, TRUE)
user.visible_message(span_warning("A powerful force shoves [user] away from [target]!"), \
- span_cultlarge("\"You shouldn't play with sharp things. You'll poke someone's eye out.\""))
+ span_cult_large("\"You shouldn't play with sharp things. You'll poke someone's eye out.\""))
if(ishuman(user))
var/mob/living/carbon/human/miscreant = user
miscreant.apply_damage(rand(force/2, force), BRUTE, pick(GLOB.arm_zones))
@@ -121,7 +121,7 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/melee/cultblade/pickup(mob/living/user)
..()
if(!IS_CULTIST(user))
- to_chat(user, span_cultlarge("\"I wouldn't advise that.\""))
+ to_chat(user, span_cult_large("\"I wouldn't advise that.\""))
/datum/action/innate/dash/cult
name = "Rend the Veil"
@@ -156,7 +156,7 @@ Striking a noncultist, however, will tear their flesh."}
return
var/mob/living/carbon/carbon_user = user
if(user.num_legs < 2 || carbon_user.legcuffed) //if they can't be ensnared, stun for the same time as it takes to breakout of bola
- to_chat(user, span_cultlarge("\"I wouldn't advise that.\""))
+ to_chat(user, span_cult_large("\"I wouldn't advise that.\""))
user.dropItemToGround(src, TRUE)
user.Paralyze(CULT_BOLA_PICKUP_STUN)
else
@@ -413,7 +413,7 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/equipped(mob/living/user, slot)
..()
if(!IS_CULTIST(user))
- to_chat(user, span_cultlarge("\"I wouldn't advise that.\""))
+ to_chat(user, span_cult_large("\"I wouldn't advise that.\""))
to_chat(user, span_warning("An overwhelming sense of nausea overpowers you!"))
user.dropItemToGround(src, TRUE)
user.set_dizzy_if_lower(1 MINUTES)
@@ -450,7 +450,7 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/clothing/suit/hooded/cultrobes/berserker/equipped(mob/living/user, slot)
..()
if(!IS_CULTIST(user))
- to_chat(user, span_cultlarge("\"I wouldn't advise that.\""))
+ to_chat(user, span_cult_large("\"I wouldn't advise that.\""))
to_chat(user, span_warning("An overwhelming sense of nausea overpowers you!"))
user.dropItemToGround(src, TRUE)
user.set_dizzy_if_lower(1 MINUTES)
@@ -467,7 +467,7 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/clothing/glasses/hud/health/night/cultblind/equipped(mob/living/user, slot)
..()
if(user.stat != DEAD && !IS_CULTIST(user) && (slot & ITEM_SLOT_EYES))
- to_chat(user, span_cultlarge("\"You want to be blind, do you?\""))
+ to_chat(user, span_cult_large("\"You want to be blind, do you?\""))
user.dropItemToGround(src, TRUE)
user.set_dizzy_if_lower(1 MINUTES)
user.Paralyze(100)
diff --git a/code/modules/antagonists/cult/cult_structure_altar.dm b/code/modules/antagonists/cult/cult_structure_altar.dm
index 1f1a9bd71cb..9347acb3321 100644
--- a/code/modules/antagonists/cult/cult_structure_altar.dm
+++ b/code/modules/antagonists/cult/cult_structure_altar.dm
@@ -30,7 +30,7 @@
options = altar_items
/obj/structure/destructible/cult/item_dispenser/altar/succcess_message(mob/living/user, obj/item/spawned_item)
- to_chat(user, span_cultitalic("You kneel before [src] and your faith is rewarded with [spawned_item]!"))
+ to_chat(user, span_cult_italic("You kneel before [src] and your faith is rewarded with [spawned_item]!"))
#undef ELDRITCH_WHETSTONE
#undef CONSTRUCT_SHELL
diff --git a/code/modules/antagonists/cult/cult_structure_archives.dm b/code/modules/antagonists/cult/cult_structure_archives.dm
index 933b90dbf4e..a9617396633 100644
--- a/code/modules/antagonists/cult/cult_structure_archives.dm
+++ b/code/modules/antagonists/cult/cult_structure_archives.dm
@@ -32,7 +32,7 @@
options = archive_items
/obj/structure/destructible/cult/item_dispenser/archives/succcess_message(mob/living/user, obj/item/spawned_item)
- to_chat(user, span_cultitalic("You summon [spawned_item] from [src]!"))
+ to_chat(user, span_cult_italic("You summon [spawned_item] from [src]!"))
// Preset for the library that doesn't spawn runed metal on destruction.
/obj/structure/destructible/cult/item_dispenser/archives/library
diff --git a/code/modules/antagonists/cult/cult_structure_forge.dm b/code/modules/antagonists/cult/cult_structure_forge.dm
index ceb38398a67..912db7d37e9 100644
--- a/code/modules/antagonists/cult/cult_structure_forge.dm
+++ b/code/modules/antagonists/cult/cult_structure_forge.dm
@@ -32,7 +32,7 @@
options = forge_items
/obj/structure/destructible/cult/item_dispenser/forge/succcess_message(mob/living/user, obj/item/spawned_item)
- to_chat(user, span_cultitalic("You work [src] as dark knowledge guides your hands, creating [spawned_item]!"))
+ to_chat(user, span_cult_italic("You work [src] as dark knowledge guides your hands, creating [spawned_item]!"))
/obj/structure/destructible/cult/item_dispenser/forge/engine
name = "magma engine"
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index ebf66a7ee15..932c3ac03c1 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -25,7 +25,7 @@
if(cult_examine_tip)
. += span_cult(cult_examine_tip)
if(!COOLDOWN_FINISHED(src, use_cooldown_duration))
- . += span_cultitalic("The magic in [src] is too weak, it will be ready to use again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown_duration))].")
+ . += span_cult_italic("The magic in [src] is too weak, it will be ready to use again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown_duration))].")
/obj/structure/destructible/cult/set_anchored(anchorvalue)
. = ..()
@@ -78,10 +78,10 @@
to_chat(user, span_warning("You're pretty sure you know exactly what this is used for and you can't seem to touch it."))
return
if(!anchored)
- to_chat(user, span_cultitalic("You need to anchor [src] to the floor first."))
+ to_chat(user, span_cult_italic("You need to anchor [src] to the floor first."))
return
if(!COOLDOWN_FINISHED(src, use_cooldown))
- to_chat(user, span_cultitalic("The magic in [src] is too weak, it will be ready to use again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))]."))
+ to_chat(user, span_cult_italic("The magic in [src] is too weak, it will be ready to use again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))]."))
return
var/list/spawned_items = get_items_to_spawn(user)
@@ -142,7 +142,7 @@
* Override for unique feedback messages on item spawn.
*/
/obj/structure/destructible/cult/item_dispenser/proc/succcess_message(mob/living/user, obj/item/spawned_item)
- to_chat(user, span_cultitalic("[src] produces a [spawned_item.name]."))
+ to_chat(user, span_cult_italic("[src] produces a [spawned_item.name]."))
/*
* Simple proc intended for use in callbacks to determine if [user] can continue to use a radial menu.
diff --git a/code/modules/antagonists/cult/cult_team.dm b/code/modules/antagonists/cult/cult_team.dm
index 1d199a113f5..c47cc2145b5 100644
--- a/code/modules/antagonists/cult/cult_team.dm
+++ b/code/modules/antagonists/cult/cult_team.dm
@@ -49,7 +49,7 @@
for(var/datum/mind/mind as anything in members)
if(mind.current)
SEND_SOUND(mind.current, 'sound/ambience/antag/bloodcult/bloodcult_eyes.ogg')
- to_chat(mind.current, span_cultlarge(span_warning("The veil weakens as your cult grows, your eyes begin to glow...")))
+ to_chat(mind.current, span_cult_large(span_warning("The veil weakens as your cult grows, your eyes begin to glow...")))
mind.current.AddElement(/datum/element/cult_eyes)
cult_risen = TRUE
log_game("The blood cult has risen with [cultplayers] players.")
@@ -58,7 +58,7 @@
for(var/datum/mind/mind as anything in members)
if(mind.current)
SEND_SOUND(mind.current, 'sound/ambience/antag/bloodcult/bloodcult_halos.ogg')
- to_chat(mind.current, span_cultlarge(span_warning("Your cult is ascendent and the red harvest approaches - you cannot hide your true nature for much longer!!")))
+ to_chat(mind.current, span_cult_large(span_warning("Your cult is ascendent and the red harvest approaches - you cannot hide your true nature for much longer!!")))
mind.current.AddElement(/datum/element/cult_halo)
cult_ascendent = TRUE
log_game("The blood cult has ascended with [cultplayers] players.")
@@ -156,7 +156,7 @@
if(cultist.current.stat == DEAD || !cultist.current.client)
continue
- to_chat(cultist.current, span_bold(span_cultlarge("[marker] has marked [blood_target] in the [target_area.name] as the cult's top priority, get there immediately!")))
+ to_chat(cultist.current, span_bold(span_cult_large("[marker] has marked [blood_target] in the [target_area.name] as the cult's top priority, get there immediately!")))
SEND_SOUND(cultist.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'), 0, 1, 75))
cultist.current.client.images += blood_target_image
@@ -175,9 +175,9 @@
continue
if(QDELETED(blood_target))
- to_chat(cultist.current, span_bold(span_cultlarge("The blood mark's target is lost!")))
+ to_chat(cultist.current, span_bold(span_cult_large("The blood mark's target is lost!")))
else
- to_chat(cultist.current, span_bold(span_cultlarge("The blood mark has expired!")))
+ to_chat(cultist.current, span_bold(span_cult_large("The blood mark has expired!")))
cultist.current.client.images -= blood_target_image
UnregisterSignal(blood_target, COMSIG_QDELETING)
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 8e5e7099be4..6fe9cf47298 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -1,6 +1,4 @@
-/// list of weakrefs to mobs OR minds that have been sacrificed
-GLOBAL_LIST(sacrificed)
/// List of all teleport runes
GLOBAL_LIST(teleport_runes)
/// Assoc list of every rune that can be drawn by ritual daggers. [rune_name] = [typepath]
@@ -100,7 +98,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
. = ..()
if(.)
return
- if(!IS_CULTIST(user))
+ if(!IS_CULTIST_OR_CULTIST_MOB(user))
to_chat(user, span_warning("You aren't able to understand the words of [src]."))
return
var/list/invokers = can_invoke(user)
@@ -110,15 +108,16 @@ Runes can either be invoked by one's self or with many different cultists. Each
to_chat(user, span_danger("You need [req_cultists - length(invokers)] more adjacent cultists to use this rune in such a manner."))
fail_invoke()
-/obj/effect/rune/attack_animal(mob/living/simple_animal/user, list/modifiers)
- if(isshade(user) || isconstruct(user))
- if(HAS_TRAIT(user, TRAIT_ANGELIC))
- to_chat(user, span_warning("You purge the rune!"))
- qdel(src)
- else if(construct_invoke || !IS_CULTIST(user)) //if you're not a cult construct we want the normal fail message
- attack_hand(user)
- else
- to_chat(user, span_warning("You are unable to invoke the rune!"))
+/obj/effect/rune/attack_animal(mob/living/user, list/modifiers)
+ if(!isshade(user) && !isconstruct(user))
+ return
+ if(HAS_TRAIT(user, TRAIT_ANGELIC))
+ to_chat(user, span_warning("You purge the rune!"))
+ qdel(src)
+ else if(construct_invoke || !IS_CULTIST(user)) //if you're not a cult construct we want the normal fail message
+ attack_hand(user)
+ else
+ to_chat(user, span_warning("You are unable to invoke the rune!"))
/obj/effect/rune/proc/conceal() //for talisman of revealing/hiding
visible_message(span_danger("[src] fades away."))
@@ -161,17 +160,19 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/proc/invoke(list/invokers)
//This proc contains the effects of the rune as well as things that happen afterwards. If you want it to spawn an object and then delete itself, have both here.
- for(var/M in invokers)
- if(isliving(M))
- var/mob/living/L = M
- if(invocation)
- L.say(invocation, language = /datum/language/common, ignore_spam = TRUE, forced = "cult invocation")
- if(invoke_damage)
- L.apply_damage(invoke_damage, BRUTE)
- to_chat(L, "[src] saps your strength!")
- else if(istype(M, /obj/item/toy/plush/narplush))
- var/obj/item/toy/plush/narplush/P = M
- P.visible_message("[P] squeaks loudly!")
+ for(var/atom/invoker in invokers)
+ if(istype(invoker, /obj/item/toy/plush/narplush))
+ invoker.visible_message(span_cult_italic("[src] squeaks_loudly!"))
+ continue
+ if(!isliving(invoker))
+ continue
+ var/mob/living/living_invoker = invoker
+ if(invocation)
+ living_invoker.say(invocation, language = /datum/language/common, ignore_spam = TRUE, forced = "cult invocation")
+ if(invoke_damage)
+ living_invoker.apply_damage(invoke_damage, BRUTE)
+ to_chat(living_invoker, span_cult_italic("[src] saps your strength!"))
+
do_invoke_glow()
/obj/effect/rune/proc/do_invoke_glow()
@@ -234,7 +235,6 @@ structure_check() searches for nearby cultist structures required for the invoca
rune_in_use = TRUE
visible_message(span_warning("[src] pulses blood red!"))
- var/oldcolor = color
color = RUNE_COLOR_DARKRED
if(length(myriad_targets))
@@ -259,9 +259,10 @@ structure_check() searches for nearby cultist structures required for the invoca
else
do_invoke_glow()
- animate(src, color = oldcolor, time = 0.5 SECONDS)
+ animate(src, color = initial(color), time = 0.5 SECONDS)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 0.5 SECONDS)
rune_in_use = FALSE
+ return ..()
/obj/effect/rune/convert/proc/do_convert(mob/living/convertee, list/invokers, datum/team/cult/cult_team)
ASSERT(convertee.mind)
@@ -286,7 +287,7 @@ structure_check() searches for nearby cultist structures required for the invoca
span_warning("[convertee] writhes in pain [(brutedamage || burndamage) \
? "even as [convertee.p_their()] wounds heal and close" \
: "as the markings below [convertee.p_them()] glow a bloody red"]!"),
- span_cultlarge("AAAAAAAAAAAAAA-"),
+ span_cult_large("AAAAAAAAAAAAAA-"),
)
// We're not guaranteed to be a human but we'll cast here since we use it in a few branches
@@ -305,11 +306,11 @@ structure_check() searches for nearby cultist structures required for the invoca
convertee.mind.special_role = ROLE_CULTIST
convertee.mind.add_antag_datum(/datum/antagonist/cult, cult_team)
- to_chat(convertee, span_cultitalic("Your blood pulses. Your head throbs. The world goes red. \
+ to_chat(convertee, span_cult_bold_italic("Your blood pulses. Your head throbs. The world goes red. \
All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
- and something evil takes root."))
- to_chat(convertee, span_cultitalic("Assist your new compatriots in their dark dealings. \
- Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back."))
+ and something evil takes root."))
+ to_chat(convertee, span_cult_bold_italic("Assist your new compatriots in their dark dealings. \
+ Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back."))
if(istype(human_convertee))
human_convertee.uncuff()
@@ -324,10 +325,10 @@ structure_check() searches for nearby cultist structures required for the invoca
var/big_sac = FALSE
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!"))
+ to_chat(invoker, span_cult_italic("[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)
+ var/signal_result = SEND_SIGNAL(sacrificial, COMSIG_LIVING_CULT_SACRIFICED, invokers, cult_team)
if(signal_result & STOP_SACRIFICE)
return FALSE
@@ -347,12 +348,12 @@ structure_check() searches for nearby cultist structures required for the invoca
if(!(signal_result & SILENCE_SACRIFICE_MESSAGE))
for(var/invoker in invokers)
if(big_sac)
- to_chat(invoker, span_cultlarge("\"Yes! This is the one I desire! You have done well.\""))
+ to_chat(invoker, span_cult_large("\"Yes! This is the one I desire! You have done well.\""))
continue
if(ishuman(sacrificial) || iscyborg(sacrificial))
- to_chat(invoker, span_cultlarge("\"I accept this sacrifice.\""))
+ to_chat(invoker, span_cult_large("\"I accept this sacrifice.\""))
else
- to_chat(invoker, span_cultlarge("\"I accept this meager sacrifice.\""))
+ to_chat(invoker, span_cult_large("\"I accept this meager sacrifice.\""))
if(iscyborg(sacrificial))
var/construct_class = show_radial_menu(invokers[1], sacrificial, GLOB.construct_radial_images, require_near = TRUE, tooltips = TRUE)
@@ -389,7 +390,7 @@ structure_check() searches for nearby cultist structures required for the invoca
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))
+ rod.visible_message(span_cult_italic(displayed_message))
switch(num_slain)
if(0, 1)
animate_spawn_sword(rod, /obj/item/melee/cultblade/dagger)
@@ -653,7 +654,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/area/place = get_area(src)
if(!(place in summon_objective.summon_spots))
- to_chat(user, span_cultlarge("The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!"))
+ to_chat(user, span_cult_large("The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!"))
return
if(locate(/obj/narsie) in SSpoints_of_interest.narsies)
for(var/invoker in invokers)
@@ -689,50 +690,50 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
- var/static/sacrifices_used = -SOULS_TO_REVIVE // Cultists get one "free" revive
/obj/effect/rune/raise_dead/examine(mob/user)
. = ..()
if(IS_CULTIST(user) || user.stat == DEAD)
- . += "Sacrifices unrewarded: [LAZYLEN(GLOB.sacrificed) - sacrifices_used]"
+ . += "Sacrifices unrewarded: [LAZYLEN(GLOB.sacrificed) - GLOB.sacrifices_used]"
/obj/effect/rune/raise_dead/invoke(list/invokers)
- var/turf/T = get_turf(src)
- var/mob/living/mob_to_revive
- var/list/potential_revive_mobs = list()
- var/mob/living/user = invokers[1]
if(rune_in_use)
return
rune_in_use = TRUE
- for(var/mob/living/M in T.contents)
- if(IS_CULTIST(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
- potential_revive_mobs |= M
+ var/mob/living/mob_to_revive
+ var/list/potential_revive_mobs = list()
+ var/mob/living/user = invokers[1]
+
+ for(var/mob/living/target in loc)
+ if(IS_CULTIST(target) && (target.stat == DEAD || isnull(target.client) || target.client.is_afk()))
+ potential_revive_mobs += target
+
if(!length(potential_revive_mobs))
- to_chat(user, "There are no dead cultists on the rune!")
+ to_chat(user, span_cult_italic("There are no dead cultists on the rune!"))
log_game("Raise Dead rune activated by [user] at [COORD(src)] failed - no cultists to revive.")
fail_invoke()
return
- if(length(potential_revive_mobs) > 1)
+
+ if(length(potential_revive_mobs) > 1 && user.mind)
mob_to_revive = tgui_input_list(user, "Cultist to revive", "Revive Cultist", potential_revive_mobs)
if(isnull(mob_to_revive))
return
else
mob_to_revive = potential_revive_mobs[1]
+
if(QDELETED(src) || !validness_checks(mob_to_revive, user))
fail_invoke()
return
- if(user.name == "Herbert West")
- invocation = "To life, to life, I bring them!"
- else
- invocation = initial(invocation)
- ..()
+
+ invocation = (user.name == "Herbert West") ? "To life, to life, I bring them!" : initial(invocation)
+
if(mob_to_revive.stat == DEAD)
- var/diff = LAZYLEN(GLOB.sacrificed) - SOULS_TO_REVIVE - sacrifices_used
+ var/diff = LAZYLEN(GLOB.sacrificed) - SOULS_TO_REVIVE - GLOB.sacrifices_used
if(diff < 0)
to_chat(user, span_warning("Your cult must carry out [abs(diff)] more sacrifice\s before it can revive another cultist!"))
fail_invoke()
return
- sacrifices_used += SOULS_TO_REVIVE
+ GLOB.sacrifices_used += SOULS_TO_REVIVE
mob_to_revive.revive(ADMIN_HEAL_ALL) //This does remove traits and such, but the rune might actually see some use because of it! //Why did you think this was a good idea
if(!mob_to_revive.client || mob_to_revive.client.is_afk())
@@ -747,21 +748,21 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
fail_invoke()
return
SEND_SOUND(mob_to_revive, 'sound/ambience/antag/bloodcult/bloodcult_gain.ogg')
- to_chat(mob_to_revive, span_cultlarge("\"PASNAR SAVRAE YAM'TOTH. Arise.\""))
+ to_chat(mob_to_revive, span_cult_large("\"PASNAR SAVRAE YAM'TOTH. Arise.\""))
mob_to_revive.visible_message(span_warning("[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes."), \
- span_cultlarge("You awaken suddenly from the void. You're alive!"))
+ span_cult_large("You awaken suddenly from the void. You're alive!"))
rune_in_use = FALSE
+ return ..()
/obj/effect/rune/raise_dead/proc/validness_checks(mob/living/target_mob, mob/living/user)
- var/turf/T = get_turf(src)
if(QDELETED(user))
return FALSE
if(!Adjacent(user) || user.incapacitated())
return FALSE
if(QDELETED(target_mob))
return FALSE
- if(!(target_mob in T.contents))
- to_chat(user, "The cultist to revive has been moved!")
+ if(!(target_mob in loc))
+ to_chat(user, span_cult_italic("The cultist to revive has been moved!"))
log_game("Raise Dead rune activated by [user] at [COORD(src)] failed - revival target moved.")
return FALSE
return TRUE
@@ -769,9 +770,9 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
/obj/effect/rune/raise_dead/fail_invoke()
..()
rune_in_use = FALSE
- for(var/mob/living/M in range(1,src))
- if(IS_CULTIST(M) && M.stat == DEAD)
- M.visible_message(span_warning("[M] twitches."))
+ for(var/mob/living/cultist in loc)
+ if(IS_CULTIST(cultist) && cultist.stat == DEAD)
+ cultist.visible_message(span_warning("[cultist] twitches."))
//Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo.
/obj/effect/rune/wall
@@ -895,7 +896,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
if(!IS_CULTIST(target) && target.blood_volume)
if(target.can_block_magic(charge_cost = 0))
continue
- to_chat(target, span_cultlarge("Your blood boils in your veins!"))
+ to_chat(target, span_cult_large("Your blood boils in your veins!"))
animate(src, color = "#FCB56D", time = 4)
sleep(0.4 SECONDS)
if(QDELETED(src))
@@ -959,10 +960,10 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
var/choice = tgui_alert(user, "You tear open a connection to the spirit realm...", "Spirit Realm", list("Summon a Cult Ghost", "Ascend as a Dark Spirit"))
if(choice == "Summon a Cult Ghost")
if(!is_station_level(T.z))
- to_chat(user, span_cultitalic("The veil is not weak enough here to manifest spirits, you must be on station!"))
+ to_chat(user, span_cult_italic("The veil is not weak enough here to manifest spirits, you must be on station!"))
return
if(ghosts >= ghost_limit)
- to_chat(user, span_cultitalic("You are sustaining too many ghosts to summon more!"))
+ to_chat(user, span_cult_italic("You are sustaining too many ghosts to summon more!"))
fail_invoke()
log_game("Manifest rune failed - too many summoned ghosts")
return list()
@@ -977,7 +978,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
if(O.client && !is_banned_from(O.ckey, ROLE_CULTIST) && !QDELETED(src) && !(isAdminObserver(O) && (O.client.prefs.toggles & ADMIN_IGNORE_CULT_GHOST)) && !QDELETED(O))
ghosts_on_rune += O
if(!length(ghosts_on_rune))
- to_chat(user, span_cultitalic("There are no spirits near [src]!"))
+ to_chat(user, span_cult_italic("There are no spirits near [src]!"))
fail_invoke()
log_game("Manifest rune failed - no nearby ghosts")
return list()
@@ -995,7 +996,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
ghosts++
playsound(src, 'sound/magic/exit_blood.ogg', 50, TRUE)
visible_message(span_warning("A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]man."))
- to_chat(user, span_cultitalic("Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely..."))
+ to_chat(user, span_cult_italic("Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely..."))
var/obj/structure/emergency_shield/cult/weak/N = new(T)
if(ghost_to_spawn.mind && ghost_to_spawn.mind.current)
new_human.AddComponent( \
@@ -1006,7 +1007,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
new_human.key = ghost_to_spawn.key
var/datum/antagonist/cult/created_cultist = new_human.mind?.add_antag_datum(/datum/antagonist/cult)
created_cultist?.silent = TRUE
- to_chat(new_human, span_cultitalic("You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar'Sie, and you are to serve them at all costs."))
+ to_chat(new_human, span_cult_italic("You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar'Sie, and you are to serve them at all costs."))
while(!QDELETED(src) && !QDELETED(user) && !QDELETED(new_human) && (user in T))
if(user.stat != CONSCIOUS || HAS_TRAIT(new_human, TRAIT_CRITICAL_CONDITION))
@@ -1018,7 +1019,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
ghosts--
if(new_human)
new_human.visible_message(span_warning("[new_human] suddenly dissolves into bones and ashes."), \
- span_cultlarge("Your link to the world fades. Your form breaks apart."))
+ span_cult_large("Your link to the world fades. Your form breaks apart."))
for(var/obj/I in new_human)
new_human.dropItemToGround(I, TRUE)
new_human.mind?.remove_antag_datum(/datum/antagonist/cult)
@@ -1047,7 +1048,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
affecting.Paralyze(40)
break
if(affecting.health <= 10)
- to_chat(G, span_cultitalic("Your body can no longer sustain the connection!"))
+ to_chat(G, span_cult_italic("Your body can no longer sustain the connection!"))
break
sleep(0.5 SECONDS)
CM.Remove(G)
@@ -1090,10 +1091,10 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
if(length(summon_objective.summon_spots) <= 1)
- to_chat(user, span_cultlarge("Only one ritual site remains - it must be reserved for the final summoning!"))
+ to_chat(user, span_cult_large("Only one ritual site remains - it must be reserved for the final summoning!"))
return
if(!(place in summon_objective.summon_spots))
- to_chat(user, span_cultlarge("The Apocalypse rune will remove a ritual site, where Nar'Sie can be summoned, it can only be scribed in [english_list(summon_objective.summon_spots)]!"))
+ to_chat(user, span_cult_large("The Apocalypse rune will remove a ritual site, where Nar'Sie can be summoned, it can only be scribed in [english_list(summon_objective.summon_spots)]!"))
return
summon_objective.summon_spots -= place
@@ -1144,7 +1145,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
addtimer(CALLBACK(M, TYPE_PROC_REF(/atom/, remove_alt_appearance),"cult_apoc",TRUE), duration)
images += C
else
- to_chat(M, span_cultlarge("An Apocalypse Rune was invoked in the [place.name], it is no longer available as a summoning site!"))
+ to_chat(M, span_cult_large("An Apocalypse Rune was invoked in the [place.name], it is no longer available as a summoning site!"))
SEND_SOUND(M, 'sound/effects/pope_entry.ogg')
image_handler(images, duration)
if(intensity >= 285) // Based on the prior formula, this means the cult makes up <15% of current players
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index 3da969c7ea7..c9bc00b1891 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -180,7 +180,7 @@
if(M == user)
return
if(IS_CULTIST(M) && IS_CULTIST(user))
- to_chat(user, span_cultlarge("\"Come now, do not capture your bretheren's soul.\""))
+ to_chat(user, span_cult_large("\"Come now, do not capture your bretheren's soul.\""))
return
if(theme == THEME_HOLY && IS_CULTIST(user))
hot_potato(user)
@@ -508,7 +508,7 @@
if(newstruct.mind && !IS_CULTIST(newstruct) && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker.HasRoundStarted())
newstruct.mind.add_antag_datum(/datum/antagonist/cult/construct)
if(IS_CULTIST(stoner) || cultoverride)
- to_chat(newstruct, span_cultbold("You are still bound to serve the cult[stoner ? " and [stoner]" : ""], follow [stoner?.p_their() || "their"] orders and help [stoner?.p_them() || "them"] complete [stoner?.p_their() || "their"] goals at all costs."))
+ to_chat(newstruct, span_cult_bold("You are still bound to serve the cult[stoner ? " and [stoner]" : ""], follow [stoner?.p_their() || "their"] orders and help [stoner?.p_them() || "them"] complete [stoner?.p_their() || "their"] goals at all costs."))
else if(stoner)
to_chat(newstruct, span_boldwarning("You are still bound to serve your creator, [stoner], follow [stoner.p_their()] orders and help [stoner.p_them()] complete [stoner.p_their()] goals at all costs."))
newstruct.clear_alert("bloodsense")
diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
index 97688417aac..0a037482bc1 100644
--- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
+++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
@@ -86,7 +86,7 @@
return
var/num_slain = LAZYLEN(cultists_slain)
- . += span_cultitalic("It has the blood of [num_slain] fallen cultist[num_slain == 1 ? "" : "s"] on it. \
+ . += span_cult_italic("It has the blood of [num_slain] fallen cultist[num_slain == 1 ? "" : "s"] on it. \
Offering it to Nar'sie will transform it into a [num_slain >= 3 ? "powerful" : "standard"] cult weapon.")
/obj/item/nullrod/godhand
diff --git a/code/modules/mob/living/basic/blob_minions/blobbernaut.dm b/code/modules/mob/living/basic/blob_minions/blobbernaut.dm
index ab3442604db..8b94063ba77 100644
--- a/code/modules/mob/living/basic/blob_minions/blobbernaut.dm
+++ b/code/modules/mob/living/basic/blob_minions/blobbernaut.dm
@@ -86,7 +86,7 @@
health = maxHealth / 2 // Start out injured to encourage not beelining away from the blob
SEND_SOUND(src, sound('sound/effects/blobattack.ogg'))
SEND_SOUND(src, sound('sound/effects/attackblob.ogg'))
- to_chat(src, span_infoplain("You are powerful, hard to kill, and slowly regenerate near nodes and cores, [span_cultlarge("but will slowly die if not near the blob")] or if the factory that made you is killed."))
+ to_chat(src, span_infoplain("You are powerful, hard to kill, and slowly regenerate near nodes and cores, [span_cult_large("but will slowly die if not near the blob")] or if the factory that made you is killed."))
to_chat(src, span_infoplain("You can communicate with other blobbernauts and overminds telepathically by attempting to speak normally"))
to_chat(src, span_infoplain("Your overmind's blob reagent is: [blobstrain.name]!"))
to_chat(src, span_infoplain("The [blobstrain.name] reagent [blobstrain.shortdesc ? "[blobstrain.shortdesc]" : "[blobstrain.description]"]"))
diff --git a/code/modules/mob/living/basic/cult/constructs/harvester.dm b/code/modules/mob/living/basic/cult/constructs/harvester.dm
index 30b30994872..da8dad827b0 100644
--- a/code/modules/mob/living/basic/cult/constructs/harvester.dm
+++ b/code/modules/mob/living/basic/cult/constructs/harvester.dm
@@ -50,7 +50,7 @@
carbon_target.Paralyze(6 SECONDS)
visible_message(span_danger("[src] knocks [carbon_target] down!"))
- to_chat(src, span_cultlarge("\"Bring [carbon_target.p_them()] to me.\""))
+ to_chat(src, span_cult_large("\"Bring [carbon_target.p_them()] to me.\""))
/datum/action/innate/seek_master
name = "Seek your Master"
@@ -80,18 +80,18 @@
the_construct.master = cult_status.cult_team.blood_target
if(!the_construct.master)
- to_chat(the_construct, span_cultitalic("You have no master to seek!"))
+ to_chat(the_construct, span_cult_italic("You have no master to seek!"))
the_construct.seeking = FALSE
return
if(tracking)
tracking = FALSE
the_construct.seeking = FALSE
- to_chat(the_construct, span_cultitalic("You are no longer tracking your master."))
+ to_chat(the_construct, span_cult_italic("You are no longer tracking your master."))
return
else
tracking = TRUE
the_construct.seeking = TRUE
- to_chat(the_construct, span_cultitalic("You are now tracking your master."))
+ to_chat(the_construct, span_cult_italic("You are now tracking your master."))
/datum/action/innate/seek_prey
@@ -113,16 +113,16 @@
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
button_icon_state = "cult_mark"
the_construct.seeking = FALSE
- to_chat(the_construct, span_cultitalic("You are now tracking Nar'Sie, return to reap the harvest!"))
+ to_chat(the_construct, span_cult_italic("You are now tracking Nar'Sie, return to reap the harvest!"))
return
if(!LAZYLEN(GLOB.cult_narsie.souls_needed))
- to_chat(the_construct, span_cultitalic("Nar'Sie has completed her harvest!"))
+ to_chat(the_construct, span_cult_italic("Nar'Sie has completed her harvest!"))
return
the_construct.master = pick(GLOB.cult_narsie.souls_needed)
var/mob/living/real_target = the_construct.master //We can typecast this way because Narsie only allows /mob/living into the souls list
- to_chat(the_construct, span_cultitalic("You are now tracking your prey, [real_target.real_name] - harvest [real_target.p_them()]!"))
+ to_chat(the_construct, span_cult_italic("You are now tracking your prey, [real_target.real_name] - harvest [real_target.p_them()]!"))
desc = "Activate to track Nar'Sie!"
button_icon_state = "sintouch"
the_construct.seeking = TRUE
diff --git a/code/modules/mob/living/basic/farm_animals/sheep.dm b/code/modules/mob/living/basic/farm_animals/sheep.dm
index e32da910ab9..2fdaeda657d 100644
--- a/code/modules/mob/living/basic/farm_animals/sheep.dm
+++ b/code/modules/mob/living/basic/farm_animals/sheep.dm
@@ -58,11 +58,11 @@
if(cult_converted)
for(var/mob/living/cultist as anything in invokers)
- to_chat(cultist, span_cultitalic("[src] has already been sacrificed!"))
+ to_chat(cultist, span_cult_italic("[src] has already been sacrificed!"))
return STOP_SACRIFICE
for(var/mob/living/cultist as anything in invokers)
- to_chat(cultist, span_cultitalic("This feels a bit too cliché, don't you think?"))
+ to_chat(cultist, span_cult_italic("This feels a bit too cliché, don't you think?"))
cult_converted = TRUE
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, say), "BAAAAAAAAH!")
diff --git a/code/modules/mob/living/basic/pets/cat/cat.dm b/code/modules/mob/living/basic/pets/cat/cat.dm
index dd8a588e915..3c2612d9a62 100644
--- a/code/modules/mob/living/basic/pets/cat/cat.dm
+++ b/code/modules/mob/living/basic/pets/cat/cat.dm
@@ -33,6 +33,7 @@
attack_verb_simple = "claw"
attack_sound = 'sound/weapons/slash.ogg'
attack_vis_effect = ATTACK_EFFECT_CLAW
+ cult_icon_state = "cat_cult"
///can this cat breed?
var/can_breed = TRUE
///can hold items?
diff --git a/code/modules/mob/living/basic/pets/dog/corgi.dm b/code/modules/mob/living/basic/pets/dog/corgi.dm
index 61c18ab5354..2011992da56 100644
--- a/code/modules/mob/living/basic/pets/dog/corgi.dm
+++ b/code/modules/mob/living/basic/pets/dog/corgi.dm
@@ -11,6 +11,7 @@
butcher_results = list(/obj/item/food/meat/slab/corgi = 3, /obj/item/stack/sheet/animalhide/corgi = 1)
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "corgi"
+ cult_icon_state = "narsian"
ai_controller = /datum/ai_controller/basic_controller/dog/corgi
///Access card for the corgi.
var/obj/item/card/id/access_card = null
@@ -507,7 +508,7 @@
/mob/living/basic/pet/dog/corgi/narsie/narsie_act()
if(stat == DEAD) //Nar'Sie loves her doggy
visible_message(span_warning("[src] arises again, revived by the dark magicks!"), \
- span_cultlarge("RISE"))
+ span_cult_large("RISE"))
revive(ADMIN_HEAL_ALL) //also means that a dead Nars-Ian can consume a pet and revive
adjustBruteLoss(-maxHealth)
diff --git a/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm b/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm
index 31c8562ce1e..0d52075a9a3 100644
--- a/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm
+++ b/code/modules/mob/living/basic/pets/dog/dog_subtypes.dm
@@ -9,6 +9,7 @@
icon_living = "pug"
icon_dead = "pug_dead"
butcher_results = list(/obj/item/food/meat/slab/pug = 3)
+ cult_icon_state = "pug_cult"
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "pug"
held_state = "pug"
diff --git a/code/modules/mob/living/basic/pets/pet.dm b/code/modules/mob/living/basic/pets/pet.dm
index c8507454f77..de5ad59eb1f 100644
--- a/code/modules/mob/living/basic/pets/pet.dm
+++ b/code/modules/mob/living/basic/pets/pet.dm
@@ -10,9 +10,12 @@
var/collar_icon_state = null
/// We have a seperate _rest collar icon state when the pet is resting.
var/has_collar_resting_icon_state = FALSE
-
/// Our collar
var/obj/item/clothing/neck/petcollar/collar
+ ///can we become cultists?
+ var/can_cult_convert = TRUE
+ ///whether we have a custom icon state when we get culted
+ var/cult_icon_state
/mob/living/basic/pet/Initialize(mapload)
. = ..()
@@ -22,6 +25,8 @@
collar = new(src)
update_icon(UPDATE_OVERLAYS)
+ if(can_cult_convert)
+ RegisterSignal(src, COMSIG_LIVING_CULT_SACRIFICED, PROC_REF(become_cultist))
/mob/living/basic/pet/Destroy()
. = ..()
@@ -43,6 +48,10 @@
/mob/living/basic/pet/update_overlays()
. = ..()
+ if(isnull(mind) && (FACTION_CULT in faction))
+ var/image/cult_indicator = image(icon = 'icons/mob/simple/pets.dmi', icon_state = "pet_cult_indicator", layer = ABOVE_GAME_PLANE)
+ . += cult_indicator
+
if(!collar || !collar_icon_state)
return
@@ -54,6 +63,12 @@
. += mutable_appearance(icon, "[collar_icon_state][stat_tag]collar")
. += mutable_appearance(icon, "[collar_icon_state][stat_tag]tag")
+/mob/living/basic/pet/update_icon_state()
+ if(cult_icon_state && (FACTION_CULT in faction))
+ icon_state = cult_icon_state
+ icon_living = cult_icon_state
+ return ..()
+
/mob/living/basic/pet/gib()
remove_collar(drop_location(), update_visuals = FALSE)
return ..()
diff --git a/code/modules/mob/living/basic/pets/pet_cult/pet_cult.dm b/code/modules/mob/living/basic/pets/pet_cult/pet_cult.dm
new file mode 100644
index 00000000000..438737a1ad2
--- /dev/null
+++ b/code/modules/mob/living/basic/pets/pet_cult/pet_cult.dm
@@ -0,0 +1,85 @@
+#define PET_CULT_ATTACK 10
+#define PET_CULT_HEALTH 50
+
+///turn into terrifying beasts
+/mob/living/basic/pet/proc/become_cultist(datum/source, list/invokers, datum/team)
+ SIGNAL_HANDLER
+
+ if(stat == DEAD || !can_cult_convert)
+ return
+
+ if(FACTION_CULT in faction)
+ return STOP_SACRIFICE
+
+ mind?.add_antag_datum(/datum/antagonist/cult, team)
+ qdel(GetComponent(/datum/component/obeys_commands))
+ melee_damage_lower = max(PET_CULT_ATTACK, initial(melee_damage_lower))
+ melee_damage_upper = max(PET_CULT_ATTACK + 5, initial(melee_damage_upper))
+ maxHealth = max(PET_CULT_HEALTH, initial(maxHealth))
+ fully_heal()
+
+ faction = list(FACTION_CULT) //we only serve the cult
+
+ if(isnull(cult_icon_state))
+ add_atom_colour(RUNE_COLOR_MEDIUMRED, FIXED_COLOUR_PRIORITY)
+
+ var/static/list/cult_appetite = list(
+ /obj/item/organ,
+ /obj/effect/decal/cleanable/blood,
+ )
+
+ var/static/list/death_loot = list(
+ /obj/effect/gibspawner/generic,
+ /obj/item/soulstone,
+ )
+
+ AddElement(/datum/element/basic_eating, heal_amt = 15, food_types = cult_appetite)
+ AddElement(/datum/element/death_drops, death_loot)
+
+ basic_mob_flags &= DEL_ON_DEATH
+ qdel(ai_controller)
+ ai_controller = new /datum/ai_controller/basic_controller/pet_cult(src)
+ var/datum/action/cooldown/spell/conjure/revive_rune/rune_ability = new(src)
+ rune_ability.Grant(src)
+ ai_controller.set_blackboard_key(BB_RUNE_ABILITY, rune_ability)
+ ai_controller.set_blackboard_key(BB_CULT_TEAM, team)
+
+ var/static/list/new_pet_commands = list(
+ /datum/pet_command/point_targeting/attack,
+ /datum/pet_command/follow,
+ /datum/pet_command/free,
+ /datum/pet_command/idle,
+ /datum/pet_command/untargeted_ability/draw_rune,
+ )
+ AddComponent(/datum/component/obeys_commands, new_pet_commands)
+ RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(activate_rune), override = TRUE)
+ update_appearance()
+ return STOP_SACRIFICE
+
+
+/mob/living/basic/pet/proc/activate_rune(datum/source, atom/target)
+ SIGNAL_HANDLER
+
+ if(!istype(target, /obj/effect/rune/raise_dead))
+ return NONE
+
+ target.attack_hand(src)
+
+ return COMPONENT_CANCEL_ATTACK_CHAIN
+
+/mob/living/basic/pet/Login()
+ . = ..()
+ if(!. || !client)
+ return FALSE
+
+ if(!(FACTION_CULT in faction))
+ return
+ var/datum/team/cult_team = locate(/datum/team/cult) in GLOB.antagonist_teams
+ if(isnull(cult_team))
+ return
+ mind.add_antag_datum(/datum/antagonist/cult, cult_team)
+ update_appearance(UPDATE_OVERLAYS)
+
+
+#undef PET_CULT_ATTACK
+#undef PET_CULT_HEALTH
diff --git a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_abilities.dm b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_abilities.dm
new file mode 100644
index 00000000000..83d70336f2c
--- /dev/null
+++ b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_abilities.dm
@@ -0,0 +1,14 @@
+/datum/action/cooldown/spell/conjure/revive_rune
+ name = "Create Revival Rune"
+ button_icon = 'icons/obj/antags/cult/rune.dmi'
+ button_icon_state = "1"
+ background_icon_state = "bg_cult"
+ overlay_icon_state = "bg_cult_border"
+ spell_requirements = NONE
+ cooldown_time = 30 SECONDS
+ summon_type = list(
+ /obj/effect/rune/raise_dead,
+ )
+ summon_radius = 0
+ create_summon_timer = 5 SECONDS
+ sound = 'sound/magic/exit_blood.ogg'
diff --git a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm
new file mode 100644
index 00000000000..dc778b5816f
--- /dev/null
+++ b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm
@@ -0,0 +1,246 @@
+/datum/ai_controller/basic_controller/pet_cult
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/cultist,
+ BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/cultist,
+ BB_FRIENDLY_MESSAGE = "eagerly awaits your command...",
+ )
+
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/befriend_cultists,
+ /datum/ai_planning_subtree/find_occupied_rune,
+ /datum/ai_planning_subtree/find_dead_cultist,
+ /datum/ai_planning_subtree/drag_target_to_rune,
+ /datum/ai_planning_subtree/pet_planning,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree,
+ )
+ ai_traits = PAUSE_DURING_DO_AFTER
+
+///if target gets pulled away, unset him
+/datum/ai_controller/basic_controller/pet_cult/proc/delete_pull_target(datum/source, atom/movable/was_pulling)
+ SIGNAL_HANDLER
+
+ UnregisterSignal(src, COMSIG_ATOM_NO_LONGER_PULLING)
+
+ if(was_pulling == blackboard[BB_DEAD_CULTIST])
+ clear_blackboard_key(BB_DEAD_CULTIST)
+
+///targeting strat to attack non cultists
+/datum/targeting_strategy/basic/cultist
+
+/datum/targeting_strategy/basic/cultist/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
+ return IS_CULTIST_OR_CULTIST_MOB(the_target)
+
+///befriend all cultists around us!
+/datum/ai_planning_subtree/befriend_cultists
+
+/datum/ai_planning_subtree/befriend_cultists/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ if(controller.blackboard_key_exists(BB_FRIENDLY_CULTIST))
+ controller.queue_behavior(/datum/ai_behavior/befriend_target, BB_FRIENDLY_CULTIST)
+ return
+
+ controller.queue_behavior(/datum/ai_behavior/find_and_set/friendly_cultist, BB_FRIENDLY_CULTIST, /mob/living/carbon)
+
+///behavior to find cultists that we befriend
+/datum/ai_behavior/find_and_set/friendly_cultist
+ action_cooldown = 5 SECONDS
+ behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
+
+/datum/ai_behavior/find_and_set/friendly_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range)
+ var/mob/living/living_pawn = controller.pawn
+ for(var/mob/living/carbon/possible_cultist in oview(search_range, controller.pawn))
+ if(IS_CULTIST(possible_cultist) && !(living_pawn.faction.Find(REF(possible_cultist))))
+ return possible_cultist
+
+ return null
+
+///subtree to find a rune with a viable target on it, so we can go activate it
+/datum/ai_planning_subtree/find_occupied_rune
+
+/datum/ai_planning_subtree/find_occupied_rune/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ if((LAZYLEN(GLOB.sacrificed) - SOULS_TO_REVIVE - GLOB.sacrifices_used) < 0)
+ controller.clear_blackboard_key(BB_OCCUPIED_RUNE)
+ return
+
+ if(controller.blackboard_key_exists(BB_OCCUPIED_RUNE))
+ controller.queue_behavior(/datum/ai_behavior/activate_rune, BB_OCCUPIED_RUNE)
+ return SUBTREE_RETURN_FINISH_PLANNING
+
+ controller.queue_behavior(/datum/ai_behavior/find_and_set/occupied_rune, BB_OCCUPIED_RUNE, /obj/effect/rune/raise_dead)
+
+/datum/ai_behavior/find_and_set/occupied_rune
+
+/datum/ai_behavior/find_and_set/occupied_rune/search_tactic(datum/ai_controller/controller, locate_path, search_range)
+ var/datum/team/cult/cult_team = controller.blackboard[BB_CULT_TEAM]
+ if(isnull(cult_team))
+ return null
+
+ for(var/obj/effect/rune/raise_dead/target_rune in oview(search_range, controller.pawn))
+ controller.set_blackboard_key(BB_NEARBY_RUNE, target_rune)
+ var/mob/living/occupant = locate(/mob/living/carbon/human) in get_turf(target_rune)
+ if(isnull(occupant))
+ continue
+ if(occupant.stat != DEAD || !IS_CULTIST(occupant))
+ continue
+ return target_rune
+
+ return null
+
+/datum/ai_behavior/activate_rune
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION | AI_BEHAVIOR_REQUIRE_REACH
+ action_cooldown = 3 SECONDS
+
+/datum/ai_behavior/activate_rune/setup(datum/ai_controller/controller, target_key)
+ . = ..()
+ var/turf/target = controller.blackboard[target_key]
+ if(isnull(target))
+ return FALSE
+ set_movement_target(controller, target)
+
+/datum/ai_behavior/activate_rune/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
+ . = ..()
+ var/atom/target = controller.blackboard[target_key]
+
+ if(QDELETED(target))
+ finish_action(controller, FALSE, target_key)
+ return
+
+ var/datum/team/cult/cult_team = controller.blackboard[BB_CULT_TEAM]
+ var/mob/living/revive_mob = locate(/mob/living) in get_turf(target)
+
+ if(isnull(revive_mob) || revive_mob.stat != DEAD || !(revive_mob.mind in cult_team.members))
+ finish_action(controller, FALSE, target_key)
+ return
+
+ var/mob/living/basic/living_pawn = controller.pawn
+ living_pawn.melee_attack(target)
+
+ finish_action(controller, TRUE, target_key)
+ return
+
+/datum/ai_behavior/activate_rune/finish_action(datum/ai_controller/controller, success, target_key)
+ . = ..()
+ controller.clear_blackboard_key(target_key)
+
+
+///find targets that we can revive
+/datum/ai_planning_subtree/find_dead_cultist
+
+/datum/ai_planning_subtree/find_dead_cultist/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ if((LAZYLEN(GLOB.sacrificed) - SOULS_TO_REVIVE - GLOB.sacrifices_used) < 0)
+ controller.clear_blackboard_key(BB_DEAD_CULTIST)
+ return
+
+ var/mob/living/living_pawn = controller.pawn
+
+ if(!isnull(living_pawn.pulling))
+ return
+
+ if(controller.blackboard_key_exists(BB_DEAD_CULTIST))
+ controller.queue_behavior(/datum/ai_behavior/pull_target/cult_revive, BB_DEAD_CULTIST)
+ return SUBTREE_RETURN_FINISH_PLANNING
+
+ controller.queue_behavior(/datum/ai_behavior/find_and_set/dead_cultist, BB_DEAD_CULTIST, /mob/living/carbon/human)
+
+/datum/ai_behavior/find_and_set/dead_cultist
+
+/datum/ai_behavior/find_and_set/dead_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range)
+ var/datum/team/cult/cult_team = controller.blackboard[BB_CULT_TEAM]
+ if(isnull(cult_team))
+ return null
+ var/mob/living/living_pawn = controller.pawn
+ for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
+ if(target.stat != DEAD)
+ continue
+ if(!IS_CULTIST(target))
+ continue
+ if(target.buckled || target.move_resist > living_pawn.move_force || target.pulledby)
+ continue
+ if(locate(/obj/effect/rune/raise_dead) in target.loc)
+ continue
+ return target
+ return null
+
+/datum/ai_behavior/pull_target/cult_revive
+
+/datum/ai_behavior/pull_target/cult_revive/finish_action(datum/ai_controller/basic_controller/controller, succeeded, target_key)
+ . = ..()
+ if(!succeeded)
+ return
+ var/atom/target = controller.blackboard[target_key]
+ if(QDELETED(target))
+ return
+ controller.RegisterSignal(controller.pawn, COMSIG_ATOM_NO_LONGER_PULLING, TYPE_PROC_REF(/datum/ai_controller/basic_controller/pet_cult, delete_pull_target), override = TRUE)
+
+/datum/ai_planning_subtree/drag_target_to_rune
+
+/datum/ai_planning_subtree/drag_target_to_rune/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+
+ if(!controller.blackboard_key_exists(BB_DEAD_CULTIST)) //no target, we dont need to do anything
+ return
+
+ var/mob/living/our_pawn = controller.pawn
+
+ if(isnull(our_pawn.pulling))
+ return
+
+ var/atom/target_rune = controller.blackboard[BB_NEARBY_RUNE]
+
+ if(QDELETED(target_rune))
+ controller.queue_behavior(/datum/ai_behavior/use_mob_ability, BB_RUNE_ABILITY)
+ return SUBTREE_RETURN_FINISH_PLANNING
+
+ if(!can_see(our_pawn, target_rune, 9))
+ controller.clear_blackboard_key(BB_NEARBY_RUNE)
+ return
+
+ controller.queue_behavior(/datum/ai_behavior/drag_target_to_rune, BB_NEARBY_RUNE, BB_DEAD_CULTIST)
+
+///behavior to drag the target onto the rune
+/datum/ai_behavior/drag_target_to_rune
+ required_distance = 0
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
+
+/datum/ai_behavior/drag_target_to_rune/setup(datum/ai_controller/controller, target_key, cultist_key)
+ . = ..()
+ var/turf/target = controller.blackboard[target_key]
+ if(isnull(target))
+ return FALSE
+ set_movement_target(controller, target)
+
+/datum/ai_behavior/drag_target_to_rune/perform(seconds_per_tick, datum/ai_controller/controller, target_key, cultist_key)
+ . = ..()
+ var/mob/living/our_pawn = controller.pawn
+ var/atom/cultist_target = controller.blackboard[cultist_key]
+ if(isnull(cultist_target))
+ finish_action(controller, FALSE, target_key, cultist_key)
+ return
+ var/list/possible_dirs = GLOB.alldirs.Copy()
+ possible_dirs -= get_dir(our_pawn, cultist_target)
+ for(var/direction in possible_dirs)
+ var/turf/possible_turf = get_step(our_pawn, direction)
+ if(possible_turf.is_blocked_turf(source_atom = our_pawn))
+ possible_dirs -= direction
+ step(our_pawn, pick(possible_dirs))
+ our_pawn.stop_pulling()
+ finish_action(controller, TRUE, target_key, cultist_key)
+
+
+/datum/ai_behavior/drag_target_to_rune/finish_action(datum/ai_controller/controller, success, target_key, cultist_key)
+ . = ..()
+ if(success)
+ var/atom/revival_rune = controller.blackboard[target_key]
+ controller.set_blackboard_key(BB_OCCUPIED_RUNE, revival_rune)
+ controller.clear_blackboard_key(cultist_key)
+ controller.clear_blackboard_key(target_key)
+
+///command ability to draw runes
+/datum/pet_command/untargeted_ability/draw_rune
+ command_name = "Draw Rune"
+ command_desc = "Draw a revival rune."
+ radial_icon = 'icons/obj/antags/cult/rune.dmi'
+ radial_icon_state = "1"
+ speech_commands = list("rune", "revival")
+ ability_key = BB_RUNE_ABILITY
diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm
index b4414027368..026aacc0e7d 100644
--- a/code/modules/pai/pai.dm
+++ b/code/modules/pai/pai.dm
@@ -458,7 +458,7 @@
SIGNAL_HANDLER
for(var/mob/living/cultist as anything in invokers)
- to_chat(cultist, span_cultitalic("You don't think this is what Nar'Sie had in mind when She asked for blood sacrifices..."))
+ to_chat(cultist, span_cult_italic("You don't think this is what Nar'Sie had in mind when She asked for blood sacrifices..."))
return STOP_SACRIFICE
/// Updates the distance we can be from our pai card
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index ca9a0ff7023..3b5cd0e4cdd 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -407,7 +407,7 @@
removed_any = TRUE
qdel(BS)
if(removed_any)
- to_chat(affected_mob, span_cultlarge("Your blood rites falter as holy water scours your body!"))
+ to_chat(affected_mob, span_cult_large("Your blood rites falter as holy water scours your body!"))
if(data["deciseconds_metabolized"] >= (25 SECONDS)) // 10 units
affected_mob.adjust_stutter_up_to(4 SECONDS * REM * seconds_per_tick, 20 SECONDS)
@@ -417,7 +417,7 @@
if(prob(10))
affected_mob.visible_message(span_danger("[affected_mob] starts having a seizure!"), span_userdanger("You have a seizure!"))
affected_mob.Unconscious(12 SECONDS)
- to_chat(affected_mob, span_cultlarge("[pick("Your blood is your bond - you are nothing without it", "Do not forget your place", \
+ to_chat(affected_mob, span_cult_large("[pick("Your blood is your bond - you are nothing without it", "Do not forget your place", \
"All that power, and you still fail?", "If you cannot scour this poison, I shall scour your meager life!")]."))
if(data["deciseconds_metabolized"] >= (1 MINUTES)) // 24 units
diff --git a/code/modules/spells/spell_types/conjure/_conjure.dm b/code/modules/spells/spell_types/conjure/_conjure.dm
index 10b14bd47d5..99f0c5af821 100644
--- a/code/modules/spells/spell_types/conjure/_conjure.dm
+++ b/code/modules/spells/spell_types/conjure/_conjure.dm
@@ -15,12 +15,17 @@
var/summon_respects_density = FALSE
/// If TRUE, no two summons can be spawned in the same turf.
var/summon_respects_prev_spawn_points = TRUE
+ /// for how long must we stay still when summoning
+ var/create_summon_timer
/datum/action/cooldown/spell/conjure/is_valid_target(atom/cast_on)
return isturf(cast_on.loc)
/datum/action/cooldown/spell/conjure/cast(atom/cast_on)
. = ..()
+ if(create_summon_timer && !do_after(owner, create_summon_timer, target = cast_on.loc))
+ owner?.balloon_alert(owner, "need to stay still!")
+ return
var/list/to_summon_in = list()
for(var/turf/summon_turf in range(summon_radius, cast_on))
if(summon_respects_density && summon_turf.density)
diff --git a/icons/mob/simple/pets.dmi b/icons/mob/simple/pets.dmi
index 51e59b13ec0..e4c333216f1 100644
Binary files a/icons/mob/simple/pets.dmi and b/icons/mob/simple/pets.dmi differ
diff --git a/modular_skyrat/master_files/code/game/objects/items/holy_weapons.dm b/modular_skyrat/master_files/code/game/objects/items/holy_weapons.dm
index 114114bf09a..f4fa02707f7 100644
--- a/modular_skyrat/master_files/code/game/objects/items/holy_weapons.dm
+++ b/modular_skyrat/master_files/code/game/objects/items/holy_weapons.dm
@@ -79,7 +79,7 @@
/obj/item/nullrod/cultdagger/attack_self(mob/user)
if(narsian)
else if(user.mind && (user.mind.holy_role))
- to_chat(user, span_cultlarge("\"Partake in the language of blood..\""))
+ to_chat(user, span_cult_large("\"Partake in the language of blood..\""))
user.grant_language(/datum/language/narsie, source = LANGUAGE_MIND)
special_desc_requirement = NONE // No point in keeping something that can't no longer be used
narsian = TRUE
@@ -93,7 +93,7 @@
/obj/item/nullrod/claymore/darkblade/attack_self(mob/user)
if(narsian)
else if(user.mind && (user.mind.holy_role))
- to_chat(user, span_cultlarge("\"Partake in the language of blood..\""))
+ to_chat(user, span_cult_large("\"Partake in the language of blood..\""))
user.grant_language(/datum/language/narsie, source = LANGUAGE_MIND)
special_desc_requirement = NONE // No point in keeping something that can't no longer be used
narsian = TRUE
diff --git a/modular_skyrat/modules/mutants/code/mutant_component.dm b/modular_skyrat/modules/mutants/code/mutant_component.dm
index c9ace66db6e..d1a71caf9cf 100644
--- a/modular_skyrat/modules/mutants/code/mutant_component.dm
+++ b/modular_skyrat/modules/mutants/code/mutant_component.dm
@@ -108,7 +108,7 @@
if(host.stat != DEAD)
return
if(!ismutant(host))
- to_chat(host, span_cultlarge("You can feel your heart stopping, but something isn't right... \
+ to_chat(host, span_cult_large("You can feel your heart stopping, but something isn't right... \
life has not abandoned your broken form. You can only feel a deep and immutable hunger that \
not even death can stop, you will rise again!"))
var/revive_time = rand(REVIVE_TIME_LOWER, REVIVE_TIME_UPPER)
@@ -151,7 +151,7 @@
/datum/component/mutant_infection/proc/mutant_death()
SIGNAL_HANDLER
var/revive_time = rand(REVIVE_TIME_LOWER, REVIVE_TIME_UPPER)
- to_chat(host, span_cultlarge("You can feel your heart stopping, but something isn't right... you will rise again!"))
+ to_chat(host, span_cult_large("You can feel your heart stopping, but something isn't right... you will rise again!"))
timer_id = addtimer(CALLBACK(src, PROC_REF(regenerate)), revive_time, TIMER_STOPPABLE)
/datum/component/mutant_infection/proc/regenerate()
diff --git a/tgstation.dme b/tgstation.dme
index 9eca34adaeb..3f9288c14b7 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -966,6 +966,7 @@
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\find_parent.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targeting.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\pick_up_item.dm"
+#include "code\datums\ai\basic_mobs\basic_ai_behaviors\pull_target.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\run_away_from_target.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\set_travel_destination.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\step_towards_turf.dm"
@@ -4820,6 +4821,9 @@
#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\parrot_hoarding.dm"
#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\parrot_perching.dm"
#include "code\modules\mob\living\basic\pets\parrot\parrot_ai\parroting_action.dm"
+#include "code\modules\mob\living\basic\pets\pet_cult\pet_cult.dm"
+#include "code\modules\mob\living\basic\pets\pet_cult\pet_cult_abilities.dm"
+#include "code\modules\mob\living\basic\pets\pet_cult\pet_cult_ai.dm"
#include "code\modules\mob\living\basic\ruin_defender\flesh.dm"
#include "code\modules\mob\living\basic\ruin_defender\living_floor.dm"
#include "code\modules\mob\living\basic\ruin_defender\skeleton.dm"
diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss
index 0dc93df67d0..64a0db0b681 100644
--- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss
+++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss
@@ -579,24 +579,24 @@ em {
color: #973e3b;
}
-.cultitalic {
+.cult_italic {
color: #973e3b;
font-style: italic;
}
-.cultbold {
+.cult_bold {
color: #973e3b;
font-style: italic;
font-weight: bold;
}
-.cultboldtalic {
+.cult_bold_italic {
color: #973e3b;
font-weight: bold;
font-size: 185%;
}
-.cultlarge {
+.cult_large {
color: #973e3b;
font-weight: bold;
font-size: 185%;
diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss
index a3055867f40..0818d48d77e 100644
--- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss
+++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss
@@ -601,19 +601,19 @@ h2.alert {
font-style: italic;
}
-.cultbold {
+.cult_bold {
color: #973e3b;
font-style: italic;
font-weight: bold;
}
-.cultboldtalic {
+.cult_bold_italic {
color: #973e3b;
font-weight: bold;
font-size: 185%;
}
-.cultlarge {
+.cult_large {
color: #973e3b;
font-weight: bold;
font-size: 185%;