diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index bdc6ea2980..7c116cc606 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -334,7 +334,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
return
var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
- if(!antag)
+ if(!antag?.cult_team)
return
var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index 15d7744205..7b798f19e4 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -45,8 +45,11 @@ Credit where due:
// PROCS //
///////////
-/proc/is_servant_of_ratvar(mob/M)
- return istype(M) && !isobserver(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/clockcult)
+/proc/is_servant_of_ratvar(mob/M, require_full_power = FALSE, holy_water_check = FALSE)
+ if(!istype(M) || isobserver(M))
+ return FALSE
+ var/datum/antagonist/clockcult/D = M?.mind?.has_antag_datum(/datum/antagonist/clockcult)
+ return D && (!require_full_power || !D.neutered) && (!holy_water_check || !D.ignore_holy_water)
/proc/is_eligible_servant(mob/M)
if(!istype(M))
@@ -70,12 +73,14 @@ Credit where due:
return TRUE
return FALSE
-/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
+/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE, override_type)
if(!L || !L.mind)
return
var/update_type = /datum/antagonist/clockcult
if(silent)
update_type = /datum/antagonist/clockcult/silent
+ if(override_type) //prioritizes
+ update_type = override_type
var/datum/antagonist/clockcult/C = new update_type(L.mind)
C.make_team = create_team
C.show_in_roundend = create_team //tutorial scarabs begone
@@ -105,9 +110,6 @@ Credit where due:
L.playsound_local(get_turf(L), 'sound/ambience/antag/clockcultalr.ogg', 40, TRUE, frequency = 100000, pressure_affected = FALSE)
flash_color(L, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 5)
-
-
-
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
return
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 497cc2f1c3..8ec4123201 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -3,8 +3,11 @@
/datum/game_mode
var/list/datum/mind/cult = list()
-/proc/iscultist(mob/living/M)
- return istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/cult)
+/proc/iscultist(mob/living/M, require_full_power = FALSE, holy_water_check = FALSE)
+ if(!istype(M))
+ return FALSE
+ var/datum/antagonist/cult/D = M?.mind?.has_antag_datum(/datum/antagonist/cult)
+ return D && (!require_full_power || !D.neutered) && (!holy_water_check || !D.ignore_holy_water)
/datum/team/cult/proc/is_sacrifice_target(datum/mind/mind)
for(var/datum/objective/sacrifice/sac_objective in objectives)
@@ -93,7 +96,7 @@
add_cultist(cult_mind, 0, equip=TRUE)
if(!main_cult)
var/datum/antagonist/cult/C = cult_mind.has_antag_datum(/datum/antagonist/cult,TRUE)
- if(C && C.cult_team)
+ if(C?.cult_team)
main_cult = C.cult_team
..()
diff --git a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
index daa4e24c69..431416ede0 100644
--- a/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/clock_sigils.dm
@@ -279,9 +279,15 @@
sigil_name = "Vitality Matrix"
var/revive_cost = 150
var/sigil_active = FALSE
+ var/min_drain_health = -INFINITY
+ var/can_dust = TRUE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
+/obj/effect/clockwork/sigil/vitality/neutered
+ min_drain_health = 20
+ can_dust = FALSE
+
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
. = ..()
if(is_servant_of_ratvar(user) || isobserver(user))
@@ -306,7 +312,7 @@
animation_number++
if(!is_servant_of_ratvar(L))
var/vitality_drained = 0
- if(L.stat == DEAD && !consumed_vitality)
+ if(L.stat == DEAD && !consumed_vitality && can_dust)
consumed_vitality = TRUE //Prevent the target from being consumed multiple times
vitality_drained = L.maxHealth
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
@@ -318,7 +324,7 @@
if(!L.dropItemToGround(W))
qdel(W)
L.dust()
- else
+ else if(L.health > min_drain_health)
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
vitality_drained = L.adjustToxLoss(1, forced = TRUE)
else
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
index b12c72b4af..6e7d830db6 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
@@ -36,6 +36,24 @@
speed_multiplier = 0
no_cost = TRUE
+/obj/item/clockwork/slab/traitor
+ var/spent = FALSE
+
+/obj/item/clockwork/slab/traitor/check_uplink_validity()
+ return !spent
+
+/obj/item/clockwork/slab/traitor/attack_self(mob/living/user)
+ if(!is_servant_of_ratvar(user) && !spent)
+ to_chat(user, "You press your hand onto [src], golden tendrils of light latching onto you. Was this the best of ideas?")
+ if(add_servant_of_ratvar(user, FALSE, FALSE, /datum/antagonist/clockcult/neutered/traitor))
+ spent = TRUE
+ // Add some (5 KW) power so they don't suffer for 100 ticks
+ GLOB.clockwork_power += 5000
+ // This intentionally does not use adjust_clockwork_power.
+ else
+ to_chat(user, "[src] falls dark. It appears you weren't worthy.")
+ return ..()
+
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
diff --git a/code/modules/antagonists/clockcult/clock_scripture.dm b/code/modules/antagonists/clockcult/clock_scripture.dm
index 753de786dc..16d251fe92 100644
--- a/code/modules/antagonists/clockcult/clock_scripture.dm
+++ b/code/modules/antagonists/clockcult/clock_scripture.dm
@@ -30,6 +30,7 @@ Applications: 8 servants, 3 caches, and 100 CV
var/primary_component
var/important = FALSE //important scripture will be italicized in the slab's interface
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
+ var/requires_full_power = FALSE //requires the user to be a full, non neutered servant of ratvar
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
var/static/list/neovgre_penalty = list("Go to the station.", "Useless.", "Don't waste time.", "Pathetic.", "Wasteful.")
@@ -77,6 +78,9 @@ Applications: 8 servants, 3 caches, and 100 CV
/datum/clockwork_scripture/proc/can_recite() //If the words can be spoken
if(!invoker || !slab || invoker.get_active_held_item() != slab)
return FALSE
+ if(!is_servant_of_ratvar(invoker, requires_full_power))
+ to_chat(invoker, "You aren't strongly connected enough to Ratvar to invoke this!")
+ return FALSE
if(!invoker.can_speak_vocal())
to_chat(invoker, "You are unable to speak the words of the scripture!")
return FALSE
@@ -236,18 +240,21 @@ Applications: 8 servants, 3 caches, and 100 CV
return FALSE
return TRUE
+/datum/clockwork_scripture/create_object/proc/get_spawn_path(mob/user)
+ return object_path
+
/datum/clockwork_scripture/create_object/scripture_effects()
if(creator_message && observer_message)
invoker.visible_message(observer_message, creator_message)
else if(creator_message)
to_chat(invoker, creator_message)
- var/obj/O = new object_path (get_turf(invoker))
+ var/to_spawn = get_spawn_path(invoker)
+ var/obj/O = new to_spawn(get_turf(invoker))
O.ratvar_act() //update the new object so it gets buffed if ratvar is alive
if(isitem(O) && put_object_in_hands)
invoker.put_in_hands(O)
return TRUE
-
//Used specifically to create construct shells.
/datum/clockwork_scripture/create_object/construct
put_object_in_hands = FALSE
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
index 5d7a95222f..6349ecb581 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
@@ -88,7 +88,7 @@
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
-
+ requires_full_power = TRUE
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
/datum/clockwork_scripture/ranged_ability/kindle
@@ -211,6 +211,7 @@
quickbind = TRUE
quickbind_desc = "Returns you to Reebe."
var/client_color
+ requires_full_power = TRUE
/datum/clockwork_scripture/abscond/check_special_requirements()
if(is_reebe(invoker.z))
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
index 4e1a5b42cb..d6296aeaa0 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
@@ -50,7 +50,6 @@
return FALSE
return ..()
-
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
/datum/clockwork_scripture/create_object/vitality_matrix
descname = "Trap, Damage to Healing"
@@ -77,6 +76,10 @@
return FALSE
return ..()
+/datum/clockwork_scripture/create_object/vitality_matrix/get_spawn_path(mob/user)
+ if(!is_servant_of_ratvar(user, TRUE))
+ return /obj/effect/clockwork/sigil/vitality/neutered
+ return ..()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm
index cf3d88983c..cbfd443744 100644
--- a/code/modules/antagonists/clockcult/clockcult.dm
+++ b/code/modules/antagonists/clockcult/clockcult.dm
@@ -5,15 +5,27 @@
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
antag_moodlet = /datum/mood_event/cult
+ var/datum/action/innate/hierophant/hierophant_network = new
threat = 3
- var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
+ var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
+ var/ignore_eligibility_check = FALSE
+ var/ignore_holy_water = FALSE
/datum/antagonist/clockcult/silent
silent = TRUE
show_in_antagpanel = FALSE //internal
+/datum/antagonist/clockcult/neutered
+ neutered = TRUE
+
+/datum/antagonist/clockcult/neutered/traitor
+ ignore_eligibility_check = TRUE
+ ignore_holy_water = TRUE
+ show_in_roundend = FALSE
+ make_team = FALSE
+
/datum/antagonist/clockcult/Destroy()
qdel(hierophant_network)
return ..()
@@ -38,7 +50,7 @@
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
- if(.)
+ if(. && !ignore_eligibility_check)
. = is_eligible_servant(new_owner.current)
/datum/antagonist/clockcult/greet()
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index c4a8c1e827..bea86d8bb4 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -439,7 +439,7 @@
"A feeling of warmth washes over you, rays of holy light surround your body and protect you from the flash of light!")
else // cult doesn't stun any longer when halos are out, instead it does burn damage + knockback!
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
- if(user_antag.cult_team.cult_ascendent)
+ if(user_antag.cult_team?.cult_ascendent)
if(!iscultist(L))
L.adjustFireLoss(20)
if(L.move_resist < MOVE_FORCE_STRONG)
@@ -577,7 +577,9 @@
var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/candidate = target
- if(candidate.use(50))
+ if(!iscultist(user, TRUE))
+ to_chat(user, "You are not strongly connected enough to Nar'sie to use make constructs...")
+ else if(candidate.use(50))
uses--
to_chat(user, "A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!")
new /obj/structure/constructshell(T)
@@ -600,7 +602,9 @@
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
- if(candidate.mmi)
+ if(!iscultist(user, TRUE))
+ to_chat(user, "You are not strongly connected enough to Nar'sie to use make constructs...")
+ else if(candidate.mmi)
user.visible_message("A dark cloud emanates from [user]'s hand and swirls around [candidate]!")
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
var/prev_color = candidate.color
@@ -820,6 +824,8 @@
if("Blood Beam (500)")
if(uses < 500)
to_chat(user, "You need 500 charges to perform this rite.")
+ else if(!iscultist(user, TRUE))
+ to_chat(user, "You are not strongly connected to Nar'sie enough to use something of this power.")
else
var/obj/rite = new /obj/item/blood_beam()
uses -= 500
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 1746fd135c..023794182a 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -11,15 +11,27 @@
var/datum/action/innate/cult/blood_magic/magic = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
+ var/make_team = TRUE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
+ var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
+ var/ignore_eligibility_checks = FALSE
+ var/ignore_holy_water = FALSE
+/datum/antagonist/cult/neutered
+ neutered = TRUE
+
+/datum/antagonist/cult/neutered/traitor
+ ignore_eligibility_checks = TRUE
+ ignore_holy_water = TRUE
+ show_in_roundend = FALSE
+ make_team = FALSE
/datum/antagonist/cult/get_team()
return cult_team
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
- if(!new_team)
+ if(!new_team && make_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
if(!H.owner)
@@ -30,12 +42,12 @@
cult_team = new /datum/team/cult
cult_team.setup_objectives()
return
- if(!istype(new_team))
+ if(make_team && !istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
cult_team = new_team
/datum/antagonist/cult/proc/add_objectives()
- objectives |= cult_team.objectives
+ objectives |= cult_team?.objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
@@ -44,7 +56,7 @@
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
- if(. && !ignore_implant)
+ if(. && !ignore_implant && !ignore_eligibility_checks)
. = is_convertable_to_cult(new_owner.current,cult_team)
/datum/antagonist/cult/greet()
@@ -62,7 +74,7 @@
SSticker.mode.update_cult_icons_added(owner)
current.log_message("has been converted to the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
- if(cult_team.blood_target && cult_team.blood_target_image && current.client)
+ if(cult_team?.blood_target && cult_team.blood_target_image && current.client)
current.client.images += cult_team.blood_target_image
@@ -105,13 +117,13 @@
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
- if(!cult_team.cult_master)
+ if(!cult_team?.cult_master)
vote.Grant(current)
communion.Grant(current)
if(ishuman(current))
magic.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
- if(cult_team.cult_risen)
+ if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
@@ -144,7 +156,7 @@
owner.current.visible_message("[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!", null, null, null, owner.current)
to_chat(owner.current, "An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.")
owner.current.log_message("has renounced the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
- if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
+ if(cult_team?.blood_target && cult_team.blood_target_image && owner.current.client)
owner.current.client.images -= cult_team.blood_target_image
. = ..()
@@ -206,7 +218,7 @@
throwing.Grant(current)
current.update_action_buttons_icon()
current.apply_status_effect(/datum/status_effect/cult_master)
- if(cult_team.cult_risen)
+ if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index 761412e9f8..8021443217 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -74,7 +74,7 @@
/datum/action/innate/cult/mastervote/IsAvailable()
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
- if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
+ if(!C?.cult_team || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
@@ -82,6 +82,9 @@
var/choice = alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
if(choice == "Yes" && IsAvailable())
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C.cult_team)
+ to_chat(owner, "Do you not alreaady lead yourself?")
+ return
pollCultists(owner,C.cult_team)
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
@@ -151,6 +154,9 @@
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
+ if(!antag.cult_team)
+ to_chat(owner, "You have no team. You are alone.")
+ return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -261,7 +267,10 @@
return FALSE
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
-
+ if(!C.cult_team)
+ to_chat(ranged_ability_user, "What is the point of marking a target for yourself?")
+ remove_ranged_ability()
+ return
if(target in view(7, get_turf(ranged_ability_user)))
if(C.cult_team.blood_target)
to_chat(ranged_ability_user, "The cult has already designated a target!")
@@ -330,8 +339,11 @@
/datum/action/innate/cult/ghostmark/Activate()
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!C.cult_team)
+ to_chat(owner, "You are alone. You do not have a team.")
+ return
if(C.cult_team.blood_target)
- if(cooldown>world.time)
+ if(cooldown > world.time)
reset_blood_target(C.cult_team)
to_chat(owner, "You have cleared the cult's blood target!")
deltimer(C.cult_team.blood_target_reset_timer)
@@ -339,7 +351,7 @@
else
to_chat(owner, "The cult has already designated a target!")
return
- if(cooldown>world.time)
+ if(cooldown > world.time)
to_chat(owner, "You aren't ready to place another blood mark yet!")
return
target = owner.orbiting?.parent || get_turf(owner)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index b31bfc0693..11c0e9ade5 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -6,6 +6,21 @@
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
+/obj/item/tome/traitor
+ var/spent = FALSE
+
+/obj/item/tome/traitor/check_uplink_validity()
+ return !spent
+
+/obj/item/tome/traitor/attack_self(mob/living/user)
+ if(!iscultist(user) && !spent)
+ to_chat(user, "You press your hand onto [src], sinister tendrils of corrupted magic swirling around you. Was this the best of ideas?")
+ if(user.mind.add_antag_datum(/datum/antagonist/cult/neutered/traitor))
+ spent = TRUE
+ else
+ to_chat(user, "[src] falls dark. It appears you weren't worthy.")
+ return ..()
+
/obj/item/melee/cultblade/dagger
name = "ritual dagger"
desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods."
@@ -509,7 +524,7 @@
var/static/curselimit = 0
/obj/item/shuttle_curse/attack_self(mob/living/user)
- if(!iscultist(user))
+ if(!iscultist(user, TRUE))
user.dropItemToGround(src, TRUE)
user.DefaultCombatKnockdown(100)
to_chat(user, "A powerful force shoves you away from [src]!")
diff --git a/code/modules/antagonists/cult/ritual.dm b/code/modules/antagonists/cult/ritual.dm
index e92f562db3..40804ccc24 100644
--- a/code/modules/antagonists/cult/ritual.dm
+++ b/code/modules/antagonists/cult/ritual.dm
@@ -59,6 +59,9 @@ This file contains the cult dagger and rune list code
rune_to_scribe = GLOB.rune_types[entered_rune_name]
if(!rune_to_scribe)
return
+ if(!iscultist(user, initial(rune_to_scribe.requires_full_power)))
+ to_chat(user, "You aren't strongly connected enough to Nar'sie to do draw this.")
+ return
if(initial(rune_to_scribe.req_keyword))
chosen_keyword = stripped_input(user, "Enter a keyword for the new rune.", "Words of Power")
if(!chosen_keyword)
@@ -84,8 +87,8 @@ This file contains the cult dagger and rune list code
to_chat(user, "Only one ritual site remains - it must be reserved for the final summoning!")
return
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
- var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
- var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
+ var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team?.objectives
+ var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team?.objectives
if(!summon_objective)
to_chat(user, "Nar'Sie does not wish to be summoned!")
return
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index ec763a66d7..b0538d6521 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -32,6 +32,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
var/scribe_delay = 40 //how long the rune takes to create
var/scribe_damage = 0.1 //how much damage you take doing it
+ var/requires_full_power = FALSE //requires full power to draw or invoke
var/invoke_damage = 0 //how much damage invokers take when invoking it
var/construct_invoke = TRUE //if constructs can invoke it
@@ -185,6 +186,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_OFFER
req_cultists = 1
rune_in_use = FALSE
+ requires_full_power = TRUE
/obj/effect/rune/convert/do_invoke_glow()
return
@@ -458,6 +460,7 @@ structure_check() searches for nearby cultist structures required for the invoca
pixel_y = -32
scribe_delay = 500 //how long the rune takes to create
scribe_damage = 40.1 //how much damage you take doing it
+ requires_full_power = TRUE
var/used = FALSE
/obj/effect/rune/narsie/Initialize(mapload, set_keyword)
@@ -482,6 +485,9 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
return
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!user_antag.cult_team)
+ to_chat(user, "You can't seem to make the arcane links to your fellows that you'd need to use this.")
+ return
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))
@@ -812,6 +818,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invoke_damage = 10
construct_invoke = FALSE
color = RUNE_COLOR_DARKRED
+ requires_full_power = TRUE
var/mob/living/affecting = null
var/ghost_limit = 3
var/ghosts = 0
@@ -942,6 +949,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
req_cultists = 3
scribe_delay = 100
+ requires_full_power = TRUE
/obj/effect/rune/apocalypse/invoke(var/list/invokers)
if(rune_in_use)
@@ -950,6 +958,9 @@ structure_check() searches for nearby cultist structures required for the invoca
var/area/place = get_area(src)
var/mob/living/user = invokers[1]
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
+ if(!user_antag.cult_team)
+ to_chat(user, "You can't seem to make the arcane links to your fellows that you'd need to use this.")
+ return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
if(summon_objective.summon_spots.len <= 1)
to_chat(user, "Only one ritual site remains - it must be reserved for the final summoning!")
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index 0f43dfaf3a..d7f1046cd7 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -31,12 +31,12 @@
/obj/item/soulstone/pickup(mob/living/user)
..()
- if(!iscultist(user) && !iswizard(user) && !usability)
+ if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.")
/obj/item/soulstone/examine(mob/user)
. = ..()
- if(usability || iscultist(user) || iswizard(user) || isobserver(user))
+ if(usability || iscultist(user, TRUE) || iswizard(user) || isobserver(user))
if (old_shard)
. += "A soulstone, used to capture a soul, either from dead humans or from freed shades."
else
@@ -53,7 +53,7 @@
//////////////////////////////Capturing////////////////////////////////////////////////////////
/obj/item/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
- if(!iscultist(user) && !iswizard(user) && !usability)
+ if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(100)
to_chat(user, "Your body is wracked with debilitating pain!")
return
@@ -74,7 +74,7 @@
/obj/item/soulstone/attack_self(mob/living/user)
if(!in_range(src, user))
return
- if(!iscultist(user) && !iswizard(user) && !usability)
+ if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(100)
to_chat(user, "Your body is wracked with debilitating pain!")
return
@@ -103,7 +103,7 @@
/obj/structure/constructshell/examine(mob/user)
. = ..()
- if(iscultist(user) || iswizard(user) || user.stat == DEAD)
+ if(iscultist(user, TRUE) || iswizard(user) || user.stat == DEAD)
. += "A construct shell, used to house bound souls from a soulstone."
. += "Placing a soulstone with a soul into this shell allows you to produce your choice of the following:"
. += "An Artificer, which can produce more shells and soulstones, as well as fortifications."
@@ -113,7 +113,7 @@
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/soulstone))
var/obj/item/soulstone/SS = O
- if(!iscultist(user) && !iswizard(user) && !SS.usability)
+ if(!iscultist(user, TRUE) && !iswizard(user) && !SS.usability)
to_chat(user, "An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.")
user.Dizzy(30)
return
@@ -145,7 +145,7 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
- if(C && C.cult_team.is_sacrifice_target(T.mind))
+ if(C && C.cult_team?.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "\"This soul is mine. SACRIFICE THEM!\"")
else
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index a6366c03fe..674cc722d8 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -392,6 +392,9 @@
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult)
if(!C)
return
+ if(!C.cult_team)
+ to_chat(the_construct, "You are alone, and have no team.")
+ return
var/datum/objective/eldergod/summon_objective = locate() in C.cult_team.objectives
if(summon_objective.check_completion())
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index a073997b9d..c471047682 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -51,7 +51,8 @@
for(var/datum/antagonist/cult/C in GLOB.antagonists)
if(!C.owner)
continue
- all_cults |= C.cult_team
+ if(C.cult_team)
+ all_cults |= C.cult_team
for(var/datum/team/cult/T in all_cults)
deltimer(T.blood_target_reset_timer)
T.blood_target = src
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index d9b2aafb4b..b73838e6c1 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -332,7 +332,7 @@
data = list("misc" = 1)
data["misc"]++
M.jitteriness = min(M.jitteriness+4,10)
- if(iscultist(M))
+ if(iscultist(M, FALSE, TRUE))
for(var/datum/action/innate/cult/blood_magic/BM in M.actions)
if(!BM.holy_dispel)
BM.holy_dispel = TRUE
@@ -361,7 +361,7 @@
if("emote")
M.visible_message("[M] [pick("whimpers quietly", "shivers as though cold", "glances around in paranoia")].")
if(data["misc"] >= 60) // 30 units, 135 seconds
- if(iscultist(M) || is_servant_of_ratvar(M))
+ if(iscultist(M, FALSE, TRUE) || is_servant_of_ratvar(M, FALSE, TRUE))
if(iscultist(M))
SSticker.mode.remove_cultist(M.mind, FALSE, TRUE)
else if(is_servant_of_ratvar(M))
diff --git a/code/modules/uplink/uplink_items/uplink_roles.dm b/code/modules/uplink/uplink_items/uplink_roles.dm
index 3d28010133..778edf8cc8 100644
--- a/code/modules/uplink/uplink_items/uplink_roles.dm
+++ b/code/modules/uplink/uplink_items/uplink_roles.dm
@@ -92,6 +92,22 @@
restricted_roles = list("Chaplain")
surplus = 5 //Very low chance to get it in a surplus crate even without being the chaplain
+/datum/uplink_item/role_restricted/clockwork_slab
+ name = "Clockwork Slab"
+ desc = "A reverse engineered clockwork slab. Is this really a good idea?."
+ item = /obj/item/clockwork/slab/traitor
+ cost = 20
+ refundable = TRUE
+ restricted_roles = list("Chaplain")
+
+/datum/uplink_item/role_restricted/arcane_tome
+ name = "Arcane Tome"
+ desc = "A replica of a Nar'sian tome. This is probably a bad idea.."
+ item = /obj/item/tome/traitor
+ cost = 20
+ refundable = TRUE
+ restricted_roles = list("Chaplain")
+
/datum/uplink_item/role_restricted/explosive_hot_potato
name = "Exploding Hot Potato"
desc = "A potato rigged with explosives. On activation, a special mechanism is activated that prevents it from being dropped. \