diff --git a/code/__DEFINES/~darkpack/splats.dm b/code/__DEFINES/~darkpack/splats.dm
index cd889cce6054..1c2468d0cf2c 100644
--- a/code/__DEFINES/~darkpack/splats.dm
+++ b/code/__DEFINES/~darkpack/splats.dm
@@ -11,11 +11,15 @@
#define SPLAT_CORAX "splat_corax" // DARKPACK TODO - CORAX
#define SPLAT_SHIFTERS list(SPLAT_GAROU, SPLAT_CORAX)
+#define SPLAT_FOMORI "splat_fomori"
+
#define SPLAT_PRIO_HALFSPLAT 100
#define SPLAT_PRIO_SPLAT 200
#define SPLAT_PRIO_KINFOLK 40 + SPLAT_PRIO_HALFSPLAT
#define SPLAT_PRIO_GHOUL 70 + SPLAT_PRIO_HALFSPLAT
+#define SPLAT_PRIO_FOMORI 20 + SPLAT_PRIO_SPLAT
#define SPLAT_PRIO_SHIFTER 40 + SPLAT_PRIO_SPLAT
#define SPLAT_PRIO_KINDRED 60 + SPLAT_PRIO_SPLAT
+
diff --git a/code/__DEFINES/~darkpack/traits/declarations.dm b/code/__DEFINES/~darkpack/traits/declarations.dm
index 15d361e121fa..02594ea5984d 100644
--- a/code/__DEFINES/~darkpack/traits/declarations.dm
+++ b/code/__DEFINES/~darkpack/traits/declarations.dm
@@ -28,6 +28,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_BLOODY_SUCKER "bloody_sucker"
#define TRAIT_NON_INT "non_intellectual"
#define TRAIT_COFFIN_THERAPY "coffin_therapy"
+// If we use combat_bite instead of vamp_bite
+#define TRAIT_COMBAT_BITE "combat_bite"
#define TRAIT_RUBICON "rubicon"
#define TRAIT_HUNGRY "hungry"
#define TRAIT_STAKE_RESISTANT "stake_resistant"
@@ -151,6 +153,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_LOUD_HOWLER "loud_howler"
#define TRAIT_RAZOR_CLAWS "razor_claws"
+// Fomori Traits
+#define TRAIT_FOMORI_REGEN "fomor_regen"
+
/// Sixth sense restricted to view range
#define TRAIT_LOCAL_SIXTHSENSE "local_sixth_sense"
/// If the mob can't have surgery done on it. See: Blood form Tzimisce
@@ -180,6 +185,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_MERIT_UNTAMABLE "merit_untamable"
#define TRAIT_FAIR_GLABRO "fair_glabro"
#define TRAIT_EAT_FOOD "eat_food"
-
+#define TRAIT_FOMORI_STIGMATA "fomori_stigmata"
// END TRAIT DEFINES
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 34ede6349de4..1750ae69dcd4 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -679,6 +679,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_CAN_ENTER_TORPOR" = TRAIT_CAN_ENTER_TORPOR, // DARKPACK EDIT ADD
"TRAIT_CHARMER" = TRAIT_CHARMER, // DARKPACK EDIT ADD
"TRAIT_COFFIN_THERAPY" = TRAIT_COFFIN_THERAPY, // DARKPACK EDIT ADD
+ "TRAIT_COMBAT_BITE" = TRAIT_COMBAT_BITE, // DARKPACK EDIT ADD
"TRAIT_CONSENSUAL_FEEDING_ONLY" = TRAIT_CONSENSUAL_FEEDING_ONLY, // DARKPACK EDIT ADD
"TRAIT_DECEPTIVE_AURA" = TRAIT_DECEPTIVE_AURA, // DARKPACK EDIT ADD
"TRAIT_DEFICIENT_VITAE" = TRAIT_DEFICIENT_VITAE, // DARKPACK EDIT ADD
@@ -695,6 +696,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_FERA_FORMS" = TRAIT_FERA_FORMS, // DARKPACK EDIT ADD - WEREWOLF
"TRAIT_FERA_FUR" = TRAIT_FERA_FUR, // DARKPACK EDIT ADD - WEREWOLF
"TRAIT_FERA_RENOWN" = TRAIT_FERA_RENOWN, // DARKPACK EDIT ADD - WEREWOLF
+ "TRAIT_FOMORI_STIGMATA" = TRAIT_FOMORI_STIGMATA, // DARKPACK EDIT ADD - FOMORI
+ "TRAIT_FOMORI_REGEN" = TRAIT_FOMORI_REGEN, // DARKPACK EDIT ADD - FOMORI
"TRAIT_FORCED_EMOTION" = TRAIT_FORCED_EMOTION, // DARKPACK EDIT ADD - Melpominee
"TRAIT_FRENETIC_AURA" = TRAIT_FRENETIC_AURA, // DARKPACK EDIT ADD
"TRAIT_GHOST_VISION" = TRAIT_GHOST_VISION, // DARKPACK EDIT ADD - POWERS - (Necromancy)
diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm
index a361a289db94..70452bfac851 100644
--- a/code/_globalvars/traits/admin_tooling.dm
+++ b/code/_globalvars/traits/admin_tooling.dm
@@ -370,6 +370,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_CAN_ENTER_TORPOR" = TRAIT_CAN_ENTER_TORPOR, // DARKPACK EDIT ADD
"TRAIT_CHARMER" = TRAIT_CHARMER, // DARKPACK EDIT ADD
"TRAIT_COFFIN_THERAPY" = TRAIT_COFFIN_THERAPY, // DARKPACK EDIT ADD
+ "TRAIT_COMBAT_BITE" = TRAIT_COMBAT_BITE, // DARKPACK EDIT ADD
"TRAIT_CONSENSUAL_FEEDING_ONLY" = TRAIT_CONSENSUAL_FEEDING_ONLY, // DARKPACK EDIT ADD
"TRAIT_DECEPTIVE_AURA" = TRAIT_DECEPTIVE_AURA, // DARKPACK EDIT ADD
"TRAIT_DEFICIENT_VITAE" = TRAIT_DEFICIENT_VITAE, // DARKPACK EDIT ADD
@@ -384,6 +385,8 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_FEEDING_RESTRICTION" = TRAIT_FEEDING_RESTRICTION, // DARKPACK EDIT ADD
"TRAIT_FERA_FUR" = TRAIT_FERA_FUR, // DARKPACK EDIT ADD - WEREWOLF
"TRAIT_FERA_RENOWN" = TRAIT_FERA_RENOWN, // DARKPACK EDIT ADD - WEREWOLF
+ "TRAIT_FOMORI_STIGMATA" = TRAIT_FOMORI_STIGMATA, // DARKPACK EDIT ADD - FOMORI
+ "TRAIT_FOMORI_REGEN" = TRAIT_FOMORI_REGEN, // DARKPACK EDIT ADD - FOMORI
"TRAIT_FRENETIC_AURA" = TRAIT_FRENETIC_AURA, // DARKPACK EDIT ADD
"TRAIT_GHOST_VISION" = TRAIT_GHOST_VISION, // DARKPACK EDIT ADD - POWERS - (Necromancy)
"TRAIT_GRIP_OF_THE_DAMNED" = TRAIT_GRIP_OF_THE_DAMNED, // DARKPACK EDIT ADD
diff --git a/config/darkpack_config.txt b/config/darkpack_config.txt
index 5e8029099242..5f83d2d54ed7 100644
--- a/config/darkpack_config.txt
+++ b/config/darkpack_config.txt
@@ -43,6 +43,7 @@ ROUNDSTART_SPLATS splat_kindred
ROUNDSTART_SPLATS splat_ghoul
ROUNDSTART_SPLATS splat_kinfolk
ROUNDSTART_SPLATS splat_garou
+ROUNDSTART_SPLATS splat_fomori
## If dead people and ghosts can LOOC to people who are alive.
DISABLE_GHOST_LOOC
diff --git a/modular_darkpack/master_files/code/modules/mob/living/carbon/carbon_defines.dm b/modular_darkpack/master_files/code/modules/mob/living/carbon/carbon_defines.dm
index 1c3c3d17781d..254e564d5cc2 100644
--- a/modular_darkpack/master_files/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/modular_darkpack/master_files/code/modules/mob/living/carbon/carbon_defines.dm
@@ -9,3 +9,7 @@
var/fakediablerist = FALSE
var/can_be_embraced = TRUE
+ //stats for combat bites // used for lupus, crinos, hispo, fomori, etc.
+ var/list/combat_bite_damages = list(BRUTE = 1 LETHAL_TTRPG_DAMAGE, BURN = 0, TOX = 0, OXY = 0, AGGRAVATED = 0)
+ var/list/combat_bite_stats = list(STAT_DEXTERITY, STAT_BRAWL)
+ var/list/combat_bite_difficulty = 5
diff --git a/modular_darkpack/master_files/code/modules/mob/living/carbon/examine.dm b/modular_darkpack/master_files/code/modules/mob/living/carbon/examine.dm
index 94b43988b00d..f6be2da4a8cd 100644
--- a/modular_darkpack/master_files/code/modules/mob/living/carbon/examine.dm
+++ b/modular_darkpack/master_files/code/modules/mob/living/carbon/examine.dm
@@ -57,6 +57,16 @@
if(HAS_TRAIT(src, TRAIT_ANIMAL_MUSK))
. += span_warning("[p_they(TRUE)] smell[p_s()] weirdly animal like...
")
+ if(HAS_TRAIT(src, TRAIT_FOMORI_STIGMATA))
+ var/datum/splat/werewolf/dog = get_werewolf_splat(user)
+ var/datum/quirk/darkpack/stigmata_of_the_wyrm/stigmata = get_quirk(/datum/quirk/darkpack/stigmata_of_the_wyrm)
+ var/stigmata_descriptor = stigmata.examine_print
+
+ if(dog.tribe?.name == TRIBE_BLACK_SPIRAL_DANCERS || get_fomori_splat(user))
+ . += span_warning("[p_They()] bear[p_s()] the Stigmata of the Wyrm, manifesting as [stigmata_descriptor].
")
+ else
+ . += span_warning("[p_They()] [p_have()] [stigmata_descriptor].
")
+
if(!(obscured_slots & HIDEFACE))
switch(st_get_stat(STAT_APPEARANCE))
if(0)
diff --git a/modular_darkpack/modules/blood_drinking/code/bite_keybinding.dm b/modular_darkpack/modules/blood_drinking/code/bite_keybinding.dm
index 39fcf252ca67..9c12cfa95be8 100644
--- a/modular_darkpack/modules/blood_drinking/code/bite_keybinding.dm
+++ b/modular_darkpack/modules/blood_drinking/code/bite_keybinding.dm
@@ -12,6 +12,9 @@
if(ishuman(user.mob))
var/mob/living/carbon/human/human_user = user.mob
- human_user.vamp_bite()
+ if(HAS_TRAIT(human_user, TRAIT_COMBAT_BITE))
+ human_user.combat_bite()
+ else
+ human_user.vamp_bite()
return TRUE
diff --git a/modular_darkpack/modules/blood_drinking/code/combat_bite.dm b/modular_darkpack/modules/blood_drinking/code/combat_bite.dm
new file mode 100644
index 000000000000..8b6cc4fb605a
--- /dev/null
+++ b/modular_darkpack/modules/blood_drinking/code/combat_bite.dm
@@ -0,0 +1,71 @@
+// Thanks to @hex37 for most of this
+/**
+ * Biting for purposes other than drinking blood
+ *
+ * Arguments:
+ * * pulling - The mob we're biting
+ * * damage_type - What kind of damage we're doing as a list. If blank, grabs from vars. (ex. list(BRUTE = 0, BURN = 0, TOX = 0, OXY = 0, AGGRAVATED = 0))
+ */
+/mob/living/carbon/proc/combat_bite(list/damage_types)
+ if(!COOLDOWN_FINISHED(src, drinkblood_use_cd) || !COOLDOWN_FINISHED(src, drinkblood_click_cd))
+ return
+ COOLDOWN_START(src, drinkblood_click_cd, 1 SECONDS)
+ if(!damage_types)
+ damage_types = combat_bite_damages
+
+ var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
+ if(skipface)
+ to_chat(src, span_warning("Take your mask off first!"))
+ return
+
+ if(grab_state > GRAB_PASSIVE)
+ if(isliving(pulling))
+ var/mob/living/bit_living = pulling
+ visible_message(span_warning("[src] starts biting [bit_living] with [p_their()] sharp teeth!"), span_warning("You start biting [bit_living] with your sharp teeth!"), span_warning("You hear the sound of flesh tearing!"))
+ bit_living.emote("scream")
+ if(ishuman(bit_living))
+ var/mob/living/carbon/human/bit_human = bit_living
+ bit_human.add_bite_animation()
+
+ do_combat_bite(bit_living, damage_types, TRUE)
+
+/mob/living/carbon/proc/do_combat_bite(mob/living/chewed_on, list/damage_types, first_bite = FALSE)
+
+ COOLDOWN_START(src, drinkblood_use_cd, 3 SECONDS)
+
+ if(isnpc(chewed_on))
+ var/mob/living/carbon/human/npc/NPC = chewed_on
+ NPC.danger_source = null
+ chewed_on.Stun(10) // NPCs can't resist right away
+
+ if(chewed_on.health < (values_sum(damage_types)*1.5))
+ to_chat(src, span_userdanger("Your victim is near death."))
+
+ if(!do_after(src, 2 SECONDS, target = chewed_on, timed_action_flags = NONE, progress = FALSE))
+ stop_chewing(chewed_on)
+ return
+
+ if(iscarbon(chewed_on))
+ var/mob/living/carbon/chewtoy = chewed_on
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/damage/bite
+ roll_datum.difficulty = combat_bite_difficulty
+ var/roll_result = roll_datum.st_roll(src, chewtoy)+1
+ if(roll_result)
+ for(var/damage_type, damage_amount in damage_types)
+ if(roll_result > 0)
+ chewtoy.apply_damage((damage_amount*roll_result), damage_type, sharpness = SHARP_POINTY)
+ playsound(get_turf(src), 'sound/items/weapons/bite.ogg', 50, TRUE)
+
+ if(chewtoy.reagents) // We might ingest some blood on accident
+ if(length(chewtoy.reagents.reagent_list))
+ if(prob(15)) // We might ingest some blood on accident
+ chewtoy.reagents.trans_to(src, min(10, chewtoy.reagents.total_volume), transferred_by = chewed_on, methods = INGEST)
+
+ if(grab_state > GRAB_PASSIVE)
+ stop_sound_channel(CHANNEL_BLOOD)
+ do_combat_bite(chewed_on, damage_types)
+
+/mob/living/carbon/proc/stop_chewing()
+ stop_sound_channel(CHANNEL_BLOOD)
+ COOLDOWN_RESET(src, drinkblood_use_cd)
+ return
diff --git a/modular_darkpack/modules/blood_drinking/code/movable_screens/drinkblood_hud.dm b/modular_darkpack/modules/blood_drinking/code/movable_screens/drinkblood_hud.dm
index 594c1e6205b8..78ce63ff6242 100644
--- a/modular_darkpack/modules/blood_drinking/code/movable_screens/drinkblood_hud.dm
+++ b/modular_darkpack/modules/blood_drinking/code/movable_screens/drinkblood_hud.dm
@@ -10,4 +10,7 @@
/atom/movable/screen/drinkblood/proc/bite()
if(ishuman(usr))
var/mob/living/carbon/human/human_user = usr
- human_user.vamp_bite()
+ if(HAS_TRAIT(human_user, TRAIT_COMBAT_BITE))
+ human_user.combat_bite()
+ else
+ human_user.vamp_bite()
diff --git a/modular_darkpack/modules/fomori/README.md b/modular_darkpack/modules/fomori/README.md
new file mode 100644
index 000000000000..2dac2a5c9c9c
--- /dev/null
+++ b/modular_darkpack/modules/fomori/README.md
@@ -0,0 +1,25 @@
+https://github.com/DarkPack13/SecondCity/pull/953
+
+## \
+
+Module ID: FOMORI
+
+### Description:
+
+This module handles everything related to Fomori and their Powers, Taints, and Merits/Flaws. Dependent on BLOOD_DRINKING for the Combat Bite code.
+
+### TG Proc/File Changes:
+
+### Modular Overrides:
+
+### Defines:
+
+- N/A
+
+### Included files that are not contained in this module:
+
+- modular_darkpack/modules/blood_drinking/code/combat_bite.dm
+
+### Credits:
+
+dwinters99 (code), Major00 (sprites), Minzeyes (sprites) ((BLOCK PR IF THIS WARNING IS STILL HERE)), FalloutFallcon (troubleshooting), Chazzyjazzy (for gargoyle wings), hex37 (for blood-drinking code)
diff --git a/modular_darkpack/modules/fomori/code/positive_quirks/stigmata_of_the_wyrm.dm b/modular_darkpack/modules/fomori/code/positive_quirks/stigmata_of_the_wyrm.dm
new file mode 100644
index 000000000000..78d69ccda64d
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/positive_quirks/stigmata_of_the_wyrm.dm
@@ -0,0 +1,56 @@
+/datum/quirk/darkpack/stigmata_of_the_wyrm
+ name = "Stigmata of the Wyrm"
+ desc = {"You have undergone some immense test or trial after total and complete devotion to the Wyrm,
+ leaving you with some kind of bodily mark that is known to other servants of the Wyrm."}
+ value = 4
+ mob_trait = TRAIT_FOMORI_STIGMATA
+ gain_text = span_notice("You feel respected by servants of the Wyrm.")
+ lose_text = span_notice("You feel forsaken by servants of the Wyrm.")
+ icon = FA_ICON_STRIKETHROUGH
+ allowed_splats = list(SPLAT_FOMORI)
+ failure_message = "You feel forsaken by servants of the Wyrm."
+ var/stigmata // String which effects examine text
+ var/examine_print
+
+/datum/quirk/darkpack/stigmata_of_the_wyrm/add(client/client_source)
+ // add runs before add_unique so we rely on it to decide
+ if(!stigmata)
+ stigmata = client_source?.prefs.read_preference(/datum/preference/choiced/stigmata_of_the_wyrm)
+
+/datum/quirk/darkpack/stigmata_of_the_wyrm/add_unique(client/client_source)
+ switch(stigmata)
+ if("scars on palms")
+ examine_print = "scars on the center of [p_their()] palms"
+ if("forked tongue")
+ examine_print = "a forked tongue"
+ if("hypnotic tattoos")
+ examine_print = "tattoos that make your head spin"
+ if("always-open eyes")
+ examine_print = "eyes that haven't blinked since you've been looking"
+ if("brand burns")
+ examine_print = "burns like that of a cattle brand"
+
+/datum/quirk_constant_data/stigmata_of_the_wyrm_choice
+ associated_typepath = /datum/quirk/darkpack/stigmata_of_the_wyrm
+ customization_options = list(/datum/preference/choiced/stigmata_of_the_wyrm)
+
+/datum/preference/choiced/stigmata_of_the_wyrm
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "stigmata_of_the_wyrm"
+ savefile_identifier = PREFERENCE_CHARACTER
+
+/datum/preference/choiced/stigmata_of_the_wyrm/init_possible_values()
+ return list("scars on palms", "forked tongue", "hypnotic tattoos", "always-open eyes", "brand burns")
+
+/datum/preference/choiced/stigmata_of_the_wyrm/create_default_value()
+ return "scars on palms"
+
+/datum/preference/choiced/stigmata_of_the_wyrm/is_accessible(datum/preferences/preferences)
+ . = ..()
+ if (!.)
+ return FALSE
+
+ return /datum/quirk/darkpack/stigmata_of_the_wyrm::name in preferences.all_quirks
+
+/datum/preference/choiced/stigmata_of_the_wyrm/apply_to_human(mob/living/carbon/human/target, value)
+ return
diff --git a/modular_darkpack/modules/fomori/code/powers/_fomori_power.dm b/modular_darkpack/modules/fomori/code/powers/_fomori_power.dm
new file mode 100644
index 000000000000..13daa2f6edf9
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/_fomori_power.dm
@@ -0,0 +1,64 @@
+// Presently a dummy placeholder, might want to do stuff like flavor the ui, change the dice roll, make fomori_powers private by default or the like
+/datum/storyteller_roll/fomori_power
+
+/datum/action/cooldown/power/fomori_power
+ background_icon = 'modular_darkpack/modules/fomori/icons/fomori_abilities.dmi'
+ background_icon_state = "bg_fomori_power"
+ button_icon = 'modular_darkpack/modules/fomori/icons/fomori_abilities.dmi'
+ //button_icon_state = ""
+ overlay_icon = 'modular_darkpack/modules/fomori/icons/fomori_abilities.dmi'
+
+ check_flags = AB_CHECK_IMMOBILE|AB_CHECK_CONSCIOUS
+
+ // Snowflake toggle behavior
+ var/deployed = FALSE
+
+ // Body feature for horns, fangs, etc.
+ var/datum/bodypart_overlay/simple/fomor_part
+ // What bodypart are we putting our feature on?
+ var/feature_bodypart = BODY_ZONE_HEAD
+
+ // What organ are we adding?
+ var/obj/item/organ/fomor_organ
+ // Where are we inserting it?
+ var/fomor_organ_slot
+
+/atom/movable/screen/alert/status_effect/fomori_power
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_abilities.dmi'
+ icon_state = "bg_fomori_power"
+ overlay_icon = 'modular_darkpack/modules/fomori/icons/fomori_abilities.dmi'
+
+
+///checks if we lose a limb a feature is attached to
+/datum/action/cooldown/power/fomori_power/proc/on_removed_limb(datum/source, obj/item/bodypart/removed_limb, special, dismembered)
+ SIGNAL_HANDLER
+
+ var/mob/living/carbon/human/carbon_owner = astype(owner, /mob/living/carbon)
+ var/obj/item/bodypart/bodypart = carbon_owner.get_bodypart(feature_bodypart)
+
+ if(fomor_part && istype(removed_limb, bodypart.type))
+ remove_feature()
+
+///for adding fomor features i.e. fangs, horns
+/datum/action/cooldown/power/fomori_power/proc/add_feature()
+ var/mob/living/carbon/human/fomor = owner
+ var/obj/item/bodypart/bodypart = fomor?.get_bodypart(feature_bodypart)
+ if(isnull(bodypart))
+ return
+ fomor_part = new fomor_part() //creates our overlay
+ bodypart.add_bodypart_overlay(fomor_part)
+
+///removes the fomor feature
+/datum/action/cooldown/power/fomori_power/proc/remove_feature()
+ var/mob/living/carbon/human/fomor = owner
+ var/obj/item/bodypart/bodypart = fomor?.get_bodypart(feature_bodypart)
+ bodypart?.remove_bodypart_overlay(fomor_part)
+ QDEL_NULL(fomor_part)
+ fomor_part = initial(fomor_part)
+
+///toggles the feature, TRUE for remove and FALSE for add
+/datum/action/cooldown/power/fomori_power/proc/toggle_feature(current_state)
+ if(current_state)
+ remove_feature()
+ else
+ add_feature()
diff --git a/modular_darkpack/modules/fomori/code/powers/_fomori_power_weapon.dm b/modular_darkpack/modules/fomori/code/powers/_fomori_power_weapon.dm
new file mode 100644
index 000000000000..97883e7f6b14
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/_fomori_power_weapon.dm
@@ -0,0 +1,46 @@
+/datum/action/cooldown/power/fomori_power/weapon
+ name = "fomor weapon power"
+ desc = "Report on github if you see this!"
+ cooldown_time = 1 TURNS // Can't sheathe/unsheathe for at least 5 seconds after use
+
+ shared_cooldown = MOB_SHARED_COOLDOWN_2
+
+ var/sheathe_text = "Your skub melts back into your skin."
+
+ var/weapon_type = /obj/item/skub
+ var/unsheathe_sound = 'sound/effects/blob/blobattack.ogg'
+ var/sheathe_sound = 'sound/effects/meatslap.ogg'
+
+/datum/action/cooldown/power/fomori_power/weapon/Activate(atom/target)
+ var/obj/item/held = owner.get_active_held_item()
+ var/obj/item/off_held = owner.get_inactive_held_item()
+ if(held && off_held && deployed)
+ qdel(held)
+ qdel(off_held)
+ to_chat(owner, span_warning(sheathe_text))
+ playsound(get_turf(owner), sheathe_sound, 50)
+ deployed = FALSE
+ return
+
+ if(held && !owner.dropItemToGround(held))
+ owner.balloon_alert(owner, "hand occupied!")
+ return FALSE
+ else if(off_held && !owner.dropItemToGround(off_held))
+ owner.balloon_alert(owner, "off-hand occupied!")
+ return FALSE
+
+ . = ..()
+
+ var/obj/item/weapon = new weapon_type(owner)
+ var/obj/item/weapon_offhand = new weapon_type(owner)
+
+ deployed = TRUE
+
+ playsound(get_turf(owner), unsheathe_sound, 50)
+ owner.put_in_l_hand(weapon)
+ owner.put_in_r_hand(weapon_offhand)
+
+
+
+
+
diff --git a/modular_darkpack/modules/fomori/code/powers/mental/berserker.dm b/modular_darkpack/modules/fomori/code/powers/mental/berserker.dm
new file mode 100644
index 000000000000..c9b8180fbc59
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/mental/berserker.dm
@@ -0,0 +1 @@
+// This file is here to hold a place! A placeholder! Need to wait for pointbuy to be implemented for this to exist.
diff --git a/modular_darkpack/modules/fomori/code/powers/mental/corrupted_visions.dm b/modular_darkpack/modules/fomori/code/powers/mental/corrupted_visions.dm
new file mode 100644
index 000000000000..be2c00a85c70
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/mental/corrupted_visions.dm
@@ -0,0 +1,45 @@
+/datum/storyteller_roll/corrupted_visions
+ bumper_text = "corrupted visions"
+ difficulty = 8
+ applicable_stats = list(STAT_MANIPULATION, STAT_SUBTERFUGE)
+ numerical = TRUE
+ roll_output_type = ROLL_PRIVATE
+
+/datum/action/cooldown/power/fomori_power/corrupted_visions
+ name = "Corrupted Visions"
+ desc = "Spend a willpower point to induce hallucinations in your prey."
+ button_icon_state = "corrupted_visions"
+ rank = 1 // of 1
+ click_to_activate = TRUE
+ willpower_cost = 1
+
+/datum/action/cooldown/power/fomori_power/corrupted_visions/Activate(atom/target)
+ if(!isliving(target))
+ return FALSE
+
+ var/mob/living/victim = target
+
+ . = ..()
+
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/corrupted_visions
+ var/roll_result = roll_datum.st_roll(owner)
+
+ to_chat(owner, span_purple("You attempt to induce visions in [target]..."))
+
+ SEND_SOUND(owner, 'modular_darkpack/modules/deprecated/sounds/insanity.ogg')
+ SEND_SOUND(victim, 'modular_darkpack/modules/deprecated/sounds/insanity.ogg')
+
+
+ if(roll_result > 0)
+ if(!victim.has_quirk(/datum/quirk/darkpack/derangement))
+ victim.add_quirk(/datum/quirk/darkpack/derangement)
+ addtimer(CALLBACK(src, PROC_REF(end_visions), victim), roll_result TURNS)
+ else
+ to_chat(owner, span_warning("[victim] doesn't seem bothered by their visions..."))
+ to_chat(victim, span_hypnophrase("The FREAK attempts to disturb the disturbed..."))
+
+ StartCooldown()
+ return TRUE
+
+/datum/action/cooldown/power/fomori_power/corrupted_visions/proc/end_visions(mob/living/victim)
+ victim.remove_quirk(/datum/quirk/darkpack/derangement)
diff --git a/modular_darkpack/modules/fomori/code/powers/mental/deception.dm b/modular_darkpack/modules/fomori/code/powers/mental/deception.dm
new file mode 100644
index 000000000000..5776876b12a5
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/mental/deception.dm
@@ -0,0 +1,31 @@
+/datum/storyteller_roll/deception
+ bumper_text = "deception"
+ difficulty = 8
+ applicable_stats = list(STAT_WITS, STAT_SUBTERFUGE)
+ numerical = TRUE
+ roll_output_type = ROLL_PRIVATE
+
+/datum/action/cooldown/power/fomori_power/deception
+ name = "Deception"
+ desc = "Spend a willpower point to disguise your taint from those capable of percieving it."
+ button_icon_state = "deception"
+ rank = 1 // of 1
+ click_to_activate = TRUE
+ willpower_cost = 1
+
+/datum/action/cooldown/power/fomori_power/deception/Activate(atom/target)
+ if(!isliving(target))
+ return FALSE
+ if(!(target in range(1, owner)))
+ return FALSE
+
+ var/mob/living/victim = target
+
+ . = ..()
+
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/deception
+ var/roll_result = roll_datum.st_roll(owner)
+
+ StartCooldown()
+ return TRUE
+#warn DECEPTION UNFINISHED
diff --git a/modular_darkpack/modules/fomori/code/powers/mental/eyes_of_the_wyrm.dm b/modular_darkpack/modules/fomori/code/powers/mental/eyes_of_the_wyrm.dm
new file mode 100644
index 000000000000..05bfe0264055
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/mental/eyes_of_the_wyrm.dm
@@ -0,0 +1,33 @@
+/datum/storyteller_roll/eyes_of_the_wyrm // For defending
+ bumper_text = "eyes_of_the_wyrm"
+ difficulty = 8
+ applicable_stats = list(STAT_TEMPORARY_WILLPOWER)
+ roll_output_type = ROLL_PRIVATE
+
+/datum/action/cooldown/power/fomori_power/eyes_of_the_wyrm
+ name = "Eyes of the Wyrm"
+ desc = "(UNFINISHED) Shock your prey into immobility with the Wyrm's Damnation."
+ button_icon_state = "eyes_of_the_wyrm"
+ rank = 1 // of 1
+ click_to_activate = TRUE
+ willpower_cost = 1
+
+/datum/action/cooldown/power/fomori_power/eyes_of_the_wyrm/Activate(atom/target)
+ if(!isliving(target))
+ return FALSE
+ if(!(target in range(1, owner)))
+ return FALSE
+
+ var/mob/living/victim = target
+
+ . = ..()
+
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/eyes_of_the_wyrm
+ var/roll_result = roll_datum.st_roll(victim)
+
+ if(roll_result != ROLL_SUCCESS)
+
+ StartCooldown()
+ return TRUE
+
+#warn EYES OF THE WYRM UNFINISHED
diff --git a/modular_darkpack/modules/fomori/code/powers/mental/mind_blast.dm b/modular_darkpack/modules/fomori/code/powers/mental/mind_blast.dm
new file mode 100644
index 000000000000..24c3b82842fd
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/mental/mind_blast.dm
@@ -0,0 +1,57 @@
+/obj/item/ammo_casing/magic/fomor_mind_blast
+ projectile_type = /obj/projectile/mind_blast
+ icon_state = ""
+
+/obj/projectile/mind_blast
+ name = "mind blast"
+ icon_state = "scatterdisabler" // Could prob get a better icon for this
+ damage = 0
+ alpha = 128
+
+/datum/storyteller_roll/mind_blast
+ bumper_text = "mind blast"
+ difficulty = 6
+ applicable_stats = list(STAT_WITS, STAT_INTIMIDATION)
+ numerical = TRUE
+ roll_output_type = ROLL_PRIVATE
+
+/datum/storyteller_roll/mind_blast/defender
+ bumper_text = "willpower"
+ applicable_stats = list(STAT_TEMPORARY_WILLPOWER)
+ numerical = TRUE
+
+/datum/action/cooldown/power/fomori_power/mind_blast
+ name = "Mind Blast"
+ desc = "Spend a willpower point to shock the mind of a victim."
+ button_icon_state = "mind_blast"
+ rank = 1 // of 1
+ click_to_activate = TRUE
+ willpower_cost = 1
+
+/datum/action/cooldown/power/fomori_power/mind_blast/Activate(atom/target)
+ if(!isliving(target))
+ return FALSE
+
+ var/mob/living/victim = target
+
+ . = ..()
+
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/mind_blast
+ var/ourpower = roll_datum.st_roll(owner)
+
+ var/datum/storyteller_roll/defender_datum = new /datum/storyteller_roll/mind_blast/defender
+ var/theirpower = defender_datum.st_roll(target)
+
+
+ if(ourpower > theirpower)
+ var/obj/item/ammo_casing/magic/fomor_mind_blast/casing = new (owner.loc)
+ casing.fire_casing(victim, owner, null, null, null, ran_zone(), 0, owner)
+ if(ishuman(victim))
+ victim.emote("groan")
+
+ victim.Stun((ourpower TURNS)) // TODO: Make this an actual skillshot
+
+ StartCooldown()
+ return TRUE
+
+
diff --git a/modular_darkpack/modules/fomori/code/powers/mental/mind_reave.dm b/modular_darkpack/modules/fomori/code/powers/mental/mind_reave.dm
new file mode 100644
index 000000000000..6b4767b25a20
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/mental/mind_reave.dm
@@ -0,0 +1,80 @@
+/datum/storyteller_roll/mind_reave
+ bumper_text = "mind reave"
+ difficulty = 6
+ applicable_stats = list(STAT_INTELLIGENCE, STAT_INTIMIDATION)
+ numerical = TRUE
+ roll_output_type = ROLL_PRIVATE
+
+/datum/storyteller_roll/mind_reave/defender
+ bumper_text = "willpower"
+ applicable_stats = list(STAT_TEMPORARY_WILLPOWER)
+ numerical = FALSE
+ roll_output_type = ROLL_NONE
+
+/datum/action/cooldown/power/fomori_power/mind_reave
+ name = "Mind Reave"
+ desc = "Spend a willpower point to rest thoughts and memories from a victim's mind."
+ button_icon_state = "mind_reave"
+ rank = 1 // of 1
+ click_to_activate = TRUE
+ willpower_cost = 1
+
+/datum/action/cooldown/power/fomori_power/mind_reave/Activate(atom/target)
+ if(!isliving(target))
+ return FALSE
+
+ var/mob/living/victim = target
+
+ . = ..()
+
+ to_chat(owner, span_warning("You begin to probe into the mind of [victim]..."))
+
+ if(!do_after(owner, 1 TURNS, victim))
+ to_chat(owner, span_userdanger("...but you stop short of getting anything out of it."))
+
+ StartCooldown()
+ return TRUE
+
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/mind_reave
+ var/ourpower = roll_datum.st_roll(owner)
+
+ var/datum/storyteller_roll/defender_datum = new /datum/storyteller_roll/mind_reave/defender
+ var/theirpower = defender_datum.st_roll(owner)
+
+
+ if(ourpower > theirpower)
+ to_chat(victim, span_userdanger("You feel your mind being ravaged by malignant energy!"))
+ SEND_SOUND(victim, sound('sound/effects/magic/clockwork/invoke_general.ogg', volume = 50))
+
+ var/successes = ourpower - theirpower
+ var/demand_text
+
+ switch(successes)
+ if(1)
+ demand_text = "surface level thoughts such as emotions or current thoughts"
+ if(2)
+ demand_text = "deep thoughts like recent memories or strong opinions"
+ if(3 to INFINITY)
+ demand_text = "your deepest and most instinctual thoughts, feelings, or secrets"
+
+ var/composed_message = "The malignant energy probing your mind reaches for [demand_text]. What does it learn?"
+
+ var/input_text = tgui_input_text(victim, composed_message, "Mind Reave", CHAT_MESSAGE_MAX_LENGTH, multiline = TRUE, timeout = 30 SECONDS)
+ victim.Stun(30 SECONDS, TRUE)
+
+ message_admins("[ADMIN_LOOKUPFLW(owner)] used [src] on [ADMIN_LOOKUPFLW(victim)] with [successes] successes.")
+
+ if(input_text)
+ message_admins("[ADMIN_LOOKUPFLW(victim)] responded to [ADMIN_LOOKUPFLW(owner)]'s Mind Reave: \"[input_text]\".")
+ to_chat(owner, span_bolddanger("Your power wrests the following information from [victim]: \"[input_text]\""))
+ to_chat(owner, span_bolddanger("Your feel your mind surrender the following information to [owner]: \"[input_text]\""))
+ victim.SetStun(1 TURNS)
+ else
+ message_admins("[ADMIN_LOOKUPFLW(victim)] failed or declined to respond to [ADMIN_LOOKUPFLW(owner)]'s Mind Reave.")
+ to_chat(owner, span_userdanger("[victim]'s mind buckles under the pressure of your mental energy!"))
+ to_chat(victim, span_userdanger("Your mind buckles under the pressure of [owner]'s mental energy!"))
+ victim.Sleeping(30 SECONDS)
+
+ StartCooldown()
+ return TRUE
+#warn MIND REAVE NEEDS 2 CLIENT TESTING
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/body_barbs.dm b/modular_darkpack/modules/fomori/code/powers/physical/body_barbs.dm
new file mode 100644
index 000000000000..9700c1e025f9
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/body_barbs.dm
@@ -0,0 +1,67 @@
+/obj/item/melee/body_barbs // Largely copied from changeling armblade
+ name = "body barb"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_items48x32.dmi'
+ icon_state = "body_barb"
+ inhand_icon_state = "body_barb"
+ lefthand_file = 'modular_darkpack/modules/fomori/icons/fomori_inhand_left.dmi'
+ righthand_file = 'modular_darkpack/modules/fomori/icons/fomori_inhand_right.dmi'
+ item_flags = ABSTRACT | DROPDEL
+ w_class = WEIGHT_CLASS_HUGE
+ force = 40 // Identical to Machete
+ throwforce = 0
+ throw_range = 0
+ throw_speed = 0
+ hitsound = 'sound/items/weapons/bladeslice.ogg'
+ wound_bonus = 10
+ exposed_wound_bonus = 10
+ armour_penetration = 35
+ attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts")
+ attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut")
+ sharpness = SHARP_EDGED
+ wound_bonus = 10
+ exposed_wound_bonus = 10
+ armour_penetration = 35
+ var/list/alt_continuous = list("stabs", "pierces", "impales")
+ var/list/alt_simple = list("stab", "pierce", "impale")
+
+ abstract_type = /obj/item/melee/body_barbs
+
+/obj/item/melee/body_barbs/Initialize(mapload,silent) // Largely copied from changeling armblade
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, INNATE_TRAIT)
+ alt_continuous = string_list(alt_continuous)
+ alt_simple = string_list(alt_simple)
+ AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5)
+ AddComponent(/datum/component/butchering, \
+ speed = 6 SECONDS, \
+ effectiveness = 80, \
+ )
+
+/datum/action/cooldown/power/fomori_power/weapon/body_barbs
+ name = "Body Barbs"
+ desc = "Use the grotesque spikes on your body to amplify your brawling ability."
+ button_icon_state = "body_barbs"
+ rank = 1 // of 5 // Determines how many extra dice we get, 2 points and 1 dice/level
+ weapon_type = /obj/item/melee/body_barbs
+ sheathe_text = "Your body barbs retract into your arms."
+
+/datum/action/cooldown/power/fomori_power/weapon/body_barbs/Activate(atom/target)
+ . = ..()
+ if(deployed)
+ owner.visible_message(span_warning("A pair of grotesque barbs extend from [owner]\'s arms!"), \
+ span_warning("Your body barbs extend from your arms."), \
+ span_hear("You hear organic matter ripping and tearing!"))
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
+
+/datum/action/cooldown/power/fomori_power/weapon/body_barbs/two
+ rank = 2
+
+/datum/action/cooldown/power/fomori_power/weapon/body_barbs/three
+ rank = 3
+
+/datum/action/cooldown/power/fomori_power/weapon/body_barbs/four
+ rank = 4
+/datum/action/cooldown/power/fomori_power/weapon/body_barbs/five
+ rank = 5
+
+#warn BODY BARBS UNFINISHED - Need to factor rank into damage
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/chameleon_coloration.dm b/modular_darkpack/modules/fomori/code/powers/physical/chameleon_coloration.dm
new file mode 100644
index 000000000000..702373827d53
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/chameleon_coloration.dm
@@ -0,0 +1,50 @@
+/datum/action/cooldown/power/fomori_power/chameleon_coloration
+ name = "Chameleon Coloration"
+ desc = "Blend into the background to strike unseen."
+ button_icon_state = "chameleon_coloration"
+ rank = 1 // of 1
+
+ var/activated = FALSE
+
+/datum/action/cooldown/power/fomori_power/chameleon_coloration/Activate(atom/target)
+ . = ..()
+ if(activated)
+ activated = FALSE
+ owner.alpha = 255
+ UnregisterSignal(owner, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_UNARMED_ATTACK))
+ else
+ activated = TRUE
+ RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
+ RegisterSignal(owner, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_attack_hand))
+ var/mob/living/living_owner = astype(owner)
+ living_owner.apply_status_effect(/datum/status_effect/chameleon_coloration)
+
+/datum/action/cooldown/power/fomori_power/chameleon_coloration/proc/on_move(atom/movable/source, atom/old_loc, move_dir, forced, list/atom/old_locs)
+ SIGNAL_HANDLER
+
+ owner.alpha = 200
+
+/datum/action/cooldown/power/fomori_power/chameleon_coloration/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, list/modifiers)
+ SIGNAL_HANDLER
+
+ if(!proximity)
+ return
+ owner.alpha = 200
+
+/datum/status_effect/chameleon_coloration
+ id = "chameleon_coloration"
+ duration = INFINITY
+
+ status_type = STATUS_EFFECT_UNIQUE
+
+ alert_type = /atom/movable/screen/alert/status_effect/chameleon_coloration
+
+/datum/status_effect/chameleon_coloration/tick(seconds_per_tick)
+ . = ..()
+ owner.alpha = max(owner.alpha - 50, 0) // TODO: use animate magic to make this look better
+
+/atom/movable/screen/alert/status_effect/chameleon_coloration
+ name = "Chameleon Coloration"
+ desc = "You are blending in with your surroundings."
+ icon = 'modular_darkpack/modules/deprecated/icons/hud/screen_alert.dmi'
+ icon_state = "riddle" // TODO: get an icon for this
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/claws.dm b/modular_darkpack/modules/fomori/code/powers/physical/claws.dm
new file mode 100644
index 000000000000..cc662612d5fe
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/claws.dm
@@ -0,0 +1,39 @@
+/obj/item/knife/fomor_claws // Just a normal knife, but part of our hands!
+ name = "claw"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_items48x32.dmi'
+ icon_state = "claw"
+ inhand_icon_state = "claw"
+ lefthand_file = 'modular_darkpack/modules/fomori/icons/fomori_inhand_left.dmi'
+ righthand_file = 'modular_darkpack/modules/fomori/icons/fomori_inhand_right.dmi'
+ icon_angle = 0
+ item_flags = ABSTRACT | DROPDEL
+ w_class = WEIGHT_CLASS_HUGE
+ throwforce = 0
+ throw_speed = 0
+ throw_range = 0
+
+ abstract_type = /obj/item/knife/fomor_claws
+
+/obj/item/knife/fomor_claws/Initialize(mapload,silent) // Largely copied from changeling armblade
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, INNATE_TRAIT)
+ AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple, -5)
+
+/datum/action/cooldown/power/fomori_power/weapon/claws
+ name = "Claws"
+ desc = "Use the grotesque claws on your hands to slice and dice."
+ button_icon_state = "claws"
+ rank = 1 // of 1
+ weapon_type = /obj/item/knife/fomor_claws
+ unsheathe_sound = 'sound/items/weapons/parry.ogg'
+ sheathe_text = "Your claws retract into your arms."
+
+/datum/action/cooldown/power/fomori_power/weapon/claws/Activate(atom/target)
+ . = ..()
+ if(deployed)
+ owner.visible_message(span_warning("A pair of grotesque claws extend from [owner]\'s hands!"), \
+ span_warning("Your claws extend from your hands."), \
+ span_hear("You hear organic matter ripping and tearing!"))
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
+
+#warn CLAWS SOFT FINISHED - Needs melee damage stats
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/darksight.dm b/modular_darkpack/modules/fomori/code/powers/physical/darksight.dm
new file mode 100644
index 000000000000..221f08b32383
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/darksight.dm
@@ -0,0 +1,34 @@
+/datum/action/cooldown/power/fomori_power/darksight // TODO: Make this work with more light sources
+ name = "Darksight"
+ desc = "See in the dark unbidden, but beware bright lights."
+ button_icon_state = "darksight"
+ rank = 1 // of 1
+
+ check_flags = AB_CHECK_CONSCIOUS
+ cooldown_time = 1 SECONDS // So we don't click too fast
+
+ var/activated = FALSE
+
+/datum/action/cooldown/power/fomori_power/darksight/Activate(atom/target)
+ . = ..()
+ to_chat(owner, span_notice("You [activated ? "activate" : "deactivate"] Darksight."))
+ if(activated)
+ activated = FALSE
+ REMOVE_TRAIT(owner, TRAIT_TRUE_NIGHT_VISION, "fomor_darksight")
+ owner.remove_client_colour("fomor_darksight")
+ UnregisterSignal(owner, COMSIG_MOB_FLASHED, PROC_REF(on_flashed))
+ else
+ activated = TRUE
+ ADD_TRAIT(owner, TRAIT_TRUE_NIGHT_VISION, "fomor_darksight")
+ owner.add_client_colour(/datum/client_colour/monochrome, "fomor_darksight")
+ RegisterSignal(owner, COMSIG_MOB_FLASHED)
+ owner.update_sight()
+
+/datum/action/cooldown/power/fomori_power/darksight/proc/on_flashed()
+ SIGNAL_HANDLER
+
+ var/mob/living/carbon/carbon_owner = owner
+ var/our_perception = carbon_owner.st_get_stat(STAT_PERCEPTION)
+ carbon_owner.Stun(our_perception TURNS) // Stunned 1 TURNS per dot in perception
+ if(our_perception > 1)
+ to_chat(owner, span_userdanger("Your enhanced vision causes you to be stunned for an extra [our_perception] turns!"))
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/ectoplasmic_extrusion.dm b/modular_darkpack/modules/fomori/code/powers/physical/ectoplasmic_extrusion.dm
new file mode 100644
index 000000000000..35096d3fb9b1
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/ectoplasmic_extrusion.dm
@@ -0,0 +1,28 @@
+/datum/bodypart_overlay/simple/ectoplasmic_extrusion
+ icon_state = "ectoplasmic_extrusion"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi'
+ layers = LOW_FACEMASK_LAYER
+
+/datum/action/cooldown/power/fomori_power/weapon/ectoplasmic_extrusion
+ name = "Ectoplasmic Extrusion"
+ desc = "(UNIMPLEMENTED) Sprout grotesque tendrils from your back to use as extra hands or as a weapon."
+ button_icon_state = "ectoplasmic_extrusion"
+ rank = 1 // of 1
+
+// weapon_type = /obj/item/melee/ectoplasmic_extrusion
+ sheathe_text = "Your ectoplasmic tendrils retract into your body."
+
+ fomor_part = /datum/bodypart_overlay/simple/ectoplasmic_extrusion
+ feature_bodypart = BODY_ZONE_CHEST
+
+/datum/action/cooldown/power/fomori_power/horns/Activate(atom/target)
+ . = ..()
+ toggle_feature(deployed)
+
+ if(deployed)
+ deployed = FALSE
+ else
+ deployed = TRUE
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
+
+#warn ECTOPLASMIC EXTRUSION UNFINISHED
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/exoskeleton.dm b/modular_darkpack/modules/fomori/code/powers/physical/exoskeleton.dm
new file mode 100644
index 000000000000..ea27b58b416b
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/exoskeleton.dm
@@ -0,0 +1,95 @@
+/datum/bodypart_overlay/simple/fomor_exoskeleton
+ icon_state = "exoskeleton"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi'
+ layers = BENEATH_HAIR_LAYER
+ var/bodyzone = BODY_ZONE_CHEST
+ var/obj/item/bodypart/assigned_bodyzone
+
+/datum/bodypart_overlay/simple/fomor_exoskeleton/head
+ icon_state = "exoskeleton-head"
+ bodyzone = BODY_ZONE_HEAD
+
+/datum/bodypart_overlay/simple/fomor_exoskeleton/r_arm
+ icon_state = "exoskeleton-r_arm"
+ bodyzone = BODY_ZONE_R_ARM
+ layers = MUTATIONS_LAYER
+
+/datum/bodypart_overlay/simple/fomor_exoskeleton/l_arm
+ icon_state = "exoskeleton-l_arm"
+ bodyzone = BODY_ZONE_L_ARM
+ layers = HALO_LAYER
+
+/datum/bodypart_overlay/simple/fomor_exoskeleton/r_leg
+ icon_state = "exoskeleton-r_leg"
+ bodyzone = BODY_ZONE_R_LEG
+
+/datum/bodypart_overlay/simple/fomor_exoskeleton/l_leg
+ icon_state = "exoskeleton-l_leg"
+ bodyzone = BODY_ZONE_L_LEG
+
+/datum/bodypart_overlay/simple/fomor_fangs/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner, mob/living/carbon/owner, is_husked = FALSE)
+ return ..() && !(bodypart_owner.owner?.obscured_slots & HIDEFACE)
+
+/datum/action/cooldown/power/fomori_power/exoskeleton
+ name = "Exoskeleton"
+ desc = "Form a thick carapace around your body, protecting you from harm and increasing your strength."
+ button_icon_state = "exoskeleton"
+ rank = 1 // of 1
+
+ //Snowflake code
+ var/list/overlay_list = list()
+
+ var/chest_overlay = /datum/bodypart_overlay/simple/fomor_exoskeleton
+ var/head_overlay = /datum/bodypart_overlay/simple/fomor_exoskeleton/head
+ var/r_arm_overlay = /datum/bodypart_overlay/simple/fomor_exoskeleton/r_arm
+ var/l_arm_overlay = /datum/bodypart_overlay/simple/fomor_exoskeleton/l_arm
+ var/r_leg_overlay = /datum/bodypart_overlay/simple/fomor_exoskeleton/r_leg
+ var/l_leg_overlay = /datum/bodypart_overlay/simple/fomor_exoskeleton/l_leg
+
+/datum/action/cooldown/power/fomori_power/exoskeleton/Activate(atom/target)
+ . = ..()
+ var/mob/living/carbon/carbon_owner = astype(owner, /mob/living/carbon)
+
+ toggle_feature(deployed)
+
+ if(deployed)
+ deployed = FALSE
+ carbon_owner.st_remove_stat_mod(STAT_STAMINA, 1, "exoskeleton")
+ carbon_owner.st_remove_stat_mod(STAT_STRENGTH, 1, "exoskeleton")
+ playsound(owner, 'modular_darkpack/modules/powers/sounds/potence_deactivate.ogg', 50)
+ owner.visible_message(span_warning("[owner]'s skin sheds it's thick carapace, returning to a normal state!"), \
+ span_warning("Your skin returns to normal."), \
+ span_hear("You hear organic matter ripping and tearing!"))
+ else
+ deployed = TRUE
+ carbon_owner.st_add_stat_mod(STAT_STAMINA, 1, "exoskeleton")
+ carbon_owner.st_add_stat_mod(STAT_STRENGTH, 1, "exoskeleton")
+ playsound(owner, 'modular_darkpack/modules/powers/sounds/potence_activate.ogg', 50)
+ owner.visible_message(span_warning("[owner]'s skin becomes a thick carapace!"), \
+ span_warning("Your skin forms a thick carapace."), \
+ span_hear("You hear organic matter ripping and tearing!"))
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
+
+///for adding fomor features i.e. fangs, horns
+/datum/action/cooldown/power/fomori_power/exoskeleton/add_feature()
+ var/mob/living/carbon/human/fomor = owner
+
+ overlay_list = list(
+ new chest_overlay, new head_overlay, new r_arm_overlay,
+ new l_arm_overlay, new r_leg_overlay, new l_leg_overlay)
+
+ for(var/datum/bodypart_overlay/simple/fomor_exoskeleton/bp_overlay in overlay_list)
+ bp_overlay.assigned_bodyzone = fomor?.get_bodypart(bp_overlay.bodyzone)
+ if(isnull(bp_overlay.assigned_bodyzone))
+ qdel(bp_overlay)
+ continue
+ bp_overlay.assigned_bodyzone.add_bodypart_overlay(bp_overlay)
+
+///removes the fomor feature
+/datum/action/cooldown/power/fomori_power/exoskeleton/remove_feature()
+ var/mob/living/carbon/human/fomor = owner
+ for(var/datum/bodypart_overlay/simple/fomor_exoskeleton/bp_overlay in overlay_list)
+ bp_overlay.assigned_bodyzone = fomor?.get_bodypart(bp_overlay.bodyzone)
+ bp_overlay.assigned_bodyzone.remove_bodypart_overlay(bp_overlay)
+ qdel(bp_overlay)
+ overlay_list = list()
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/fangs.dm b/modular_darkpack/modules/fomori/code/powers/physical/fangs.dm
new file mode 100644
index 000000000000..b0753f5a8ec1
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/fangs.dm
@@ -0,0 +1,31 @@
+/datum/bodypart_overlay/simple/fomor_fangs
+ icon_state = "fangs"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi'
+ layers = MUTATIONS_LAYER
+
+/datum/bodypart_overlay/simple/fomor_fangs/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner, mob/living/carbon/owner, is_husked = FALSE)
+ return ..() && !(bodypart_owner.owner?.obscured_slots & HIDEFACE)
+
+/datum/action/cooldown/power/fomori_power/fangs
+ name = "Fangs"
+ desc = "Use the grotesque fangs spilling from your mouth to bite your enemies."
+ button_icon_state = "fangs"
+ rank = 1 // of 1
+
+ fomor_part = /datum/bodypart_overlay/simple/fomor_fangs
+
+/datum/action/cooldown/power/fomori_power/fangs/Activate(atom/target)
+ . = ..()
+ var/mob/living/carbon/carbon_owner = astype(owner, /mob/living/carbon)
+ toggle_feature(deployed)
+
+ if(deployed)
+ REMOVE_TRAITS_IN(owner, "fomor_fangs")
+ deployed = FALSE
+ carbon_owner.combat_bite_damages = carbon_owner::combat_bite_damages
+ else
+ ADD_TRAIT(owner, TRAIT_COMBAT_BITE, "fomor_fangs")
+ ADD_TRAIT(owner, TRAIT_MASQUERADE_VIOLATING_FACE, "fomor_fangs")
+ deployed = TRUE
+ carbon_owner.combat_bite_damages = list(BRUTE = 0, BURN = 0, TOX = 0, OXY = 0, AGGRAVATED = 1 TTRPG_DAMAGE)
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/hide_of_the_wyrm.dm b/modular_darkpack/modules/fomori/code/powers/physical/hide_of_the_wyrm.dm
new file mode 100644
index 000000000000..2d0028614403
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/hide_of_the_wyrm.dm
@@ -0,0 +1,49 @@
+/datum/bodypart_overlay/simple/hide_of_the_wyrm
+ icon_state = "hide_of_the_wyrm"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi'
+ layers = EXTERNAL_FRONT
+
+/datum/action/cooldown/power/fomori_power/hide_of_the_wyrm
+ name = "Hide of the Wyrm"
+ desc = "Form a hard, leathery hide around your body, protecting you from harm."
+ button_icon_state = "hide_of_the_wyrm"
+ rank = 1 // of 5
+
+ fomor_part = /datum/bodypart_overlay/simple/hide_of_the_wyrm
+ feature_bodypart = BODY_ZONE_CHEST
+
+ var/datum/status_effect/status_effect_type
+
+/datum/action/cooldown/power/fomori_power/hide_of_the_wyrm/Grant(mob/granted_to)
+ . = ..()
+ switch(rank)
+ if(1)
+ status_effect_type = /datum/status_effect/fortitude/one
+ if(2)
+ status_effect_type = /datum/status_effect/fortitude/two
+ if(3)
+ status_effect_type = /datum/status_effect/fortitude/three
+ if(4)
+ status_effect_type = /datum/status_effect/fortitude/four
+ if(5)
+ status_effect_type = /datum/status_effect/fortitude/one
+
+/datum/action/cooldown/power/fomori_power/hide_of_the_wyrm/Activate(atom/target) // TODO: replace fortitude with soak dice if/when we get it
+ . = ..()
+ var/mob/living/carbon/carbon_owner = astype(owner, /mob/living/carbon)
+
+ toggle_feature(deployed)
+
+ if(deployed)
+ deployed = FALSE
+ owner.visible_message(span_warning("[owner]'s skin is no longer hard and leathery."), \
+ span_warning("Your skin is no longer hard and leathery."))
+ carbon_owner.remove_status_effect(status_effect_type)
+ playsound(owner, 'modular_darkpack/modules/powers/sounds/potence_deactivate.ogg', 50)
+ else
+ deployed = TRUE
+ owner.visible_message(span_warning("[owner]'s skin becomes hard and leathery!"), \
+ span_warning("Your skin becomes hard and leathery."))
+ carbon_owner.apply_status_effect(status_effect_type) // ! if we ever plan on allowing vampiric fomor, give this it's own status effect !
+ playsound(owner, 'modular_darkpack/modules/powers/sounds/potence_activate.ogg', 50)
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/horns.dm b/modular_darkpack/modules/fomori/code/powers/physical/horns.dm
new file mode 100644
index 000000000000..0db8905a72ea
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/horns.dm
@@ -0,0 +1,23 @@
+/datum/bodypart_overlay/simple/fomor_horns
+ icon_state = "horns"
+ icon = 'modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi'
+ layers = LOW_FACEMASK_LAYER
+
+/datum/action/cooldown/power/fomori_power/horns
+ name = "Horns"
+ desc = "(UNIMPLEMENTED) Use the grotesque horns atop your head to gore your enemies."
+ button_icon_state = "horns"
+ rank = 1 // of 1
+
+ fomor_part = /datum/bodypart_overlay/simple/fomor_horns
+
+/datum/action/cooldown/power/fomori_power/horns/Activate(atom/target)
+ . = ..()
+ toggle_feature(deployed)
+
+ if(deployed)
+ deployed = FALSE
+ else
+ deployed = TRUE
+ SEND_SIGNAL(owner, COMSIG_MASQUERADE_VIOLATION)
+#warn HORNS UNFINISHED
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/infectious_touch.dm b/modular_darkpack/modules/fomori/code/powers/physical/infectious_touch.dm
new file mode 100644
index 000000000000..7b522e2d0ffb
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/infectious_touch.dm
@@ -0,0 +1,52 @@
+/datum/storyteller_roll/infectious_touch
+ bumper_text = "infectious touch"
+ difficulty = 7
+ applicable_stats = list(STAT_STAMINA, STAT_MEDICINE)
+ numerical = TRUE
+ roll_output_type = ROLL_PRIVATE
+
+/datum/storyteller_roll/infectious_touch/defender
+ applicable_stats = list(STAT_STAMINA)
+ roll_output_type = ROLL_NONE
+
+/datum/action/cooldown/power/fomori_power/infectious_touch
+ name = "Infectious Touch"
+ desc = "Spend a willpower point to cause an unnatural sickness to set in to your target's body."
+ button_icon_state = "infectious_touch"
+ rank = 1 // of 1
+ click_to_activate = TRUE
+ willpower_cost = 1
+
+/datum/action/cooldown/power/fomori_power/infectious_touch/Activate(atom/target)
+ if(!isliving(target))
+ return
+ if(!(target in range(1, owner)))
+ return
+
+ . = ..()
+ var/mob/living/defender = target
+
+ to_chat(owner, span_warning("You touch [defender], intending to infect them with a grotesque illness..."))
+
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/infectious_touch
+ var/datum/storyteller_roll/roll_datum_defender = new /datum/storyteller_roll/infectious_touch/defender
+ var/our_power = roll_datum.st_roll(owner)
+ var/their_power = roll_datum_defender.st_roll(defender)
+
+ playsound(get_turf(src), 'sound/items/weapons/thudswoosh.ogg', 25, TRUE, -15) // Only hearable in extreme proximity
+
+ if(our_power > their_power)
+ var/net_power = our_power - their_power
+ if(get_vampire_splat(defender))
+ return // Stops just before applying damage without feedback so it's not a splat detector
+
+ addtimer(CALLBACK(src, PROC_REF(infect), target, net_power), 3 TURNS)
+
+ StartCooldown()
+ return TRUE
+
+/datum/action/cooldown/power/fomori_power/infectious_touch/proc/infect(mob/living/target, net_power)
+ target.apply_damage(30*net_power, TOX) // Rules as written it's supposed to be aggravated, but this is better for flavor I think.
+ if(target.stat < DEAD)
+ to_chat(target, span_userdanger("You feel woozy."))
+ SEND_SOUND(target, 'sound/effects/wounds/sizzle2.ogg')
diff --git a/modular_darkpack/modules/fomori/code/powers/physical/regeneration.dm b/modular_darkpack/modules/fomori/code/powers/physical/regeneration.dm
new file mode 100644
index 000000000000..212856839f55
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/powers/physical/regeneration.dm
@@ -0,0 +1,62 @@
+/datum/storyteller_roll/fomor_regeneration
+ bumper_text = "regeneration"
+ difficulty = 6
+ applicable_stats = list(STAT_STAMINA)
+ numerical = FALSE
+ roll_output_type = ROLL_PRIVATE
+
+/datum/action/cooldown/power/fomori_power/regeneration
+ name = "Regeneration"
+ desc = "Recover from your wounds much the same as the bestial Garou do."
+ button_icon_state = "regeneration"
+ rank = 1 // of 1
+
+/datum/action/cooldown/power/fomori_power/regeneration/Grant(mob/granted_to)
+ . = ..()
+ ADD_TRAIT(owner, TRAIT_FOMORI_REGEN, "regeneration")
+
+/datum/action/cooldown/power/fomori_power/regeneration/Activate(atom/target)
+ . = ..()
+ var/datum/storyteller_roll/roll_datum = new /datum/storyteller_roll/fomor_regeneration
+ var/roll_result = roll_datum.st_roll(owner)
+
+ if(roll_result)
+ force_heal()
+
+/datum/action/cooldown/power/fomori_power/regeneration/proc/force_heal()
+ var/mob/living/carbon/carbon_owner = astype(owner, /mob/living/carbon)
+
+ //normal bashing/lethal damage
+ carbon_owner.heal_ordered_damage(30, list(BRUTE, TOX, OXY, STAMINA))
+
+ if(length(carbon_owner.all_wounds))
+ for (var/i in 1 to min(rank, length(carbon_owner.all_wounds)))
+ var/datum/wound/wound = carbon_owner.all_wounds[i]
+ wound.remove_wound()
+
+ //brain damage and traumas healing
+ var/obj/item/organ/brain/brain = carbon_owner.get_organ_slot(ORGAN_SLOT_BRAIN)
+ if (brain)
+ brain.apply_organ_damage(-30)
+
+ for (var/i in 1 to min(rank, length(brain.get_traumas_type())))
+ var/datum/brain_trauma/healing_trauma = pick(brain.get_traumas_type())
+ brain.cure_trauma_type(healing_trauma, resilience = TRAUMA_RESILIENCE_WOUND)
+
+ //miscellaneous organ damage healing
+ var/obj/item/organ/eyes/eyes = carbon_owner.get_organ_slot(ORGAN_SLOT_EYES)
+ if (eyes)
+ eyes.apply_organ_damage(-30)
+
+ carbon_owner.adjust_temp_blindness(-6)
+ carbon_owner.adjust_eye_blur(-6)
+
+ carbon_owner.visible_message(
+ span_warning("[carbon_owner]'s wounds heal with unnatural speed!"),
+ span_warning("Your wounds visibly heal with unnatural speed!"))
+
+ SEND_SIGNAL(carbon_owner, COMSIG_MASQUERADE_VIOLATION)
+
+ //update UI
+ carbon_owner.update_damage_overlays()
+ carbon_owner.update_health_hud()
diff --git a/modular_darkpack/modules/fomori/code/splats/fomori_splat.dm b/modular_darkpack/modules/fomori/code/splats/fomori_splat.dm
new file mode 100644
index 000000000000..abaa4d1dd356
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/splats/fomori_splat.dm
@@ -0,0 +1,72 @@
+/datum/splat/werewolf/fomori
+ name = "Fomori"
+ desc = "Mortals who have lost themselves to the Wyrm's corruption. \
+ A slow death of the self — most do not even realize what has happened to them before the bane takes over completely. \
+ Tools of Dancers, and wretched things to mercifully be slain by Gaians. \
+ You are but another pawn in a scheme older and grander than you could've ever imagined."
+
+ id = SPLAT_FOMORI
+
+ splat_priority = SPLAT_PRIO_FOMORI
+
+ power_type = /datum/action/cooldown/power/fomori_power
+
+ uses_veil = TRUE
+ COOLDOWN_DECLARE(passive_healing_cd)
+
+/datum/splat/werewolf/fomori/splat_life(seconds_per_tick)
+ if(HAS_TRAIT(owner, TRAIT_FOMORI_REGEN))
+ if(COOLDOWN_FINISHED(src, passive_healing_cd))
+ owner.heal_storyteller_health(1, heal_scars = TRUE, heal_blood = TRUE)
+ COOLDOWN_START(src, passive_healing_cd, 1 TURNS)
+
+/mob/living/carbon/human/splat/fomori
+ auto_splats = list(/datum/splat/werewolf/fomori)
+
+/datum/splat/werewolf/fomori/on_gain() // WIP: Will be pointbuy eventually. Don't merge with this code in-tact
+ // PHYSICAL POWERS
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/weapon/body_barbs, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/weapon/claws, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/horns, 1) // unfinished
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/fangs, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/chameleon_coloration, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/darksight, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/exoskeleton, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/regeneration, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/hide_of_the_wyrm, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/infectious_touch, 1) // done
+ // MENTAL POWERS
+// owner.give_st_power(/datum/action/cooldown/power/fomori_power/berserker, 1) // need pointbuy
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/corrupted_visions, 1) // done
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/deception, 1)
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/eyes_of_the_wyrm, 1)
+ owner.give_st_power(/datum/action/cooldown/power/fomori_power/mind_blast, 1) // done
+ owner.give_st_power(/datum/storyteller_roll/mind_reave, 1) // need 2 client testing
+
+
+/datum/splat/werewolf/fomori/get_power(power_type)
+ RETURN_TYPE(/datum/action/cooldown/power/fomori_power)
+
+ for(var/datum/action/cooldown/power/fomori_power/found_action as anything in powers)
+ if(!istype(found_action, power_type))
+ continue
+
+ return found_action
+
+/datum/splat/werewolf/fomori/add_power(power_type, level)
+ // Prevent duplicates
+ if(get_power(power_type))
+ return FALSE
+ var/datum/action/cooldown/power/fomori_power/adding_action = new power_type()
+ adding_action.Grant(owner)
+ LAZYADD(powers, adding_action)
+ return TRUE
+
+/datum/splat/werewolf/fomori/remove_power(power_type)
+ var/datum/action/cooldown/power/fomori_power/found_action = get_power(power_type)
+ if(!found_action)
+ return FALSE
+
+ LAZYREMOVE(powers, found_action)
+ qdel(found_action)
+ return TRUE
diff --git a/modular_darkpack/modules/fomori/code/splats/is_fomori_helpers.dm b/modular_darkpack/modules/fomori/code/splats/is_fomori_helpers.dm
new file mode 100644
index 000000000000..3972705e0b44
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/splats/is_fomori_helpers.dm
@@ -0,0 +1,4 @@
+/proc/get_fomori_splat(mob/character)
+ RETURN_TYPE(/datum/splat/werewolf/fomori)
+
+ return character.get_splat(/datum/splat/werewolf/fomori)
diff --git a/modular_darkpack/modules/fomori/code/splats/pref_lore.dm b/modular_darkpack/modules/fomori/code/splats/pref_lore.dm
new file mode 100644
index 000000000000..bca21bc49910
--- /dev/null
+++ b/modular_darkpack/modules/fomori/code/splats/pref_lore.dm
@@ -0,0 +1,39 @@
+/datum/splat/werewolf/fomori/prepare_human_for_preview(mob/living/carbon/human/human)
+ human.set_haircolor("#554435", update = FALSE)
+ human.set_hairstyle("Boddicker", update = TRUE)
+ human.set_facial_hairstyle("Beard (Seven o Clock Shadow)", update = TRUE)
+ human.set_eye_color("#8281ca")
+ human.undershirt = "Tank Top (White)"
+ human.update_body()
+ human.equipOutfit(/datum/outfit/civillian4, TRUE)
+
+/datum/splat/werewolf/fomori/get_splat_description()
+ return "Mortals who have lost themselves to the Wyrm's corruption. \
+ A slow death of the self — most do not even realize what has happened to them before the bane takes over completely. \
+ Tools of Dancers, and wretched things to mercifully be slain by Gaians. \
+ You are but another pawn in a scheme older and grander than you could've ever imagined."
+
+/datum/splat/werewolf/fomori/get_splat_lore()
+ return list(
+ "The fomori are created when a Bane possesses a human or an animal via a spiritual \"hole\" left by some form of sin or spiritual corruption. The Bane will slowly gain more and more influence, until they are completely fused with the host and cannot be separated.",
+ )
+
+/datum/splat/werewolf/fomori/create_pref_unique_perks()
+ var/list/to_add = list()
+
+ to_add += list(
+ list(
+ SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK,
+ SPECIES_PERK_ICON = FA_ICON_BOOK_DEAD,
+ SPECIES_PERK_NAME = "Bane Possession",
+ SPECIES_PERK_DESC = "Fomori are possessed by spirits called Banes, which imbues them with various powers and taints.",
+ ),
+ list(
+ SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK,
+ SPECIES_PERK_ICON = FA_ICON_CROSSHAIRS,
+ SPECIES_PERK_NAME = "Hunted and Subservient",
+ SPECIES_PERK_DESC = "Fomori are hunted by Gaians and expected to serve the Wyrm.",
+ ),
+ )
+
+ return to_add
diff --git a/modular_darkpack/modules/fomori/icons/fomori_abilities.dmi b/modular_darkpack/modules/fomori/icons/fomori_abilities.dmi
new file mode 100644
index 000000000000..49df90f25bc3
Binary files /dev/null and b/modular_darkpack/modules/fomori/icons/fomori_abilities.dmi differ
diff --git a/modular_darkpack/modules/fomori/icons/fomori_inhand_left.dmi b/modular_darkpack/modules/fomori/icons/fomori_inhand_left.dmi
new file mode 100644
index 000000000000..805605e6f620
Binary files /dev/null and b/modular_darkpack/modules/fomori/icons/fomori_inhand_left.dmi differ
diff --git a/modular_darkpack/modules/fomori/icons/fomori_inhand_right.dmi b/modular_darkpack/modules/fomori/icons/fomori_inhand_right.dmi
new file mode 100644
index 000000000000..71392944059f
Binary files /dev/null and b/modular_darkpack/modules/fomori/icons/fomori_inhand_right.dmi differ
diff --git a/modular_darkpack/modules/fomori/icons/fomori_items48x32.dmi b/modular_darkpack/modules/fomori/icons/fomori_items48x32.dmi
new file mode 100644
index 000000000000..cfa738b7871e
Binary files /dev/null and b/modular_darkpack/modules/fomori/icons/fomori_items48x32.dmi differ
diff --git a/modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi b/modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi
new file mode 100644
index 000000000000..addd7f20a7dc
Binary files /dev/null and b/modular_darkpack/modules/fomori/icons/fomori_sprite_accessories.dmi differ
diff --git a/modular_darkpack/modules/masquerade/code/components/violation_observer.dm b/modular_darkpack/modules/masquerade/code/components/violation_observer.dm
index 50662339f8f6..ea06e61fd2a1 100644
--- a/modular_darkpack/modules/masquerade/code/components/violation_observer.dm
+++ b/modular_darkpack/modules/masquerade/code/components/violation_observer.dm
@@ -67,17 +67,27 @@
source.observe_masquerade_reinforce(player_breacher)
breached_players -= player_breacher
-/atom/proc/observe_masquerade_violation(player_breacher)
+/atom/proc/observe_masquerade_violation(mob/living/player_breacher)
do_alert_animation()
- if(get_werewolf_splat(player_breacher))
+ var/should_use_veil
+ for(var/datum/splat/breacher_splat in player_breacher.splats)
+ if(breacher_splat.uses_veil)
+ should_use_veil = TRUE
+
+ if(should_use_veil)
to_chat(player_breacher, span_userdanger(span_bold("VEIL VIOLATION")))
playsound(player_breacher, 'modular_darkpack/modules/masquerade/sound/veil_violation.ogg', 50, FALSE, -5)
return
playsound(player_breacher, 'modular_darkpack/modules/masquerade/sound/masquerade_violation.ogg', 50, FALSE, -5)
to_chat(player_breacher, span_userdanger(span_bold("MASQUERADE VIOLATION")))
-/atom/proc/observe_masquerade_reinforce(player_breacher)
- if(get_werewolf_splat(player_breacher))
+/atom/proc/observe_masquerade_reinforce(mob/living/player_breacher)
+ var/should_use_veil
+ for(var/datum/splat/breacher_splat in player_breacher.splats)
+ if(breacher_splat.uses_veil)
+ should_use_veil = TRUE
+
+ if(should_use_veil)
to_chat(player_breacher, span_big(span_boldnicegreen("VEIL REINFORCED")))
playsound(player_breacher, 'modular_darkpack/modules/masquerade/sound/humanity_gain.ogg', 50, FALSE, -5)
return
diff --git a/modular_darkpack/modules/splats/code/__splat.dm b/modular_darkpack/modules/splats/code/__splat.dm
index 0791d389f72f..d4bd3f6d5fc2 100644
--- a/modular_darkpack/modules/splats/code/__splat.dm
+++ b/modular_darkpack/modules/splats/code/__splat.dm
@@ -35,6 +35,8 @@
var/splat_biotypes
/// Base type of the powers that this splat has
var/power_type
+ /// Whether or not we use the MASQUERADE or the VEIL
+ var/uses_veil
/// Splats that someone with this splat cannot gain
var/list/incompatible_splats
diff --git a/modular_darkpack/modules/werewolf_the_apocalypse/code/hud.dm b/modular_darkpack/modules/werewolf_the_apocalypse/code/hud.dm
index 0f9059e82980..f0d6139bb779 100644
--- a/modular_darkpack/modules/werewolf_the_apocalypse/code/hud.dm
+++ b/modular_darkpack/modules/werewolf_the_apocalypse/code/hud.dm
@@ -13,7 +13,8 @@
/datum/splat/werewolf/add_relevent_huds(datum/hud/hud_used)
- hud_used.add_werewolf_elements()
+ if(uses_hud)
+ hud_used.add_werewolf_elements()
/atom/movable/screen/auspice
name = "auspice"
diff --git a/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/fera_splat.dm b/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/fera_splat.dm
index b6d6eab37e21..6b612a7cab20 100644
--- a/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/fera_splat.dm
+++ b/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/fera_splat.dm
@@ -4,6 +4,8 @@
power_type = /datum/action/cooldown/power/gift
+ uses_veil = TRUE
+
// Perm is for rolls
// Non-perm/ or temp is for expenditure
var/uses_rage = FALSE
@@ -14,6 +16,8 @@
var/permanent_gnosis = 10
var/gnosis = 0
+ var/uses_hud = FALSE
+
var/list/renown = list()
var/renown_rank = RANK_CUB
@@ -101,6 +105,8 @@
uses_rage = TRUE
uses_gnosis = TRUE
+ uses_hud = TRUE
+
splat_priority = SPLAT_PRIO_SHIFTER
var/list/transformation_list = list()
diff --git a/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/is_werewolf_helpers.dm b/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/is_werewolf_helpers.dm
index 08665939ddf5..e4c47f144655 100644
--- a/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/is_werewolf_helpers.dm
+++ b/modular_darkpack/modules/werewolf_the_apocalypse/code/splats/is_werewolf_helpers.dm
@@ -27,4 +27,3 @@
RETURN_TYPE(/datum/splat/werewolf/kinfolk)
return character.get_splat(/datum/splat/werewolf/kinfolk)
-
diff --git a/tgstation.dme b/tgstation.dme
index a01a0abf082c..b136fbd240b0 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -7143,6 +7143,7 @@
#include "modular_darkpack\modules\bitcoinminer\code\bitcoinminer.dm"
#include "modular_darkpack\modules\blood_drinking\code\bite_helper_procs.dm"
#include "modular_darkpack\modules\blood_drinking\code\bite_keybinding.dm"
+#include "modular_darkpack\modules\blood_drinking\code\combat_bite.dm"
#include "modular_darkpack\modules\blood_drinking\code\drinksomeblood.dm"
#include "modular_darkpack\modules\blood_drinking\code\vamp_bite.dm"
#include "modular_darkpack\modules\blood_drinking\code\kiss_status_effect\status_effect_kiss.dm"
@@ -7291,6 +7292,29 @@
#include "modular_darkpack\modules\flavor_text\code\preferences\masked_flavor_text_preference.dm"
#include "modular_darkpack\modules\flavor_text\code\preferences\nsfw_content_preference.dm"
#include "modular_darkpack\modules\flavor_text\code\preferences\record_preferences.dm"
+#include "modular_darkpack\modules\fomori\code\positive_quirks\stigmata_of_the_wyrm.dm"
+#include "modular_darkpack\modules\fomori\code\powers\_fomori_power.dm"
+#include "modular_darkpack\modules\fomori\code\powers\_fomori_power_weapon.dm"
+#include "modular_darkpack\modules\fomori\code\powers\mental\berserker.dm"
+#include "modular_darkpack\modules\fomori\code\powers\mental\corrupted_visions.dm"
+#include "modular_darkpack\modules\fomori\code\powers\mental\deception.dm"
+#include "modular_darkpack\modules\fomori\code\powers\mental\eyes_of_the_wyrm.dm"
+#include "modular_darkpack\modules\fomori\code\powers\mental\mind_blast.dm"
+#include "modular_darkpack\modules\fomori\code\powers\mental\mind_reave.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\body_barbs.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\chameleon_coloration.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\claws.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\darksight.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\ectoplasmic_extrusion.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\exoskeleton.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\fangs.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\hide_of_the_wyrm.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\horns.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\infectious_touch.dm"
+#include "modular_darkpack\modules\fomori\code\powers\physical\regeneration.dm"
+#include "modular_darkpack\modules\fomori\code\splats\fomori_splat.dm"
+#include "modular_darkpack\modules\fomori\code\splats\is_fomori_helpers.dm"
+#include "modular_darkpack\modules\fomori\code\splats\pref_lore.dm"
#include "modular_darkpack\modules\font_adjustments\font_procs.dm"
#include "modular_darkpack\modules\food\code\drinking_glass.dm"
#include "modular_darkpack\modules\food\code\drinks.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 3cdaa85c123e..2503bd94518f 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
@@ -11,10 +11,15 @@ export const territorial: FeatureChoiced = {
export const prey_exclusion: FeatureChoiced = {
name: 'Prey Exclusion',
description: 'The Prey Exclusion of this character.',
- component: FeatureDropdownInput
-}
+ component: FeatureDropdownInput,
+};
export const missing_arm: FeatureChoiced = {
name: 'Missing Arm',
component: FeatureDropdownInput,
};
+
+export const stigmata_of_the_wyrm: FeatureChoiced = {
+ name: 'Stigmata of the Wyrm',
+ component: FeatureDropdownInput,
+};