Chaplains can deaconize one person, everyone else loses bible perms (#90686)

This commit is contained in:
John Willard
2025-05-04 10:49:36 -04:00
committed by Roxy
parent 73c822433b
commit 7e7b78ad05
9 changed files with 217 additions and 148 deletions

View File

@@ -61,3 +61,10 @@
#define BLESSING_IGNORED "ignored"
/// Blessed successfully by healing or whatever
#define BLESSING_SUCCESS "success"
///The rite will automatically delete itself by the religious tool calling it after it's invoked.
#define RITE_AUTO_DELETE (1<<0)
///The rite can be performed multiple times with a religious tool, so don't delete/null it.
#define RITE_ALLOW_MULTIPLE_PERFORMS (1<<1)
///The rite can only be fully performed once, so we'll completely remove it from the rite list afterwards.
#define RITE_ONE_TIME_USE (1<<2)

View File

@@ -25,13 +25,13 @@
var/list/rite_types_allowlist
/datum/component/religious_tool/Initialize(
operation_flags = ALL,
force_catalyst_afterattack = FALSE,
after_sect_select_cb = null,
catalyst_type = /obj/item/book/bible,
charges = -1,
rite_types_allowlist = null,
)
operation_flags = ALL,
force_catalyst_afterattack = FALSE,
after_sect_select_cb = null,
catalyst_type = /obj/item/book/bible,
charges = -1,
rite_types_allowlist = null,
)
. = ..()
SetGlobalToLocal() //attempt to connect on start in case one already exists!
src.operation_flags = operation_flags
@@ -44,8 +44,8 @@
RegisterSignal(SSdcs, COMSIG_RELIGIOUS_SECT_RESET, PROC_REF(on_sect_reset))
/datum/component/religious_tool/Destroy(force)
QDEL_NULL(performing_rite)
easy_access_sect = null
performing_rite = null
catalyst_type = null
after_sect_select_cb = null
return ..()
@@ -166,22 +166,30 @@
if(rite_types_allowlist && !is_path_in_list(path, rite_types_allowlist))
to_chat(user, span_warning("This cannot perform that kind of rite."))
return
if(performing_rite)
to_chat(user, span_notice("There is a rite currently being performed here already."))
return
if(!user.can_perform_action(parent, FORBID_TELEKINESIS_REACH))
to_chat(user,span_warning("You are not close enough to perform the rite."))
return
performing_rite = new path(parent)
//we have a rite already, but we want to do a new one.
if(performing_rite && !ispath(performing_rite.type, path))
QDEL_NULL(performing_rite)
if(!performing_rite)
performing_rite = new path(parent)
if(!performing_rite.perform_rite(user, parent))
QDEL_NULL(performing_rite)
if(!(performing_rite.rite_flags & RITE_ALLOW_MULTIPLE_PERFORMS))
QDEL_NULL(performing_rite)
return
performing_rite.invoke_effect(user, parent)
if(performing_rite.invoke_effect(user, parent))
performing_rite.post_invoke_effects(user, parent)
easy_access_sect.adjust_favor(-performing_rite.favor_cost)
if(performing_rite.auto_delete)
QDEL_NULL(performing_rite)
else
performing_rite = null
if(!(performing_rite.rite_flags & RITE_ALLOW_MULTIPLE_PERFORMS))
if(performing_rite.rite_flags & RITE_AUTO_DELETE)
QDEL_NULL(performing_rite)
else
performing_rite = null
if(charges)
charges--
if(!charges)

View File

@@ -280,42 +280,40 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
log_combat(user, target_mob, "attacked", src)
/obj/item/book/bible/interact_with_atom(atom/bible_smacked, mob/living/user, list/modifiers)
if(!user.mind?.holy_role)
return
if(SEND_SIGNAL(bible_smacked, COMSIG_BIBLE_SMACKED, user) & COMSIG_END_BIBLE_CHAIN)
return ITEM_INTERACT_SUCCESS
if(isfloorturf(bible_smacked))
if(user.mind?.holy_role)
var/area/current_area = get_area(bible_smacked)
if(!GLOB.chaplain_altars.len && istype(current_area, /area/station/service/chapel))
make_new_altar(bible_smacked, user)
return ITEM_INTERACT_SUCCESS
for(var/obj/effect/rune/nearby_runes in range(2, user))
nearby_runes.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
var/area/current_area = get_area(bible_smacked)
if(!GLOB.chaplain_altars.len && istype(current_area, /area/station/service/chapel))
make_new_altar(bible_smacked, user)
return ITEM_INTERACT_SUCCESS
for(var/obj/effect/rune/nearby_runes in range(2, user))
nearby_runes.SetInvisibility(INVISIBILITY_NONE, id=type, priority=INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
bible_smacked.balloon_alert(user, "floor smacked!")
return ITEM_INTERACT_SUCCESS
if(user.mind?.holy_role)
if(bible_smacked.reagents?.has_reagent(/datum/reagent/water)) // blesses all the water in the holder
bible_smacked.balloon_alert(user, "blessed")
var/water2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/water)
bible_smacked.reagents.del_reagent(/datum/reagent/water)
bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,water2holy)
. = ITEM_INTERACT_SUCCESS
if(bible_smacked.reagents?.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me
bible_smacked.balloon_alert(user, "purified")
var/unholy2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/fuel/unholywater)
bible_smacked.reagents.del_reagent(/datum/reagent/fuel/unholywater)
bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,unholy2holy)
. = ITEM_INTERACT_SUCCESS
if(istype(bible_smacked, /obj/item/book/bible) && !istype(bible_smacked, /obj/item/book/bible/syndicate))
bible_smacked.balloon_alert(user, "converted")
var/obj/item/book/bible/other_bible = bible_smacked
other_bible.name = name
other_bible.icon_state = icon_state
other_bible.inhand_icon_state = inhand_icon_state
other_bible.deity_name = deity_name
. = ITEM_INTERACT_SUCCESS
if(.)
return .
if(bible_smacked.reagents?.has_reagent(/datum/reagent/water)) // blesses all the water in the holder
bible_smacked.balloon_alert(user, "blessed")
var/water2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/water)
bible_smacked.reagents.del_reagent(/datum/reagent/water)
bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,water2holy)
return ITEM_INTERACT_SUCCESS
if(bible_smacked.reagents?.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me
bible_smacked.balloon_alert(user, "purified")
var/unholy2holy = bible_smacked.reagents.get_reagent_amount(/datum/reagent/fuel/unholywater)
bible_smacked.reagents.del_reagent(/datum/reagent/fuel/unholywater)
bible_smacked.reagents.add_reagent(/datum/reagent/water/holywater,unholy2holy)
return ITEM_INTERACT_SUCCESS
if(istype(bible_smacked, /obj/item/book/bible) && !istype(bible_smacked, /obj/item/book/bible/syndicate))
bible_smacked.balloon_alert(user, "converted")
var/obj/item/book/bible/other_bible = bible_smacked
other_bible.name = name
other_bible.icon_state = icon_state
other_bible.inhand_icon_state = inhand_icon_state
other_bible.deity_name = deity_name
return ITEM_INTERACT_SUCCESS
if(istype(bible_smacked, /obj/item/melee/cultblade/haunted) && !IS_CULTIST(user))
var/obj/item/melee/cultblade/haunted/sword_smacked = bible_smacked

View File

@@ -0,0 +1,91 @@
/**
* Deaconize
* Makes a sentient, non-cult member of the station into a Holy person, able to use bibles & other chap gear.
* Is a one-time use ability, given to all sects that don't have their own variation of it.
*/
/datum/religion_rites/deaconize
name = "Deaconize"
desc = "Converts someone to your sect. They must be willing, so the first invocation will instead prompt them to join. \
They will gain the same holy abilities as you, this is a one-time use so make sure they are worthy!"
ritual_length = 30 SECONDS
ritual_invocations = list(
"A good, honorable person has been brought here by faith ...",
"With their hands ready to serve ...",
"Heart ready to listen ...",
"And soul ready to follow ...",
"May we offer our own hand in return ..."
)
invoke_msg = "And use them to the best of our abilities."
rite_flags = RITE_ALLOW_MULTIPLE_PERFORMS | RITE_ONE_TIME_USE
///The person currently being deaconized.
var/mob/living/carbon/human/potential_deacon
/datum/religion_rites/deaconize/Destroy()
potential_deacon = null
return ..()
/datum/religion_rites/deaconize/perform_rite(mob/living/user, atom/religious_tool)
if(!ismovable(religious_tool))
to_chat(user, span_warning("This rite requires a religious device that individuals can be buckled to."))
return FALSE
var/atom/movable/movable_reltool = religious_tool
if(!movable_reltool)
return FALSE
var/mob/living/carbon/human/possible_deacon = locate() in movable_reltool.buckled_mobs
if(!possible_deacon)
to_chat(user, span_warning("Nothing is buckled to the [movable_reltool]!"))
return FALSE
if(!is_valid_for_deacon(possible_deacon, user))
return FALSE
//no one invited or this is not the invited person
if(!potential_deacon || (possible_deacon != potential_deacon))
INVOKE_ASYNC(src, PROC_REF(invite_deacon), possible_deacon)
to_chat(user, span_notice("They have been offered the oppertunity to join our ranks. Wait for them to decide and try again."))
return FALSE
return ..()
/datum/religion_rites/deaconize/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool)
. = ..()
if(!(potential_deacon in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled
to_chat(user, span_warning("[potential_deacon] is no longer on the altar!"))
return FALSE
if(potential_deacon.stat != CONSCIOUS)
to_chat(user, span_warning("[potential_deacon] has to be conscious for the rite to work!"))
return FALSE
if(!potential_deacon.mind)
to_chat(user, span_warning("[potential_deacon]'s mind appears to be elsewhere!"))
return FALSE
if(IS_CULTIST(potential_deacon))//what the fuck?!
to_chat(user, span_warning("[GLOB.deity] has seen a true, dark evil in [potential_deacon]'s heart, and they have been smitten!"))
playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE)
potential_deacon.gib(DROP_ORGANS|DROP_BODYPARTS)
return FALSE
var/datum/brain_trauma/special/honorbound/honor = user.has_trauma_type(/datum/brain_trauma/special/honorbound)
if(honor && (potential_deacon in honor.guilty))
honor.guilty -= potential_deacon
to_chat(user, span_notice("[GLOB.deity] has bound [potential_deacon] to the code! They are now a holy role! (albeit the lowest level of such)"))
potential_deacon.mind.holy_role = HOLY_ROLE_DEACON
GLOB.religious_sect.on_conversion(potential_deacon)
playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE)
return TRUE
///Helper if the passed possible_deacon is valid to become a deacon or not.
/datum/religion_rites/deaconize/proc/is_valid_for_deacon(mob/living/carbon/human/possible_deacon, mob/living/user)
if(possible_deacon.stat != CONSCIOUS)
to_chat(user, span_warning("[possible_deacon] needs to be alive and conscious to join!"))
return FALSE
if(possible_deacon.mind && possible_deacon.mind.holy_role)
to_chat(user, span_warning("[possible_deacon] is already a member of the religion!"))
return FALSE
return TRUE
/**
* Async proc that waits for a response on joining the sect.
* If they accept, the deaconize rite can now recruit them instead of just offering more invites.
*/
/datum/religion_rites/deaconize/proc/invite_deacon(mob/living/carbon/human/invited)
var/ask = tgui_alert(invited, "Join [GLOB.deity]? You will be expected to follow the Chaplain's order.", "Invitation", list("Yes", "No"), 60 SECONDS)
if(ask != "Yes")
return
potential_deacon = invited

View File

@@ -58,7 +58,7 @@
desc = "this is a prototype."
ritual_length = 10 SECONDS
favor_cost = 10
auto_delete = FALSE
rite_flags = NONE
///if repeats count as continuations instead of a song's end, TRUE
var/repeats_okay = TRUE
///personal message sent to the chaplain as feedback for their chosen song
@@ -142,7 +142,7 @@
/datum/religion_rites/song_tuner/light/Destroy()
QDEL_NULL(performer_light_obj)
. = ..()
return ..()
/datum/religion_rites/song_tuner/light/finish_effect(mob/living/carbon/human/listener, atom/song_source)
listener.apply_status_effect(/datum/status_effect/song/light)

View File

@@ -1,79 +1,3 @@
/// how much favor is gained when someone joins the crusade and is deaconized
#define DEACONIZE_FAVOR_GAIN 300
///Makes the person holy, but they now also have to follow the honorbound code (CBT). Actually earns favor, convincing others to uphold the code (tm) is not easy
/datum/religion_rites/deaconize
name = "Join Crusade"
desc = "Converts someone to your sect. They must be willing, so the first invocation will instead prompt them to join. \
They will become honorbound like you, and you will gain a massive favor boost!"
ritual_length = 30 SECONDS
ritual_invocations = list(
"A good, honorable crusade against evil is required.",
"We need the righteous ...",
"... the unflinching ...",
"... and the just.",
"Sinners must be silenced ...",
)
invoke_msg = "... And the code must be upheld!"
///the invited crusader
var/mob/living/carbon/human/new_crusader
/datum/religion_rites/deaconize/perform_rite(mob/living/user, atom/religious_tool)
var/datum/religion_sect/honorbound/sect = GLOB.religious_sect
if(!ismovable(religious_tool))
to_chat(user, span_warning("This rite requires a religious device that individuals can be buckled to."))
return FALSE
var/atom/movable/movable_reltool = religious_tool
if(!movable_reltool)
return FALSE
if(!LAZYLEN(movable_reltool.buckled_mobs))
to_chat(user, span_warning("Nothing is buckled to the altar!"))
return FALSE
for(var/mob/living/carbon/human/possible_crusader in movable_reltool.buckled_mobs)
if(possible_crusader.stat != CONSCIOUS)
to_chat(user, span_warning("[possible_crusader] needs to be alive and conscious to join the crusade!"))
return FALSE
if((TRAIT_GENELESS in possible_crusader.dna.species.inherent_traits) && !issynthetic(possible_crusader)) // BUBBER EDIT: Allow synths to be part of a crusade: ORIGINAL: if(TRAIT_GENELESS in possible_crusader.dna.species.inherent_traits)
to_chat(user, span_warning("This species disgusts [GLOB.deity]! They would never be allowed to join the crusade!"))
return FALSE
if(possible_crusader in sect.currently_asking)
to_chat(user, span_warning("Wait for them to decide on whether to join or not!"))
return FALSE
if(!(possible_crusader in sect.possible_crusaders))
INVOKE_ASYNC(sect, TYPE_PROC_REF(/datum/religion_sect/honorbound, invite_crusader), possible_crusader)
to_chat(user, span_notice("They have been given the option to consider joining the crusade against evil. Wait for them to decide and try again."))
return FALSE
new_crusader = possible_crusader
return ..()
/datum/religion_rites/deaconize/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool)
..()
var/mob/living/carbon/human/joining_now = new_crusader
new_crusader = null
if(!(joining_now in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled
to_chat(user, span_warning("The new member is no longer on the altar!"))
return FALSE
if(joining_now.stat != CONSCIOUS)
to_chat(user, span_warning("The new member has to stay alive for the rite to work!"))
return FALSE
if(!joining_now.mind)
to_chat(user, span_warning("The new member has no mind!"))
return FALSE
if(joining_now.mind.has_antag_datum(/datum/antagonist/cult))//what the fuck?!
to_chat(user, span_warning("[GLOB.deity] has seen a true, dark evil in [joining_now]'s heart, and they have been smitten!"))
playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE)
joining_now.gib(DROP_ORGANS|DROP_BODYPARTS)
return FALSE
var/datum/brain_trauma/special/honorbound/honor = user.has_trauma_type(/datum/brain_trauma/special/honorbound)
if(joining_now in honor.guilty)
honor.guilty -= joining_now
GLOB.religious_sect.adjust_favor(DEACONIZE_FAVOR_GAIN, user)
to_chat(user, span_notice("[GLOB.deity] has bound [joining_now] to the code! They are now a holy role! (albeit the lowest level of such)"))
joining_now.mind.holy_role = HOLY_ROLE_DEACON
GLOB.religious_sect.on_conversion(joining_now)
playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE)
return TRUE
///Mostly useless funny rite for forgiving someone, making them innocent once again.
/datum/religion_rites/forgive
name = "Forgive"
@@ -179,4 +103,47 @@
"}
return ..()
/// how much favor is gained when someone is deaconized
#define DEACONIZE_FAVOR_GAIN 300
/**
* Crusader deaconize
* Along with making the person holy & being an infinite-use type, it comes with the cost
* of enforcing an honorbound code onto convertees.
* Earns the church favor per conversion, but convincing others to uphold the code is not easy.
* Geneless species are not welcome for reasons
* (The actual reason is because the honorbound trauma used to be a mutation which they couldn't get,
* maybe it's time we let them join? idk)
*/
/datum/religion_rites/deaconize/crusader
name = "Join Crusade"
desc = "Converts someone to your sect. They must be willing, so the first invocation will instead prompt them to join. \
They will become honorbound like you, and you will gain a massive favor boost!"
ritual_length = 30 SECONDS
ritual_invocations = list(
"A good, honorable crusade against evil is required.",
"We need the righteous ...",
"... the unflinching ...",
"... and the just.",
"Sinners must be silenced ...",
)
invoke_msg = "... And the code must be upheld!"
rite_flags = RITE_ALLOW_MULTIPLE_PERFORMS
/datum/religion_rites/deaconize/crusader/post_invoke_effects(mob/living/user, atom/religious_tool)
. = ..()
GLOB.religious_sect.adjust_favor(DEACONIZE_FAVOR_GAIN, user)
/datum/religion_rites/deaconize/crusader/is_valid_for_deacon(mob/living/carbon/human/possible_deacon, mob/living/user)
if((TRAIT_GENELESS in possible_deacon.dna.species.inherent_traits) && !issynthetic(possible_deacon)) // BUBBER EDIT CHANGE: Let synths join crusades. Original: if(TRAIT_GENELESS in possible_deacon.dna.species.inherent_traits)
to_chat(user, span_warning("This species disgusts [GLOB.deity]! They would never be allowed to join the crusade!"))
return FALSE
return ..()
/datum/religion_rites/deaconize/crusader/invite_deacon(mob/living/carbon/human/invited)
var/ask = tgui_alert(invited, "Join [GLOB.deity]? You will be bound to a code of honor.", "Invitation", list("Yes", "No"), 60 SECONDS)
if(ask != "Yes")
return
potential_deacon = invited
#undef DEACONIZE_FAVOR_GAIN

View File

@@ -31,7 +31,7 @@
/// Autopopulated by `desired_items`
var/list/desired_items_typecache
/// Lists of rites by type. Converts itself into a list of rites with "name - desc (favor_cost)" = type
var/list/rites_list
var/list/rites_list = list()
/// Changes the Altar of Gods icon
var/altar_icon
/// Changes the Altar of Gods icon_state
@@ -47,6 +47,8 @@
. = ..()
if(desired_items)
desired_items_typecache = typecacheof(desired_items)
if(!locate(/datum/religion_rites/deaconize) in rites_list)
rites_list += list(/datum/religion_rites/deaconize)
on_select()
/// Activates once selected
@@ -416,22 +418,7 @@
tgui_icon = "scroll"
altar_icon_state = "convertaltar-white"
alignment = ALIGNMENT_GOOD
rites_list = list(/datum/religion_rites/deaconize, /datum/religion_rites/forgive, /datum/religion_rites/summon_rules)
///people who have agreed to join the crusade, and can be deaconized
var/list/possible_crusaders = list()
///people who have been offered an invitation, they haven't finished the alert though.
var/list/currently_asking = list()
/**
* Called by deaconize rite, this async'd proc waits for a response on joining the sect.
* If yes, the deaconize rite can now recruit them instead of just offering invites
*/
/datum/religion_sect/honorbound/proc/invite_crusader(mob/living/carbon/human/invited)
currently_asking += invited
var/ask = tgui_alert(invited, "Join [GLOB.deity]? You will be bound to a code of honor.", "Invitation", list("Yes", "No"), 60 SECONDS)
currently_asking -= invited
if(ask == "Yes")
possible_crusaders += invited
rites_list = list(/datum/religion_rites/deaconize/crusader, /datum/religion_rites/forgive, /datum/religion_rites/summon_rules)
/datum/religion_sect/honorbound/on_conversion(mob/living/carbon/new_convert)
..()

View File

@@ -10,8 +10,10 @@
/// message when you invoke
var/invoke_msg
var/favor_cost = 0
/// does the altar auto-delete the rite
var/auto_delete = TRUE
///Rite flags we use mostly to know when it should be deleted.
// RITE_AUTO_DELETE | RITE_ALLOW_MULTIPLE_PERFORMS | RITE_ONE_TIME_USE
var/rite_flags = RITE_AUTO_DELETE
/datum/religion_rites/New()
. = ..()
@@ -60,9 +62,15 @@
///Does the thing if the rite was successfully performed. return value denotes that the effect successfully (IE a harm rite does harm)
/datum/religion_rites/proc/invoke_effect(mob/living/user, atom/religious_tool)
SHOULD_CALL_PARENT(TRUE)
GLOB.religious_sect.on_riteuse(user,religious_tool)
GLOB.religious_sect.on_riteuse(user, religious_tool)
return TRUE
///Called if invoke effect returns TRUE, for effects meant to occur only if the rite passes.
/datum/religion_rites/proc/post_invoke_effects(mob/living/user, atom/religious_tool)
SHOULD_CALL_PARENT(TRUE)
if(!(rite_flags & RITE_ONE_TIME_USE))
return
GLOB.religious_sect.rites_list.Remove(src.type)
/**** Mechanical God ****/
@@ -119,8 +127,10 @@
name = "Receive Blessing"
desc = "Receive a blessing from the machine god to further your ascension."
ritual_length = 5 SECONDS
ritual_invocations =list( "Let your will power our forges.",
"...Help us in our great conquest!")
ritual_invocations = list(
"Let your will power our forges.",
"...Help us in our great conquest!",
)
invoke_msg = "The end of flesh is near!"
favor_cost = 2000

View File

@@ -6087,6 +6087,7 @@
#include "code\modules\recycling\disposal\outlet.dm"
#include "code\modules\recycling\disposal\pipe.dm"
#include "code\modules\recycling\disposal\pipe_sorting.dm"
#include "code\modules\religion\deaconize.dm"
#include "code\modules\religion\religion_sects.dm"
#include "code\modules\religion\religion_structures.dm"
#include "code\modules\religion\rites.dm"