diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index fbb6dc398b428..7e574345fc9ca 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -82,6 +82,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isoozeling(A) (is_species(A, /datum/species/oozeling)) #define iszombie(A) (is_species(A, /datum/species/zombie)) #define isskeleton(A) (is_species(A, /datum/species/skeleton)) +#define isshadow(A) (is_species(A, /datum/species/shadow)) #define ismoth(A) (is_species(A, /datum/species/moth)) #define ishumanbasic(A) (is_species(A, /datum/species/human) && !is_species(A, /datum/species/human/krokodil_addict)) #define iscatperson(A) (is_species(A, /datum/species/human/felinid) ) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 5860b46095142..e8ccee3b39abf 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -73,6 +73,8 @@ init_crafting_recipes(GLOB.crafting_recipes) + init_religion_sects() + /// Inits the crafting recipe list, sorting crafting recipe requirements in the process. /proc/init_crafting_recipes(list/crafting_recipes) for(var/path in subtypesof(/datum/crafting_recipe)) @@ -159,3 +161,8 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list( /obj/structure/light_construct, /obj/machinery/light ))) + +/proc/init_religion_sects() + for(var/path in subtypesof(/datum/religion_sect)) + var/datum/religion_sect/each_sect = new path() + GLOB.religion_sect_datums += each_sect diff --git a/code/_globalvars/religion.dm b/code/_globalvars/religion.dm index a91461c895e3c..53f771359bd1b 100644 --- a/code/_globalvars/religion.dm +++ b/code/_globalvars/religion.dm @@ -3,6 +3,7 @@ GLOBAL_VAR(religion) GLOBAL_VAR(deity) GLOBAL_DATUM(religious_sect, /datum/religion_sect) GLOBAL_VAR(favor) +GLOBAL_LIST_EMPTY(religion_sect_datums) //bible GLOBAL_VAR(bible_name) diff --git a/code/datums/components/religious_tool.dm b/code/datums/components/religious_tool.dm index 7ff3ac1282d97..ba7759c7f437d 100644 --- a/code/datums/components/religious_tool.dm +++ b/code/datums/components/religious_tool.dm @@ -21,7 +21,6 @@ /datum/component/religious_tool/Initialize(_flags = ALL, _force_catalyst_afterattack = FALSE, _after_sect_select_cb, override_catalyst_type) . = ..() - SetGlobalToLocal() //attempt to connect on start in case one already exists! operation_flags = _flags force_catalyst_afterattack = _force_catalyst_afterattack after_sect_select_cb = _after_sect_select_cb @@ -35,19 +34,6 @@ /datum/component/religious_tool/UnregisterFromParent() UnregisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE)) -/** - * Sets the easy access variable to the global if it exists. - */ -/datum/component/religious_tool/proc/SetGlobalToLocal() - if(easy_access_sect) - return TRUE - if(!GLOB.religious_sect) - return FALSE - easy_access_sect = GLOB.religious_sect - if(after_sect_select_cb) - after_sect_select_cb.Invoke() - return TRUE - /** * Since all of these involve attackby, we require mega proc. Handles Invocation, Sacrificing, And Selection of Sects. */ @@ -86,7 +72,7 @@ /datum/component/religious_tool/ui_data(mob/user) var/list/data = list() //cannot find global vars, so lets offer options - if(!SetGlobalToLocal()) + if(!easy_access_sect) data["sects"] = generate_available_sects(user) data["alignment"] = ALIGNMENT_NEUT //neutral theme if you have no sect else @@ -120,11 +106,15 @@ /// Select the sect, called from [/datum/component/religious_tool/proc/AttemptActions] /datum/component/religious_tool/proc/select_sect(mob/living/user, path) + for(var/datum/religion_sect/each_sect in GLOB.religion_sect_datums) + if(each_sect.type == text2path(path)) + if(!each_sect.is_available(user)) + return if(!ispath(text2path(path), /datum/religion_sect)) message_admins("[ADMIN_LOOKUPFLW(usr)] has tried to spawn an item when selecting a sect.") return if(user.mind.holy_role != HOLY_ROLE_HIGHPRIEST) - to_chat(user, "You are not the high priest, and therefore cannot select a religious sect.") + to_chat(user, "You are not the high priest, and therefore cannot select a religious sect.") return if(!user.canUseTopic(parent, BE_CLOSE, FALSE, NO_TK)) to_chat(user, "You cannot select a sect at this time.") @@ -132,6 +122,7 @@ if(GLOB.religious_sect) return GLOB.religious_sect = new path() + GLOB.religious_sect.on_select() for(var/i in GLOB.player_list) if(!isliving(i)) continue @@ -175,13 +166,10 @@ */ /datum/component/religious_tool/proc/generate_available_sects(mob/user) var/list/sects_to_pick = list() - var/human_highpriest = ishuman(user) - var/mob/living/carbon/human/highpriest = user - for(var/path in subtypesof(/datum/religion_sect)) - if(human_highpriest && initial(easy_access_sect.invalidating_qualities)) - var/datum/species/highpriest_species = highpriest.dna.species - if(initial(easy_access_sect.invalidating_qualities) in highpriest_species.inherent_traits) - continue + for(var/datum/religion_sect/each_sect in GLOB.religion_sect_datums) + var/path = each_sect.type + if(!each_sect.is_available(user)) + continue var/list/sect = list() var/datum/religion_sect/not_a_real_instance_rs = path sect["name"] = initial(not_a_real_instance_rs.name) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 355c7f671c532..4d9cfde8bd1ac 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -258,3 +258,12 @@ ignore_flags = 0 reagent_flags = NONE list_reagents = list(/datum/reagent/magillitis = 5) + +/obj/item/reagent_containers/hypospray/medipen/shadow_species_mutator + name = "Shadow Person mutator autoinjector" + desc = "Become one with the shadows, and change your race to a Shadow Person today!" + icon_state = "syndipen" + item_state = "tbpen" + volume = 10 + amount_per_transfer_from_this = 10 + list_reagents = list(/datum/reagent/mutationtoxin/shadow = 10) diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 58e942d51838d..c7128dc6683d3 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -45,12 +45,13 @@ /// 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) - on_select() /// Activates once selected /datum/religion_sect/proc/on_select() @@ -308,3 +309,51 @@ to_chat(L, "You offer [N] to [GLOB.deity], pleasing them and gaining 25 favor in the process.") qdel(N) return TRUE + +/**** Shadow Sect ****/ + +/datum/religion_sect/shadow_sect + starter = FALSE + name = "Shadow" + desc = "A sect dedicated to the darkness. The manifested obelisks will generate favor from being in darkness." + quote = "Turn out the lights, and let the darkness cover the world!" + tgui_icon = "moon" + alignment = ALIGNMENT_EVIL + favor = 100 //Starts off with enough favor to make an obelisk + max_favor = 25000 + desired_items = list(/obj/item/flashlight) + rites_list = list(/datum/religion_rites/expand_shadows,/datum/religion_rites/shadow_obelisk, /datum/religion_rites/shadow_conversion,/datum/religion_rites/shadow_blessing,/datum/religion_rites/shadow_eyes) + altar_icon_state = "convertaltar-dark" + var/light_reach = 1 + var/light_power = 0 + var/list/obelisks = list() + +/datum/religion_sect/shadow_sect/is_available(mob/user) + if(isshadow(user)) + return TRUE + return FALSE + +//Shadow bibles don't heal or do anything special apart from the standard holy water blessings +/datum/religion_sect/shadow_sect/sect_bless(mob/living/blessed, mob/living/user) + return TRUE + +/datum/religion_sect/shadow_sect/on_sacrifice(obj/item/N, mob/living/L) + if(!istype(N, /obj/item/flashlight)) + return + adjust_favor(5, L) + to_chat(L, "You offer [N] to [GLOB.deity], pleasing them and gaining 5 favor in the process.") + qdel(N) + return TRUE + +/datum/religion_sect/shadow_sect/on_select(atom/religious_tool, mob/living/user) + . = ..() + if(!religious_tool || !user) + return + religious_tool.AddComponent(/datum/component/dark_favor, user) + +/datum/religion_sect/shadow_sect/on_conversion(mob/living/chap) //When sect is selected, and when a new chaplain joins after sect has been selected + . = ..() + if(is_special_character(chap)) + to_chat(chap, "As you are an antagonist role, you are free to spread darkness across the station.") + else + to_chat(chap, "You are not an antagonist, please do not spread darkness outside of the chapel without Command Staff approval.") diff --git a/code/modules/religion/religion_structures.dm b/code/modules/religion/religion_structures.dm index 0c5ff0452d17c..929544ec4c31d 100644 --- a/code/modules/religion/religion_structures.dm +++ b/code/modules/religion/religion_structures.dm @@ -163,3 +163,54 @@ if(I.tool_behaviour == TOOL_WRENCH) return return ..() + +////Shadow Sect //Original code by DingoDongler + +/obj/structure/destructible/religion/shadow_obelisk + name = "Shadow Obelisk" + desc = "Grants favor from being shrouded in shadows." + icon = 'icons/obj/hand_of_god_structures.dmi' + icon_state = "shadow-obelisk" + anchored = FALSE + break_message = "The Obelisk crumbles before you!" + +/obj/structure/destructible/religion/shadow_obelisk/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/nullrod)) + if(user.mind?.holy_role == NONE) + to_chat(user, "Only the faithful may control the disposition of [src]!") + return + anchored = !anchored + user.visible_message("[user] [anchored ? "" : "un"]anchors [src] [anchored ? "to" : "from"] the floor with [I].", "You [anchored ? "" : "un"]anchor [src] [anchored ? "to" : "from"] the floor with [I].") + playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1) + user.do_attack_animation(src) + return + if(I.tool_behaviour == TOOL_WRENCH) + return + return ..() + +// Favor generator component. Used on the altar and obelisks +/datum/component/dark_favor //Original code by DingoDongler + var/mob/living/creator + +/datum/component/dark_favor/Initialize(mob/living/L) + . = ..() + if(!L) + return + creator = L + START_PROCESSING(SSobj, src) + +/datum/component/dark_favor/Destroy() //Original code by DingoDongler + . = ..() + STOP_PROCESSING(SSobj, src) + +/datum/component/dark_favor/process(delta_time) //Original code by DingoDongler + var/datum/religion_sect/shadow_sect/sect = GLOB.religious_sect + if(!istype(parent, /atom) || !istype(creator) || !istype(sect)) + return + var/atom/P = parent + var/turf/T = P.loc + if(!istype(T)) + return + var/light_amount = T.get_lumcount() + var/favor_gained = max(1 - light_amount, 0) * delta_time + sect.adjust_favor(favor_gained, creator) diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index 350abd66b43bf..54dfddbccd5b2 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -780,3 +780,195 @@ rite_target.set_species(/datum/species/pod) rite_target.visible_message("[rite_target] has been converted by the rite of [name]!") return TRUE + +/**** Shadow rites ****/ //Original code by DingoDongler + +#define DARKNESS_INVERSE_COLOR "#AAD84B" //The color of light has to be inverse, since we're using negative light power + +/datum/religion_rites/shadow_conversion + name = "Shadowperson Conversion" + desc = "Converts a humanoid into a shadowperson, a race blessed by darkness." + ritual_length = 30 SECONDS + ritual_invocations = list("Let the darkness seep into you...", + "... And cover you, envelope you ...", + "... And make you one with it ...") + invoke_msg = "... And let you be born again!" + favor_cost = 1200 + +/datum/religion_rites/shadow_conversion/perform_rite(mob/living/user, atom/religious_tool) + if(!ismovable(religious_tool)) + to_chat(user, "This rite requires a religious device that individuals can be buckled to.") + return FALSE + var/atom/movable/movable_reltool = religious_tool + if(LAZYLEN(movable_reltool.buckled_mobs)) + to_chat(user,"You're going to convert the one buckled on [movable_reltool].") + else + if(!movable_reltool.can_buckle) //yes, if you have somehow managed to have someone buckled to something that now cannot buckle, we will still let you perform the rite! + to_chat(user,"This rite requires a religious device that individuals can be buckled to.") + return FALSE + if(isshadow(user)) + to_chat(user,"You've already converted yourself. To convert others, they must be buckled to [movable_reltool].") + return FALSE + to_chat(user,"You're going to convert yourself with this ritual.") + return ..() + +/datum/religion_rites/shadow_conversion/invoke_effect(mob/living/user, atom/religious_tool) + ..() + if(!ismovable(religious_tool)) + CRASH("[name]'s perform_rite had a movable atom that has somehow turned into a non-movable!") + var/atom/movable/movable_reltool = religious_tool + var/mob/living/carbon/human/rite_target + if(!movable_reltool?.buckled_mobs?.len) + rite_target = user + else + for(var/buckled in movable_reltool.buckled_mobs) + if(ishuman(buckled)) + rite_target = buckled + break + if(!rite_target) + return FALSE + rite_target.set_species(/datum/species/shadow) + rite_target.visible_message("[rite_target] has been converted by the rite of [name]!") + return TRUE + +/datum/religion_rites/shadow_obelisk + name = "Obelisk Manifestation" + desc = "Creates an obelisk that generates favor when in a dark area." + ritual_length = 45 SECONDS + ritual_invocations = list("Let the shadows combine...", + "... Solidify and grow ...", + "... Make an idol to eminate shadows ...") + invoke_msg = "I summon forth an obelisk, to appease the darkness." + favor_cost = 100 //Sect starts with 100 favor to begin + +/datum/religion_rites/shadow_obelisk/invoke_effect(mob/living/user, atom/religious_tool) + var/altar_turf = get_turf(religious_tool) + var/obj/structure/destructible/religion/shadow_obelisk/obelisk = new(altar_turf) + var/datum/religion_sect/shadow_sect/sect = GLOB.religious_sect + sect.obelisks += obelisk + obelisk.AddComponent(/datum/component/dark_favor, user) + obelisk.set_light(sect.light_reach, sect.light_power, DARKNESS_INVERSE_COLOR) + playsound(altar_turf, 'sound/magic/fireball.ogg', 50, TRUE) + return ..() + +/datum/religion_rites/expand_shadows + name = "Shadow Expansion" + desc = "Grow the reach of shadows extending from the altar, and any obelisks." + ritual_length = 40 SECONDS + ritual_invocations = list("Spread out...", + "... Kill the light ...", + "... Encompass it all in darkness ...") + invoke_msg = "Shadows, reach your tendrils from my altar, and extend thy domain." + favor_cost = 175 + +/datum/religion_rites/expand_shadows/perform_rite(mob/living/user, atom/religious_tool) + var/datum/religion_sect/shadow_sect/sect = GLOB.religious_sect + if((sect.light_power <= -5) || (sect.light_reach >= 10)) + to_chat(user, "The shadows emanating from your idols is as strong as it could be.") + return FALSE + return ..() + +/datum/religion_rites/expand_shadows/invoke_effect(mob/living/user, atom/religious_tool) + . = ..() + var/datum/religion_sect/shadow_sect/sect = GLOB.religious_sect + if(!sect) + return + sect.light_reach += 2 + sect.light_power -= 1 + religious_tool.set_light(sect.light_reach, sect.light_power, DARKNESS_INVERSE_COLOR) + for(var/obj/structure/destructible/religion/shadow_obelisk/D in sect.obelisks) + D.set_light(sect.light_reach, sect.light_power, DARKNESS_INVERSE_COLOR) + +/datum/religion_rites/shadow_blessing + name = "Shadow Blessing" + desc = "Bless someone with the power of shadows, and make them immune to all magic." + ritual_length = 60 SECONDS + ritual_invocations = list("Let the darkness reside within us...", + "... Let the power flow ...", + "... Encompass our souls in shade ...", + "... And let the demons know ...", + "... That their powers will not work apon us any more...",) + invoke_msg = "Bless thy brethen, and grant them immunity!" + favor_cost = 8000 + +/datum/religion_rites/shadow_blessing/perform_rite(mob/living/user, atom/religious_tool) + if(!ismovable(religious_tool)) + to_chat(user, "This rite requires a religious device that individuals can be buckled to.") + return FALSE + var/atom/movable/movable_reltool = religious_tool + if(LAZYLEN(movable_reltool.buckled_mobs)) + to_chat(user,"You're going to bless the one buckled on [movable_reltool].") + else + if(!movable_reltool.can_buckle) //yes, if you have somehow managed to have someone buckled to something that now cannot buckle, we will still let you perform the rite! + to_chat(user,"This rite requires a religious device that individuals can be buckled to.") + return FALSE + if(isshadow(user)) + to_chat(user,"You've already blessed yourself. To convert others, they must be buckled to [movable_reltool].") + return FALSE + to_chat(user,"You're going to bless yourself with this ritual.") + return ..() + +/datum/religion_rites/shadow_blessing/invoke_effect(mob/living/user, atom/religious_tool) + ..() + if(!ismovable(religious_tool)) + CRASH("[name]'s perform_rite had a movable atom that has somehow turned into a non-movable!") + var/atom/movable/movable_reltool = religious_tool + var/mob/living/carbon/human/rite_target + if(!movable_reltool?.buckled_mobs?.len) + rite_target = user + else + for(var/buckled in movable_reltool.buckled_mobs) + if(ishuman(buckled)) + rite_target = buckled + break + if(!rite_target) + return FALSE + ADD_TRAIT(rite_target, TRAIT_ANTIMAGIC, MAGIC_TRAIT) + //glowing wings overlay + playsound(rite_target, 'sound/weapons/fwoosh.ogg', 75, 0) + rite_target.visible_message("[rite_target] has been blessed by the rite of [name]!") + return TRUE + + +/datum/religion_rites/shadow_eyes + name = "Grant Shadow Eyes" + desc = "Grants either the caster, or the buckled person, shadow eyes that give night vision." + ritual_length = 30 SECONDS + ritual_invocations = list("Grant us the sight ...", + "... We call upon the shadows ...", + "... Show us the way ...") + invoke_msg = "... Let the darkness be our guide!!" + favor_cost = 1000 + +/datum/religion_rites/shadow_eyes/perform_rite(mob/living/user, atom/religious_tool) + if(!ismovable(religious_tool)) + to_chat(user,"This rite requires a religious device that individuals can be buckled to.") + return FALSE + var/atom/movable/movable_reltool = religious_tool + if(length(movable_reltool.buckled_mobs)) + to_chat(user,"You're going to grant the eyes to the one buckled on [movable_reltool].") + else if(!movable_reltool.can_buckle) //yes, if you have somehow managed to have someone buckled to something that now cannot buckle, we will still let you perform the rite! + to_chat(user,"This rite requires a religious device that individuals can be buckled to.") + return FALSE + to_chat(user,"You're going to grant the eyes to yourself with this ritual.") + return ..() + +/datum/religion_rites/shadow_eyes/invoke_effect(mob/living/user, atom/religious_tool) + ..() + var/obj/item/organ/eyes/night_vision/organ = new() + if(!ismovable(religious_tool)) + CRASH("[name]'s perform_rite had a movable atom that has somehow turned into a non-movable!") + var/atom/movable/movable_reltool = religious_tool + var/mob/living/carbon/human/rite_target + if(!length(movable_reltool.buckled_mobs)) + rite_target = user + else + for(var/buckled in movable_reltool.buckled_mobs) + if(ishuman(buckled)) + rite_target = buckled + break + if(!rite_target) + return FALSE + organ.Insert(rite_target) + rite_target.visible_message("[organ] have been merged into [rite_target] by the rite of [name]!") + return TRUE diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 59f3568dec195..0a495a7be7827 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -2238,6 +2238,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 20 restricted_roles = list(JOB_NAME_CHAPLAIN) +/datum/uplink_item/role_restricted/shadowmutationtoxin + name = "Shadow Person Mutation Toxin" + desc = "Become one with the night, Rumors have it that there is a secret sect dedicated to the shadows and must be of their species to unlock it, be aware however, you will take damage in the light." + item = /obj/item/reagent_containers/hypospray/medipen/shadow_species_mutator + cost = 5 + restricted_roles = list(JOB_NAME_CHAPLAIN) + /datum/uplink_item/role_restricted/spanish_flu name = "Spanish Flu Culture" desc = "A bottle of cursed blood, full of angry spirits which will burn all the heretics with the fires of hell.\ diff --git a/icons/obj/hand_of_god_structures.dmi b/icons/obj/hand_of_god_structures.dmi index 03623473c1e76..c221431d5f627 100644 Binary files a/icons/obj/hand_of_god_structures.dmi and b/icons/obj/hand_of_god_structures.dmi differ