diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index 932c7927ef09..ff9ba5a9ee0b 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -30,6 +30,7 @@ SUBSYSTEM_DEF(minor_mapping) weakpoint_spawns += SSmapping.current_map.bonus_weakpoints //This will add 0 by default, or additional on large maps where it's included in the config. place_weakpoints(weakpoint_spawns) + spawn_umbra_artifacts(rand(CONFIG_GET(number/umbra_artifact_min), CONFIG_GET(number/umbra_artifact_max))) // DARKPACK EDIT ADD - OCCULT_ARTIFACTS return SS_INIT_SUCCESS #endif diff --git a/config/darkpack_config.txt b/config/darkpack_config.txt index ff43a079134d..616247795f04 100644 --- a/config/darkpack_config.txt +++ b/config/darkpack_config.txt @@ -29,9 +29,12 @@ ON_CRIT_ADDITIONAL_DIE ##Artifact spawn chance from crates - note, crates usually drop random artifact subtype, so this probability is typically multiplied by the random probability ARTIFACT_CRATE_PROBABILITY 20 - ##Artifact spawn chance from mapped in random spots ARTIFACT_RANDOM_PROBABILITY 50 +## Min amount of initiallly placed corpses with banes and artifacts around them +UMBRA_ARTIFACT_MIN 1 +## Max amount of initiallly placed corpses with banes and artifacts around them +UMBRA_ARTIFACT_MAX 3 ## Time til day define TIME_TILL_DAY 198000 diff --git a/modular_darkpack/modules/merits_flaws/code/_darkpack_quirk.dm b/modular_darkpack/modules/merits_flaws/code/_darkpack_quirk.dm index b64b641edb48..68e87e305c2d 100644 --- a/modular_darkpack/modules/merits_flaws/code/_darkpack_quirk.dm +++ b/modular_darkpack/modules/merits_flaws/code/_darkpack_quirk.dm @@ -78,3 +78,49 @@ return TRUE + + +/// Subtype quirk that has some bonus logic to spawn items for the player. +/datum/quirk/darkpack/item_quirk + /// Lazylist of strings describing where all the quirk items have been spawned. + var/list/where_items_spawned + /// If true, the backpack automatically opens on post_add(). Usually set to TRUE when an item is equipped inside the player's backpack. + var/open_backpack = FALSE + abstract_type = /datum/quirk/darkpack/item_quirk + +/** + * Handles inserting an item in any of the valid slots provided, then allows for post_add notification. + * + * If no valid slot is available for an item, the item is left at the mob's feet. + * Arguments: + * * quirk_item - The item to give to the quirk holder. If the item is a path, the item will be spawned in first on the player's turf. + * * valid_slots - List of LOCATION_X that is fed into [/mob/living/carbon/proc/equip_in_one_of_slots]. + * * flavour_text - Optional flavour text to append to the where_items_spawned string after the item's location. + * * default_location - If the item isn't possible to equip in a valid slot, this is a description of where the item was spawned. + * * notify_player - If TRUE, adds strings to where_items_spawned list to be output to the player in [/datum/quirk/darkpack/item_quirk/post_add()] + */ +/datum/quirk/darkpack/item_quirk/proc/give_item_to_holder(obj/item/quirk_item, list/valid_slots, flavour_text = null, default_location = "at your feet", notify_player = FALSE) + if(ispath(quirk_item)) + quirk_item = new quirk_item(get_turf(quirk_holder)) + + var/mob/living/carbon/human/human_holder = quirk_holder + + var/where = human_holder.equip_in_one_of_slots(quirk_item, valid_slots, qdel_on_fail = FALSE, indirect_action = TRUE) || default_location + + if(where == LOCATION_BACKPACK) + open_backpack = TRUE + + if(notify_player) + LAZYADD(where_items_spawned, span_boldnotice("You have \a [quirk_item] [where]. [flavour_text]")) + +/datum/quirk/darkpack/item_quirk/post_add() + if(open_backpack) + var/mob/living/carbon/human/human_holder = quirk_holder + // post_add() can be called via delayed callback. Check they still have a backpack equipped before trying to open it. + if(human_holder.back) + human_holder.back.atom_storage.show_contents(human_holder) + + for(var/chat_string in where_items_spawned) + to_chat(quirk_holder, chat_string) + + where_items_spawned = null diff --git a/modular_darkpack/modules/merits_flaws/code/positive_quirks/fetish.dm b/modular_darkpack/modules/merits_flaws/code/positive_quirks/fetish.dm new file mode 100644 index 000000000000..d26b6c178ee7 --- /dev/null +++ b/modular_darkpack/modules/merits_flaws/code/positive_quirks/fetish.dm @@ -0,0 +1,69 @@ +GLOBAL_LIST_INIT(fetish_merit_choice, generate_merit_fetishes()) + +/proc/generate_merit_fetishes() + var/list/choices = list() + for(var/obj/item/occult_artifact/werewolf/fetish as anything in valid_subtypesof(/obj/item/occult_artifact/werewolf)) + if(fetish::rank != 1) + continue + choices[fetish::true_name] = fetish + return choices + +// W20 p. 383 for the kinfolk fetish +// W20 p. 137 for the garou background rather then the kinfolk merit. +/datum/quirk/darkpack/item_quirk/fetish + name = "Fetish" + desc = "You own a weak fetish. You may have inherited this item, received it as a gift, it should have an important value to you." + value = 3 // Middle ground price between the kinfolk merit or garou background + // Acctually a kinfolk merit in the books. + allowed_splats = list(SPLAT_KINFOLK, SPLAT_GAROU, SPLAT_CORAX) + icon = FA_ICON_MAGIC + +/datum/quirk/darkpack/item_quirk/fetish/add_unique(client/client_source) + var/mob/living/carbon/human/fetish_owner = astype(quirk_holder) + if(!fetish_owner) + return + + var/fetish_type = GLOB.fetish_merit_choice[client_source?.prefs?.read_preference(/datum/preference/choiced/fetish_merit)] || /obj/item/occult_artifact/werewolf/nyxs_bangle + if(isnull(fetish_type)) + fetish_type = GLOB.fetish_merit_choice[pick(GLOB.fetish_merit_choice)] + var/obj/item/occult_artifact/werewolf/new_heirloom = new fetish_type(get_turf(fetish_owner)) + + give_item_to_holder( + new_heirloom, + list( + LOCATION_LPOCKET, + LOCATION_RPOCKET, + LOCATION_BACKPACK, + LOCATION_HANDS, + ), + flavour_text = "This is your precious fetish!", + notify_player = TRUE, + ) + + new_heirloom.identify(fetish_owner) + + +/datum/quirk_constant_data/blindfoldcolor + associated_typepath = /datum/quirk/darkpack/item_quirk/fetish + customization_options = list(/datum/preference/choiced/fetish_merit) + + +/datum/preference/choiced/fetish_merit + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "fetish_merit" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/choiced/fetish_merit/init_possible_values() + return list("Random") + GLOB.fetish_merit_choice + +/datum/preference/choiced/fetish_merit/create_default_value() + return "Random" + +/datum/preference/choiced/fetish_merit/is_accessible(datum/preferences/preferences) + . = ..() + if (!.) + return FALSE + return /datum/quirk/darkpack/item_quirk/fetish::name in preferences.all_quirks + +/datum/preference/choiced/fetish_merit/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/modular_darkpack/modules/occult_artifacts/code/_artifact.dm b/modular_darkpack/modules/occult_artifacts/code/_artifact.dm index ca34674704af..2c5a68a5ba8d 100644 --- a/modular_darkpack/modules/occult_artifacts/code/_artifact.dm +++ b/modular_darkpack/modules/occult_artifacts/code/_artifact.dm @@ -23,10 +23,15 @@ abstract_type = /obj/item/occult_artifact w_class = WEIGHT_CLASS_SMALL var/mob/living/owner + /// Name set upon identifying the artifact var/true_name + /// Desc set upon identifying the artifact var/true_desc var/identified = FALSE + /// How many points this grants when fed into the treme artifact muncher var/research_value = 0 + /// "Rank" of artifact as used in the TTRPG. + var/rank = 1 var/can_be_identified_without_ritual = TRUE var/grant_sound // = 'sound/effects/magic/swap.ogg' @@ -147,17 +152,18 @@ /obj/effect/spawner/random/occult/artifact/werewolf_only name = "random garou fetish" loot = list( - /obj/item/occult_artifact/werewolf/nyxs_bangle = 45, - /obj/item/occult_artifact/werewolf/dagger_of_retribution = 45, - /obj/effect/spawner/random/occult/artifact/klaive = 10, + /obj/item/occult_artifact/werewolf/nyxs_bangle = 33, + /obj/item/occult_artifact/werewolf/dagger_of_retribution = 33, + /obj/item/occult_artifact/werewolf/magpies_ears = 33, + /obj/effect/spawner/random/occult/artifact/klaive = 1, ) - /obj/effect/spawner/random/occult/artifact/klaive name = "random klaive" loot = list( - /obj/item/occult_artifact/werewolf/klaive = 32, - /obj/item/occult_artifact/werewolf/klaive/bane = 32, - /obj/item/occult_artifact/werewolf/klaive/karambit = 32, - /obj/item/occult_artifact/werewolf/klaive/grand = 4, // Idk this thing is mega scary and mabye even doesnt belong here. + /obj/item/occult_artifact/werewolf/klaive = 33, + /obj/item/occult_artifact/werewolf/klaive/bane = 33, + /obj/item/occult_artifact/werewolf/klaive/karambit = 33, ) +// I've elected to remove grand klaives in favor of making them something you have to kill a real boss for. + diff --git a/modular_darkpack/modules/occult_artifacts/code/_werewolf.dm b/modular_darkpack/modules/occult_artifacts/code/_werewolf.dm index 945b57b1091d..106d887b986e 100644 --- a/modular_darkpack/modules/occult_artifacts/code/_werewolf.dm +++ b/modular_darkpack/modules/occult_artifacts/code/_werewolf.dm @@ -1,6 +1,7 @@ GLOBAL_LIST_INIT(night_spirits, world.file2list("modular_darkpack/modules/occult_artifacts/strings/night_spirits.txt")) GLOBAL_LIST_INIT(darkness_spirits, world.file2list("modular_darkpack/modules/occult_artifacts/strings/darkness_spirits.txt")) GLOBAL_LIST_INIT(vengeance_spirits, world.file2list("modular_darkpack/modules/occult_artifacts/strings/vengeance_spirits.txt")) +GLOBAL_LIST_INIT(animal_spirits, world.file2list("modular_darkpack/modules/occult_artifacts/strings/animal_spirits.txt")) /obj/item/occult_artifact/werewolf icon = 'modular_darkpack/modules/occult_artifacts/icons/fetishes.dmi' @@ -25,6 +26,8 @@ GLOBAL_LIST_INIT(vengeance_spirits, world.file2list("modular_darkpack/modules/oc spirit_table = GLOB.darkness_spirits if(SPIRIT_VENGEANCE) spirit_table = GLOB.vengeance_spirits + if(SPIRIT_ANIMAL) + spirit_table = GLOB.animal_spirits if(length(spirit_table)) spirit_name = pick(spirit_table) diff --git a/modular_darkpack/modules/occult_artifacts/code/fetishes/magpies_ears.dm b/modular_darkpack/modules/occult_artifacts/code/fetishes/magpies_ears.dm new file mode 100644 index 000000000000..30ae7455d5ec --- /dev/null +++ b/modular_darkpack/modules/occult_artifacts/code/fetishes/magpies_ears.dm @@ -0,0 +1,51 @@ +// Homebrew I made up for a special little snowflake +/obj/item/occult_artifact/werewolf/magpies_ears + name = "strange doll" + desc = "A handcrafted doll with strange accoutrements." + true_name = "Magpie's Ears" + true_desc = "A handmade doll with a penchant for listening." + icon_state = "argemia" + icon = 'modular_darkpack/modules/toys/icons/toys.dmi' + ONFLOOR_ICON_HELPER('modular_darkpack/modules/toys/icons/toys_onfloor.dmi') + spirit_type = SPIRIT_ANIMAL + var/list/heard_messages + COOLDOWN_DECLARE(yap_cooldown) + +/obj/item/occult_artifact/werewolf/magpies_ears/Initialize(mapload) + . = ..() + spirit_name = generate_spirit_name(spirit_type) + add_traits(list(TRAIT_ACUTE_HEARING, TRAIT_XRAY_HEARING, TRAIT_GOOD_HEARING), INNATE_TRAIT) + become_hearing_sensitive() + +/obj/item/occult_artifact/werewolf/magpies_ears/Hear(atom/movable/speaker, message_language, raw_message, radio_freq, radio_freq_name, radio_freq_color, list/spans, list/message_mods, message_range, source) + . = ..() + if((speaker == owner) || (speaker == src)) + return . + + var/number_of_excess_strings = LAZYLEN(heard_messages) - 100 + if(number_of_excess_strings > 0) // only remove if we're overfull + for(var/i in 1 to number_of_excess_strings) + LAZYREMOVE(heard_messages, pick(heard_messages)) + + LAZYADD(heard_messages, html_decode(raw_message)) + Shake(duration = 0.2 SECONDS) + +/obj/item/occult_artifact/werewolf/magpies_ears/attack_self(mob/user, modifiers) + if(!identified) + return ..() + + if(!COOLDOWN_FINISHED(src, yap_cooldown)) + return + + if(!length(heard_messages)) + say("I'm afraid I have nothing to say.") + + COOLDOWN_START(src, yap_cooldown, 5 SECONDS) + var/message = pick(heard_messages) + say(message) + LAZYREMOVE(heard_messages, message) + return TRUE + +/obj/item/occult_artifact/werewolf/magpies_ears/identify() + . = ..() + say("I am [spirit_name]... I lend my ears and secrets to you...") diff --git a/modular_darkpack/modules/occult_artifacts/code/umbra_spawns.dm b/modular_darkpack/modules/occult_artifacts/code/umbra_spawns.dm new file mode 100644 index 000000000000..de067f9a2d87 --- /dev/null +++ b/modular_darkpack/modules/occult_artifacts/code/umbra_spawns.dm @@ -0,0 +1,61 @@ +/obj/effect/spawner/umbra_corpse_setpiece + var/fetish_value = 4 + +/obj/effect/spawner/umbra_corpse_setpiece/Initialize(mapload) + var/static/list/obj/item/occult_artifact/werewolf/fetish_types = valid_subtypesof(/obj/item/occult_artifact/werewolf) + var/static/list/mob/living/basic/bane/bane_protectors = valid_subtypesof(/mob/living/basic/bane) + + . = ..() + + fetish_value += rand(-1, 1) + // Store the value so we can match the value of fetishes + var/bane_protection = fetish_value + rand(-1, 1) + + var/turf/center_turf = get_turf(src) + new /obj/effect/mob_spawn/corpse/human/garou(center_turf) + for(var/i in 1 to 10) + if(fetish_value <= 0) + break + + var/obj/item/occult_artifact/werewolf/artifact_type = pick(fetish_types) + if(artifact_type::rank < fetish_value) + var/spawning_turf = pick(get_adjacent_open_turfs(center_turf) + center_turf) + fetish_value -= artifact_type::rank + new artifact_type(spawning_turf) + + for(var/i in 1 to 10) + if(bane_protection <= 0) + break + + var/mob/living/basic/bane/chud = pick(bane_protectors) + if(chud::power_rank < bane_protection) + var/spawning_turf = pick(get_adjacent_open_turfs(center_turf) + center_turf) + bane_protection -= chud::power_rank + new chud(spawning_turf) + + + +/obj/effect/mob_spawn/corpse/human/garou + mob_type = /mob/living/carbon/human/splat/garou + outfit = /datum/outfit/job/vampire/guardian + outfit_override = list("r_pocket" = /obj/item/stack/dollar/rand) + +/datum/controller/subsystem/minor_mapping/proc/spawn_umbra_artifacts(amount) + var/list/zlevels = SSmapping.levels_by_trait(ZTRAIT_MINING) + + if(!length(zlevels)) + return + + for(var/i in 1 to amount) + var/turf/center = find_safe_turf(zlevels) + if(center) + new /obj/effect/spawner/umbra_corpse_setpiece(center) + + +/datum/config_entry/number/umbra_artifact_min + default = 1 + min_val = 0 + +/datum/config_entry/number/umbra_artifact_max + default = 3 + min_val = 0 diff --git a/modular_darkpack/modules/occult_artifacts/strings/animal_spirits.txt b/modular_darkpack/modules/occult_artifacts/strings/animal_spirits.txt new file mode 100644 index 000000000000..686ecf9781c2 --- /dev/null +++ b/modular_darkpack/modules/occult_artifacts/strings/animal_spirits.txt @@ -0,0 +1,26 @@ +Western-Crow-Spirit +Eastern-Raven-Spirit +Lesser-Corvid-Sprit +River-Toad-Spirit +River-Fish-Spirit +Green-Crab-Spirit +Red-Crab-Spirit +Prairie-Bird-Spirit +Whispers-in-Grass +Lantern-Between-the-Trees +He-Who-Waits-Beneath-Stones +Feather-on-the-Wind +Many-Eyes-in-the-Dark +The Last Leaf to Fall +Tracks-Through-the-Garbage +Shell-Against-the-Storm +Singer-of-the-Summer-Night +She-Who-Returns-to-the-River +Teeth-Hidden-Behind-a-Smile +Collector-of-Bright-Things +Little Shadow Beneath the Porch +Feathered-Whispers +River-Wader +Sparkly +Storied Walker +Wet-Hands diff --git a/modular_darkpack/modules/werewolf_the_apocalypse/code/basic_mobs/banes/_banes.dm b/modular_darkpack/modules/werewolf_the_apocalypse/code/basic_mobs/banes/_banes.dm index 34458348d8ee..033f5590d905 100644 --- a/modular_darkpack/modules/werewolf_the_apocalypse/code/basic_mobs/banes/_banes.dm +++ b/modular_darkpack/modules/werewolf_the_apocalypse/code/basic_mobs/banes/_banes.dm @@ -26,6 +26,8 @@ bloodquality = BLOOD_QUALITY_LOW ai_controller = /datum/ai_controller/basic_controller/simple/simple_hostile_obstacles + // General spitball of the "power" of the bane so we can use that for difficulty calculations + var/power_rank = 1 /mob/living/basic/bane/Initialize(mapload) . = ..() diff --git a/modular_darkpack/modules/werewolf_the_apocalypse/code/weapons/klaives.dm b/modular_darkpack/modules/werewolf_the_apocalypse/code/weapons/klaives.dm index 588534b05c8a..51bf61ba798f 100644 --- a/modular_darkpack/modules/werewolf_the_apocalypse/code/weapons/klaives.dm +++ b/modular_darkpack/modules/werewolf_the_apocalypse/code/weapons/klaives.dm @@ -18,6 +18,7 @@ armor_type = /datum/armor/item_claymore resistance_flags = FIRE_PROOF custom_materials = list(/datum/material/silver = (2 * SHEET_MATERIAL_AMOUNT)) + rank = 4 spirit_type = SPIRIT_VENGEANCE var/stirred_spirit = FALSE var/silver_damage = 2 @@ -83,5 +84,6 @@ attack_difficulty = 7 w_class = WEIGHT_CLASS_HUGE custom_materials = list(/datum/material/silver = (4 * SHEET_MATERIAL_AMOUNT)) + rank = 5 silver_damage = 3 awakened_force = 6 LETHAL_TTRPG_DAMAGE diff --git a/tgstation.dme b/tgstation.dme index 923b14b1b677..a65e262cfa83 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7623,6 +7623,7 @@ #include "modular_darkpack\modules\merits_flaws\code\positive_quirks\eat_food_quirk.dm" #include "modular_darkpack\modules\merits_flaws\code\positive_quirks\efficient_digestion.dm" #include "modular_darkpack\modules\merits_flaws\code\positive_quirks\fair_glabro.dm" +#include "modular_darkpack\modules\merits_flaws\code\positive_quirks\fetish.dm" #include "modular_darkpack\modules\merits_flaws\code\positive_quirks\giovanni_sanguine_incongruity.dm" #include "modular_darkpack\modules\merits_flaws\code\positive_quirks\hidden_diablerie.dm" #include "modular_darkpack\modules\merits_flaws\code\positive_quirks\metamorph.dm" @@ -7705,6 +7706,7 @@ #include "modular_darkpack\modules\occult_artifacts\code\_artifact_config.dm" #include "modular_darkpack\modules\occult_artifacts\code\_vampire.dm" #include "modular_darkpack\modules\occult_artifacts\code\_werewolf.dm" +#include "modular_darkpack\modules\occult_artifacts\code\umbra_spawns.dm" #include "modular_darkpack\modules\occult_artifacts\code\artifacts\bloodstar.dm" #include "modular_darkpack\modules\occult_artifacts\code\artifacts\bloodstone.dm" #include "modular_darkpack\modules\occult_artifacts\code\artifacts\daimonori.dm" @@ -7717,6 +7719,7 @@ #include "modular_darkpack\modules\occult_artifacts\code\artifacts\tarulfang.dm" #include "modular_darkpack\modules\occult_artifacts\code\artifacts\weekapaug_thistle.dm" #include "modular_darkpack\modules\occult_artifacts\code\fetishes\dagger_of_retribution.dm" +#include "modular_darkpack\modules\occult_artifacts\code\fetishes\magpies_ears.dm" #include "modular_darkpack\modules\occult_artifacts\code\fetishes\nyxs_bangle.dm" #include "modular_darkpack\modules\onfloor_icons\code\apply_onfloor_icon_element.dm" #include "modular_darkpack\modules\onfloor_icons\code\dynamic_item_icon.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_merits_flaws_preferences.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_merits_flaws_preferences.tsx index d9edd1466156..e6a84fc439eb 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_merits_flaws_preferences.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/darkpack_merits_flaws_preferences.tsx @@ -28,3 +28,9 @@ export const acute_sense: FeatureChoiced = { name: 'Acute Sense', component: FeatureDropdownInput, }; + +export const fetish_merit: FeatureChoiced = { + name: 'Fetish', + description: 'Choice of fetish.', + component: FeatureDropdownInput, +};