diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index eb85025d6d5..f51c970038f 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -58,6 +58,9 @@ #define HARS /datum/mutation/human/headless #define BIOTECHCOMPAT /datum/mutation/human/biotechcompat +#define HONORBOUND /datum/mutation/human/honorbound +#define BURDENED /datum/mutation/human/burdened + #define UI_CHANGED "ui changed" #define UE_CHANGED "ue changed" diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index f491b3437b7..a42b0af59fa 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -137,3 +137,8 @@ GLOBAL_VAR_INIT(ghost_role_flags, (~0)) #define GHOSTROLE_SILICONS (1<<3) //ie mafia, ctf #define GHOSTROLE_MINIGAME (1<<4) + +//smite defines + +#define LIGHTNING_BOLT_DAMAGE 75 +#define LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH 40 diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 316a4d30c88..677f83fbe4b 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -620,6 +620,18 @@ #define COMSIG_CARBON_EMBED_REMOVAL "item_embed_remove_safe" ///Called when someone attempts to cuff a carbon #define COMSIG_CARBON_CUFF_ATTEMPTED "carbon_attempt_cuff" +///Called when a carbon mutates (source = dna, mutation = mutation added) +#define COMSIG_CARBON_GAIN_MUTATION "carbon_gain_mutation" +///Called when a carbon loses a mutation (source = dna, mutation = mutation lose) +#define COMSIG_CARBON_LOSE_MUTATION "carbon_lose_mutation" +///Called when a carbon becomes addicted (source = what addiction datum, addicted_mind = mind of the addicted carbon) +#define COMSIG_CARBON_GAIN_ADDICTION "carbon_gain_addiction" +///Called when a carbon is no longer addicted (source = what addiction datum was lost, addicted_mind = mind of the freed carbon) +#define COMSIG_CARBON_LOSE_ADDICTION "carbon_lose_addiction" +///Called when a carbon gets a brain trauma (source = carbon, trauma = what trauma was added) - this is before on_gain() +#define COMSIG_CARBON_GAIN_TRAUMA "carbon_gain_trauma" +///Called when a carbon loses a brain trauma (source = carbon, trauma = what trauma was removed) +#define COMSIG_CARBON_LOSE_TRAUMA "carbon_lose_trauma" // /mob/living/simple_animal/hostile signals #define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget" @@ -822,11 +834,16 @@ // /obj/item/gun signals -///called in /obj/item/gun/process_fire (user, target, params, zone_override) +///called in /obj/item/gun/process_fire (src, target, params, zone_override) #define COMSIG_MOB_FIRED_GUN "mob_fired_gun" ///called in /obj/item/gun/process_fire (user, target, params, zone_override) #define COMSIG_GUN_FIRED "gun_fired" +// /obj/effect/proc_holder/spell signals + +///called from /obj/effect/proc_holder/spell/perform (src) +#define COMSIG_MOB_CAST_SPELL "mob_cast_spell" + // /obj/item/grenade signals ///called in /obj/item/gun/process_fire (user, target, params, zone_override) diff --git a/code/__DEFINES/magic.dm b/code/__DEFINES/magic.dm new file mode 100644 index 00000000000..02f936ef97d --- /dev/null +++ b/code/__DEFINES/magic.dm @@ -0,0 +1,29 @@ + +//schools of magic - unused for years and years on end, finally has a use with chaplains getting punished for using "evil" spells + +//use this if your spell isn't actually a spell, it's set by default (and actually, i really suggest if that's the case you should use datum/actions instead - see spider.dm for an example) +#define SCHOOL_UNSET "unset" + +//GOOD SCHOOLS (allowed by honorbound gods, some of these you can get on station) +#define SCHOOL_HOLY "holy" +#define SCHOOL_MIME "mime" +#define SCHOOL_RESTORATION "restoration" //heal shit + +//NEUTRAL SPELLS (punished by honorbound gods if you get caught using it) +#define SCHOOL_EVOCATION "evocation" //kill or destroy shit, usually out of thin air +#define SCHOOL_TRANSMUTATION "transmutation" //transform shit +#define SCHOOL_TRANSLOCATION "illusion" //movement based +#define SCHOOL_CONJURATION "conjuration" //summoning + +//EVIL SPELLS (instant smite + banishment) +#define SCHOOL_NECROMANCY "necromancy" //>>>necromancy +#define SCHOOL_FORBIDDEN "forbidden" //>heretic shit and other fucked up magic + +//invocation types - what does the wizard need to do to invoke (cast) the spell? + +///Forces the wizard to shout (and be able to) to cast the spell. +#define INVOCATION_SHOUT "shout" +///Forces the wizard to emote (and be able to) to cast the spell. +#define INVOCATION_EMOTE "emote" +///Forces the wizard to whisper (and be able to) to cast the spell. +#define INVOCATION_WHISPER "whisper" diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 74005467f08..ba42499ba18 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -515,8 +515,9 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE))) //Religion -#define HOLY_ROLE_PRIEST 1 //default priestly role -#define HOLY_ROLE_HIGHPRIEST 2 //the one who designates the religion +#define HOLY_ROLE_DEACON 1 //role below priests, for losing most powers of priests but still being holy. +#define HOLY_ROLE_PRIEST 2 //default priestly role +#define HOLY_ROLE_HIGHPRIEST 3 //the one who designates the religion #define ALIGNMENT_GOOD "good" #define ALIGNMENT_NEUT "neutral" diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 8530bf63cad..9dd767c02e3 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -22,7 +22,8 @@ #define BEING_REMOVED (1<<0) #define IN_INVENTORY (1<<1) //is this item equipped into an inventory slot or hand of a mob? used for tooltips #define FORCE_STRING_OVERRIDE (1<<2) // used for tooltips -#define NEEDS_PERMIT (1<<3) //Used by security bots to determine if this item is safe for public use. +///Used by security bots to determine if this item is safe for public use. +#define NEEDS_PERMIT (1<<3) #define SLOWS_WHILE_IN_HAND (1<<4) #define NO_MAT_REDEMPTION (1<<5) // Stops you from putting things like an RCD or other items into an ORM or protolathe for materials. #define DROPDEL (1<<6) // When dropped, it calls qdel on itself diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index e04dee39d9e..be5838c9588 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -92,9 +92,7 @@ #define MSG_VISUAL (1<<0) #define MSG_AUDIBLE (1<<1) -#define INVOCATION_SHOUT "shout" -#define INVOCATION_EMOTE "emote" -#define INVOCATION_WHISPER "whisper" + //Used in visible_message_flags, audible_message_flags and runechat_flags #define EMOTE_MESSAGE (1<<0) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 8a9b45aa06e..4106cd00957 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -283,6 +283,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_KISS_OF_DEATH "kiss_of_death" /// Used on limbs in the process of turning a human into a plasmaman while in plasma lava #define TRAIT_PLASMABURNT "plasma_burnt" +/// Addictions don't tick down, basically they're permanently addicted +#define TRAIT_HOPELESSLY_ADDICTED "hopelessly_addicted" +/// Special examine if eyes are visible +#define CULT_EYES "cult_eyes" /// This mob should never close UI even if it doesn't have a client #define TRAIT_PRESERVE_UI_WITHOUT_CLIENT "preserve_ui_without_client" @@ -520,7 +524,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define STASIS_MUTE "stasis" #define GENETICS_SPELL "genetics_spell" #define EYES_COVERED "eyes_covered" -#define CULT_EYES "cult_eyes" #define TRAIT_SANTA "santa" #define SCRYING_ORB "scrying-orb" #define ABDUCTOR_ANTAGONIST "abductor-antagonist" diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm index b0e5d6c6896..89aba180830 100644 --- a/code/controllers/subsystem/vis_overlays.dm +++ b/code/controllers/subsystem/vis_overlays.dm @@ -30,7 +30,7 @@ SUBSYSTEM_DEF(vis_overlays) if(MC_TICK_CHECK) return -//the "thing" var can be anything with vis_contents which includes images +//the "thing" var can be anything with vis_contents which includes images - in the future someone should totally allow vis overlays to be passed in as an arg instead of all this bullshit /datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE) var/obj/effect/overlay/vis/overlay if(!unique) diff --git a/code/datums/achievements/job_achievements.dm b/code/datums/achievements/job_achievements.dm index f70d250b601..13a68462edd 100644 --- a/code/datums/achievements/job_achievements.dm +++ b/code/datums/achievements/job_achievements.dm @@ -30,3 +30,5 @@ desc = "Centcom is very impressed with your department!" database_id = MEDAL_GOOD_SERVICE icon = "chem_tut" + +//civilian achievies! while not recognized by the code, it is recognized by our hearts diff --git a/code/datums/components/religious_tool.dm b/code/datums/components/religious_tool.dm index 5c39a934962..612dab2de31 100644 --- a/code/datums/components/religious_tool.dm +++ b/code/datums/components/religious_tool.dm @@ -7,6 +7,8 @@ dupe_mode = COMPONENT_DUPE_UNIQUE /// Enables access to the global sect directly var/datum/religion_sect/easy_access_sect + /// Prevents double selecting sects + var/selecting_sect = FALSE /// What extent do we want this religious tool to act? In case you don't want full access to the list. Generated on New var/operation_flags /// The rite currently being invoked @@ -42,7 +44,8 @@ if(!GLOB.religious_sect) return FALSE easy_access_sect = GLOB.religious_sect - after_sect_select_cb.Invoke() + if(after_sect_select_cb) + after_sect_select_cb.Invoke() return TRUE @@ -53,20 +56,8 @@ /datum/component/religious_tool/proc/AttemptActions(datum/source, obj/item/the_item, mob/living/user) SIGNAL_HANDLER - /**********Sect Selection**********/ - if(!SetGlobalToLocal()) - if(!(operation_flags & RELIGION_TOOL_SECTSELECT)) - return - //At this point you're intentionally trying to select a sect. - INVOKE_ASYNC(src, .proc/select_sect, user) - return COMPONENT_NO_AFTERATTACK - - /**********Rite Invocation**********/ - else if(istype(the_item, catalyst_type)) - if(!(operation_flags & RELIGION_TOOL_INVOKE)) - return - INVOKE_ASYNC(src, .proc/perform_rite, user) - return (force_catalyst_afterattack ? NONE : COMPONENT_NO_AFTERATTACK) + if(istype(the_item, catalyst_type)) + INVOKE_ASYNC(src, /datum.proc/ui_interact, user) //asynchronous to avoid sleeping in a signal /**********Sacrificing**********/ else if(operation_flags & RELIGION_TOOL_SACRIFICE) @@ -75,21 +66,69 @@ easy_access_sect.on_sacrifice(the_item,user) return COMPONENT_NO_AFTERATTACK -/// Select the sect, called async from [/datum/component/religious_tool/proc/AttemptActions] -/datum/component/religious_tool/proc/select_sect(mob/living/user) +/datum/component/religious_tool/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ReligiousTool") + ui.open() + return COMPONENT_NO_AFTERATTACK + +/datum/component/religious_tool/ui_state(mob/user) + if(!iscarbon(usr)) + return GLOB.never_state + var/mob/living/carbon/carbon = usr + if(!carbon.is_holding_item_of_type(catalyst_type)) + return GLOB.never_state + return GLOB.default_state + +/datum/component/religious_tool/ui_data(mob/user) + var/list/data = list() + //cannot find global vars, so lets offer options + if(!SetGlobalToLocal()) + data["sects"] = generate_available_sects(user) + data["alignment"] = ALIGNMENT_NEUT //neutral theme if you have no sect + else + data["sects"] = null + data["name"] = easy_access_sect.name + data["desc"] = easy_access_sect.desc + data["quote"] = easy_access_sect.quote + data["alignment"] = easy_access_sect.alignment + data["icon"] = easy_access_sect.tgui_icon + data["favordesc"] = easy_access_sect.tool_examine(user) + data["favor"] = easy_access_sect.favor + data["deity"] = GLOB.deity + data["rites"] = generate_available_rites() + data["wanted"] = generate_sacrifice_list() + + var/atom/atom_parent = parent + data["toolname"] = atom_parent.name + data["can_select_sect"] = (operation_flags & RELIGION_TOOL_SECTSELECT) + data["can_invoke_rite"] = (operation_flags & RELIGION_TOOL_INVOKE) + data["can_sacrifice_item"] = (operation_flags & RELIGION_TOOL_SACRIFICE) + return data + +/datum/component/religious_tool/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + switch(action) + if("sect_select") + select_sect(usr, params["path"]) + if("perform_rite") + perform_rite(usr, params["path"]) + else + to_chat(world, action) + + +/// Select the sect, called from [/datum/component/religious_tool/proc/AttemptActions] +/datum/component/religious_tool/proc/select_sect(mob/living/user, path) if(user.mind.holy_role != HOLY_ROLE_HIGHPRIEST) to_chat(user, "You are not the high priest, and therefore cannot select a religious sect.") return - var/list/available_options = generate_available_sects(user) - if(!available_options) + if(!user.canUseTopic(parent, BE_CLOSE, FALSE, NO_TK)) + to_chat(user,"You cannot select a sect at this time.") return - - var/sect_select = input(user,"Select a sect (You CANNOT revert this decision!)","Select a Sect",null) in available_options - if(!sect_select || !user.canUseTopic(parent, BE_CLOSE, FALSE, NO_TK)) - to_chat(user,"You cannot select a sect at this time.") + if(GLOB.religious_sect) return - var/type_selected = available_options[sect_select] - GLOB.religious_sect = new type_selected() + GLOB.religious_sect = new path() for(var/i in GLOB.player_list) if(!isliving(i)) continue @@ -100,20 +139,18 @@ easy_access_sect = GLOB.religious_sect after_sect_select_cb.Invoke() -/// Perform the rite, called async from [/datum/component/religious_tool/proc/AttemptActions] -/datum/component/religious_tool/proc/perform_rite(mob/living/user) - if(!easy_access_sect.rites_list) - to_chat(user, "Your sect doesn't have any rites to perform!") +/// Perform the rite, called from [/datum/component/religious_tool/proc/AttemptActions] +/datum/component/religious_tool/proc/perform_rite(mob/living/user, path) + if(user.mind.holy_role == HOLY_ROLE_DEACON) + to_chat(user, "You are merely a deacon of [GLOB.deity], and therefore cannot perform rites.") return if(performing_rite) - to_chat(user, "There is a rite currently being performed here already!") + to_chat(user, "There is a rite currently being performed here already.") return - var/rite_select = input(user,"Select a rite to perform!","Select a rite",null) in easy_access_sect.rites_list - if(!rite_select || !user.canUseTopic(parent, BE_CLOSE, FALSE, NO_TK)) - to_chat(user,"You cannot perform the rite at this time.") + if(!user.canUseTopic(parent, BE_CLOSE, FALSE, NO_TK)) + to_chat(user,"You are not close enough to perform the rite.") return - var/selection2type = easy_access_sect.rites_list[rite_select] - performing_rite = new selection2type(parent) + performing_rite = new path(parent) if(!performing_rite.perform_rite(user, parent)) QDEL_NULL(performing_rite) else @@ -122,14 +159,58 @@ QDEL_NULL(performing_rite) /** - * Generates a list of available sects to the user. Intended to support custom-availability sects. Because these are not instanced, we cannot put the availability on said sect beyond variables. + * Generates a list of available sects to the user. Intended to support custom-availability sects. */ /datum/component/religious_tool/proc/generate_available_sects(mob/user) - . = list() - for(var/i in subtypesof(/datum/religion_sect)) - var/datum/religion_sect/not_a_real_instance_rs = i - if(initial(not_a_real_instance_rs.starter)) - . += list(initial(not_a_real_instance_rs.name) = i) + 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 + var/list/sect = list() + var/datum/religion_sect/not_a_real_instance_rs = path + sect["name"] = initial(not_a_real_instance_rs.name) + sect["desc"] = initial(not_a_real_instance_rs.desc) + sect["alignment"] = initial(not_a_real_instance_rs.alignment) + sect["quote"] = initial(not_a_real_instance_rs.quote) + sect["icon"] = initial(not_a_real_instance_rs.tgui_icon) + sect["path"] = path + sects_to_pick += list(sect) + return sects_to_pick + +/** + * Generates available rites to pick from. It expects the sect to be picked by the time it was called (by tgui data) + */ +/datum/component/religious_tool/proc/generate_available_rites() + var/list/rites_to_pick = list() + for(var/path in easy_access_sect.rites_list) + ///checks to invalidate + var/list/rite = list() + var/datum/religion_rites/rite_type = path + rite["name"] = initial(rite_type.name) + rite["desc"] = initial(rite_type.desc) + var/cost = initial(rite_type.favor_cost) + rite["favor"] = cost + rite["can_cast"] = cost > easy_access_sect.favor + rite["path"] = path + rites_to_pick += list(rite) + return rites_to_pick + +/** + * Generates an english list (so string) of wanted sac items. Returns null if no targets! + */ +/datum/component/religious_tool/proc/generate_sacrifice_list() + if(!easy_access_sect.desired_items) + return //specifically null so the data sends as such + var/list/item_names = list() + for(var/atom/sac_type as anything in easy_access_sect.desired_items) + var/append = easy_access_sect.desired_items[sac_type] + var/entry = "[initial(sac_type.name)]s [append]" + item_names += entry + return english_list(item_names) /** * Appends to examine so the user knows it can be used for religious purposes. @@ -147,14 +228,12 @@ if(!can_i_see) return + examine_list += "Use a bible to interact with this." if(!easy_access_sect) if(operation_flags & RELIGION_TOOL_SECTSELECT) examine_list += "This looks like it can be used to select a sect." return - - examine_list += "The sect currently has [round(easy_access_sect.favor)] favor with [GLOB.deity].[(operation_flags & RELIGION_TOOL_SACRIFICE) ? "Desired items can be used on this to increase favor." : ""]" - if(!easy_access_sect.rites_list) - return //if we dont have rites it doesnt do us much good if the object can be used to invoke them! - if(operation_flags & RELIGION_TOOL_INVOKE) - examine_list += "List of available Rites:" - examine_list += easy_access_sect.rites_list + if(operation_flags & RELIGION_TOOL_SACRIFICE)//this can be moved around if things change but usually no rites == no sacrifice + examine_list += "Desired items can be used on this to increase favor." + if(easy_access_sect.rites_list && operation_flags & RELIGION_TOOL_INVOKE) + examine_list += "You can invoke rites from this." diff --git a/code/datums/dna.dm b/code/datums/dna.dm index cde3621958c..18445becacf 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -68,6 +68,7 @@ mutation_type = HM.type if(get_mutation(mutation_type)) return + SEND_SIGNAL(holder, COMSIG_CARBON_GAIN_MUTATION, mutation_type, class) return force_give(new mutation_type (class, time, copymut = mutation)) /datum/dna/proc/remove_mutation(mutation_type) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 599f9151c40..cd9dd3e534b 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -338,3 +338,13 @@ description = "MY PRECIOUS WINGS!!\n" mood_change = -10 timeout = 10 MINUTES + +/datum/mood_event/holy_smite //punished + description = "I have been punished by my deity!\n" + mood_change = -5 + timeout = 5 MINUTES + +/datum/mood_event/banished //when the chaplain is sus! (and gets forcably de-holy'd) + description = "I have been excommunicated!\n" + mood_change = -10 + timeout = 10 MINUTES diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 9ee7ffedc36..abea270a7d1 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -34,6 +34,12 @@ mood_change = 3 timeout = 8 MINUTES +/datum/mood_event/maintenance_adaptation + mood_change = 8 + +/datum/mood_event/maintenance_adaptation/add_effects() + description = "[GLOB.deity] has helped me adapt to the maintenance shafts!\n" + /datum/mood_event/book_nerd description = "I have recently read a book.\n" mood_change = 1 @@ -236,3 +242,7 @@ /datum/mood_event/kiss/add_effects(mob/beau) if(beau) description = "[beau.name] blew a kiss at me, I must be a real catch!\n" + +/datum/mood_event/honorbound + description = "Following my honorbound code is fulfilling!\n" + mood_change = 4 diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index 9aadccf9971..d9ae1a6c699 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -117,7 +117,7 @@ /obj/effect/proc_holder/spell/aimed/firebreath name = "Fire Breath" desc = "You can breathe fire at a target." - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 600 clothes_req = FALSE range = 20 @@ -176,7 +176,7 @@ /obj/effect/proc_holder/spell/self/void name = "Convoke Void" //magic the gathering joke here desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly." - school = "evocation" + school = SCHOOL_EVOCATION clothes_req = FALSE charge_max = 600 invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!" diff --git a/code/datums/mutations/holy_mutation/burdened.dm b/code/datums/mutations/holy_mutation/burdened.dm new file mode 100644 index 00000000000..97be748f23a --- /dev/null +++ b/code/datums/mutations/holy_mutation/burdened.dm @@ -0,0 +1,189 @@ + +///Burdened grants some more mutations upon injuring yourself sufficiently +/datum/mutation/human/burdened + name = "Burdened" + desc = "Less of a genome and more of a forceful rewrite of genes. Nothing Nanotrasen supplies allows for a genetic restructure like this... \ + The user feels compelled to injure themselves in various incapacitating and horrific ways. Oddly enough, this gene seems to be connected \ + to several other ones, possibly ready to trigger more genetic changes in the future." + quality = POSITIVE //so it gets carried over on revives + locked = TRUE + text_gain_indication = "You feel burdened!" + text_lose_indication = "You no longer feel the need to burden yourself!" + /// goes from 0 to 6 (but can be beyond 6, just does nothing) and gives rewards. increased by disabling yourself with debuffs + var/burden_level = 0 + +/datum/mutation/human/burdened/on_acquiring(mob/living/carbon/human/owner) + if(..()) + return + RegisterSignal(owner, COMSIG_CARBON_GAIN_ORGAN, .proc/organ_added_burden) + RegisterSignal(owner, COMSIG_CARBON_LOSE_ORGAN, .proc/organ_removed_burden) + + RegisterSignal(owner, COMSIG_CARBON_ATTACH_LIMB, .proc/limbs_added_burden) + RegisterSignal(owner, COMSIG_CARBON_REMOVE_LIMB, .proc/limbs_removed_burden) + + RegisterSignal(owner, COMSIG_CARBON_GAIN_ADDICTION, .proc/addict_added_burden) + RegisterSignal(owner, COMSIG_CARBON_LOSE_ADDICTION, .proc/addict_removed_burden) + + RegisterSignal(owner, COMSIG_CARBON_GAIN_MUTATION, .proc/mutation_added_burden) + RegisterSignal(owner, COMSIG_CARBON_LOSE_MUTATION, .proc/mutation_removed_burden) + + RegisterSignal(owner, COMSIG_CARBON_GAIN_TRAUMA, .proc/trauma_added_burden) + RegisterSignal(owner, COMSIG_CARBON_LOSE_TRAUMA, .proc/trauma_removed_burden) + +/datum/mutation/human/burdened/on_losing(mob/living/carbon/human/owner) + . = ..() + UnregisterSignal(owner, list( + COMSIG_CARBON_GAIN_ORGAN, + COMSIG_CARBON_LOSE_ORGAN, + COMSIG_CARBON_ATTACH_LIMB, + COMSIG_CARBON_REMOVE_LIMB, + COMSIG_CARBON_GAIN_ADDICTION, + COMSIG_CARBON_LOSE_ADDICTION, + COMSIG_CARBON_GAIN_MUTATION, + COMSIG_CARBON_LOSE_MUTATION, + COMSIG_CARBON_GAIN_TRAUMA, + COMSIG_CARBON_LOSE_TRAUMA, + )) + +/** + * Called by hooked signals whenever burden_level var needs to go up or down by 1. + * Sends messages on burden level, gives powers and takes them if needed, etc + * + * Arguments: + * * increase: whether to tick burden_level up or down 1 + */ +/datum/mutation/human/burdened/proc/update_burden(increase) + //adjust burden + burden_level = increase ? burden_level + 1 : burden_level - 1 + if(burden_level < 0) //basically a clamp with a stack on it, because this shouldn't be happening + stack_trace("somehow, burden mutation is removing more burden than it's adding.") + burden_level = 0 + //send a message and handle rewards + switch(burden_level) + if(0) + to_chat(owner, "You feel no weight on your shoulders. You are not feeling [GLOB.deity]'s suffering.") + if(1) + if(increase) + to_chat(owner, "You begin to feel the scars on [GLOB.deity]. You must continue to burden yourself.") + else + to_chat(owner, "The weight on your shoulders feels lighter. You are barely feeling [GLOB.deity]'s suffering.") + if(2) + if(increase) + to_chat(owner, "You have done well to understand [GLOB.deity]. You are almost at a breakthrough.") + else + to_chat(owner, "The weight on your shoulders feels lighter. You have lost some universal truths.") + dna.remove_mutation(TELEPATHY) + dna.remove_mutation(MUT_MUTE) + owner.remove_filter("burden_outline") + if(3) + if(increase) + to_chat(owner, "Your suffering is only a fraction of [GLOB.deity]'s, and yet the universal truths are coming to you.") + dna.add_mutation(TELEPATHY) + dna.add_mutation(MUT_MUTE) + owner.add_filter("burden_outline", 9, list("type" = "outline", "color" = "#6c6eff")) + else + to_chat(owner, "The weight on your shoulders feels lighter. You feel like you're about to forget.") + if(4) + if(increase) + to_chat(owner, "The weight on your shoulders is immense. [GLOB.deity] is shattered across the cosmos.") + else + to_chat(owner, "The weight on your shoulders feels lighter. You're growing further from your goal.") + if(5) + if(increase) + to_chat(owner, "You're on the cusp of another breakthrough. [GLOB.deity] lost everything.") + else + to_chat(owner, "The weight on your shoulders feels lighter. You have lost some universal truths.") + dna.remove_mutation(TK) + dna.remove_mutation(MINDREAD) + if(6) + to_chat(owner, "You have finally broken yourself enough to understand [GLOB.deity]. It's all so clear to you.") + dna.add_mutation(TK) + dna.add_mutation(MINDREAD) + +/// Signal to decrease burden_level (see update_burden proc) if an organ is added +/datum/mutation/human/burdened/proc/organ_added_burden(mob/burdened, obj/item/organ/new_organ, special) + SIGNAL_HANDLER + + if(special) //aheals + return + + if(istype(new_organ, /obj/item/organ/eyes)) + var/obj/item/organ/eyes/new_eyes = new_organ + if(new_eyes.tint < TINT_BLIND) //unless you added unworking eyes (flashlight eyes), this is removing burden + update_burden(FALSE) + return + update_burden(FALSE)//working organ + +/// Signal to increase burden_level (see update_burden proc) if an organ is removed +/datum/mutation/human/burdened/proc/organ_removed_burden(mob/burdened, obj/item/organ/old_organ, special) + SIGNAL_HANDLER + + if(special) //aheals + return + + if(istype(old_organ, /obj/item/organ/eyes)) + var/obj/item/organ/eyes/old_eyes = old_organ + if(old_eyes.tint < TINT_BLIND) //unless you were already blinded by them (flashlight eyes), this is adding burden! + update_burden(TRUE) + + update_burden(TRUE)//lost organ + +/// Signal to decrease burden_level (see update_burden proc) if a limb is added +/datum/mutation/human/burdened/proc/limbs_added_burden(datum/source, obj/item/bodypart/new_limb, special) + SIGNAL_HANDLER + + if(special) //something we don't wanna consider, like instaswapping limbs + return + update_burden(FALSE) + +/// Signal to increase burden_level (see update_burden proc) if a limb is removed +/datum/mutation/human/burdened/proc/limbs_removed_burden(datum/source, obj/item/bodypart/old_limb, special) + SIGNAL_HANDLER + + if(special) //something we don't wanna consider, like instaswapping limbs + return + update_burden(TRUE) + +/// Signal to increase burden_level (see update_burden proc) if an addiction is added +/datum/mutation/human/burdened/proc/addict_added_burden(datum/addiction/new_addiction, datum/mind/addict_mind) + SIGNAL_HANDLER + + update_burden(TRUE) + +/// Signal to decrease burden_level (see update_burden proc) if an addiction is removed +/datum/mutation/human/burdened/proc/addict_removed_burden(datum/addiction/old_addiction, datum/mind/nonaddict_mind) + SIGNAL_HANDLER + + update_burden(FALSE) + +/// Signal to increase burden_level (see update_burden proc) if a mutation is added +/datum/mutation/human/burdened/proc/mutation_added_burden(mob/living/carbon/burdened, datum/mutation/human/mutation_type, class) + SIGNAL_HANDLER + + if(class == MUT_OTHER) //getting a mutation can give a mutation as a reward, which in turn triggers this, which then rewards a mutation, which in turn... + return + if(initial(mutation_type.quality) == NEGATIVE) + update_burden(TRUE) + +/// Signal to decrease burden_level (see update_burden proc) if a mutation is removed +/datum/mutation/human/burdened/proc/mutation_removed_burden(mob/living/carbon/burdened, datum/mutation/human/mutation_type) + SIGNAL_HANDLER + + if(class == MUT_OTHER) //see above + return + if(initial(mutation_type.quality) == NEGATIVE) + update_burden(FALSE) + +/// Signal to increase burden_level (see update_burden proc) if a trauma is added +/datum/mutation/human/burdened/proc/trauma_added_burden(mob/living/carbon/burdened, datum/brain_trauma/trauma_added) + SIGNAL_HANDLER + + if(istype(trauma_added, /datum/brain_trauma/severe)) + update_burden(TRUE) + +/// Signal to decrease burden_level (see update_burden proc) if a trauma is removed +/datum/mutation/human/burdened/proc/trauma_removed_burden(mob/living/carbon/burdened, datum/brain_trauma/trauma_removed) + SIGNAL_HANDLER + + if(istype(trauma_removed, /datum/brain_trauma/severe)) + update_burden(FALSE) diff --git a/code/datums/mutations/holy_mutation/honorbound.dm b/code/datums/mutations/holy_mutation/honorbound.dm new file mode 100644 index 00000000000..9b94e5d9204 --- /dev/null +++ b/code/datums/mutations/holy_mutation/honorbound.dm @@ -0,0 +1,276 @@ + +///Honorbound prevents you from attacking the unready, the just, or the innocent +/datum/mutation/human/honorbound + name = "Honorbound" + desc = "Less of a genome and more of a forceful rewrite of genes. Nothing Nanotrasen supplies allows for a genetic restructure like this... \ + The user feels compelled to follow supposed \"rules of combat\" but in reality they physically are unable to. \ + Their brain is rewired to excuse any curious inabilities that arise from this odd effect." + quality = POSITIVE //so it gets carried over on revives + power = /obj/effect/proc_holder/spell/pointed/declare_evil + locked = TRUE + text_gain_indication = "You feel honorbound!" + text_lose_indication = "You feel unshackled from your code of honor!" + /// list of guilty people + var/list/guilty = list() + +/datum/mutation/human/honorbound/on_acquiring(mob/living/carbon/human/owner) + if(..()) + return + //moodlet + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "honorbound", /datum/mood_event/honorbound) + //checking spells cast by honorbound + RegisterSignal(owner, COMSIG_MOB_CAST_SPELL, .proc/spell_check) + RegisterSignal(owner, COMSIG_MOB_FIRED_GUN, .proc/staff_check) + //signals that check for guilt + RegisterSignal(owner, COMSIG_PARENT_ATTACKBY, .proc/attackby_guilt) + RegisterSignal(owner, COMSIG_ATOM_HULK_ATTACK, .proc/hulk_guilt) + RegisterSignal(owner, COMSIG_ATOM_ATTACK_HAND, .proc/hand_guilt) + RegisterSignal(owner, COMSIG_ATOM_ATTACK_PAW, .proc/paw_guilt) + RegisterSignal(owner, COMSIG_ATOM_BULLET_ACT, .proc/bullet_guilt) + RegisterSignal(owner, COMSIG_ATOM_HITBY, .proc/thrown_guilt) + + //signal that checks for dishonorable attacks + RegisterSignal(owner, COMSIG_MOB_CLICKON, .proc/attack_honor) + +/datum/mutation/human/honorbound/on_losing(mob/living/carbon/human/owner) + SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "honorbound") + UnregisterSignal(owner, list( + COMSIG_PARENT_ATTACKBY, + COMSIG_ATOM_HULK_ATTACK, + COMSIG_ATOM_ATTACK_HAND, + COMSIG_ATOM_ATTACK_PAW, + COMSIG_ATOM_BULLET_ACT, + COMSIG_ATOM_HITBY, + COMSIG_MOB_CLICKON, + COMSIG_MOB_CAST_SPELL, + COMSIG_MOB_FIRED_GUN, + )) + . = ..() + +/// Signal to see if the mutation allows us to attack a target +/datum/mutation/human/honorbound/proc/attack_honor(mob/living/carbon/human/honorbound, atom/clickingon, params) + SIGNAL_HANDLER + + var/obj/item/weapon = honorbound.get_active_held_item() + var/list/modifiers = params2list(params) + + if(!isliving(clickingon)) + return + if(!honorbound.DirectAccess(clickingon) && !isgun(weapon)) + return + if(weapon.item_flags & NOBLUDGEON) + return + if(!honorbound.combat_mode && ((!weapon || !weapon.force) && !LAZYACCESS(modifiers, RIGHT_CLICK))) + return + var/mob/living/clickedmob = clickingon + if(!is_honorable(honorbound, clickedmob)) + return (COMSIG_MOB_CANCEL_CLICKON) + +/** + * Called by hooked signals whenever someone attacks the person with this mutation + * Checks if the attacker should be considered guilty and adds them to the guilty list if true + * + * Arguments: + * * user: person who attacked the honorbound + * * declaration: if this wasn't an attack, but instead the honorbound spending favor on declaring this person guilty + */ +/datum/mutation/human/honorbound/proc/guilty(mob/living/user, declaration = FALSE) + if(user in guilty) + return + var/datum/mind/guilty_conscience = user.mind + if(guilty_conscience) //sec and medical are immune to becoming guilty through attack (we don't check holy because holy shouldn't be able to attack eachother anyways) + var/job = guilty_conscience.assigned_role + if(job in (GLOB.security_positions + GLOB.medical_positions)) + return + if(declaration) + to_chat(owner, "[user] is now considered guilty by [GLOB.deity] from your declaration.") + else + to_chat(owner, "[user] is now considered guilty by [GLOB.deity] for attacking you first.") + to_chat(user, "[GLOB.deity] no longer considers you innocent!") + guilty += user + +/** + * Called by attack_honor signal to check whether an attack should be allowed or not + * + * Arguments: + * * honorbound_human: typecasted owner of mutation + * * target_creature: person honorbound_human is attacking + */ +/datum/mutation/human/honorbound/proc/is_honorable(mob/living/carbon/human/honorbound_human, mob/living/target_creature) + var/is_guilty = (target_creature in guilty) + //THE UNREADY (Applies over ANYTHING else!) + if(honorbound_human == target_creature) + return TRUE //oh come on now + if(target_creature.IsSleeping() || target_creature.IsUnconscious() || HAS_TRAIT(target_creature, TRAIT_RESTRAINED)) + to_chat(honorbound_human, "There is no honor in attacking the unready.") + return FALSE + //THE JUST (Applies over guilt except for med, so you best be careful!) + if(ishuman(target_creature)) + var/mob/living/carbon/human/target_human = target_creature + var/job = target_human.mind?.assigned_role + var/is_holy = target_human.mind?.holy_role + if(job in GLOB.security_positions || is_holy) + to_chat(honorbound_human, "There is nothing righteous in attacking the just.") + return FALSE + if(job in GLOB.medical_positions) + to_chat(honorbound_human, "If you truly think this healer is not innocent, declare them guilty.") + return FALSE + //THE INNOCENT + if(!is_guilty) + to_chat(honorbound_human, "There is nothing righteous in attacking the innocent.") + return FALSE + return TRUE + +// SIGNALS THAT ARE FOR BEING ATTACKED FIRST (GUILTY) +/datum/mutation/human/honorbound/proc/attackby_guilt(datum/source, obj/item/I, mob/attacker) + SIGNAL_HANDLER + if(I.force && I.damtype != STAMINA) + guilty(attacker) + +/datum/mutation/human/honorbound/proc/hulk_guilt(datum/source, mob/attacker) + SIGNAL_HANDLER + guilty(attacker) + +/datum/mutation/human/honorbound/proc/hand_guilt(datum/source, mob/living/attacker) + SIGNAL_HANDLER + if(attacker.combat_mode) + guilty(attacker) + +/datum/mutation/human/honorbound/proc/paw_guilt(datum/source, mob/living/attacker) + SIGNAL_HANDLER + guilty(attacker) + +/datum/mutation/human/honorbound/proc/bullet_guilt(datum/source, obj/projectile/proj) + SIGNAL_HANDLER + var/mob/living/shot_honorbound = source + var/guilty_projectiles = typecacheof(list( + /obj/projectile/beam, + /obj/projectile/bullet, + /obj/projectile/magic, + )) + if(!is_type_in_typecache(proj, guilty_projectiles)) + return + if((proj.damage_type == STAMINA)) + return + if(!proj.nodamage && proj.damage < shot_honorbound.health && isliving(proj.firer)) + guilty(proj.firer) + +/datum/mutation/human/honorbound/proc/thrown_guilt(datum/source, atom/movable/thrown_movable, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + if(istype(thrown_movable, /obj/item)) + var/mob/living/honorbound = source + var/obj/item/thrown_item = thrown_movable + if(thrown_item.throwforce < honorbound.health && ishuman(thrown_item.thrownby)) + guilty(thrown_item.thrownby) + +//spell checking +/datum/mutation/human/honorbound/proc/spell_check(mob/user, obj/effect/proc_holder/spell/spell_cast) + SIGNAL_HANDLER + punishment(user, spell_cast.school) + +/datum/mutation/human/honorbound/proc/staff_check(mob/user, obj/item/gun/gun_fired, target, params, zone_override) + SIGNAL_HANDLER + if(!istype(gun_fired, /obj/item/gun/magic)) + return + var/obj/item/gun/magic/offending_staff = gun_fired + punishment(user, offending_staff.school) + +/** + * Called when a spell is casted or a magic gun is fired, checks the signal and punishes accordingly + * + * Arguments: + * * user: typecasted owner of mutation + * * school: school of magic casted from the staff/spell + */ +/datum/mutation/human/honorbound/proc/punishment(mob/living/carbon/human/user, school) + switch(school) + if(SCHOOL_NECROMANCY, SCHOOL_FORBIDDEN) + to_chat(user, "[GLOB.deity] is enraged by your use of forbidden magic!") + lightningbolt(user) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "honorbound", /datum/mood_event/banished) + user.dna.remove_mutation(HONORBOUND) + user.mind.holy_role = NONE + to_chat(user, "You have been excommunicated! You are no longer holy!") + else + to_chat(user, "[GLOB.deity] is angered by your use of [school] magic!") + lightningbolt(user) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "honorbound", /datum/mood_event/holy_smite)//permanently lose your moodlet after this + +/datum/mutation/human/honorbound/proc/lightningbolt(mob/living/user) + var/turf/lightning_source = get_step(get_step(user, NORTH), NORTH) + lightning_source.Beam(user, icon_state="lightning[rand(1,12)]", time = 5) + user.adjustFireLoss(LIGHTNING_BOLT_DAMAGE) + playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, TRUE) + if(ishuman(user)) + var/mob/living/carbon/human/human_target = user + human_target.electrocution_animation(LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH) + +/obj/effect/proc_holder/spell/pointed/declare_evil + name = "Declare Evil" + desc = "If someone is so obviously an evil of this world you can spend a huge amount of favor to declare them guilty." + school = SCHOOL_HOLY + charge_max = 0 + clothes_req = FALSE + range = 7 + cooldown_min = 0 + ranged_mousepointer = 'icons/effects/mouse_pointers/honorbound.dmi' + action_icon_state = "declaration" + active_msg = "You prepare to declare a sinner..." + deactive_msg = "You decide against a declaration." + +/obj/effect/proc_holder/spell/pointed/declare_evil/cast(list/targets, mob/living/carbon/human/user, silent = FALSE) + if(!ishuman(user)) + return FALSE + var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(HONORBOUND) + var/datum/religion_sect/honorbound/honorsect = GLOB.religious_sect + if(honorsect.favor < 150) + to_chat(user, "You need at least 150 favor to declare someone evil!") + return FALSE + if(!honormut) + return FALSE + if(!targets.len) + if(!silent) + to_chat(user, "Nobody to declare evil here!") + return FALSE + if(targets.len > 1) + if(!silent) + to_chat(user, "Too many people to declare! Pick ONE!") + return FALSE + var/declaration_message = "[targets[1]]! By the divine light of [GLOB.deity], You are an evil of this world that must be wrought low!" + if(!user.can_speak(declaration_message)) + to_chat(user, "You can't get the declaration out!") + return FALSE + if(!can_target(targets[1], user, silent)) + return FALSE + GLOB.religious_sect.adjust_favor(-150, user) + user.say(declaration_message) + honormut.guilty(targets[1], declaration = TRUE) + return TRUE + +/obj/effect/proc_holder/spell/pointed/declare_evil/can_target(atom/target, mob/user, silent) + . = ..() + if(!.) + return FALSE + if(!isliving(target)) + if(!silent) + to_chat(user, "You can only declare living beings evil!") + return FALSE + var/mob/living/victim = target + if(victim.stat == DEAD) + if(!silent) + to_chat(user, "Declaration on the dead? Really?") + return FALSE + var/datum/mind/guilty_conscience = victim.mind + if(!victim.key ||!guilty_conscience) //sec and medical are immune to becoming guilty through attack (we don't check holy because holy shouldn't be able to attack eachother anyways) + if(!silent) + to_chat(user, "There is no evil a vacant mind can do.") + return FALSE + if(guilty_conscience.holy_role)//also handles any kind of issues with self declarations + if(!silent) + to_chat(user, "Followers of [GLOB.deity] cannot be evil!") + return FALSE + if(guilty_conscience.assigned_role in GLOB.security_positions) + if(!silent) + to_chat(user, "Members of security are uncorruptable! You cannot declare one evil!") + return FALSE + return TRUE diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index fa2740d6608..9cae2819b27 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -617,7 +617,7 @@ else set_light(0) - +//type and subtypes spawned and used to give some eyes lights, /obj/item/flashlight/eyelight name = "eyelight" desc = "This shouldn't exist outside of someone's head, how are you seeing this?" @@ -627,3 +627,11 @@ flags_1 = CONDUCT_1 item_flags = DROPDEL actions_types = list() + +/obj/item/flashlight/eyelight/adapted + name = "adaptedlight" + desc = "There is no possible way for a player to see this, so I can safely talk at length about why this exists. Adapted eyes come \ + with icons that go above the lighting layer so to make sure the red eyes that pierce the darkness are always visible we make the \ + human emit the smallest amount of light possible. Thanks for reading :)" + light_range = 1 + light_power = 0.07 diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 8e9df6a1049..b3de30318f9 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -177,6 +177,15 @@ . = ..() RegisterSignal(src, COMSIG_ITEM_GRILLED, .proc/OnGrill) +/obj/item/food/badrecipe/moldy + name = "moldy mess" + desc = "A rancid, living culture of mold. Somewhere, under there, at SOME POINT... there was food." + food_reagents = list(/datum/reagent/consumable/mold = 30) + +/obj/item/food/badrecipe/moldy/Initialize() + . = ..() + AddElement(/datum/element/swabable, CELL_LINE_TABLE_MOLD, CELL_VIRUS_TABLE_GENERIC, rand(2,4), 25) + ///Prevents grilling burnt shit from well, burning. /obj/item/food/badrecipe/proc/OnGrill() return COMPONENT_HANDLED_GRILLING diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 61d9eea22b8..31563e9a0fc 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -555,7 +555,7 @@ else to_chat(user, "You secure [src].") set_anchored(!anchored) - return + return TRUE else if(!open && !user.combat_mode) to_chat(user, "[src] must be open to move it.") return diff --git a/code/modules/admin/smites/lightning.dm b/code/modules/admin/smites/lightning.dm index 3148ae7d4f5..92eca51f291 100644 --- a/code/modules/admin/smites/lightning.dm +++ b/code/modules/admin/smites/lightning.dm @@ -1,6 +1,3 @@ -#define LIGHTNING_BOLT_DAMAGE 75 -#define LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH 40 - /// Strikes the target with a lightning bolt /datum/smite/lightning name = "Lightning bolt" @@ -10,10 +7,8 @@ var/turf/lightning_source = get_step(get_step(target, NORTH), NORTH) lightning_source.Beam(target, icon_state="lightning[rand(1,12)]", time = 5) target.adjustFireLoss(LIGHTNING_BOLT_DAMAGE) + playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, TRUE) if(ishuman(target)) var/mob/living/carbon/human/human_target = target human_target.electrocution_animation(LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH) to_chat(target, "The gods have punished you for your sins!", confidential = TRUE) - -#undef LIGHTNING_BOLT_DAMAGE -#undef LIGHTNING_BOLT_ELECTROCUTION_ANIMATION_LENGTH diff --git a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm index b22343e5158..f5eee869fcb 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash name = "Ashen Passage" desc = "A short range spell allowing you to pass unimpeded through a few walls." - school = "transmutation" + school = SCHOOL_FORBIDDEN invocation = "ASH'N P'SSG'" invocation_type = INVOCATION_WHISPER charge_max = 150 @@ -33,7 +33,7 @@ name = "Mansus Grasp" desc = "A touch spell that lets you channel the power of the Old Gods through your grip." hand_path = /obj/item/melee/touch_attack/mansus_fist - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 100 clothes_req = FALSE action_icon = 'icons/mob/actions/actions_ecult.dmi' @@ -83,7 +83,7 @@ /obj/effect/proc_holder/spell/aoe_turf/rust_conversion name = "Aggressive Spread" desc = "Spreads rust onto nearby surfaces." - school = "transmutation" + school = SCHOOL_FORBIDDEN charge_max = 300 //twice as long as mansus grasp clothes_req = FALSE invocation = "A'GRSV SPR'D" @@ -110,7 +110,7 @@ /obj/effect/proc_holder/spell/pointed/blood_siphon name = "Blood Siphon" desc = "A touch spell that heals your wounds while damaging the enemy. It has a chance to transfer wounds between you and your enemy." - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 150 clothes_req = FALSE invocation = "FL'MS O'ET'RN'ITY" @@ -167,6 +167,7 @@ name = "Patron's Reach" desc = "Channels energy into your gauntlet- unleashing it creates a wave of rust in its wake." proj_type = /obj/projectile/magic/spell/rust_wave + school = SCHOOL_FORBIDDEN charge_max = 350 clothes_req = FALSE action_icon = 'icons/mob/actions/actions_ecult.dmi' @@ -216,7 +217,7 @@ /obj/effect/proc_holder/spell/pointed/cleave name = "Cleave" desc = "Causes severe bleeding on a target and several targets around them." - school = "transmutation" + school = SCHOOL_FORBIDDEN charge_max = 350 clothes_req = FALSE invocation = "CL'VE" @@ -271,7 +272,7 @@ /obj/effect/proc_holder/spell/pointed/touch/mad_touch name = "Touch of Madness" desc = "A touch spell that drains your enemy's sanity." - school = "transmutation" + school = SCHOOL_FORBIDDEN charge_max = 150 clothes_req = FALSE invocation_type = "none" @@ -305,7 +306,7 @@ /obj/effect/proc_holder/spell/pointed/ash_final name = "Nightwatcher's Rite" desc = "A powerful spell that releases 5 streams of fire away from you." - school = "transmutation" + school = SCHOOL_FORBIDDEN invocation = "F'RE" invocation_type = INVOCATION_WHISPER charge_max = 300 @@ -383,6 +384,7 @@ /obj/effect/proc_holder/spell/targeted/emplosion/eldritch name = "Energetic Pulse" invocation = "E'P" + school = SCHOOL_FORBIDDEN invocation_type = INVOCATION_WHISPER clothes_req = FALSE action_background_icon_state = "bg_ecult" @@ -395,7 +397,7 @@ /obj/effect/proc_holder/spell/aoe_turf/fire_cascade name = "Fire Cascade" desc = "Heats the air around you." - school = "transmutation" + school = SCHOOL_FORBIDDEN charge_max = 300 //twice as long as mansus grasp clothes_req = FALSE invocation = "C'SC'DE" @@ -434,6 +436,7 @@ desc = "For a minute, you will passively create a ring of fire around you." invocation = "FL'MS" invocation_type = INVOCATION_WHISPER + school = SCHOOL_FORBIDDEN clothes_req = FALSE action_background_icon_state = "bg_ecult" range = -1 @@ -472,6 +475,7 @@ name = "Force Contract" desc = "Forces your body to contract onto a single tile." invocation_type = "none" + school = SCHOOL_FORBIDDEN clothes_req = FALSE action_background_icon_state = "bg_ecult" range = -1 @@ -503,6 +507,7 @@ desc = "Drains nearby alive people that are engulfed in flames. It heals 10 of each damage type per person. If a target is in critical condition it drains the last of their vitality, killing them." invocation = "GL'RY T' TH' N'GHT'W'TCH'ER" invocation_type = INVOCATION_WHISPER + school = SCHOOL_FORBIDDEN clothes_req = FALSE action_background_icon_state = "bg_ecult" range = -1 @@ -533,7 +538,7 @@ /obj/effect/proc_holder/spell/pointed/manse_link name = "Mansus Link" desc = "Piercing through reality, connecting minds. This spell allows you to add people to a Mansus Net, allowing them to communicate with each other from afar." - school = "transmutation" + school = SCHOOL_FORBIDDEN charge_max = 300 clothes_req = FALSE invocation = "PI'RC' TH' M'ND" @@ -639,7 +644,7 @@ /obj/effect/proc_holder/spell/cone/staggered/entropic_plume name = "Entropic Plume" desc = "Spews forth a disorienting plume that causes enemies to strike each other, briefly blinds them(increasing with range) and poisons them(decreasing with range). Also spreads rust in the path of the plume." - school = "illusion" + school = SCHOOL_FORBIDDEN invocation = "'NTR'P'C PL'M'" invocation_type = INVOCATION_WHISPER clothes_req = FALSE @@ -681,6 +686,7 @@ desc = "Shed your fragile form, become one with the arms, become one with the emperor." invocation_type = INVOCATION_SHOUT invocation = "REALITY UNCOIL!" + school = SCHOOL_FORBIDDEN clothes_req = FALSE action_background_icon_state = "bg_ecult" range = -1 @@ -723,6 +729,7 @@ name = "Void Phase" desc = "Let's you blink to your pointed destination, causes 3x3 aoe damage bubble around your pointed destination and your current location. It has a minimum range of 3 tiles and a maximum range of 9 tiles." invocation_type = INVOCATION_WHISPER + school = SCHOOL_FORBIDDEN invocation = "RE'L'TY PH'S'E" clothes_req = FALSE range = 9 @@ -781,6 +788,7 @@ desc = "Call the void, this pulls all nearby people closer to you, damages people already around you. If they are 4 tiles or closer they are also knocked down and a micro-stun is applied." invocation_type = INVOCATION_WHISPER invocation = "BR'NG F'RTH TH'M T' M'" + school = SCHOOL_FORBIDDEN clothes_req = FALSE action_background_icon_state = "bg_ecult" range = -1 diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm index 65f4c06aad6..f8447d5f237 100644 --- a/code/modules/awaymissions/mission_code/Academy.dm +++ b/code/modules/awaymissions/mission_code/Academy.dm @@ -370,6 +370,7 @@ charge_max = 100 clothes_req = 0 invocation = "JE VES" + school = SCHOOL_CONJURATION invocation_type = INVOCATION_WHISPER range = -1 level_max = 0 //cannot be improved diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index c3dd39409af..3198d3515e1 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -384,6 +384,7 @@ actual_trauma.brain = src if(owner) actual_trauma.owner = owner + SEND_SIGNAL(owner, COMSIG_CARBON_GAIN_TRAUMA, trauma) actual_trauma.on_gain() if(resilience) actual_trauma.resilience = resilience diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 3fb75dd1efe..ce5d86c33e8 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -196,6 +196,9 @@ GLOBAL_LIST_EMPTY(roundstart_races) ///List of results you get from knife-butchering. null means you cant butcher it. Associated by resulting type - value of amount var/list/knife_butcher_results + ///List of visual overlays created by handle_body() + var/list/body_vis_overlays = list() + /////////// // PROCS // /////////// @@ -629,50 +632,67 @@ GLOBAL_LIST_EMPTY(roundstart_races) * Handles lipstick, having no eyes, eye color, undergarnments like underwear, undershirts, and socks, and body layers. * Calls [handle_mutant_bodyparts][/datum/species/proc/handle_mutant_bodyparts] * Arguments: - * * H - Human, whoever we're handling the body for + * * species_human - Human, whoever we're handling the body for */ -/datum/species/proc/handle_body(mob/living/carbon/human/H) - H.remove_overlay(BODY_LAYER) +/datum/species/proc/handle_body(mob/living/carbon/human/species_human) + species_human.remove_overlay(BODY_LAYER) var/list/standing = list() - var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) + var/obj/item/bodypart/head/HD = species_human.get_bodypart(BODY_ZONE_HEAD) - if(HD && !(HAS_TRAIT(H, TRAIT_HUSK))) + if(HD && !(HAS_TRAIT(species_human, TRAIT_HUSK))) // lipstick - if(H.lip_style && (LIPS in species_traits)) - var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER) - lip_overlay.color = H.lip_color - if(OFFSET_FACE in H.dna.species.offset_features) - lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] - lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] + if(species_human.lip_style && (LIPS in species_traits)) + var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[species_human.lip_style]", -BODY_LAYER) + lip_overlay.color = species_human.lip_color + if(OFFSET_FACE in species_human.dna.species.offset_features) + lip_overlay.pixel_x += species_human.dna.species.offset_features[OFFSET_FACE][1] + lip_overlay.pixel_y += species_human.dna.species.offset_features[OFFSET_FACE][2] standing += lip_overlay // eyes if(!(NOEYESPRITES in species_traits)) - var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES) - var/mutable_appearance/eye_overlay - if(!E) - eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER) - else - eye_overlay = mutable_appearance('icons/mob/human_face.dmi', E.eye_icon_state, -BODY_LAYER) - if((EYECOLOR in species_traits) && E) - eye_overlay.color = "#" + H.eye_color - if(OFFSET_FACE in H.dna.species.offset_features) - eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1] - eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2] - standing += eye_overlay + var/obj/item/organ/eyes/eye_organ = species_human.getorganslot(ORGAN_SLOT_EYES) + var/mutable_appearance/no_eyeslay + var/list/eye_overlays + var/obscured = species_human.check_obscured_slots(TRUE) //eyes that shine in the dark shouldn't show when you have glasses + var/add_pixel_x = 0 + var/add_pixel_y = 0 + //cut any possible vis overlays + if(body_vis_overlays.len) + SSvis_overlays.remove_vis_overlay(species_human, body_vis_overlays) + if(OFFSET_FACE in species_human.dna.species.offset_features) + add_pixel_x = species_human.dna.species.offset_features[OFFSET_FACE][1] + add_pixel_y = species_human.dna.species.offset_features[OFFSET_FACE][2] + if(!eye_organ) + no_eyeslay = mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER) + no_eyeslay.pixel_x += add_pixel_x + no_eyeslay.pixel_y += add_pixel_y + standing += no_eyeslay + if(!no_eyeslay)//we need eyes + if(eye_organ.overlay_ignore_lighting && !(obscured & ITEM_SLOT_EYES)) + eye_overlays += mutable_appearance('icons/mob/human_face.dmi', eye_organ.eye_icon_state, -BODY_LAYER) + eye_overlays += mutable_appearance('icons/mob/human_face.dmi', eye_organ.eye_icon_state, -BODY_LAYER, EMISSIVE_PLANE) + else + eye_overlays += mutable_appearance('icons/mob/human_face.dmi', eye_organ.eye_icon_state, -BODY_LAYER) + for(var/mutable_appearance/eye_overlay as anything in eye_overlays) + eye_overlay.pixel_x += add_pixel_x + eye_overlay.pixel_y += add_pixel_y + if((EYECOLOR in species_traits) && eye_organ) + eye_overlay.color = "#" + species_human.eye_color + standing += eye_overlay // organic body markings if(HAS_MARKINGS in species_traits) - var/obj/item/bodypart/chest/chest = H.get_bodypart(BODY_ZONE_CHEST) - var/obj/item/bodypart/r_arm/right_arm = H.get_bodypart(BODY_ZONE_R_ARM) - var/obj/item/bodypart/l_arm/left_arm = H.get_bodypart(BODY_ZONE_L_ARM) - var/obj/item/bodypart/r_leg/right_leg = H.get_bodypart(BODY_ZONE_R_LEG) - var/obj/item/bodypart/l_leg/left_leg = H.get_bodypart(BODY_ZONE_L_LEG) - var/datum/sprite_accessory/markings = GLOB.moth_markings_list[H.dna.features["moth_markings"]] + var/obj/item/bodypart/chest/chest = species_human.get_bodypart(BODY_ZONE_CHEST) + var/obj/item/bodypart/r_arm/right_arm = species_human.get_bodypart(BODY_ZONE_R_ARM) + var/obj/item/bodypart/l_arm/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM) + var/obj/item/bodypart/r_leg/right_leg = species_human.get_bodypart(BODY_ZONE_R_LEG) + var/obj/item/bodypart/l_leg/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG) + var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]] - if(!HAS_TRAIT(H, TRAIT_HUSK)) + if(!HAS_TRAIT(species_human, TRAIT_HUSK)) if(HD && (HD.status != BODYPART_ROBOTIC)) var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head", -BODY_LAYER) standing += markings_head_overlay @@ -699,36 +719,36 @@ GLOBAL_LIST_EMPTY(roundstart_races) //Underwear, Undershirts & Socks if(!(NO_UNDERWEAR in species_traits)) - if(H.underwear) - var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[H.underwear] + if(species_human.underwear) + var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[species_human.underwear] var/mutable_appearance/underwear_overlay if(underwear) - if(H.dna.species.sexes && H.body_type == FEMALE && (underwear.gender == MALE)) + if(species_human.dna.species.sexes && species_human.body_type == FEMALE && (underwear.gender == MALE)) underwear_overlay = wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL) else underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER) if(!underwear.use_static) - underwear_overlay.color = "#" + H.underwear_color + underwear_overlay.color = "#" + species_human.underwear_color standing += underwear_overlay - if(H.undershirt) - var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[H.undershirt] + if(species_human.undershirt) + var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[species_human.undershirt] if(undershirt) - if(H.dna.species.sexes && H.body_type == FEMALE) + if(species_human.dna.species.sexes && species_human.body_type == FEMALE) standing += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER) else standing += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER) - if(H.socks && H.num_legs >= 2 && !(DIGITIGRADE in species_traits)) - var/datum/sprite_accessory/socks/socks = GLOB.socks_list[H.socks] + if(species_human.socks && species_human.num_legs >= 2 && !(DIGITIGRADE in species_traits)) + var/datum/sprite_accessory/socks/socks = GLOB.socks_list[species_human.socks] if(socks) standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) if(standing.len) - H.overlays_standing[BODY_LAYER] = standing + species_human.overlays_standing[BODY_LAYER] = standing - H.apply_overlay(BODY_LAYER) - handle_mutant_bodyparts(H) + species_human.apply_overlay(BODY_LAYER) + handle_mutant_bodyparts(species_human) /** * Handles the mutant bodyparts of a human diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index b32b81b838c..7ab3e41b2c2 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -330,7 +330,7 @@ if(user) if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex target = pick(orange(2, target)) - SEND_SIGNAL(user, COMSIG_MOB_FIRED_GUN, user, target, params, zone_override) + SEND_SIGNAL(user, COMSIG_MOB_FIRED_GUN, src, target, params, zone_override) SEND_SIGNAL(src, COMSIG_GUN_FIRED, user, target, params, zone_override) diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 3fe2435b774..757b1b1a10e 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -9,6 +9,8 @@ fire_sound = 'sound/weapons/emitter.ogg' flags_1 = CONDUCT_1 w_class = WEIGHT_CLASS_HUGE + ///what kind of magic is this + var/school = SCHOOL_EVOCATION var/checks_antimagic = TRUE var/max_charges = 6 var/charges = 0 diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 203a49d1b97..35593a520e5 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -14,6 +14,7 @@ ammo_type = /obj/item/ammo_casing/magic/change icon_state = "staffofchange" inhand_icon_state = "staffofchange" + school = SCHOOL_TRANSMUTATION /obj/item/gun/magic/staff/animate name = "staff of animation" @@ -22,6 +23,7 @@ ammo_type = /obj/item/ammo_casing/magic/animate icon_state = "staffofanimation" inhand_icon_state = "staffofanimation" + school = SCHOOL_EVOCATION /obj/item/gun/magic/staff/healing name = "staff of healing" @@ -30,6 +32,7 @@ ammo_type = /obj/item/ammo_casing/magic/heal icon_state = "staffofhealing" inhand_icon_state = "staffofhealing" + school = SCHOOL_RESTORATION /obj/item/gun/magic/staff/healing/handle_suicide() //Stops people trying to commit suicide to heal themselves return @@ -44,6 +47,7 @@ max_charges = 10 recharge_rate = 2 no_den_usage = 1 + school = SCHOOL_FORBIDDEN //this staff is evil. okay? it just is. look at this projectile type list. this is wrong. var/allowed_projectile_types = list(/obj/projectile/magic/change, /obj/projectile/magic/animate, /obj/projectile/magic/resurrection, /obj/projectile/magic/death, /obj/projectile/magic/teleport, /obj/projectile/magic/door, /obj/projectile/magic/aoe/fireball, /obj/projectile/magic/spellblade, /obj/projectile/magic/arcane_barrage, /obj/projectile/magic/locker, /obj/projectile/magic/flying, @@ -64,6 +68,7 @@ max_charges = 10 recharge_rate = 2 no_den_usage = 1 + school = SCHOOL_TRANSMUTATION /obj/item/gun/magic/staff/honk name = "staff of the honkmother" @@ -74,6 +79,7 @@ inhand_icon_state = "honker" max_charges = 4 recharge_rate = 8 + school = SCHOOL_EVOCATION /obj/item/gun/magic/staff/spellblade name = "spellblade" @@ -90,6 +96,7 @@ block_chance = 50 sharpness = SHARP_EDGED max_charges = 4 + school = SCHOOL_EVOCATION /obj/item/gun/magic/staff/spellblade/Initialize() . = ..() @@ -110,6 +117,7 @@ worn_icon_state = "lockerstaff" max_charges = 6 recharge_rate = 4 + school = SCHOOL_TRANSMUTATION //in a way //yes, they don't have sounds. they're admin staves, and their projectiles will play the chaos bolt sound anyway so why bother? @@ -121,6 +129,7 @@ icon_state = "staffofflight" inhand_icon_state = "staffofchange" worn_icon_state = "flightstaff" + school = SCHOOL_EVOCATION /obj/item/gun/magic/staff/sapping name = "staff of sapping" @@ -130,6 +139,7 @@ icon_state = "staffofsapping" inhand_icon_state = "staffofdoor" worn_icon_state = "sapstaff" + school = SCHOOL_FORBIDDEN //evil /obj/item/gun/magic/staff/necropotence name = "staff of necropotence" @@ -139,6 +149,7 @@ icon_state = "staffofnecropotence" inhand_icon_state = "staffofchaos" worn_icon_state = "necrostaff" + school = SCHOOL_NECROMANCY //REALLY evil /obj/item/gun/magic/staff/wipe name = "staff of possession" @@ -148,3 +159,4 @@ icon_state = "staffofwipe" inhand_icon_state = "pharoah_sceptre" worn_icon_state = "wipestaff" + school = SCHOOL_FORBIDDEN //arguably the worst staff in the entire game effect wise diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index e7055bb34c3..26d57e37034 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -62,6 +62,7 @@ /obj/item/gun/magic/wand/death name = "wand of death" desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail." + school = SCHOOL_NECROMANCY fire_sound = 'sound/magic/wandodeath.ogg' ammo_type = /obj/item/ammo_casing/magic/death icon_state = "deathwand" @@ -100,6 +101,7 @@ /obj/item/gun/magic/wand/resurrection name = "wand of healing" desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason." + school = SCHOOL_RESTORATION ammo_type = /obj/item/ammo_casing/magic/heal fire_sound = 'sound/magic/staff_healing.ogg' icon_state = "revivewand" @@ -137,6 +139,7 @@ /obj/item/gun/magic/wand/polymorph name = "wand of polymorph" desc = "This wand is attuned to chaos and will radically alter the victim's form." + school = SCHOOL_TRANSMUTATION ammo_type = /obj/item/ammo_casing/magic/change icon_state = "polywand" base_icon_state = "polywand" @@ -156,6 +159,7 @@ /obj/item/gun/magic/wand/teleport name = "wand of teleportation" desc = "This wand will wrench targets through space and time to move them somewhere else." + school = SCHOOL_TRANSLOCATION ammo_type = /obj/item/ammo_casing/magic/teleport fire_sound = 'sound/magic/wand_teleport.ogg' icon_state = "telewand" @@ -174,6 +178,7 @@ /obj/item/gun/magic/wand/safety name = "wand of safety" desc = "This wand will use the lightest of bluespace currents to gently place the target somewhere safe." + school = SCHOOL_TRANSLOCATION ammo_type = /obj/item/ammo_casing/magic/safety fire_sound = 'sound/magic/wand_teleport.ogg' icon_state = "telewand" @@ -207,6 +212,7 @@ /obj/item/gun/magic/wand/door name = "wand of door creation" desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics." + school = SCHOOL_TRANSMUTATION ammo_type = /obj/item/ammo_casing/magic/door icon_state = "doorwand" base_icon_state = "doorwand" @@ -226,6 +232,7 @@ /obj/item/gun/magic/wand/fireball name = "wand of fireball" desc = "This wand shoots scorching balls of fire that explode into destructive flames." + school = SCHOOL_EVOCATION fire_sound = 'sound/magic/fireball.ogg' ammo_type = /obj/item/ammo_casing/magic/fireball icon_state = "firewand" diff --git a/code/modules/reagents/withdrawal/_addiction.dm b/code/modules/reagents/withdrawal/_addiction.dm index e87a6825ef7..2f2b1a50235 100644 --- a/code/modules/reagents/withdrawal/_addiction.dm +++ b/code/modules/reagents/withdrawal/_addiction.dm @@ -34,6 +34,7 @@ ///Called when you become addicted /datum/addiction/proc/become_addicted(datum/mind/victim_mind) LAZYSET(victim_mind.active_addictions, type, 1) //Start at first cycle. + SEND_SIGNAL(victim_mind.current, COMSIG_CARBON_GAIN_ADDICTION, victim_mind) log_game("[key_name(victim_mind.current)] has become addicted to [name].") @@ -49,6 +50,7 @@ /datum/addiction/proc/lose_addiction(datum/mind/victim_mind) SEND_SIGNAL(victim_mind.current, COMSIG_CLEAR_MOOD_EVENT, "[type]_addiction") + SEND_SIGNAL(victim_mind.current, COMSIG_CARBON_LOSE_ADDICTION, victim_mind) to_chat(victim_mind.current, "You feel like you've gotten over your need for drugs.") end_withdrawal(victim_mind.current) LAZYREMOVE(victim_mind.active_addictions, type) @@ -76,7 +78,7 @@ else withdrawal_stage = 0 - if(!on_drug_of_this_addiction) + if(!on_drug_of_this_addiction && !HAS_TRAIT(affected_carbon, TRAIT_HOPELESSLY_ADDICTED)) if(affected_carbon.mind.remove_addiction_points(type, addiction_loss_per_stage[withdrawal_stage + 1] * delta_time)) //If true was returned, we lost the addiction! return diff --git a/code/modules/reagents/withdrawal/generic_addictions.dm b/code/modules/reagents/withdrawal/generic_addictions.dm index dceddc54e5e..ff97d0c9257 100644 --- a/code/modules/reagents/withdrawal/generic_addictions.dm +++ b/code/modules/reagents/withdrawal/generic_addictions.dm @@ -92,6 +92,7 @@ /datum/addiction/maintenance_drugs name = "maintenance drug" + withdrawal_stage_messages = list("", "", "") /datum/addiction/maintenance_drugs/withdrawal_enters_stage_1(mob/living/carbon/affected_carbon) . = ..() @@ -120,12 +121,17 @@ . = ..() if(!ishuman(affected_carbon)) return + to_chat(affected_carbon, "You feel yourself adapt to the darkness.") + var/mob/living/carbon/human/affected_human = affected_carbon - var/mob/living/carbon/human/affected_human - var/obj/item/organ/eyes/eyes = affected_human.getorgan(/obj/item/organ/eyes) + var/obj/item/organ/liver/empowered_liver = affected_carbon.getorgan(/obj/item/organ/liver) + if(empowered_liver) + ADD_TRAIT(empowered_liver, TRAIT_GREYTIDE_METABOLISM, "maint_drug_addiction") - ADD_TRAIT(affected_human, TRAIT_NIGHT_VISION, type) - eyes.refresh() + var/obj/item/organ/eyes/empowered_eyes = affected_human.getorgan(/obj/item/organ/eyes) + if(empowered_eyes) + ADD_TRAIT(affected_human, TRAIT_NIGHT_VISION, "maint_drug_addiction") + empowered_eyes?.refresh() /datum/addiction/maintenance_drugs/withdrawal_stage_3_process(mob/living/carbon/affected_carbon, delta_time) if(!ishuman(affected_carbon)) @@ -133,7 +139,7 @@ var/mob/living/carbon/human/affected_human = affected_carbon var/turf/T = get_turf(affected_human) var/lums = T.get_lumcount() - if(lums >= 0.4) + if(lums > 0.5) SEND_SIGNAL(affected_human, COMSIG_ADD_MOOD_EVENT, "too_bright", /datum/mood_event/bright_light) affected_human.dizziness = min(40, affected_human.dizziness + 3) affected_human.set_confusion(min(affected_human.get_confusion() + (0.5 * delta_time), 20)) @@ -149,7 +155,7 @@ affected_human.dna?.species.liked_food = initial(affected_human.dna?.species.liked_food) affected_human.dna?.species.disliked_food = initial(affected_human.dna?.species.disliked_food) affected_human.dna?.species.toxic_food = initial(affected_human.dna?.species.toxic_food) - REMOVE_TRAIT(affected_human, TRAIT_NIGHT_VISION, type) + REMOVE_TRAIT(affected_human, TRAIT_NIGHT_VISION, "maint_drug_addiction") var/obj/item/organ/eyes/eyes = affected_human.getorgan(/obj/item/organ/eyes) eyes.refresh() diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 324ff8b5c22..8599f80d62c 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -8,78 +8,73 @@ * */ /datum/religion_sect -/// Name of the religious sect + /// Name of the religious sect var/name = "Religious Sect Base Type" -/// Description of the religious sect, Presents itself in the selection menu (AKA be brief) + /// 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?!!?!?!?" -/// Opening message when someone gets converted - var/convert_opener -/// holder for alignments. + /// 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? + /// Does this require something before being available as an option? var/starter = TRUE -/// The Sect's 'Mana' + /// 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 + /// The max amount of favor the sect can have var/max_favor = 1000 -/// The default value for an item that can be sacrificed + /// The default value for an item that can be sacrificed var/default_item_favor = 5 -/// Turns into 'desired_items_typecache', lists the types that can be sacrificed barring optional features in can_sacrifice() + /// Turns into 'desired_items_typecache', and is optionally assoc'd to sacrifice instructions if needed. var/list/desired_items -/// Autopopulated by `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 + /// 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 + /// Changes the Altar of Gods icon var/altar_icon -/// Changes the Altar of Gods icon_state + /// Changes the Altar of Gods icon_state var/altar_icon_state -/// Currently Active (non-deleted) rites + /// Currently Active (non-deleted) rites var/list/active_rites /datum/religion_sect/New() . = ..() if(desired_items) desired_items_typecache = typecacheof(desired_items) - if(rites_list) - var/listylist = generate_rites_list() - rites_list = listylist on_select() -///Generates a list of rites with 'name' = 'type' -/datum/religion_sect/proc/generate_rites_list() - . = list() - for(var/i in rites_list) - if(!ispath(i)) - continue - var/datum/religion_rites/RI = i - var/name_entry = "[initial(RI.name)]" - if(initial(RI.desc)) - name_entry += " - [initial(RI.desc)]" - if(initial(RI.favor_cost)) - name_entry += " ([initial(RI.favor_cost)] favor)" - - . += list("[name_entry]" = i) - /// Activates once selected /datum/religion_sect/proc/on_select() /// Activates once selected and on newjoins, oriented around people who become holy. -/datum/religion_sect/proc/on_conversion(mob/living/L) - to_chat(L, "[convert_opener]\"[quote]\"[desc]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/L) - return adjust_favor(default_item_favor,L) +/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/L) +/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 @@ -88,7 +83,7 @@ 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/L) +/datum/religion_sect/proc/set_favor(amount = 0, mob/living/chap) favor = clamp(0,max_favor,amount) return favor @@ -96,124 +91,286 @@ /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/L, mob/living/user) - if(!ishuman(L)) +/datum/religion_sect/proc/sect_bless(mob/living/target, mob/living/chap) + if(!ishuman(target)) return FALSE - var/mob/living/carbon/human/H = L - for(var/X in H.bodyparts) - var/obj/item/bodypart/BP = X - if(BP.status == BODYPART_ROBOTIC) - to_chat(user, "[GLOB.deity] refuses to heal this metallic taint!") + var/mob/living/carbon/human/blessed = target + for(var/X in blessed.bodyparts) + var/obj/item/bodypart/bodypart = X + if(bodypart.status == BODYPART_ROBOTIC) + to_chat(chap, "[GLOB.deity] refuses to heal this metallic taint!") return TRUE var/heal_amt = 10 - var/list/hurt_limbs = H.get_damaged_bodyparts(1, 1, null, BODYPART_ORGANIC) + var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYPART_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, BODYPART_ORGANIC)) - H.update_damage_overlays() - H.visible_message("[user] heals [H] with the power of [GLOB.deity]!") - to_chat(H, "May the power of [GLOB.deity] compel you to be healed!") - playsound(user, "punch", 25, TRUE, -1) - SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) + blessed.update_damage_overlays() + blessed.visible_message("[chap] heals [blessed] with the power of [GLOB.deity]!") + to_chat(blessed, "May the power of [GLOB.deity] compel you to be healed!") + playsound(chap, "punch", 25, TRUE, -1) + SEND_SIGNAL(blessed, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) return TRUE -/datum/religion_sect/puritanism - name = "Puritanism (Default)" - desc = "Nothing special." - convert_opener = "Your run-of-the-mill sect, there are no benefits or boons associated. Praise normalcy!" +/**** Nanotrasen Approved God ****/ -/datum/religion_sect/technophile - name = "Technophile" - desc = "A sect oriented around technology." - convert_opener = "May you find peace in a metal shell, acolyte.
Bibles now recharge cyborgs and heal robotic limbs if targeted, but they do not heal organic limbs. You can now sacrifice cells, with favor depending on their charge." +/datum/religion_sect/puritanism + name = "Nanotrasen Approved God" + desc = "Your run-of-the-mill sect, there are no benefits or boons associated." + quote = "Nanotrasen Recommends!" + tgui_icon = "bible" + +/**** Mechanical God ****/ + +/datum/religion_sect/mechanical + name = "Mechanical God" + quote = "May you find peace in a metal shell." + desc = "Bibles now recharge cyborgs and heal robotic limbs if targeted, but they \ + do not heal organic limbs. You can now sacrifice cells, with favor depending on their charge." + tgui_icon = "robot" alignment = ALIGNMENT_NEUT - desired_items = list(/obj/item/stock_parts/cell) + desired_items = list(/obj/item/stock_parts/cell = "with battery charge") rites_list = list(/datum/religion_rites/synthconversion) altar_icon_state = "convertaltar-blue" -/datum/religion_sect/technophile/sect_bless(mob/living/L, mob/living/user) - if(iscyborg(L)) - var/mob/living/silicon/robot/R = L +/datum/religion_sect/mechanical/sect_bless(mob/living/target, mob/living/chap) + if(iscyborg(target)) + var/mob/living/silicon/robot/R = target var/charge_amt = 50 - if(L.mind?.holy_role == HOLY_ROLE_HIGHPRIEST) + if(target.mind?.holy_role == HOLY_ROLE_HIGHPRIEST) charge_amt *= 2 R.cell?.charge += charge_amt - R.visible_message("[user] charges [R] with the power of [GLOB.deity]!") + R.visible_message("[chap] charges [R] with the power of [GLOB.deity]!") to_chat(R, "You are charged by the power of [GLOB.deity]!") SEND_SIGNAL(R, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) - playsound(user, 'sound/effects/bang.ogg', 25, TRUE, -1) + playsound(chap, 'sound/effects/bang.ogg', 25, TRUE, -1) return TRUE - if(!ishuman(L)) + if(!ishuman(target)) return - var/mob/living/carbon/human/H = L + var/mob/living/carbon/human/blessed = target //first we determine if we can charge them var/did_we_charge = FALSE - var/obj/item/organ/stomach/ethereal/eth_stomach = H.getorganslot(ORGAN_SLOT_STOMACH) + var/obj/item/organ/stomach/ethereal/eth_stomach = blessed.getorganslot(ORGAN_SLOT_STOMACH) if(istype(eth_stomach)) eth_stomach.adjust_charge(60) did_we_charge = TRUE //if we're not targetting a robot part we stop early - var/obj/item/bodypart/BP = H.get_bodypart(user.zone_selected) - if(BP.status != BODYPART_ROBOTIC) + var/obj/item/bodypart/bodypart = blessed.get_bodypart(chap.zone_selected) + if(bodypart.status != BODYPART_ROBOTIC) if(!did_we_charge) - to_chat(user, "[GLOB.deity] scoffs at the idea of healing such fleshy matter!") + to_chat(chap, "[GLOB.deity] scoffs at the idea of healing such fleshy matter!") else - H.visible_message("[user] charges [H] with the power of [GLOB.deity]!") - to_chat(H, "You feel charged by the power of [GLOB.deity]!") - SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) - playsound(user, 'sound/machines/synth_yes.ogg', 25, TRUE, -1) + blessed.visible_message("[chap] charges [blessed] with the power of [GLOB.deity]!") + to_chat(blessed, "You feel charged by the power of [GLOB.deity]!") + SEND_SIGNAL(blessed, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) + playsound(chap, 'sound/machines/synth_yes.ogg', 25, TRUE, -1) return TRUE //charge(?) and go - if(BP.heal_damage(5,5,null,BODYPART_ROBOTIC)) - H.update_damage_overlays() + if(bodypart.heal_damage(5,5,null,BODYPART_ROBOTIC)) + blessed.update_damage_overlays() - H.visible_message("[user] [did_we_charge ? "repairs" : "repairs and charges"] [H] with the power of [GLOB.deity]!") - to_chat(H, "The inner machinations of [GLOB.deity] [did_we_charge ? "repairs" : "repairs and charges"] you!") - playsound(user, 'sound/effects/bang.ogg', 25, TRUE, -1) - SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) + blessed.visible_message("[chap] [did_we_charge ? "repairs" : "repairs and charges"] [blessed] with the power of [GLOB.deity]!") + to_chat(blessed, "The inner machinations of [GLOB.deity] [did_we_charge ? "repairs" : "repairs and charges"] you!") + playsound(chap, 'sound/effects/bang.ogg', 25, TRUE, -1) + SEND_SIGNAL(blessed, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) return TRUE -/datum/religion_sect/technophile/on_sacrifice(obj/item/I, mob/living/L) +/datum/religion_sect/mechanical/on_sacrifice(obj/item/I, mob/living/chap) var/obj/item/stock_parts/cell/the_cell = I if(!istype(the_cell)) //how... return if(the_cell.charge < 300) - to_chat(L,"[GLOB.deity] does not accept pity amounts of power.") + to_chat(chap,"[GLOB.deity] does not accept pity amounts of power.") return - adjust_favor(round(the_cell.charge/300), L) - to_chat(L, "You offer [the_cell]'s power to [GLOB.deity], pleasing them.") + adjust_favor(round(the_cell.charge/300), chap) + to_chat(chap, "You offer [the_cell]'s power to [GLOB.deity], pleasing them.") qdel(I) return TRUE -/**** Ever-Burning Candle sect ****/ +/**** Pyre God ****/ -/datum/religion_sect/candle_sect - name = "Ever-Burning Candle" - desc = "A sect dedicated to candles." - convert_opener = "May you be the wax to keep the Ever-Burning Candle burning, acolyte.
Sacrificing burning corpses with a lot of burn damage and candles grants you favor" +/datum/religion_sect/pyre + name = "Pyre God" + desc = "Sacrificing burning corpses with a lot of burn damage and candles grants you favor." + quote = "It must burn! The primal energy must be respected." + tgui_icon = "fire-alt" alignment = ALIGNMENT_NEUT max_favor = 10000 - desired_items = list(/obj/item/candle) + desired_items = list(/obj/item/candle = "already lit") rites_list = list(/datum/religion_rites/fireproof, /datum/religion_rites/burning_sacrifice, /datum/religion_rites/infinite_candle) altar_icon_state = "convertaltar-red" //candle sect bibles don't heal or do anything special apart from the standard holy water blessings -/datum/religion_sect/candle_sect/sect_bless(mob/living/blessed, mob/living/user) +/datum/religion_sect/pyre/sect_bless(mob/living/target, mob/living/chap) return TRUE -/datum/religion_sect/candle_sect/on_sacrifice(obj/item/candle/offering, mob/living/user) +/datum/religion_sect/pyre/on_sacrifice(obj/item/candle/offering, mob/living/user) if(!istype(offering)) return if(!offering.lit) to_chat(user, "The candle needs to be lit to be offered!") return - to_chat(user, "Another candle for [GLOB.deity]'s collection") + to_chat(user, "[GLOB.deity] is pleased with your sacrifice.") adjust_favor(20, user) //it's not a lot but hey there's a pacifist favor option at least qdel(offering) return TRUE + +#define GREEDY_HEAL_COST 50 + +/datum/religion_sect/greed + name = "Greedy God" + quote = "Greed is good." + desc = "In the eyes of your mercantile deity, your wealth is your favor. Earn enough wealth to purchase some more business opportunities." + tgui_icon = "dollar-sign" + altar_icon_state = "convertaltar-yellow" + alignment = ALIGNMENT_EVIL //greed is not good wtf + rites_list = list(/datum/religion_rites/greed/vendatray, /datum/religion_rites/greed/custom_vending) + altar_icon_state = "convertaltar-yellow" + +/datum/religion_sect/greed/tool_examine(mob/living/holy_creature) //display money policy + return "In the eyes of [GLOB.deity], your wealth is your favor." + +/datum/religion_sect/greed/sect_bless(mob/living/blessed_living, mob/living/chap) + var/datum/bank_account/account = chap.get_bank_account() + if(!account) + to_chat(chap, "You need a way to pay for the heal!") + return TRUE + if(account.account_balance < GREEDY_HEAL_COST) + to_chat(chap, "Healing from [GLOB.deity] costs [GREEDY_HEAL_COST] credits for 30 health!") + return TRUE + if(!ishuman(blessed_living)) + return FALSE + var/mob/living/carbon/human/blessed = blessed_living + for(var/obj/item/bodypart/robolimb as anything in blessed.bodyparts) + if(robolimb.status == BODYPART_ROBOTIC) + to_chat(chap, "[GLOB.deity] refuses to heal this metallic taint!") + return TRUE + + account.adjust_money(-GREEDY_HEAL_COST) + var/heal_amt = 30 + var/list/hurt_limbs = blessed.get_damaged_bodyparts(1, 1, null, BODYPART_ORGANIC) + if(hurt_limbs.len) + for(var/obj/item/bodypart/affecting as anything in hurt_limbs) + if(affecting.heal_damage(heal_amt, heal_amt, null, BODYPART_ORGANIC)) + blessed.update_damage_overlays() + blessed.visible_message("[chap] barters a heal for [blessed] from [GLOB.deity]!") + to_chat(blessed, "May the power of [GLOB.deity] compel you to be healed! Thank you for choosing [GLOB.deity]!") + playsound(chap, 'sound/effects/cashregister.ogg', 60, TRUE) + SEND_SIGNAL(blessed, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) + return TRUE + +#undef GREEDY_HEAL_COST + +/datum/religion_sect/honorbound + name = "Honorbound God" + quote = "A good, honorable crusade against evil is required." + desc = "Your deity requires fair fights from you. You may not attack the unready, the just, or the innocent. \ + You earn favor by getting others to join the crusade, and you may spend favor to announce a battle, bypassing some conditions to attack." + tgui_icon = "scroll" + altar_icon_state = "convertaltar-white" + alignment = ALIGNMENT_GOOD + invalidating_qualities = TRAIT_GENELESS + 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")) + currently_asking -= invited + if(ask == "Yes") + possible_crusaders += invited + +/datum/religion_sect/honorbound/on_conversion(mob/living/carbon/new_convert) + ..() + if(!ishuman(new_convert)) + to_chat("[GLOB.deity] has no respect for lower creatures, and refuses to make you honorbound.") + return FALSE + if(TRAIT_GENELESS in new_convert.dna.species.inherent_traits) + to_chat("[GLOB.deity] has deemed your species as one that could never show honor.") + return FALSE + var/datum/dna/holy_dna = new_convert.dna + holy_dna.add_mutation(HONORBOUND) + +/datum/religion_sect/burden + name = "Punished God" + quote = "To feel the freedom, you must first understand captivity." + desc = "Incapacitate yourself in any way possible. Bad mutations, lost limbs, traumas, \ + even addictions. You will learn the secrets of the universe from your defeated shell." + tgui_icon = "user-injured" + altar_icon_state = "convertaltar-burden" + alignment = ALIGNMENT_NEUT + invalidating_qualities = TRAIT_GENELESS + +/datum/religion_sect/burden/on_conversion(mob/living/carbon/human/new_convert) + ..() + if(!ishuman(new_convert)) + to_chat("[GLOB.deity] needs higher level creatures to fully comprehend the suffering. You are not burdened.") + return + if(TRAIT_GENELESS in new_convert.dna.species.inherent_traits) + to_chat("[GLOB.deity] cannot help a species such as yourself comprehend the suffering. You are not burdened.") + return + var/datum/dna/holy_dna = new_convert.dna + holy_dna.add_mutation(/datum/mutation/human/burdened) + +/datum/religion_sect/burden/tool_examine(mob/living/carbon/human/burdened) //display burden level + if(!ishuman(burdened)) + return FALSE + var/datum/mutation/human/burdened/burdenmut = burdened.dna.check_mutation(/datum/mutation/human/burdened) + if(burdenmut) + return "You are at burden level [burdenmut.burden_level]/6." + return "You are not burdened." + +#define MINIMUM_YUCK_REQUIRED 5 + +/datum/religion_sect/maintenance + name = "Maintenance God" + quote = "Your kingdom in the darkness." + desc = "Sacrifice the organic slurry created from rats dipped in welding fuel to gain favor. Exchange favor to adapt to the maintenance shafts." + tgui_icon = "eye" + altar_icon_state = "convertaltar-maint" + alignment = ALIGNMENT_EVIL //while maint is more neutral in my eyes, the flavor of it kinda pertains to rotting and becoming corrupted by the maints + rites_list = list(/datum/religion_rites/maint_adaptation, /datum/religion_rites/adapted_eyes, /datum/religion_rites/adapted_food, /datum/religion_rites/ritual_totem) + desired_items = list(/obj/item/reagent_containers = "holding organic slurry") + +/datum/religion_sect/maintenance/sect_bless(mob/living/blessed_living, mob/living/chap) + if(!ishuman(blessed_living)) + return TRUE + var/mob/living/carbon/human/blessed = blessed_living + if(blessed.reagents.has_reagent(/datum/reagent/drug/maint/sludge)) + to_chat(blessed, "[GLOB.deity] has already empowered them.") + return TRUE + blessed.reagents.add_reagent(/datum/reagent/drug/maint/sludge, 5) + blessed.visible_message("[chap] empowers [blessed] with the power of [GLOB.deity]!") + to_chat(blessed, "The power of [GLOB.deity] has made you harder to wound for a while!") + playsound(chap, "punch", 25, TRUE, -1) + SEND_SIGNAL(blessed, COMSIG_ADD_MOOD_EVENT, "blessing", /datum/mood_event/blessing) + return TRUE //trust me, you'll be feeling the pain from the maint drugs all well enough + +/datum/religion_sect/maintenance/on_sacrifice(obj/item/reagent_containers/offering, mob/living/user) + if(!istype(offering)) + return + var/datum/reagent/yuck/wanted_yuck = offering.reagents.has_reagent(/datum/reagent/yuck, MINIMUM_YUCK_REQUIRED) + var/favor_earned = offering.reagents.get_reagent_amount(/datum/reagent/yuck) + if(!wanted_yuck) + to_chat(user, "[offering] does not have enough organic slurry for [GLOB.deity] to enjoy.") + return + to_chat(user, "[GLOB.deity] loves organic slurry.") + adjust_favor(favor_earned, user) + playsound(get_turf(offering), 'sound/items/drink.ogg', 50, TRUE) + offering.reagents.clear_reagents() + return TRUE + +#undef MINIMUM_YUCK_REQUIRED diff --git a/code/modules/religion/religion_structures.dm b/code/modules/religion/religion_structures.dm index 1b0a17cfaa6..720858c986b 100644 --- a/code/modules/religion/religion_structures.dm +++ b/code/modules/religion/religion_structures.dm @@ -43,3 +43,53 @@ icon = sect_to_altar.altar_icon if(sect_to_altar.altar_icon_state) icon_state = sect_to_altar.altar_icon_state + +/obj/item/ritual_totem + name = "ritual totem" + desc = "A wooden totem with strange carvings on it." + icon_state = "ritual_totem" + inhand_icon_state = "sheet-wood" + lefthand_file = 'icons/mob/inhands/misc/sheets_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/sheets_righthand.dmi' + //made out of a single sheet of wood + custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT) + item_flags = NO_PIXEL_RANDOM_DROP + +/obj/item/ritual_totem/Initialize() + . = ..() + AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, 1, FALSE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire))//one charge of anti_magic + AddComponent(/datum/component/religious_tool, RELIGION_TOOL_INVOKE, FALSE) + +/obj/item/ritual_totem/proc/block_magic(mob/user, major) + if(major) + to_chat(user, "[src] consumes the magic within itself!") + +/obj/item/ritual_totem/proc/expire(mob/user) + to_chat(user, "[src] quickly decays into rot!") + qdel(src) + new /obj/effect/decal/cleanable/ash(drop_location()) + +/obj/item/ritual_totem/can_be_pulled(user, grab_state, force) + . = ..() + return FALSE //no + +/obj/item/ritual_totem/examine(mob/user) + . = ..() + var/is_holy = user.mind?.holy_role + if(is_holy) + . += "[src] can only be moved by important followers of [GLOB.deity]." + +/obj/item/ritual_totem/pickup(mob/taker) + var/initial_loc = loc + var/holiness = taker.mind?.holy_role + var/no_take = FALSE + if(holiness == NONE) + to_chat(taker, "Try as you may, you're seemingly unable to pick [src] up!") + no_take = TRUE + else if(holiness == HOLY_ROLE_DEACON) //deacons cannot pick them up either + no_take = TRUE + to_chat(taker, "You cannot pick [src] up. It seems you aren't important enough to [GLOB.deity] to do that.") + ..() + if(no_take) + taker.dropItemToGround(src) + forceMove(initial_loc) diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index 97f7e401f0e..b3e0fd6793d 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -23,11 +23,15 @@ 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, "This rite requires more favor!") + 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(GLOB.religious_sect?.favor < favor_cost) - to_chat(user, "This rite requires more favor!") + if(!can_afford(user)) return FALSE to_chat(user, "You begin to perform the rite of [name]...") if(!ritual_invocations) @@ -54,19 +58,20 @@ ///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 -/*********Technophiles**********/ +/**** Mechanical God ****/ /datum/religion_rites/synthconversion name = "Synthetic Conversion" desc = "Convert a human-esque individual into a (superior) Android." ritual_length = 30 SECONDS - ritual_invocations = list("By the inner workings of our god...", - "... We call upon you, in the face of adversity...", - "... to complete us, removing that which is undesirable...") + ritual_invocations = list("By the inner workings of our god ...", + "... We call upon you, in the face of adversity ...", + "... to complete us, removing that which is undesirable ...") invoke_msg = "... Arise, our champion! Become that which your soul craves, live in the world as your true form!!" favor_cost = 1000 @@ -87,6 +92,7 @@ return ..() /datum/religion_rites/synthconversion/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 @@ -104,7 +110,7 @@ return TRUE -/*********Ever-Burning Candle**********/ +/**** Pyre God ****/ ///apply a bunch of fire immunity effect to clothing /datum/religion_rites/fireproof/proc/apply_fireproof(obj/item/clothing/fireproofed) @@ -114,7 +120,7 @@ fireproofed.resistance_flags |= FIRE_PROOF /datum/religion_rites/fireproof - name = "Unmelting Wax" + name = "Unmelting Protection" desc = "Grants fire immunity to any piece of clothing." ritual_length = 15 SECONDS ritual_invocations = list("And so to support the holder of the Ever-Burning candle...", @@ -134,6 +140,7 @@ return FALSE /datum/religion_rites/fireproof/invoke_effect(mob/living/user, atom/religious_tool) + ..() if(!QDELETED(chosen_clothing) && get_turf(religious_tool) == chosen_clothing.loc) //check if the same clothing is still there if(istype(chosen_clothing,/obj/item/clothing/suit/hooded) || istype(chosen_clothing,/obj/item/clothing/suit/space/hardsuit )) for(var/obj/item/clothing/head/integrated_helmet in chosen_clothing.contents) //check if the clothing has a hood/helmet integrated and fireproof it if there is one. @@ -148,14 +155,14 @@ /datum/religion_rites/burning_sacrifice - name = "Candle Fuel" + name = "Burning Offering" desc = "Sacrifice a buckled burning corpse for favor, the more burn damage the corpse has the more favor you will receive." ritual_length = 20 SECONDS - ritual_invocations = list("To feed the fire of the one true flame ...", - "... to make it burn brighter ...", - "... so that it may consume all in its path ...", - "... I offer you this pitiful being ...") - invoke_msg = "... may it join you in the amalgamation of wax and fire, and become one in the black and white scene. " + ritual_invocations = list("Burning body ...", + "... cleansed by the flame ...", + "... we were all created from fire ...", + "... and to it ...") + invoke_msg = "... WE RETURN! " ///the burning corpse chosen for the sacrifice of the rite var/mob/living/carbon/chosen_sacrifice @@ -183,6 +190,7 @@ return ..() /datum/religion_rites/burning_sacrifice/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() if(!(chosen_sacrifice in religious_tool.buckled_mobs)) //checks one last time if the right corpse is still buckled to_chat(user, "The right sacrifice is no longer on the altar!") chosen_sacrifice = null @@ -196,8 +204,8 @@ chosen_sacrifice = null return FALSE var/favor_gained = 100 + round(chosen_sacrifice.getFireLoss()) - GLOB.religious_sect?.adjust_favor(favor_gained, user) - to_chat(user, "[GLOB.deity] absorb the burning corpse and any trace of fire with it. [GLOB.deity] rewards you with [favor_gained] favor.") + GLOB.religious_sect.adjust_favor(favor_gained, user) + to_chat(user, "[GLOB.deity] absorbs the burning corpse and any trace of fire with it. [GLOB.deity] rewards you with [favor_gained] favor.") chosen_sacrifice.dust(force = TRUE) playsound(get_turf(religious_tool), 'sound/effects/supermatter.ogg', 50, TRUE) chosen_sacrifice = null @@ -209,12 +217,369 @@ name = "Immortal Candles" desc = "Creates 5 candles that never run out of wax." ritual_length = 10 SECONDS - invoke_msg = "please lend us five of your candles so we may bask in your burning glory." + invoke_msg = "Burn bright, little candles, for you will only extinguish along with the universe." favor_cost = 200 /datum/religion_rites/infinite_candle/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() var/altar_turf = get_turf(religious_tool) for(var/i in 1 to 5) new /obj/item/candle/infinite(altar_turf) playsound(altar_turf, 'sound/magic/fireball.ogg', 50, TRUE) return TRUE + +/*********Greedy God**********/ + +///all greed rites cost money instead +/datum/religion_rites/greed + ritual_length = 5 SECONDS + invoke_msg = "Sorry I was late, I was just making a shitload of money." + var/money_cost = 0 + +/datum/religion_rites/greed/can_afford(mob/living/user) + var/datum/bank_account/account = user.get_bank_account() + if(!account) + to_chat(user, "You need a way to pay for the rite!") + return FALSE + if(account.account_balance < money_cost) + to_chat(user, "This rite requires more money!") + return FALSE + return TRUE + +/datum/religion_rites/greed/invoke_effect(mob/living/user, atom/movable/religious_tool) + var/datum/bank_account/account = user.get_bank_account() + if(!account || account.account_balance < money_cost) + to_chat(user, "This rite requires more money!") + return FALSE + account.adjust_money(-money_cost) + . = ..() + +/datum/religion_rites/greed/vendatray + name = "Purchase Vend-a-tray" + desc = "Summons a Vend-a-tray. You can use it to sell items!" + invoke_msg = "I need a vend-a-tray to make some more money!" + money_cost = 300 + +/datum/religion_rites/greed/vendatray/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/altar_turf = get_turf(religious_tool) + new /obj/structure/displaycase/forsale(altar_turf) + playsound(get_turf(religious_tool), 'sound/effects/cashregister.ogg', 60, TRUE) + return TRUE + +/datum/religion_rites/greed/custom_vending + name = "Purchase Personal Vending Machine" + desc = "Summons a custom vending machine. You can use it to sell MANY items!" + invoke_msg = "If I get a custom vending machine for my products, I can be RICH!" + money_cost = 1000 //quite a step up from vendatray + +/datum/religion_rites/greed/custom_vending/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/altar_turf = get_turf(religious_tool) + new /obj/machinery/vending/custom/greed(altar_turf) + playsound(get_turf(religious_tool), 'sound/effects/cashregister.ogg', 60, TRUE) + return TRUE + +/*********Honorbound God**********/ + +///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, "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, "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, "[possible_crusader] needs to be alive and conscious to join the crusade!") + return FALSE + if(TRAIT_GENELESS in possible_crusader.dna.species.inherent_traits) + to_chat(user, "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, "Wait for them to decide on whether to join or not!") + return FALSE + if(!(possible_crusader in sect.possible_crusaders)) + INVOKE_ASYNC(sect, /datum/religion_sect/honorbound.proc/invite_crusader, possible_crusader) + to_chat(user, "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, "The new member is no longer on the altar!") + return FALSE + if(joining_now.stat != CONSCIOUS) + to_chat(user, "The new member has to stay alive for the rite to work!") + return FALSE + if(!joining_now.mind) + to_chat(user, "The new member has no mind!") + return FALSE + if(joining_now.mind.has_antag_datum(/datum/antagonist/cult))//what the fuck?! + to_chat(user, "[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(TRUE) + return FALSE + var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(HONORBOUND) + if(joining_now in honormut.guilty) + honormut.guilty -= joining_now + GLOB.religious_sect.adjust_favor(200, user) + to_chat(user, "[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" + desc = "Forgives someone, making them no longer considered guilty. A kind gesture, all things considered!" + invoke_msg = "You are absolved of sin." + var/mob/living/who + +/datum/religion_rites/forgive/perform_rite(mob/living/carbon/human/user, atom/religious_tool) + if(!ishuman(user)) + return FALSE + var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(HONORBOUND) + if(!honormut) + return FALSE + if(!honormut.guilty.len) + to_chat(user, "[GLOB.deity] is holding no grudges to forgive.") + return FALSE + var/forgiven_choice = input(user, "Choose one of [GLOB.deity]'s guilty to forgive.", "Forgive") as null|anything in honormut.guilty + if(!forgiven_choice) + return FALSE + who = forgiven_choice + return ..() + +/datum/religion_rites/forgive/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool) + ..() + if(in_range(user, religious_tool)) + return FALSE + var/datum/mutation/human/honorbound/honormut = user.dna.check_mutation(HONORBOUND) + if(!honormut) //edge case + return FALSE + honormut.guilty -= who + who = null + playsound(get_turf(religious_tool), 'sound/effects/pray.ogg', 50, TRUE) + return TRUE + +/datum/religion_rites/summon_rules + name = "Summon Honorbound Rules" + desc = "Enscribes a paper with the honorbound rules and regulations." + invoke_msg = "Bring forth the holy writ!" + ///paper to turn into holy writ + var/obj/item/paper/writ_target + +/datum/religion_rites/summon_rules/perform_rite(mob/living/user, atom/religious_tool) + for(var/obj/item/paper/could_writ in get_turf(religious_tool)) + if(istype(could_writ, /obj/item/paper/holy_writ)) + continue + if(could_writ.info) //blank paper pls + continue + writ_target = could_writ //PLEASE SIGN MY AUTOGRAPH + return ..() + to_chat(user, "You need to place blank paper on [religious_tool] to do this!") + return FALSE + +/datum/religion_rites/summon_rules/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/obj/item/paper/autograph = writ_target + var/turf/tool_turf = get_turf(religious_tool) + writ_target = null + if(QDELETED(autograph) || !(tool_turf == autograph.loc)) //check if the same food is still there + to_chat(user, "Your target left the altar!") + return FALSE + autograph.visible_message("words magically form on [autograph]!") + playsound(tool_turf, 'sound/effects/pray.ogg', 50, TRUE) + new /obj/item/paper/holy_writ(tool_turf) + qdel(autograph) + return TRUE + +/obj/item/paper/holy_writ + icon = 'icons/obj/wizard.dmi' + icon_state = "scroll" + slot_flags = null + show_written_words = FALSE + + //info set in here because we need GLOB.deity +/obj/item/paper/holy_writ/Initialize() + add_filter("holy_outline", 9, list("type" = "outline", "color" = "#fdff6c")) + name = "[GLOB.deity]'s honorbound rules" + info = {"[GLOB.deity]'s honorbound rules: +
+ 1.) Thou shalt not attack the unready!
+ Those who are not ready for battle should not be wrought low. The evil of this world must lose + in a fair battle if you are to conquer them completely. +
+
+ 2.) Thou shalt not attack the just!
+ Those who fight for justice and good must not be harmed. Security is uncorruptable and must + be respected. Healers are mostly uncorruptable and if you are truly sure Medical has fallen + to the scourge of evil, use a declaration of evil. +
+
+ 3.) Thou shalt not attack the innocent!
+ There is no honor on a pre-emptive strike, unless they are truly evil vermin. + Those who are guilty will either lay a hand on you first, or you may declare their evil. +
+
+ 4.) Thou shalt not use profane magicks!
+ You are not a warlock, you are an honorable warrior. There is nothing more corruptive than + the vile magicks used by witches, warlocks, and necromancers. There are exceptions to this rule.
+ You may use holy magic, and, if you recruit one, the mime may use holy mimery. Restoration has also + been allowed as it is a school focused on the light and mending of this world. + "} + . = ..() + +/*********Maintenance God**********/ + +/datum/religion_rites/maint_adaptation + name = "Maintenance Adaptation" + desc = "Begin your metamorphasis into a being more fit for Maintenance." + ritual_length = 10 SECONDS + ritual_invocations = list("I abandon the world ...", + "... to become one with the deep.", + "My form will become twisted ...") + invoke_msg = "... but my smile I will keep!" + favor_cost = 150 //150u of organic slurry + +/datum/religion_rites/maint_adaptation/perform_rite(mob/living/carbon/human/user, atom/religious_tool) + if(!ishuman(user)) + return FALSE + //uses HAS_TRAIT_FROM because junkies are also hopelessly addicted + if(HAS_TRAIT_FROM(user, TRAIT_HOPELESSLY_ADDICTED, "maint_adaptation")) + to_chat(user, "You've already adapted.") + return FALSE + return ..() + +/datum/religion_rites/maint_adaptation/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + to_chat(user, "You feel your genes rattled and reshaped. You're becoming something new.") + user.emote("laughs") + ADD_TRAIT(user, TRAIT_HOPELESSLY_ADDICTED, "maint_adaptation") + //addiction sends some nasty mood effects but we want the maint adaption to be enjoyed like a fine wine + SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "maint_adaptation", /datum/mood_event/maintenance_adaptation) + if(iscarbon(user)) + var/mob/living/carbon/vomitorium = user + vomitorium.vomit() + var/datum/dna/dna = vomitorium.has_dna() + dna?.add_mutation(/datum/mutation/human/stimmed) //some fluff mutations + dna?.add_mutation(/datum/mutation/human/strong) + user.mind.add_addiction_points(/datum/addiction/maintenance_drugs, 1000)//ensure addiction + +/datum/religion_rites/adapted_eyes + name = "Adapted Eyes" + desc = "Only available after maintenance adaptation. Your eyes will adapt as well, becoming useless in the light." + ritual_length = 10 SECONDS + invoke_msg = "I no longer want to see the light." + favor_cost = 300 //300u of organic slurry, i'd consider this a reward of the sect + +/datum/religion_rites/adapted_eyes/perform_rite(mob/living/carbon/human/user, atom/religious_tool) + if(!ishuman(user)) + return FALSE + if(!HAS_TRAIT_FROM(user, TRAIT_HOPELESSLY_ADDICTED, "maint_adaptation")) + to_chat(user, "You need to adapt to maintenance first.") + return FALSE + var/obj/item/organ/eyes/night_vision/maintenance_adapted/adapted = user.getorganslot(ORGAN_SLOT_EYES) + if(adapted && istype(adapted)) + to_chat(user, "Your eyes are already adapted!") + return FALSE + return ..() + +/datum/religion_rites/adapted_eyes/invoke_effect(mob/living/carbon/human/user, atom/movable/religious_tool) + ..() + var/obj/item/organ/eyes/oldeyes = user.getorganslot(ORGAN_SLOT_EYES) + to_chat(user, "You feel your eyes adapt to the darkness!") + if(oldeyes) + oldeyes.Remove(user, special = TRUE) + qdel(oldeyes)//eh + var/obj/item/organ/eyes/night_vision/maintenance_adapted/neweyes = new + neweyes.Insert(user, special = TRUE) + +/datum/religion_rites/adapted_food + name = "Moldify" + desc = "Once adapted to the Maintenance, you will not be able to eat regular food. This should help." + ritual_length = 5 SECONDS + invoke_msg = "Moldify!" + favor_cost = 5 //5u of organic slurry + ///the food that will be molded, only one per rite + var/obj/item/food/mold_target + +/datum/religion_rites/adapted_food/perform_rite(mob/living/user, atom/religious_tool) + for(var/obj/item/food/could_mold in get_turf(religious_tool)) + if(istype(could_mold, /obj/item/food/badrecipe/moldy)) + continue + mold_target = could_mold //moldify this o great one + return ..() + to_chat(user, "You need to place food on [religious_tool] to do this!") + return FALSE + +/datum/religion_rites/adapted_food/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/obj/item/food/moldify = mold_target + mold_target = null + if(QDELETED(moldify) || !(get_turf(religious_tool) == moldify.loc)) //check if the same food is still there + to_chat(user, "Your target left the altar!") + return FALSE + to_chat(user, "[moldify] becomes rancid!") + user.emote("laughs") + new /obj/item/food/badrecipe/moldy(get_turf(religious_tool)) + qdel(moldify) + return TRUE + +/datum/religion_rites/ritual_totem + name = "Create Ritual Totem" + desc = "Creates a Ritual Totem, a portable tool for performing rites on the go. Requires wood. Can only be picked up by the holy." + favor_cost = 100 + invoke_msg = "Padala!!" + ///the food that will be molded, only one per rite + var/obj/item/stack/sheet/mineral/wood/converted + +/datum/religion_rites/ritual_totem/perform_rite(mob/living/user, atom/religious_tool) + for(var/obj/item/stack/sheet/mineral/wood/could_totem in get_turf(religious_tool)) + converted = could_totem //totemify this o great one + return ..() + to_chat(user, "You need at least 1 wood to do this!") + return FALSE + +/datum/religion_rites/ritual_totem/invoke_effect(mob/living/user, atom/movable/religious_tool) + ..() + var/altar_turf = get_turf(religious_tool) + var/obj/item/stack/sheet/mineral/wood/padala = converted + converted = null + if(QDELETED(padala) || !(get_turf(religious_tool) == padala.loc)) //check if the same food is still there + to_chat(user, "Your target left the altar!") + return FALSE + to_chat(user, "[padala] reshapes into a totem!") + if(!padala.use(1))//use one wood + return + user.emote("laughs") + new /obj/item/ritual_totem(altar_turf) + return TRUE + + diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 6b30abc9d63..14509b0e8c7 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -100,7 +100,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th density = FALSE opacity = FALSE - var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit? + ///checked by some holy sects to punish the caster for casting things that do not align with their sect's alignment - see magic.dm in defines to learn more + var/school = SCHOOL_UNSET var/charge_type = "recharge" //can be recharge or charges, see charge_max and charge_counter descriptions; can also be based on the holder's vars now, use "holder_var" for that @@ -316,6 +317,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th recharging = TRUE if(sound) playMagSound() + SEND_SIGNAL(user, COMSIG_MOB_CAST_SPELL, src) cast(targets,user=user) after_cast(targets) if(action) @@ -363,7 +365,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th /obj/effect/proc_holder/spell/proc/cast(list/targets,mob/user = usr) - return /obj/effect/proc_holder/spell/proc/view_or_range(distance = world.view, center=usr, type="view") switch(type) @@ -560,7 +561,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th cooldown_min = 50 invocation = "Victus sano!" invocation_type = INVOCATION_WHISPER - school = "restoration" + school = SCHOOL_RESTORATION sound = 'sound/magic/staff_healing.ogg' /obj/effect/proc_holder/spell/self/basic_heal/cast(list/targets, mob/living/carbon/human/user) //Note the lack of "list/targets" here. Instead, use a "user" var depending on mob requirements. diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm index 6829e812b1f..ecdaab5a34c 100644 --- a/code/modules/spells/spell_types/aimed.dm +++ b/code/modules/spells/spell_types/aimed.dm @@ -93,7 +93,7 @@ /obj/effect/proc_holder/spell/aimed/lightningbolt name = "Lightning Bolt" desc = "Fire a lightning bolt at your foes! It will jump between targets, but can't knock them down." - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 100 clothes_req = FALSE invocation = "P'WAH, UNLIM'TED P'WAH" @@ -111,7 +111,7 @@ /obj/effect/proc_holder/spell/aimed/fireball name = "Fireball" desc = "This spell fires an explosive fireball at a target." - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 60 clothes_req = FALSE invocation = "ONI SOMA" @@ -134,7 +134,7 @@ /obj/effect/proc_holder/spell/aimed/spell_cards name = "Spell Cards" desc = "Blazing hot rapid-fire homing cards. Send your foes to the shadow realm with their mystical power!" - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 50 clothes_req = FALSE invocation = "Sigi'lu M'Fan 'Tasia" diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm index 5eb83e82450..9b963b9aa47 100644 --- a/code/modules/spells/spell_types/area_teleport.dm +++ b/code/modules/spells/spell_types/area_teleport.dm @@ -2,6 +2,7 @@ name = "Area teleport" desc = "This spell teleports you to a type of area of your selection." nonabstract_req = TRUE + school = SCHOOL_TRANSLOCATION var/randomise_selection = FALSE //if it lets the usr choose the teleport loc or picks it from the list var/invocation_area = TRUE //if the invocation appends the selected area diff --git a/code/modules/spells/spell_types/charge.dm b/code/modules/spells/spell_types/charge.dm index d67d7442f93..06e803e2f9a 100644 --- a/code/modules/spells/spell_types/charge.dm +++ b/code/modules/spells/spell_types/charge.dm @@ -2,7 +2,7 @@ name = "Charge" desc = "This spell can be used to recharge a variety of things in your hands, from magical artifacts to electrical components. A creative wizard can even use it to grant magical power to a fellow magic user." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 600 clothes_req = FALSE invocation = "DIRI CEL" diff --git a/code/modules/spells/spell_types/cone_spells.dm b/code/modules/spells/spell_types/cone_spells.dm index 26dd1579861..7b371665d6e 100644 --- a/code/modules/spells/spell_types/cone_spells.dm +++ b/code/modules/spells/spell_types/cone_spells.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/cone name = "Cone of Nothing" desc = "Does nothing in a cone! Wow!" - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 100 clothes_req = FALSE invocation = "FUKAN NOTHAN" diff --git a/code/modules/spells/spell_types/conjure.dm b/code/modules/spells/spell_types/conjure.dm index de568d34a16..5ebfd4bc98e 100644 --- a/code/modules/spells/spell_types/conjure.dm +++ b/code/modules/spells/spell_types/conjure.dm @@ -2,6 +2,8 @@ name = "Conjure" desc = "This spell conjures objs of the specified types in range." + school = SCHOOL_CONJURATION + var/list/summon_type = list() //determines what exactly will be summoned //should be text, like list("/mob/living/simple_animal/bot/ed209") @@ -76,7 +78,7 @@ clothes_req = FALSE var/obj/item/item var/item_type = /obj/item/banhammer - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 150 cooldown_min = 10 var/delete_old = TRUE //TRUE to delete the last summoned object if it's still there, FALSE for infinite item stream weeeee diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm index 7bd0eee96cd..5dc71b05444 100644 --- a/code/modules/spells/spell_types/construct_spells.dm +++ b/code/modules/spells/spell_types/construct_spells.dm @@ -12,7 +12,7 @@ name = "Area Conversion" desc = "This spell instantly converts a small area around you." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 5 SECONDS clothes_req = FALSE invocation = "none" @@ -32,7 +32,7 @@ name = "Summon Cult Floor" desc = "This spell constructs a cult floor." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 2 SECONDS clothes_req = FALSE invocation = "none" @@ -48,7 +48,7 @@ name = "Summon Cult Wall" desc = "This spell constructs a cult wall." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 10 SECONDS clothes_req = FALSE invocation = "none" @@ -65,7 +65,7 @@ name = "Greater Construction" desc = "This spell constructs a reinforced metal wall." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 30 SECONDS clothes_req = FALSE invocation = "none" @@ -78,7 +78,7 @@ name = "Summon Soulstone" desc = "This spell reaches into Nar'Sie's realm, summoning one of the legendary fragments across time and space." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 4 MINUTES clothes_req = FALSE invocation = "none" @@ -106,7 +106,7 @@ /obj/effect/proc_holder/spell/targeted/forcewall/cult name = "Shield" desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 40 SECONDS clothes_req = FALSE invocation = "none" @@ -122,7 +122,7 @@ name = "Phase Shift" desc = "This spell allows you to pass through walls." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 25 SECONDS clothes_req = FALSE invocation = "none" @@ -151,7 +151,7 @@ name = "Lesser Magic Missile" desc = "This spell fires several, slow moving, magic projectiles at nearby targets." - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 40 SECONDS clothes_req = FALSE invocation = "none" @@ -169,7 +169,7 @@ name = "Paralysing Smoke" desc = "This spell spawns a cloud of paralysing smoke." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 20 SECONDS clothes_req = FALSE invocation = "none" @@ -189,7 +189,7 @@ charge_max = 75 SECONDS range = 5 stat_allowed = FALSE - school = "evocation" + school = SCHOOL_EVOCATION clothes_req = FALSE invocation = "none" invocation_type = "none" @@ -249,7 +249,7 @@ charge_max = 1 MINUTES range = 7 stat_allowed = FALSE - school = "evocation" + school = SCHOOL_EVOCATION clothes_req = FALSE invocation = "none" invocation_type = "none" diff --git a/code/modules/spells/spell_types/emplosion.dm b/code/modules/spells/spell_types/emplosion.dm index 0959d8009fc..1d9ddcb9c45 100644 --- a/code/modules/spells/spell_types/emplosion.dm +++ b/code/modules/spells/spell_types/emplosion.dm @@ -2,6 +2,7 @@ name = "Emplosion" desc = "This spell emplodes an area." + school = SCHOOL_EVOCATION var/emp_heavy = 2 var/emp_light = 3 diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm index 21067929ec2..93a022e6bae 100644 --- a/code/modules/spells/spell_types/ethereal_jaunt.dm +++ b/code/modules/spells/spell_types/ethereal_jaunt.dm @@ -2,7 +2,7 @@ name = "Ethereal Jaunt" desc = "This spell turns your form ethereal, temporarily making you invisible and able to pass through walls." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 30 SECONDS clothes_req = TRUE invocation = "none" diff --git a/code/modules/spells/spell_types/explosion.dm b/code/modules/spells/spell_types/explosion.dm index f2b8a0c3a66..dadbd190fa6 100644 --- a/code/modules/spells/spell_types/explosion.dm +++ b/code/modules/spells/spell_types/explosion.dm @@ -2,6 +2,8 @@ name = "Explosion" desc = "This spell explodes an area." + school = SCHOOL_EVOCATION + var/ex_severe = 1 var/ex_heavy = 2 var/ex_light = 3 diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm index 64eca54e3d7..272c9e99ac8 100644 --- a/code/modules/spells/spell_types/forcewall.dm +++ b/code/modules/spells/spell_types/forcewall.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/targeted/forcewall name = "Forcewall" desc = "Create a magical barrier that only you can pass through." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 100 clothes_req = FALSE invocation = "TARCOL MINTI ZHERI" diff --git a/code/modules/spells/spell_types/genetic.dm b/code/modules/spells/spell_types/genetic.dm index 9397484aeb6..f68f6f984ba 100644 --- a/code/modules/spells/spell_types/genetic.dm +++ b/code/modules/spells/spell_types/genetic.dm @@ -2,6 +2,8 @@ name = "Genetic" desc = "This spell inflicts a set of mutations and disabilities upon the target." + school = SCHOOL_TRANSMUTATION + var/list/active_on = list() var/list/traits = list() //disabilities var/list/mutations = list() //mutation defines diff --git a/code/modules/spells/spell_types/infinite_guns.dm b/code/modules/spells/spell_types/infinite_guns.dm index ff780600db3..c98fe950b97 100644 --- a/code/modules/spells/spell_types/infinite_guns.dm +++ b/code/modules/spells/spell_types/infinite_guns.dm @@ -5,7 +5,7 @@ include_user = TRUE range = -1 - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 750 clothes_req = TRUE cooldown_min = 10 //Gun wizard diff --git a/code/modules/spells/spell_types/inflict_handler.dm b/code/modules/spells/spell_types/inflict_handler.dm index 6f4250f0bca..b2179a69d8c 100644 --- a/code/modules/spells/spell_types/inflict_handler.dm +++ b/code/modules/spells/spell_types/inflict_handler.dm @@ -2,6 +2,8 @@ name = "Inflict Handler" desc = "This spell blinds and/or destroys/damages/heals and/or knockdowns/stuns the target." + school = SCHOOL_EVOCATION + var/amt_paralyze = 0 var/amt_unconscious = 0 var/amt_stun = 0 diff --git a/code/modules/spells/spell_types/knock.dm b/code/modules/spells/spell_types/knock.dm index 28430fd8622..921bbe5a9e0 100644 --- a/code/modules/spells/spell_types/knock.dm +++ b/code/modules/spells/spell_types/knock.dm @@ -2,7 +2,7 @@ name = "Knock" desc = "This spell opens nearby doors and closets." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 100 clothes_req = FALSE invocation = "AULIE OXIN FIERA" diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index ddce7ca10f3..b227f984267 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -6,7 +6,7 @@ between reincarnations grows steadily with use, along with the weakness \ that the new skeleton body will experience upon 'birth'. Note that \ becoming a lich destroys all internal organs except the brain." - school = "necromancy" + school = SCHOOL_NECROMANCY charge_max = 10 clothes_req = FALSE centcom_cancast = FALSE diff --git a/code/modules/spells/spell_types/lightning.dm b/code/modules/spells/spell_types/lightning.dm index 8a1cc04afe3..bc031ad1e5b 100644 --- a/code/modules/spells/spell_types/lightning.dm +++ b/code/modules/spells/spell_types/lightning.dm @@ -6,6 +6,7 @@ clothes_req = TRUE invocation = "UN'LTD P'WAH!" invocation_type = INVOCATION_SHOUT + school = SCHOOL_EVOCATION range = 7 cooldown_min = 30 selection_type = "view" diff --git a/code/modules/spells/spell_types/mime.dm b/code/modules/spells/spell_types/mime.dm index c2b820a7da2..61c7cef7a7a 100644 --- a/code/modules/spells/spell_types/mime.dm +++ b/code/modules/spells/spell_types/mime.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall name = "Invisible Wall" desc = "The mime's performance transmutates a wall into physical reality." - school = "mime" + school = SCHOOL_MIME panel = "Mime" summon_type = list(/obj/effect/forcefield/mime) invocation_type = INVOCATION_EMOTE @@ -31,7 +31,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_chair name = "Invisible Chair" desc = "The mime's performance transmutates a chair into physical reality." - school = "mime" + school = SCHOOL_MIME panel = "Mime" summon_type = list(/obj/structure/chair/mime) invocation_type = INVOCATION_EMOTE @@ -69,7 +69,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_box name = "Invisible Box" desc = "The mime's performance transmutates a box into physical reality." - school = "mime" + school = SCHOOL_MIME panel = "Mime" summon_type = list(/obj/item/storage/box/mime) invocation_type = INVOCATION_EMOTE @@ -108,7 +108,7 @@ /obj/effect/proc_holder/spell/targeted/mime/speak name = "Speech" desc = "Make or break a vow of silence." - school = "mime" + school = SCHOOL_MIME panel = "Mime" clothes_req = FALSE human_req = TRUE @@ -148,7 +148,7 @@ /obj/effect/proc_holder/spell/targeted/forcewall/mime name = "Invisible Blockade" desc = "Form an invisible three tile wide blockade." - school = "mime" + school = SCHOOL_MIME panel = "Mime" wall_type = /obj/effect/forcefield/mime/advanced invocation_type = INVOCATION_EMOTE @@ -177,7 +177,7 @@ /obj/effect/proc_holder/spell/aimed/finger_guns name = "Finger Guns" desc = "Shoot a mimed bullet from your fingers that stuns and does some damage." - school = "mime" + school = SCHOOL_MIME panel = "Mime" charge_max = 300 clothes_req = FALSE diff --git a/code/modules/spells/spell_types/pointed/barnyard.dm b/code/modules/spells/spell_types/pointed/barnyard.dm index 18a10ff3d8c..bca67a880a4 100644 --- a/code/modules/spells/spell_types/pointed/barnyard.dm +++ b/code/modules/spells/spell_types/pointed/barnyard.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/pointed/barnyardcurse name = "Curse of the Barnyard" desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_type = "recharge" charge_max = 150 charge_counter = 0 diff --git a/code/modules/spells/spell_types/pointed/blind.dm b/code/modules/spells/spell_types/pointed/blind.dm index 5051a6516b0..3d09bfc989b 100644 --- a/code/modules/spells/spell_types/pointed/blind.dm +++ b/code/modules/spells/spell_types/pointed/blind.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/pointed/trigger/blind name = "Blind" desc = "This spell temporarily blinds a single target." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 300 clothes_req = FALSE invocation = "STI KALY" diff --git a/code/modules/spells/spell_types/pointed/mind_transfer.dm b/code/modules/spells/spell_types/pointed/mind_transfer.dm index 1c54e4c2427..b3f30ab97e9 100644 --- a/code/modules/spells/spell_types/pointed/mind_transfer.dm +++ b/code/modules/spells/spell_types/pointed/mind_transfer.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/pointed/mind_transfer name = "Mind Transfer" desc = "This spell allows the user to switch bodies with a target next to him." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 600 clothes_req = FALSE invocation = "GIN'YU CAPAN" diff --git a/code/modules/spells/spell_types/rod_form.dm b/code/modules/spells/spell_types/rod_form.dm index 6e8d792f59d..9bd0b151117 100644 --- a/code/modules/spells/spell_types/rod_form.dm +++ b/code/modules/spells/spell_types/rod_form.dm @@ -6,6 +6,7 @@ charge_max = 250 cooldown_min = 100 range = -1 + school = SCHOOL_TRANSMUTATION include_user = TRUE invocation = "CLANG!" invocation_type = INVOCATION_SHOUT diff --git a/code/modules/spells/spell_types/santa.dm b/code/modules/spells/spell_types/santa.dm index 350206eaf73..fa80e0a1584 100644 --- a/code/modules/spells/spell_types/santa.dm +++ b/code/modules/spells/spell_types/santa.dm @@ -2,7 +2,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/presents name = "Conjure Presents!" desc = "This spell lets you reach into S-space and retrieve presents! Yay!" - school = "santa" + school = SCHOOL_CONJURATION charge_max = 600 clothes_req = FALSE antimagic_allowed = TRUE diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm index 32989fd2da5..9a81ff8d36b 100644 --- a/code/modules/spells/spell_types/shapeshift.dm +++ b/code/modules/spells/spell_types/shapeshift.dm @@ -1,6 +1,7 @@ /obj/effect/proc_holder/spell/targeted/shapeshift name = "Shapechange" desc = "Take on the shape of another for a time to use their natural abilities. Once you've made your choice it cannot be changed." + school = SCHOOL_TRANSMUTATION clothes_req = FALSE human_req = FALSE charge_max = 200 diff --git a/code/modules/spells/spell_types/soultap.dm b/code/modules/spells/spell_types/soultap.dm index b7d731b28c4..548f1d5c434 100644 --- a/code/modules/spells/spell_types/soultap.dm +++ b/code/modules/spells/spell_types/soultap.dm @@ -7,7 +7,7 @@ /obj/effect/proc_holder/spell/self/tap name = "Soul Tap" desc = "Fuel your spells using your own soul!" - school = "necromancy" //i could see why this wouldn't be necromancy but messing with souls or whatever. ectomancy? + school = SCHOOL_NECROMANCY //i could see why this wouldn't be necromancy but messing with souls or whatever. ectomancy? charge_max = 10 invocation = "AT ANY COST!" invocation_type = INVOCATION_SHOUT diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm index a6e29928583..933ba77736c 100644 --- a/code/modules/spells/spell_types/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/spacetime_distortion.dm @@ -6,6 +6,7 @@ range = 7 var/list/effects var/ready = TRUE + school = SCHOOL_EVOCATION centcom_cancast = FALSE sound = 'sound/effects/magic.ogg' cooldown_min = 300 diff --git a/code/modules/spells/spell_types/summonitem.dm b/code/modules/spells/spell_types/summonitem.dm index 3eab7ca93ac..80752e3e5d1 100644 --- a/code/modules/spells/spell_types/summonitem.dm +++ b/code/modules/spells/spell_types/summonitem.dm @@ -1,7 +1,7 @@ /obj/effect/proc_holder/spell/targeted/summonitem name = "Instant Summons" desc = "This spell can be used to recall a previously marked item to your hand from anywhere in the universe." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 100 clothes_req = FALSE invocation = "GAR YOK" diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm index e555e9f2f3c..c977fa61107 100644 --- a/code/modules/spells/spell_types/touch_attacks.dm +++ b/code/modules/spells/spell_types/touch_attacks.dm @@ -64,7 +64,7 @@ desc = "This spell charges your hand with an unholy energy that can be used to cause a touched victim to violently explode." hand_path = /obj/item/melee/touch_attack/disintegrate - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 600 clothes_req = TRUE cooldown_min = 200 //100 deciseconds reduction per rank @@ -76,7 +76,7 @@ desc = "This spell charges your hand with the power to turn victims into inert statues for a long period of time." hand_path = /obj/item/melee/touch_attack/fleshtostone - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 600 clothes_req = TRUE cooldown_min = 200 //100 deciseconds reduction per rank @@ -89,8 +89,8 @@ desc = "A spell that summons a duffel bag demon on the target, slowing them down and slowly eating them." hand_path = /obj/item/melee/touch_attack/duffelbag action_icon_state = "duffelbag_curse" - - school = "conjuration" + + school = SCHOOL_CONJURATION charge_max = 60 clothes_req = FALSE cooldown_min = 20 diff --git a/code/modules/spells/spell_types/turf_teleport.dm b/code/modules/spells/spell_types/turf_teleport.dm index f9ae58ee750..3e37aa9337c 100644 --- a/code/modules/spells/spell_types/turf_teleport.dm +++ b/code/modules/spells/spell_types/turf_teleport.dm @@ -3,6 +3,8 @@ desc = "This spell teleports the target to the turf in range." nonabstract_req = TRUE + school = SCHOOL_TRANSLOCATION + var/inner_tele_radius = 1 var/outer_tele_radius = 2 diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm index 9488d4ed9db..c2218bfe730 100644 --- a/code/modules/spells/spell_types/wizard.dm +++ b/code/modules/spells/spell_types/wizard.dm @@ -2,7 +2,7 @@ name = "Magic Missile" desc = "This spell fires several, slow moving, magic projectiles at nearby targets." - school = "evocation" + school = SCHOOL_EVOCATION charge_max = 200 clothes_req = TRUE invocation = "FORTI GY AMA" @@ -41,7 +41,7 @@ name = "Mutate" desc = "This spell causes you to turn into a hulk and gain laser vision for a short while." - school = "transmutation" + school = SCHOOL_TRANSMUTATION charge_max = 400 clothes_req = TRUE invocation = "BIRUZ BENNAR" @@ -61,7 +61,7 @@ name = "Smoke" desc = "This spell spawns a cloud of choking smoke at your location." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 120 clothes_req = FALSE invocation = "none" @@ -80,7 +80,7 @@ name = "Smoke" desc = "This spell spawns a small cloud of choking smoke at your location." - school = "conjuration" + school = SCHOOL_HOLY charge_max = 360 clothes_req = FALSE invocation = "none" @@ -112,7 +112,7 @@ name = "Blink" desc = "This spell randomly teleports you a short distance." - school = "abjuration" + school = SCHOOL_FORBIDDEN charge_max = 20 clothes_req = TRUE invocation = "none" @@ -142,7 +142,7 @@ name = "Teleport" desc = "This spell teleports you to an area of your selection." - school = "abjuration" + school = SCHOOL_FORBIDDEN charge_max = 600 clothes_req = TRUE invocation = "SCYAR NILA" @@ -171,6 +171,7 @@ clothes_req = TRUE invocation = "TOKI YO TOMARE" invocation_type = INVOCATION_SHOUT + school = SCHOOL_FORBIDDEN //fucking with time is not appreciated by anyone range = 0 cooldown_min = 100 action_icon_state = "time" @@ -184,7 +185,7 @@ name = "Summon Carp" desc = "This spell conjures a simple carp." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 1200 clothes_req = TRUE invocation = "NOUK FHUNMM SACP RISSKA" @@ -197,7 +198,7 @@ /obj/effect/proc_holder/spell/aoe_turf/conjure/construct name = "Artificer" desc = "This spell conjures a construct which may be controlled by Shades." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 600 clothes_req = FALSE invocation = "none" @@ -212,7 +213,7 @@ name = "Summon Creature Swarm" desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth." - school = "conjuration" + school = SCHOOL_CONJURATION charge_max = 1200 clothes_req = FALSE invocation = "IA IA" @@ -249,6 +250,7 @@ clothes_req = TRUE invocation = "GITTAH WEIGH" invocation_type = INVOCATION_SHOUT + school = SCHOOL_EVOCATION range = 5 cooldown_min = 150 selection_type = "view" @@ -325,6 +327,7 @@ clothes_req = FALSE invocation = "FI'RAN DADISKO" invocation_type = INVOCATION_SHOUT + school = SCHOOL_EVOCATION max_targets = 0 range = 6 include_user = TRUE diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 9cb259fcdb9..dae559384c7 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -20,6 +20,8 @@ low_threshold_cleared = "Your vision is cleared of any ailment." var/sight_flags = 0 + /// changes how the eyes overlay is applied, makes it apply over the lighting layer + var/overlay_ignore_lighting = FALSE var/see_in_dark = 2 var/tint = 0 var/eye_color = "" //set to a hex code to override a mob's eye color @@ -452,3 +454,49 @@ /obj/item/organ/eyes/fly/Remove(mob/living/carbon/M, special = FALSE) REMOVE_TRAIT(M, TRAIT_FLASH_SENSITIVE, ORGAN_TRAIT) return ..() + +/obj/item/organ/eyes/night_vision/maintenance_adapted + name = "adapted eyes" + desc = "These red eyes look like two foggy marbles. They give off a particularly worrying glow in the dark." + flash_protect = FLASH_PROTECTION_SENSITIVE + eye_color = "f00" + icon_state = "adapted_eyes" + eye_icon_state = "eyes_glow" + overlay_ignore_lighting = TRUE + var/obj/item/flashlight/eyelight/adapted/adapt_light + +/obj/item/organ/eyes/night_vision/maintenance_adapted/Initialize() + . = ..() + +/obj/item/organ/eyes/night_vision/maintenance_adapted/Insert(mob/living/carbon/adapted, special = FALSE) + . = ..() + //add lighting + if(!adapt_light) + adapt_light = new /obj/item/flashlight/eyelight/adapted() + adapt_light.on = TRUE + adapt_light.forceMove(adapted) + adapt_light.update_brightness(adapted) + //traits + ADD_TRAIT(adapted, TRAIT_FLASH_SENSITIVE, ORGAN_TRAIT) + ADD_TRAIT(adapted, CULT_EYES, ORGAN_TRAIT) + +/obj/item/organ/eyes/night_vision/maintenance_adapted/on_life(delta_time, times_fired) + var/turf/T = get_turf(owner) + var/lums = T.get_lumcount() + if(lums > 0.5) //we allow a little more than usual so we can produce light from the adapted eyes + to_chat(owner, "Your eyes! They burn in the light!") + applyOrganDamage(10) //blind quickly + playsound(owner, 'sound/machines/grill/grillsizzle.ogg', 50) + else + applyOrganDamage(-10) //heal quickly + . = ..() + +/obj/item/organ/eyes/night_vision/maintenance_adapted/Remove(mob/living/carbon/unadapted, special = FALSE) + //remove lighting + adapt_light.on = FALSE + adapt_light.update_brightness(unadapted) + adapt_light.forceMove(src) + //traits + REMOVE_TRAIT(unadapted, TRAIT_FLASH_SENSITIVE, ORGAN_TRAIT) + REMOVE_TRAIT(unadapted, CULT_EYES, ORGAN_TRAIT) + return ..() diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index cf9608198f4..31bc2618ff4 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -61,7 +61,7 @@ else qdel(replaced) - SEND_SIGNAL(M, COMSIG_CARBON_GAIN_ORGAN, src) + SEND_SIGNAL(M, COMSIG_CARBON_GAIN_ORGAN, src, special) owner = M M.internal_organs |= src @@ -94,7 +94,7 @@ var/datum/action/A = X A.Remove(M) - SEND_SIGNAL(M, COMSIG_CARBON_LOSE_ORGAN, src) + SEND_SIGNAL(M, COMSIG_CARBON_LOSE_ORGAN, src, special) START_PROCESSING(SSobj, src) diff --git a/code/modules/tgui/states/never.dm b/code/modules/tgui/states/never.dm new file mode 100644 index 00000000000..f8b5faeeb3b --- /dev/null +++ b/code/modules/tgui/states/never.dm @@ -0,0 +1,15 @@ +/*! + * Copyright (c) 2021 Arm A. Hammer + * SPDX-License-Identifier: MIT + */ + +/** + * tgui state: never_state + * + * Always closes the UI, no matter what. See the ui_state in religious_tool.dm to see an example + */ + +GLOBAL_DATUM_INIT(never_state, /datum/ui_state/never_state, new) + +/datum/ui_state/never_state/can_use_topic(src_object, mob/user) + return UI_CLOSE diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index c022aaa8018..eb9a66ce8af 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1205,3 +1205,22 @@ GLOBAL_LIST_EMPTY(vending_products) var/obj/item/I = target I.custom_price = price to_chat(user, "You set the price of [I] to [price] cr.") + +/obj/machinery/vending/custom/greed //name and like decided by the spawn + custom_materials = list(/datum/material/gold = MINERAL_MATERIAL_AMOUNT * 5) + material_flags = MATERIAL_COLOR //it's grey anyway, let's bling out + +/obj/machinery/vending/custom/greed/Initialize(mapload) + . = ..() + //starts in a state where you can move it + panel_open = TRUE + anchored = FALSE + add_overlay("[initial(icon_state)]-panel") + //and references the deity + name = "[GLOB.deity]'s Consecrated Vendor" + desc = "A vending machine created by [GLOB.deity]." + slogan_list = list("[GLOB.deity] says: It's your divine right to buy!") + add_filter("vending_outline", 9, list("type" = "outline", "color" = "#FFFFFF")) + add_filter("vending_rays", 10, list("type" = "rays", "size" = 35)) + + diff --git a/icons/effects/mouse_pointers/honorbound.dmi b/icons/effects/mouse_pointers/honorbound.dmi new file mode 100644 index 00000000000..8c19973933b Binary files /dev/null and b/icons/effects/mouse_pointers/honorbound.dmi differ diff --git a/icons/mob/actions/actions_spells.dmi b/icons/mob/actions/actions_spells.dmi index 51159458db6..a3d1a2b72bc 100644 Binary files a/icons/mob/actions/actions_spells.dmi and b/icons/mob/actions/actions_spells.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index a1f08b17c05..f9fa5dcfaa5 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/obj/hand_of_god_structures.dmi b/icons/obj/hand_of_god_structures.dmi index 3f640d4d576..bd95eece476 100644 Binary files a/icons/obj/hand_of_god_structures.dmi and b/icons/obj/hand_of_god_structures.dmi differ diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi index 328f658f4b2..5fdbfb05d6b 100644 Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 457119307e7..bf3130fcfaa 100755 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/tgstation.dme b/tgstation.dme index ad7fda7c778..f1f6bb3edff 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -80,6 +80,7 @@ #include "code\__DEFINES\living.dm" #include "code\__DEFINES\logging.dm" #include "code\__DEFINES\machines.dm" +#include "code\__DEFINES\magic.dm" #include "code\__DEFINES\maps.dm" #include "code\__DEFINES\materials.dm" #include "code\__DEFINES\maths.dm" @@ -767,6 +768,8 @@ #include "code\datums\mutations\speech.dm" #include "code\datums\mutations\telekinesis.dm" #include "code\datums\mutations\touch.dm" +#include "code\datums\mutations\holy_mutation\burdened.dm" +#include "code\datums\mutations\holy_mutation\honorbound.dm" #include "code\datums\quirks\_quirk.dm" #include "code\datums\quirks\good.dm" #include "code\datums\quirks\negative.dm" @@ -3405,6 +3408,7 @@ #include "code\modules\tgui\states\human_adjacent.dm" #include "code\modules\tgui\states\inventory.dm" #include "code\modules\tgui\states\language_menu.dm" +#include "code\modules\tgui\states\never.dm" #include "code\modules\tgui\states\new_player.dm" #include "code\modules\tgui\states\not_incapacitated.dm" #include "code\modules\tgui\states\notcontained.dm" diff --git a/tgui/packages/tgui/interfaces/ReligiousTool.js b/tgui/packages/tgui/interfaces/ReligiousTool.js new file mode 100644 index 00000000000..c5c28ae75db --- /dev/null +++ b/tgui/packages/tgui/interfaces/ReligiousTool.js @@ -0,0 +1,217 @@ +import { capitalize } from 'common/string'; +import { useBackend, useSharedState } from '../backend'; +import { AnimatedNumber, BlockQuote, Box, Button, Collapsible, Dimmer, Icon, LabeledList, NoticeBox, ProgressBar, Section, Stack, Tabs } from '../components'; +import { Window } from '../layouts'; + +const ALIGNMENT2COLOR = { + "good": "yellow", + "neutral": "white", + "evil": "red", +}; + +export const ReligiousTool = (props, context) => { + const { act, data } = useBackend(context); + const [tab, setTab] = useSharedState(context, 'tab', 1); + const { + sects, + alignment, + toolname, + } = data; + return ( + + + + + + setTab(1)}> + Sect + + {!sects && ( + setTab(2)}> + Rites + + )} + + + + {tab === 1 && ( + !!sects && ( + + ) || ( + + ) + )} + {tab === 2 && ( + + )} + + + + + ); +}; + +const SectTab = (props, context) => { + const { act, data } = useBackend(context); + const { + name, + quote, + desc, + icon, + favordesc, + favor, + wanted, + deity, + alignment, + } = data; + return ( +
+ + + + {" " + name + " "} + + + + {"\""+quote+"\""} + + + {favordesc} + + +
+ {desc} +
+
+ +
+ {!wanted && ( + deity + " doesn't want any sacrifices." + ) || ( + deity + " wishes for " + wanted + "." + )} +
+
+
+
+ ); +}; + +const SectSelectTab = (props, context) => { + const { act, data } = useBackend(context); + const { + sects, + } = data; + return ( +
+ + {sects.map(sect => ( + <> + + + + + + {sect.name} + + + {"\""+sect.quote+"\""} + + + )} + color="transparent"> + + {sect.desc}
+ +
+ + + + ))} + +
+ ); +}; + +const RiteTab = (props, context) => { + const { act, data } = useBackend(context); + const { + rites, + deity, + icon, + alignment, + favor, + } = data; + return ( + <> + {!rites.length && ( +
+ + + + + + + {deity} does not have any invocations. + + + +
+ )} + + {rites.map(rite => ( + +
act('perform_rite', { + path: rite.path, + })} > + Invoke + + )} > + + Costs {rite.favor} favor. + +
+ {rite.desc} +
+
+
+ ))} +
+ + ); +};