Merge branch 'master' into upstream-24-11b

This commit is contained in:
lessthanthree
2024-11-16 01:25:09 -08:00
28 changed files with 458 additions and 4 deletions
+1
View File
@@ -19,6 +19,7 @@
"stamp-merged" = 'icons/stamp_icons/large_stamp-merged.png',
"stamp-closed" = 'icons/stamp_icons/large_stamp-closed.png',
"stamp-crow" = 'icons/stamp_icons/crow-stamp.png',
"stamp-warden" = 'icons/stamp_icons/large_stamp-warden.png',
//BUBBERSTATION ADDITION: END - Bubberstation Stamp Icons
"stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
+1 -1
View File
@@ -4,7 +4,7 @@
#define BALLOON_TEXT_FULLY_VISIBLE_TIME (0.7 SECONDS)
#define BALLOON_TEXT_TOTAL_LIFETIME(mult) (BALLOON_TEXT_SPAWN_TIME + BALLOON_TEXT_FULLY_VISIBLE_TIME*mult + BALLOON_TEXT_FADE_TIME)
/// The increase in duration per character in seconds
#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT (0.05)
#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT (0.07) // BUBBER EDIT CHANGE - Original: 0.05
/// The amount of characters needed before this increase takes into effect
#define BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN 10
@@ -0,0 +1,7 @@
author: "Middiwiddi, LT3"
delete-after: True
changes:
- rscadd: "Added 'nyamagotchi', a tamagotchi clone that's cute and cat-themed. Interactive and able to attach on belt."
- rscadd: "Added nyamagotchi to toy vending machine and clothesdrobe"
- rscadd: "Added nyamagotchi to 'pockets' loadout options."
- rscadd: "nyamagotchi works as a companion for monophobia.\n:cl:\n<!-- Both :cl:'s are required for the changelog to work! You can put your name to the right of the first :cl: if you want to overwrite your GitHub username as author ingame. -->\n<!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. -->\n<!-- By opening a pull request. You have read and understood the repository rules located on the main README.md on this project. -->"
@@ -0,0 +1,4 @@
author: "xPokee"
delete-after: True
changes:
- bugfix: "fixed bacon and cloth cookies from cyborg snack dispensers not having a proper taste"
@@ -0,0 +1,5 @@
author: "Majkl-J and Cepha"
delete-after: True
changes:
- rscadd: "Ponytails (Berly) hair added"
- rscadd: "Short (Side) hair added"
+10
View File
@@ -326,3 +326,13 @@
2024-11-14:
LT3:
- bugfix: Alternate meow and purr emotes work again
2024-11-15:
Arturlang:
- bugfix: Fixes the bokken having 16 damage when unwielded, and 8 when it is
Boviro:
- rscadd: gives the warden a stamp
sippykot:
- balance: NT's bluespace technology doubles lunchbox storage from 4 to 8 items
with special lining
- rscadd: lunchboxes can also hold condiments and gum now... and cigarettes and
lighters, at the insistence of our sponsors in the space tobacco industry
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -411,3 +411,9 @@
/datum/loadout_item/toys/purple_laser
name = "Purple Laser Pointer"
item_path = /obj/item/laser_pointer/limited/purple
/datum/loadout_item/toys/nyamagotchi
name = "Nyamagotchi"
item_path = /obj/item/toy/nyamagotchi
ui_icon = 'modular_zubbers/icons/obj/toys/toys.dmi'
ui_icon_state = "nya"
@@ -148,6 +148,7 @@
icon = 'modular_skyrat/master_files/icons/obj/food/snacks.dmi'
icon_state = "bacon_strip"
foodtypes = MEAT
tastes = list("bacon" = 1)
/obj/item/food/cookie/cloth
name = "odd cookie"
@@ -155,3 +156,4 @@
icon = 'modular_skyrat/master_files/icons/obj/food/snacks.dmi'
icon_state = "cookie_cloth"
foodtypes = CLOTH
tastes = list("synthetic clothing fibers" = 1)
@@ -314,7 +314,7 @@
/obj/item/forging/reagent_weapon/bokken
name = "reagent bokken"
desc = "A bokken that is capable of blocking attacks when wielding in two hands, possibly including bullets should the user be brave enough."
force = 16
force = 8
icon_state = "bokken"
inhand_icon_state = "bokken"
worn_icon_state = "bokken_back"
@@ -349,7 +349,7 @@
. = ..()
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
AddComponent(/datum/component/two_handed, force_multiplier = 0.5)
AddComponent(/datum/component/two_handed, force_multiplier = 1.5)
/obj/item/forging/reagent_weapon/bokken/proc/on_wield()
SIGNAL_HANDLER
@@ -946,6 +946,7 @@ GLOBAL_LIST_INIT(common_loot, list( //common: basic items
/obj/item/instrument/violin = 10,
/obj/item/instrument/violin/golden = 1
) = 25,
/obj/item/toy/nyamagotchi = 15,
/obj/item/paper/fluff/stations/soap = 50,
list(
/obj/item/soap = 50,
@@ -6,6 +6,12 @@
for(var/obj/item/toy/plush/plush in owner.held_items) //Now you have an excuse to carry a shark plushie around all the time
if(plush.stuffed)
return FALSE
for(var/obj/item/toy/nyamagotchi/cat in oview(owner, 1))
if(cat.alive == 1)
return FALSE
for(var/obj/item/toy/nyamagotchi/cat in owner.held_items) // virtual pets are friends too!
if(cat.alive == 1)
return FALSE
for(var/mob/M in owner.held_items) //makes sure to check hands for your tiny friends!
if(!isliving(M))
continue
@@ -0,0 +1,3 @@
/obj/structure/closet/secure_closet/warden/PopulateContents()
. = ..()
new /obj/item/stamp/warden(src)
@@ -1,3 +1,4 @@
/datum/quirk/monophobia
value = -8
mob_trait = TRAIT_MONOPHOBIA
mail_goodies = list(/obj/item/toy/nyamagotchi)
@@ -53,6 +53,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool_classic, list(
/obj/item/toy/katana = 100,
/obj/item/toy/minimeteor = 50,
/obj/item/toy/nuke = 50,
/obj/item/toy/nyamagotchi = 75,
/obj/item/toy/redbutton = 50,
/obj/item/toy/spinningtoy = 50,
/obj/item/toy/spinningtoy/dark_matter = 50,
@@ -13,10 +13,14 @@
/obj/item/storage/lunchbox/Initialize(mapload)
. = ..()
atom_storage.max_slots = 4
atom_storage.max_slots = 8
atom_storage.set_holdable(list(
/obj/item/food,
/obj/item/reagent_containers/cup,
/obj/item/reagent_containers/condiment,
/obj/item/storage/box/gum,
/obj/item/storage/fancy/cigarettes,
/obj/item/lighter,
))
/obj/item/storage/lunchbox/nanotrasen
@@ -44,3 +44,14 @@
icon = 'modular_zubbers/icons/customization/hair.dmi'
name = "Inari"
icon_state = "hair_inari"
// short_side and ponytails_berly sprites by Cepha
/datum/sprite_accessory/hair/short_side
icon = 'modular_zubbers/icons/customization/hair.dmi'
name = "Short (Side)"
icon_state = "hair_short_side"
/datum/sprite_accessory/hair/ponytails_berly
icon = 'modular_zubbers/icons/customization/hair.dmi'
name = "Ponytails (Berly)"
icon_state = "hair_tails_berly"
@@ -0,0 +1,383 @@
#define NO_ANIMAL 0
#define ANIMAL_ALIVE 1
#define ANIMAL_DEAD 2
#define MEOW_NORMAL 'sound/creatures/cat/cat_meow1.ogg'
#define MEOW_SAD 'modular_zubbers/code/modules/nyamagotchi/sound/cat_sad.ogg'
#define MEOW_CRITICAL 'modular_zubbers/code/modules/nyamagotchi/sound/cat_alert.ogg'
#define EAT_FOOD 'modular_zubbers/code/modules/nyamagotchi/sound/cat_eat.ogg'
#define PURR_PLAY 'sound/creatures/cat/cat_purr1.ogg'
#define PURR_SLEEP 'sound/creatures/cat/cat_purr3.ogg'
/obj/item/toy/nyamagotchi
name = "Nyamagotchi"
desc = "A small electronic 'pet' that requires care and attention. An ancient relic sure to evoke nostalgic feelings."
icon = 'modular_zubbers/icons/obj/toys/toys.dmi'
icon_state = "nya"
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
inhand_icon_state = "electronic"
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
force = 2
throwforce = 2
actions_types = list(/datum/action/item_action/nyamagotchi_menu)
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT, /datum/material/plastic = SMALL_MATERIAL_AMOUNT)
// interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY
var/list/icons_available = list()
var/radial_icon_file = 'modular_zubbers/code/modules/nyamagotchi/sprites/radial_nyamagotchi.dmi'
/// Hunger level (0 = full, 100 = starving)
var/hunger = 0
/// Happiness level (0 = sad, 100 = very happy)
var/happiness = 100
/// Energy level (0 = tired, 100 = full of energy)
var/energy = 0
/// Age in "days" or some unit of time
var/age = 0
/// How often a 'life' cycle of the pet runs
var/update_rate = 45 SECONDS
/// The last action the pet performed
var/last_task = null
var/alive = NO_ANIMAL
var/list/rest_messages = list(
"Zzz... Zzz... Zzz...",
"Honk, shew! Hooonk, shewww...!",
"Snoozin' time, nya...",
"Honk shoo!",
"Nini...~",
"Zzz... Zzz... Zzz... Zzz... Zzz...",
)
var/list/play_messages = list(
"Wowzers meowzers, that was fun!",
"That was so much fun, nya!",
"YAY!!!",
"I had a great time playing with you!",
"YIPPEEE!!!", "That was a blast!",
"Wowzers meowzers, that was a blast!",
)
var/list/feed_messages = list(
"NOM NOM NOM. Ice cream, yum!",
"Mmm, that was tasty!",
"So yummy!",
"Oooh! Delicious!",
"MONCH MONCH MONCH.",
"MUNCH MUNCH, that was so heckin' tasty, nya!",
"Yum, that was delicious!",
"What a PURRFECT meal, nya!",
)
var/list/hunger_warning = list(
"Wowzers meowzers, I'm hungry, nya!",
"Excuse me! I'm feeling a bit peckish, nya!",
"I could eat the world right now, nya!",
"Soooo hongry!",
"I'm feeling a bit hungry, nya!",
"I needs the food, mrow!",
)
var/list/hunger_critical = list(
"HELLO! Food, pwease?...",
"HEY!!! I'm starving...",
"HONNNNGRYYY!!!",
"so so hungry...",
)
var/list/happiness_warning = list(
"Some fun would be purrfect, nya...",
"I'm feeling a bit down, nya...",
"Playtime! Now!",
"This is no fun...",
"I'm BORED, nya!",
"So sad! So bored! Need to play!",
"Wah... So sad, nya...",
"I'm feeling a bit blue, nya...",
"I'm sad...",
"Play with meeee! PLEASE.",
"My fun levels are low, nya...",
)
var/list/full_critical = list(
"So this... is how it ends for me...",
"Is this how it ends... cold, alone, unfed...",
"Fading... fast... my last request: snacks and snuggles, please...",
"I see the end... all nine lives gone...",
"Abandoned... like a stray... in my own virtual world...",
"Its getting so dark and cold...",
)
var/list/energy_warning = list(
"I'm feeling a bit sleepy, nya...",
"Sleempy...",
"I be needin' a naps, nya!",
"Need to do the big sleeps, please!",
"I'm feeling a bit exhausted, nya...",
"I could go for a nap...",
)
var/list/energy_critical = list(
"SO, SO EEPY, NYA...",
"Please, I need to rest...",
"I'm feel like I'm gonna pass out...",
"Why won't you let me sleep?...",
"EEPY. EEPY. eepy...",
)
COOLDOWN_DECLARE(mute_pet)
COOLDOWN_DECLARE(needs_alert)
/obj/item/toy/nyamagotchi/Initialize(mapload)
. = ..()
if(prob(3))
name = "pocket pussy" // mrowwww!
register_context()
update_available_icons()
/obj/item/toy/nyamagotchi/examine(mob/user)
. = ..()
if(in_range(src, user) || isobserver(user))
. += "[readout()]"
if(!COOLDOWN_FINISHED(src, mute_pet))
. += span_notice("<b>Alt-click</b> to disable mute feature.")
else
. += span_notice("<b>Alt-click</b> to temporarily mute notifications.")
/obj/item/toy/nyamagotchi/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
context[SCREENTIP_CONTEXT_LMB] = "Interact"
context[SCREENTIP_CONTEXT_ALT_LMB] = "Toggle mute"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/toy/nyamagotchi/proc/readout()
switch(alive)
if(NO_ANIMAL)
return span_notice("[src] is ready to be started!")
if(ANIMAL_ALIVE)
return span_notice("[src] is alive, it has reached age [age]! Use the <b>'Check Status'</b> button to see its stats!")
if(ANIMAL_DEAD)
return span_purple("[src] is DEAD. You're a terrible person.")
/obj/item/toy/nyamagotchi/proc/update_available_icons()
icons_available = list()
if(alive == ANIMAL_ALIVE)
icons_available += list(
"Feed" = image(radial_icon_file, "feed"),
"Play" = image(radial_icon_file, "play"),
"Rest" = image(radial_icon_file, "rest"),
"Check Status" = image(radial_icon_file, "status",
))
else
icons_available += list("Start!" = image(radial_icon_file, "start"))
/obj/item/toy/nyamagotchi/attack_self(mob/user)
pet_menu(user)
/obj/item/toy/nyamagotchi/proc/pet_menu(mob/user, list/modifiers)
update_available_icons()
if(icons_available)
var/selection = show_radial_menu(user, src, icons_available, radius = 38, require_near = TRUE, tooltips = TRUE)
if(!selection)
return
switch(selection)
if("Start!")
start()
if("Feed")
feed()
if("Play")
play()
if("Rest")
rest()
if("Check Status")
check_status()
/obj/item/toy/nyamagotchi/click_alt(mob/living/user)
if(user != loc)
return
if(COOLDOWN_FINISHED(src, mute_pet))
COOLDOWN_START(src, mute_pet, update_rate * 5.75)
user.balloon_alert(user, "muted!")
to_chat(user, span_notice("You turn on [src]'s mute feature."))
else
COOLDOWN_RESET(src, mute_pet)
user.balloon_alert(user, "unmuted!")
to_chat(user, span_notice("You turn off [src]'s mute feature."))
be_known(sfx = MEOW_NORMAL)
/obj/item/toy/nyamagotchi/proc/start()
alive = ANIMAL_ALIVE
// give a slightly random start
hunger = rand(30, 60)
happiness = rand(80, 100)
energy = rand(60, 90)
be_known(sfx = 'sound/misc/bloop.ogg', speech = "I'm alive, nya!")
addtimer(CALLBACK(src, PROC_REF(be_known), MEOW_NORMAL), 2 SECONDS)
addtimer(CALLBACK(src, PROC_REF(update)), update_rate)
// status update loop
/obj/item/toy/nyamagotchi/proc/update()
if(!alive)
return
last_task = null
if(happiness <= 21) // unhappy pets get hungry and tired faster
hunger += rand(1, 2)
energy -= rand(1, 3)
if(hunger >= 70 || energy <= 30)
happiness -= clamp(rand(2, 4), 0, happiness)
age += 1 // Increase age over time
hunger += rand(1, 3) // Increase hunger over time
happiness -= clamp(rand(1, 3), 0, happiness) // Decrease happiness over time
energy -= rand(1, 3) // Decrease energy over time
// check if the nyamagotchi is still alive
if(hunger >= 100 || energy <= 0)
die()
return
// schedule our next check
addtimer(CALLBACK(src, PROC_REF(update)), update_rate)
// make the nyamagotchi say things if attention is needed, otherwise just a small chance of a reminder meow
var/list/tama_alerts = list()
var/selected_alert
if((hunger >= 83 || energy <= 17) && happiness <= 21)
be_known(sfx = MEOW_CRITICAL, speech = pick(full_critical))
return
if(hunger >= 83)
tama_alerts += "vhungry"
if(energy <= 17)
tama_alerts += "vtired"
if(tama_alerts.len)
selected_alert = pick(tama_alerts)
switch(selected_alert)
if("vhungry")
be_known(sfx = MEOW_CRITICAL, speech = pick(hunger_critical))
return
if("vtired")
be_known(sfx = MEOW_CRITICAL, speech = pick(energy_critical))
return
if(!COOLDOWN_FINISHED(src, needs_alert))
return // to not be too annoying
if(hunger >= 70)
tama_alerts += "hungry"
if(happiness <= 30)
tama_alerts += "sad"
if(energy <= 30)
tama_alerts += "tired"
if(tama_alerts.len)
COOLDOWN_START(src, needs_alert, update_rate * 2.25)
selected_alert = pick(tama_alerts)
switch(selected_alert)
if("hungry")
be_known(sfx = MEOW_SAD, speech = pick(hunger_warning))
if("sad")
be_known(sfx = MEOW_SAD, speech = pick(happiness_warning))
if("tired")
be_known(sfx = MEOW_SAD, speech = pick(energy_warning))
else if(prob(25))
be_known(sfx = MEOW_NORMAL)
/obj/item/toy/nyamagotchi/proc/be_known(sfx, speech, visible)
if(!COOLDOWN_FINISHED(src, mute_pet))
return
if(!isnull(sfx))
playsound(source = src, soundin = sfx, vol = 40, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
if(!isnull(speech))
say(speech, message_range = 2)
if(!isnull(visible))
balloon_alert_to_viewers(message = visible, vision_distance = COMBAT_MESSAGE_RANGE + 2)
// Interactions
/obj/item/toy/nyamagotchi/proc/action_check()
if(!isnull(last_task))
usr.balloon_alert(usr, "still [last_task]!")
be_known(sfx = MEOW_SAD)
return FALSE
return TRUE
/obj/item/toy/nyamagotchi/proc/feed()
if(!action_check())
return
else if(hunger > 20)
hunger -= min(rand(30, 40), hunger)
to_chat(usr, span_purple("You fed [src]! Its hunger is now at [hunger]."))
be_known(sfx = EAT_FOOD, speech = pick(feed_messages))
last_task = "eating"
else
usr.balloon_alert(usr, "not hungry!")
/obj/item/toy/nyamagotchi/proc/play()
if(!action_check())
return
else if(happiness < 80)
happiness += min(rand(30, 40), 100 - happiness)
to_chat(usr, span_purple("You play with [src]! Its happiness is now [happiness]."))
be_known(sfx = PURR_PLAY, speech = pick(play_messages))
last_task = "playing"
else
usr.balloon_alert(usr, "not bored!")
/obj/item/toy/nyamagotchi/proc/rest()
if(!action_check())
return
else if(energy < 80)
energy += min(rand(30, 40), 100 - energy)
to_chat(usr, span_purple("[src] rests and regains energy. Its energy is now [energy]."))
be_known(sfx = PURR_SLEEP, speech = pick(rest_messages))
last_task = "resting"
else
usr.balloon_alert(usr, "not tired!")
// Function for when the nyamagotchi dies
/obj/item/toy/nyamagotchi/proc/die()
last_task = null
alive = ANIMAL_DEAD
audible_message(span_warning("[src] makes a weak, sad noise and then goes silent... Rest in peace."), hearing_distance = COMBAT_MESSAGE_RANGE)
if(ishuman(loc))
to_chat(loc, span_warning("[src] shows an x3 on its display. It's dead. You're a terrible person."))
//src.icon_state = "dead"
be_known(sfx = 'sound/misc/sadtrombone.ogg', visible = "nyamagotchi died!")
update_available_icons()
/obj/item/toy/nyamagotchi/proc/check_status()
balloon_alert(usr, "hunger: [hunger] happiness: [happiness] energy: [energy]")
/datum/action/item_action/nyamagotchi_menu
name = "Check Nyamagotchi"
button_icon = 'modular_zubbers/icons/obj/toys/toys.dmi'
button_icon_state = "nya"
/datum/job/psychologist/New()
LAZYADDASSOC(mail_goodies, /obj/item/toy/nyamagotchi, 45)
. = ..()
/obj/effect/spawner/random/entertainment/dice
name = "dice spawner"
icon_state = "dice_bag"
spawn_loot_count = 3
spawn_loot_double = FALSE
spawn_loot_split = TRUE
loot = list(
/obj/item/dice/d4,
/obj/item/dice/d6,
/obj/item/dice/d8,
/obj/item/dice/d10,
/obj/item/dice/d12,
/obj/item/dice/d20,
/obj/item/dice/fourdd6,
/obj/item/toy/nyamagotchi,
)
#undef NO_ANIMAL
#undef ANIMAL_ALIVE
#undef ANIMAL_DEAD
#undef MEOW_NORMAL
#undef MEOW_SAD
#undef MEOW_CRITICAL
#undef EAT_FOOD
#undef PURR_PLAY
#undef PURR_SLEEP
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -24,3 +24,9 @@
icon_state = "stamp-crow"
desc = "A rubber stamp for stamping vaguely legal contracts."
dye_color = DYE_BLACK
/obj/item/stamp/warden
name = "warden's rubber stamp"
icon = 'modular_zubbers/icons/obj/service/bureaucracy.dmi'
icon_state = "stamp-warden"
dye_color = DYE_HOS
@@ -111,6 +111,7 @@
/obj/item/holosign_creator/hardlight_wheelchair = 3,
/obj/item/instrument/piano_synth/headphones/catear_headphone = 3,
/obj/item/clothing/accessory/pocketwatch = 3,
/obj/item/toy/nyamagotchi = 3,
),
)
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

+2
View File
@@ -8810,6 +8810,7 @@
#include "modular_zubbers\code\game\objects\structures\beds_chairs\sofa.dm"
#include "modular_zubbers\code\game\objects\structures\crates_lockers\closets.dm"
#include "modular_zubbers\code\game\objects\structures\crates_lockers\closets\secure\scientist.dm"
#include "modular_zubbers\code\game\objects\structures\crates_lockers\closets\secure\security.dm"
#include "modular_zubbers\code\game\objects\structures\flags\signs_flags.dm"
#include "modular_zubbers\code\game\objects\structures\plaques\static_plaques.dm"
#include "modular_zubbers\code\game\traits\negative.dm"
@@ -9179,6 +9180,7 @@
#include "modular_zubbers\code\modules\modular_weapons\code\company_and_or_faction_based\szot_dynamica\pistol.dm"
#include "modular_zubbers\code\modules\movespeed\_movespeed_modifier.dm"
#include "modular_zubbers\code\modules\movespeed\modifiers\status_effects.dm"
#include "modular_zubbers\code\modules\nyamagotchi\nyamagotchi.dm"
#include "modular_zubbers\code\modules\opposing_force\code\items.dm"
#include "modular_zubbers\code\modules\opposing_force\code\equipment\antagonist_powers.dm"
#include "modular_zubbers\code\modules\pai\ghost_pai.dm"