Skip to content

Commit

Permalink
religion code clean up (#10689)
Browse files Browse the repository at this point in the history
  • Loading branch information
EvilDragonfiend authored May 8, 2024
1 parent ec10994 commit a335d33
Show file tree
Hide file tree
Showing 14 changed files with 1,593 additions and 1,553 deletions.
13 changes: 10 additions & 3 deletions beestation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -3684,9 +3684,16 @@
#include "code\modules\recycling\disposal\pipe.dm"
#include "code\modules\recycling\disposal\pipe_sorting.dm"
#include "code\modules\relay\relay.dm"
#include "code\modules\religion\religion_sects.dm"
#include "code\modules\religion\religion_structures.dm"
#include "code\modules\religion\rites.dm"
#include "code\modules\religion\_religion_sects.dm"
#include "code\modules\religion\_religion_structures.dm"
#include "code\modules\religion\_rites.dm"
#include "code\modules\religion\sects\candle_sect.dm"
#include "code\modules\religion\sects\carp_sect.dm"
#include "code\modules\religion\sects\necro_sect.dm"
#include "code\modules\religion\sects\plant_sect.dm"
#include "code\modules\religion\sects\puritan_sect.dm"
#include "code\modules\religion\sects\shadow_sect.dm"
#include "code\modules\religion\sects\techno_sect.dm"
#include "code\modules\requests\request.dm"
#include "code\modules\requests\request_manager.dm"
#include "code\modules\research\designs.dm"
Expand Down
123 changes: 123 additions & 0 deletions code/modules/religion/_religion_sects.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* # Religious Sects
*
* Religious Sects are a way to convert the fun of having an active 'god' (admin) to code-mechanics so you aren't having to press adminwho.
*
* Sects are not meant to overwrite the fun of choosing a custom god/religion, but meant to enhance it.
* The idea is that Space Jesus (or whoever you worship) can be an evil bloodgod who takes the lifeforce out of people, a nature lover, or all things righteous and good. You decide!
*
*/
/datum/religion_sect
/// Name of the religious sect
var/name = "Religious Sect Base Type"
/// Flavorful quote given about the sect, used in tgui
var/quote = "Hail Coderbus! Coderbus #1! Fuck the playerbase!"
/// Opening message when someone gets converted
var/desc = "Oh My! What Do We Have Here?!!?!?!?"
/// Tgui icon used by this sect - https://fontawesome.com/icons/
var/tgui_icon = "bug"
/// holder for alignments.
var/alignment = ALIGNMENT_GOOD
/// Does this require something before being available as an option?
var/starter = TRUE
/// species traits that block you from picking
var/invalidating_qualities = NONE
/// The Sect's 'Mana'
var/favor = 0 //MANA!
/// The max amount of favor the sect can have
var/max_favor = 1000
/// The default value for an item that can be sacrificed
var/default_item_favor = 5
/// Turns into 'desired_items_typecache', and is optionally assoc'd to sacrifice instructions if needed.
var/list/desired_items
/// 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
/// Changes the Altar of Gods icon
var/altar_icon
/// Changes the Altar of Gods icon_state
var/altar_icon_state
/// Currently Active (non-deleted) rites
var/list/active_rites
/// Whether the structure has CANDLE OVERLAYS!
var/candle_overlay = TRUE
/// Whether the altar of the gods is anchored
var/altar_anchored = TRUE

/datum/religion_sect/proc/is_available(mob/user)
return TRUE // basically all available

/datum/religion_sect/New()
. = ..()
if(desired_items)
desired_items_typecache = typecacheof(desired_items)

/// Activates once selected
/datum/religion_sect/proc/on_select()
SHOULD_CALL_PARENT(TRUE)
SSblackbox.record_feedback("text", "sect_chosen", 1, name)

/// Activates once selected and on newjoins, oriented around people who become holy.
/datum/religion_sect/proc/on_conversion(mob/living/chap)
SHOULD_CALL_PARENT(TRUE)
to_chat(chap, "<span class='bold notice'>\"[quote]\"</span>")
to_chat(chap, "<span class='notice'>[desc]</span>")

/// Returns TRUE if the item can be sacrificed. Can be modified to fit item being tested as well as person offering. Returning TRUE will stop the attackby sequence and proceed to on_sacrifice.
/datum/religion_sect/proc/can_sacrifice(obj/item/I, mob/living/chap)
. = TRUE
if(chap.mind.holy_role == HOLY_ROLE_DEACON)
to_chat(chap, "<span class='warning'>You are merely a deacon of [GLOB.deity], and therefore cannot perform rites.")
return
if(!is_type_in_typecache(I,desired_items_typecache))
return FALSE

/// Activates when the sect sacrifices an item. This proc has NO bearing on the attackby sequence of other objects when used in conjunction with the religious_tool component.
/datum/religion_sect/proc/on_sacrifice(obj/item/I, mob/living/chap)
return adjust_favor(default_item_favor,chap)

/// Returns a description for religious tools
/datum/religion_sect/proc/tool_examine(mob/living/holy_creature)
return "You are currently at [round(favor)] favor with [GLOB.deity]."

/// Adjust Favor by a certain amount. Can provide optional features based on a user. Returns actual amount added/removed
/datum/religion_sect/proc/adjust_favor(amount = 0, mob/living/chap)
. = amount
if(favor + amount < 0)
. = favor //if favor = 5 and we want to subtract 10, we'll only be able to subtract 5
if((favor + amount > max_favor))
. = (max_favor-favor) //if favor = 5 and we want to add 10 with a max of 10, we'll only be able to add 5
favor = clamp(0,max_favor, favor+amount)

/// Sets favor to a specific amount. Can provide optional features based on a user.
/datum/religion_sect/proc/set_favor(amount = 0, mob/living/chap)
favor = clamp(0,max_favor,amount)
return favor

/// Activates when an individual uses a rite. Can provide different/additional benefits depending on the user.
/datum/religion_sect/proc/on_riteuse(mob/living/user, atom/religious_tool)

/// Replaces the bible's bless mechanic. Return TRUE if you want to not do the brain hit.
/datum/religion_sect/proc/sect_bless(mob/living/target, mob/living/chap)
if(!ishuman(target))
return FALSE
var/mob/living/carbon/human/blessed = target
for(var/obj/item/bodypart/bodypart as anything in blessed.bodyparts)
if(!IS_ORGANIC_LIMB(bodypart))
to_chat(chap, "<span class='warning'>[GLOB.deity] refuses to heal this metallic taint!</span>")
return TRUE

var/heal_amt = 10
var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYTYPE_ORGANIC)

if(hurt_limbs.len)
for(var/X in hurt_limbs)
var/obj/item/bodypart/affecting = X
if(affecting.heal_damage(heal_amt, heal_amt, null, BODYTYPE_ORGANIC))
blessed.update_damage_overlays()
blessed.visible_message("<span class='notice'>[chap] heals [blessed] with the power of [GLOB.deity]!</span>")
to_chat(blessed, "<span class='boldnotice'>May the power of [GLOB.deity] compel you to be healed!</span>")
playsound(chap, "punch", 25, TRUE, -1)
SEND_SIGNAL(blessed, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing)
return TRUE
71 changes: 71 additions & 0 deletions code/modules/religion/_religion_structures.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/obj/structure/altar_of_gods
name = "\improper Altar of the Gods"
desc = "An altar which allows the head of the church to choose a sect of religious teachings as well as provide sacrifices to earn favor."
icon = 'icons/obj/hand_of_god_structures.dmi'
icon_state = "convertaltar"
density = TRUE
anchored = TRUE
layer = TABLE_LAYER
pass_flags_self = LETPASSTHROW
can_buckle = TRUE
buckle_lying = 90 //we turn to you!
resistance_flags = INDESTRUCTIBLE
///Avoids having to check global everytime by referencing it locally.
var/datum/religion_sect/sect_to_altar

/obj/structure/altar_of_gods/Initialize(mapload)
. = ..()
reflect_sect_in_icons()
AddElement(/datum/element/climbable)

/obj/structure/altar_of_gods/ComponentInitialize()
. = ..()
AddComponent(/datum/component/religious_tool, ALL, FALSE, CALLBACK(src, PROC_REF(reflect_sect_in_icons)))

/obj/structure/altar_of_gods/attack_hand(mob/living/user)
if(!Adjacent(user) || !user.pulling)
return ..()
if(!isliving(user.pulling))
return ..()
var/mob/living/pushed_mob = user.pulling
if(pushed_mob.buckled)
to_chat(user, "<span class='warning'>[pushed_mob] is buckled to [pushed_mob.buckled]!</span>")
return ..()
to_chat(user,"<span class='notice>You try to coax [pushed_mob] onto [src]...</span>")
if(!do_after(user,(5 SECONDS),target = pushed_mob))
return ..()
pushed_mob.forceMove(loc)
return ..()

/obj/structure/altar_of_gods/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/nullrod))
if(user.mind?.holy_role == NONE)
to_chat(user, "<span class='warning'>Only the faithful may control the disposition of [src]!</span>")
return
anchored = !anchored
if(GLOB.religious_sect)
GLOB.religious_sect.altar_anchored = anchored //Having more than one altar of the gods is only possible through adminbus so this should screw with normal gameplay
user.visible_message("<span class ='notice'>[user] [anchored ? "" : "un"]anchors [src] [anchored ? "to" : "from"] the floor with [I].</span>", "<span class ='notice'>You [anchored ? "" : "un"]anchor [src] [anchored ? "to" : "from"] the floor with [I].</span>")
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
user.do_attack_animation(src)
return
if(I.tool_behaviour == TOOL_WRENCH)
return
return ..()


/obj/structure/altar_of_gods/proc/reflect_sect_in_icons()
if(GLOB.religious_sect)
sect_to_altar = GLOB.religious_sect
if(sect_to_altar.altar_icon)
icon = sect_to_altar.altar_icon
if(sect_to_altar.altar_icon_state)
icon_state = sect_to_altar.altar_icon_state

/obj/structure/destructible/religion
density = TRUE
anchored = FALSE
icon = 'icons/obj/religion.dmi'
light_power = 2
var/cooldowntime = 0
break_sound = 'sound/effects/glassbr2.ogg'
78 changes: 78 additions & 0 deletions code/modules/religion/_rites.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/datum/religion_rites
/// name of the religious rite
var/name = "religious rite"
/// Description of the religious rite
var/desc = "immm gonna rooon"
/// length it takes to complete the ritual
var/ritual_length = (10 SECONDS) //total length it'll take
/// list of invocations said (strings) throughout the rite
var/list/ritual_invocations //strings that are by default said evenly throughout the rite
/// message when you invoke
var/invoke_msg
var/favor_cost = 0
/// does the altar auto-delete the rite
var/auto_delete = TRUE

/datum/religion_rites/New()
. = ..()
if(!GLOB?.religious_sect)
return
LAZYADD(GLOB.religious_sect.active_rites, src)

/datum/religion_rites/Destroy()
if(!GLOB?.religious_sect)
return
LAZYREMOVE(GLOB.religious_sect.active_rites, src)
return ..()

/datum/religion_rites/proc/can_afford(mob/living/user)
if(GLOB.religious_sect?.favor < favor_cost)
to_chat(user, "<span class='warning'>This rite requires more favor!</span>")
return FALSE
return TRUE

///Called to perform the invocation of the rite, with args being the performer and the altar where it's being performed. Maybe you want it to check for something else?
/datum/religion_rites/proc/perform_rite(mob/living/user, atom/religious_tool)
if(!can_afford(user))
return FALSE
var/turf/T = get_turf(religious_tool)
if(!T.is_holy())
to_chat(user, "<span class='warning'>The altar can only function in a holy area!</span>")
return FALSE
if(!GLOB.religious_sect.altar_anchored)
to_chat(user, "<span class='warning'>The altar must be secured to the floor if you wish to perform the rite!</span>")
return FALSE
to_chat(user, "<span class='notice'>You begin to perform the rite of [name]...</span>")
if(!ritual_invocations)
if(do_after(user, target = user, delay = ritual_length))
return TRUE
return FALSE
var/first_invoke = TRUE
for(var/i in ritual_invocations)
if(!GLOB.religious_sect.altar_anchored)
to_chat(user, "<span class='warning'>The altar must be secured to the floor if you wish to perform the rite!</span>")
return FALSE
if(first_invoke) //instant invoke
user.say(i)
first_invoke = FALSE
continue
if(!length(ritual_invocations)) //we divide so we gotta protect
return FALSE
if(!do_after(user, target = user, delay = ritual_length/length(ritual_invocations)))
return FALSE
user.say(i)
if(!do_after(user, target = user, delay = ritual_length/length(ritual_invocations))) //because we start at 0 and not the first fraction in invocations, we still have another fraction of ritual_length to complete
return FALSE
if(!GLOB.religious_sect.altar_anchored)
to_chat(user, "<span class='warning'>The altar must be secured to the floor if you wish to perform the rite!</span>")
return FALSE
if(invoke_msg)
user.say(invoke_msg)
return TRUE


///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)
return TRUE
Loading

0 comments on commit a335d33

Please sign in to comment.