diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index a9b1b0f8d41b..756489bbc9bb 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -166,7 +166,14 @@ GLOBAL_LIST_INIT(turfs_openspace, typecacheof(list( #define isdrone(A) (istype(A, /mob/living/basic/drone)) -#define iscat(A) (istype(A, /mob/living/simple_animal/pet/cat)) +GLOBAL_LIST_INIT(cat_typecache, typecacheof(list( + /mob/living/simple_animal/pet/cat, + /mob/living/simple_animal/hostile/syndicat, + /mob/living/simple_animal/hostile/feral, + /mob/living/simple_animal/hostile/feraltabby, +))) + +#define iscat(A) (is_type_in_typecache(A, GLOB.cat_typecache)) #define isdog(A) (istype(A, /mob/living/basic/pet/dog)) diff --git a/code/__DEFINES/~monkestation/lighting.dm b/code/__DEFINES/~monkestation/lighting.dm new file mode 100644 index 000000000000..2610f8952e97 --- /dev/null +++ b/code/__DEFINES/~monkestation/lighting.dm @@ -0,0 +1,3 @@ +#define LIGHTING_CUTOFF_FELINE_RED 45 +#define LIGHTING_CUTOFF_FELINE_GREEN 50 +#define LIGHTING_CUTOFF_FELINE_BLUE 40 diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index b9bd8cee9bdf..c8429a9b8078 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -27,7 +27,7 @@ screens -= category - if(animated) + if(!QDELETED(src) && animated) animate(screen, alpha = 0, time = animated) addtimer(CALLBACK(src, PROC_REF(clear_fullscreen_after_animate), screen), animated, TIMER_CLIENT_TIME) else diff --git a/code/modules/spells/spell_types/shapeshift/_shape_status.dm b/code/modules/spells/spell_types/shapeshift/_shape_status.dm index eab7645476c4..b1aa75c820ee 100644 --- a/code/modules/spells/spell_types/shapeshift/_shape_status.dm +++ b/code/modules/spells/spell_types/shapeshift/_shape_status.dm @@ -30,6 +30,10 @@ return ..() /datum/status_effect/shapechange_mob/on_apply() + // monkestation start: always use caster's gender for the mob + owner.gender = caster_mob.gender + owner.regenerate_icons() + // monkestation end caster_mob.mind?.transfer_to(owner) caster_mob.forceMove(owner) ADD_TRAIT(caster_mob, TRAIT_NO_TRANSFORM, TRAIT_STATUS_EFFECT(id)) diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 2531da79d805..88f10d144436 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -90,7 +90,7 @@ /mob/living/simple_animal/pet/gondola/virtual_domain, /mob/living/simple_animal/soulscythe, - //MONKESTATION-SPECIFIC ENTRIES END + //MONKESTATION-SPECIFIC ENTRIES START /mob/living/simple_animal/bot/buttbot, /mob/living/simple_animal/bot/secbot/beepsky/big, /mob/living/simple_animal/fish, @@ -109,6 +109,7 @@ /mob/living/simple_animal/hostile/illusion/khan_warrior, /mob/living/simple_animal/hostile/megafauna/wendigo/monkestation_override, /mob/living/simple_animal/hostile/syndicat, + /mob/living/simple_animal/hostile/syndicat/super, /mob/living/simple_animal/pet/cat/breadcat/super, /mob/living/simple_animal/pet/cat/original/super, /mob/living/simple_animal/pet/cat/super, diff --git a/monkestation/code/modules/mapfluff/ruins/spaceruin_code/mrow_thats_right.dm b/monkestation/code/modules/mapfluff/ruins/spaceruin_code/mrow_thats_right.dm index 06efde0c14e7..dd08b57d00fd 100644 --- a/monkestation/code/modules/mapfluff/ruins/spaceruin_code/mrow_thats_right.dm +++ b/monkestation/code/modules/mapfluff/ruins/spaceruin_code/mrow_thats_right.dm @@ -1,59 +1,124 @@ +/// How much health super kitties have by default. +#define SUPER_KITTY_HEALTH 50 +/// How much health syndicate super kitties have by default. +#define SYNDIE_SUPER_KITTY_HEALTH 80 + /obj/item/organ/internal/ears/cat/super name = "Super Kitty Ears" desc = "A pair of kitty ears that harvest the true energy of cats. Mrow!" icon_state = "superkitty" decay_factor = 0 // Space ruin item damage_multiplier = 0.5 // SUPER + organ_flags = ORGAN_HIDDEN + organ_traits = list(TRAIT_CAT) + /// The instance of kitty form spell given to the user. + /// The spell will be initialized using the initial typepath. + var/datum/action/cooldown/spell/shapeshift/kitty/kitty_spell = /datum/action/cooldown/spell/shapeshift/kitty -/datum/action/cooldown/spell/shapeshift/kitty - name = "KITTY POWER!!" - desc = "Take on the shape of a kitty cat! Gain their powers at a loss of vitality." +/obj/item/organ/internal/ears/cat/super/Initialize(mapload) + if(ispath(kitty_spell)) + kitty_spell = new kitty_spell(src) + else + stack_trace("kitty_spell is invalid typepath ([kitty_spell || "null"])") + return ..() - cooldown_time = 20 SECONDS - invocation = "MRR MRRRW!!" - invocation_type = INVOCATION_SHOUT - spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC +/obj/item/organ/internal/ears/cat/super/Destroy() + QDEL_NULL(kitty_spell) + return ..() - possible_shapes = list( - /mob/living/simple_animal/pet/cat/super, - /mob/living/simple_animal/pet/cat/super, - /mob/living/simple_animal/pet/cat/super, - ) - - // Stole this from demon heart hard, but hey it works /obj/item/organ/internal/ears/cat/super/attack(mob/target_mob, mob/living/carbon/user, obj/target) - if(target_mob != user) + if(target_mob != user || !implant_on_use(user)) return ..() +/obj/item/organ/internal/ears/cat/super/attack_self(mob/user, modifiers) + implant_on_use(user) + return ..() + +/obj/item/organ/internal/ears/cat/super/on_insert(mob/living/carbon/ear_owner) + . = ..() + kitty_spell.Grant(ear_owner) + +/obj/item/organ/internal/ears/cat/super/on_remove(mob/living/carbon/ear_owner, special = FALSE) + . = ..() + kitty_spell.Remove(ear_owner) + +// Stole this from demon heart hard, but hey it works +/obj/item/organ/internal/ears/cat/super/proc/implant_on_use(mob/living/carbon/user) + if(!iscarbon(user) || !user.is_holding(src)) + return FALSE user.visible_message( - span_warning("[user] raises the [src] to [user.p_their()] head and genetly places it on [user.p_their()] head!"), - span_danger("A strange feline comes over you. You place the [src] on your head!"), + span_warning("[user] raises \the [src] to [user.p_their()] head and gently places it on [user.p_their()] head!"), + span_danger("A strange feline comes over you. You place \the [src] on your head!"), ) playsound(user, 'sound/effects/meow1.ogg', 50, TRUE) user.visible_message( - span_warning("The [src] melt into [user]'s head!"), + span_warning("\The [src] melt into [user]'s head!"), span_userdanger("Everything is so much louder!"), ) - user.temporarilyRemoveItemFromInventory(src, TRUE) - src.Insert(user) + user.temporarilyRemoveItemFromInventory(src, force = TRUE) + Insert(user) + return TRUE -/obj/item/organ/internal/ears/cat/super/on_insert(mob/living/carbon/heart_owner) - . = ..() - var/datum/action/cooldown/spell/shapeshift/kitty/heart = new(heart_owner) - heart.Grant(heart_owner) +/datum/action/cooldown/spell/shapeshift/kitty + name = "KITTY POWER!!" + desc = "Take on the shape of a kitty cat! Gain their powers at a loss of vitality." -/obj/item/organ/internal/ears/cat/super/on_remove(mob/living/carbon/heart_owner, special = FALSE) - . = ..() - var/datum/action/cooldown/spell/shapeshift/kitty/heart = locate() in heart_owner.actions - qdel(heart) + cooldown_time = 20 SECONDS + invocation = "MRR MRRRW!!" + invocation_type = INVOCATION_SHOUT + spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC + + possible_shapes = list( + /mob/living/simple_animal/pet/cat/super, + /mob/living/simple_animal/pet/cat/breadcat/super, + /mob/living/simple_animal/pet/cat/original/super, + ) + keep_name = TRUE /mob/living/simple_animal/pet/cat/super - health = 50 + maxHealth = SUPER_KITTY_HEALTH + health = SUPER_KITTY_HEALTH + speed = 0 + gold_core_spawnable = NO_SPAWN /mob/living/simple_animal/pet/cat/breadcat/super - health = 50 + maxHealth = SUPER_KITTY_HEALTH + health = SUPER_KITTY_HEALTH + speed = 0 + gold_core_spawnable = NO_SPAWN /mob/living/simple_animal/pet/cat/original/super - health = 50 + maxHealth = SUPER_KITTY_HEALTH + health = SUPER_KITTY_HEALTH + speed = 0 + gold_core_spawnable = NO_SPAWN + +/obj/item/organ/internal/ears/cat/super/syndie + kitty_spell = /datum/action/cooldown/spell/shapeshift/kitty/syndie + +/datum/action/cooldown/spell/shapeshift/kitty/syndie + name = "SYNDICATE KITTY POWER!!" + desc = "Take on the shape of an kitty cat, clad in blood-red armor! Gain their powers at a loss of vitality." + possible_shapes = list(/mob/living/simple_animal/hostile/syndicat/super) + +/mob/living/simple_animal/hostile/syndicat/super + maxHealth = SYNDIE_SUPER_KITTY_HEALTH + health = SYNDIE_SUPER_KITTY_HEALTH + speed = 0 + // it's clad in blood-red armor + damage_coeff = list(BRUTE = 0.8, BURN = 0.9, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY + unsuitable_atmos_damage = 0 + +/mob/living/simple_animal/hostile/syndicat/super/Initialize(mapload) + . = ..() + // get rid of the microbomb normal syndie cats have + for(var/obj/item/implant/explosive/implant_to_remove in implants) + qdel(implant_to_remove) + +#undef SYNDIE_SUPER_KITTY_HEALTH +#undef SUPER_KITTY_HEALTH diff --git a/monkestation/code/modules/mob/living/simple_animal/friendly/cat.dm b/monkestation/code/modules/mob/living/simple_animal/friendly/cat.dm new file mode 100644 index 000000000000..2cab13113df1 --- /dev/null +++ b/monkestation/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -0,0 +1,4 @@ +/mob/living/simple_animal/pet/cat + lighting_cutoff_red = LIGHTING_CUTOFF_FELINE_RED + lighting_cutoff_green = LIGHTING_CUTOFF_FELINE_GREEN + lighting_cutoff_blue = LIGHTING_CUTOFF_FELINE_RED diff --git a/monkestation/code/modules/mob/living/simple_animal/hostile/syndicat.dm b/monkestation/code/modules/mob/living/simple_animal/hostile/syndicat.dm index 0f02bc3cd091..8e65aec28516 100644 --- a/monkestation/code/modules/mob/living/simple_animal/hostile/syndicat.dm +++ b/monkestation/code/modules/mob/living/simple_animal/hostile/syndicat.dm @@ -37,9 +37,13 @@ attack_sound = 'sound/weapons/slash.ogg' attack_vis_effect = ATTACK_EFFECT_CLAW footstep_type = FOOTSTEP_MOB_CLAW + lighting_cutoff_red = LIGHTING_CUTOFF_FELINE_RED + lighting_cutoff_green = LIGHTING_CUTOFF_FELINE_GREEN + lighting_cutoff_blue = LIGHTING_CUTOFF_FELINE_RED /mob/living/simple_animal/hostile/syndicat/Initialize(mapload) . = ..() + ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) var/obj/item/implant/toinstall = list(/obj/item/implant/weapons_auth, /obj/item/implant/explosive) for(var/obj/item/implant/original_implants as anything in toinstall) var/obj/item/implant/copied_implant = new original_implants.type diff --git a/monkestation/code/modules/spells/spell_types/shapeshift/_shapeshift.dm b/monkestation/code/modules/spells/spell_types/shapeshift/_shapeshift.dm new file mode 100644 index 000000000000..bdf6457620c8 --- /dev/null +++ b/monkestation/code/modules/spells/spell_types/shapeshift/_shapeshift.dm @@ -0,0 +1,11 @@ +/datum/action/cooldown/spell/shapeshift + /// If TRUE, the mob will keep the name of the caster. + var/keep_name = FALSE + +/datum/action/cooldown/spell/shapeshift/do_shapeshift(mob/living/caster) + . = ..() + var/mob/living/new_form = . + if(istype(new_form) && keep_name) + new_form.real_name = caster.real_name + new_form.name = caster.real_name + new_form.update_name_tag() diff --git a/monkestation/code/modules/uplink/uplink_items/misc.dm b/monkestation/code/modules/uplink/uplink_items/misc.dm index 1d1d40966179..017aa9c6cae6 100644 --- a/monkestation/code/modules/uplink/uplink_items/misc.dm +++ b/monkestation/code/modules/uplink/uplink_items/misc.dm @@ -36,3 +36,15 @@ purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) item = /obj/item/card/plasma_license cost = 20 + +/datum/uplink_item/device_tools/super_kitty_ears + name = "Super Syndie-Kitty Ears" + desc = "Developed by several Interdyne Pharmaceutics scientists and Wizard Federation archmages during a record-breaking rager, \ + this set of feline ears combines the finest of bio-engineering and thamaturgy to allow the user to transform to and from a cat at will, \ + granting them all the benefits (and downsides) of being a true feline, such as ventcrawling. \ + However, this form will be clad in blood-red Syndicate armor, making its origin somewhat obvious." + purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) + item = /obj/item/organ/internal/ears/cat/super/syndie + cost = 16 // double the price of stealth implant + surplus = 5 + limited_stock = 1 diff --git a/tgstation.dme b/tgstation.dme index d8d52c645836..c2d4d6dab9e6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -437,6 +437,7 @@ #include "code\__DEFINES\~monkestation\jobs.dm" #include "code\__DEFINES\~monkestation\keybinding.dm" #include "code\__DEFINES\~monkestation\level_traits.dm" +#include "code\__DEFINES\~monkestation\lighting.dm" #include "code\__DEFINES\~monkestation\living.dm" #include "code\__DEFINES\~monkestation\logging.dm" #include "code\__DEFINES\~monkestation\maps.dm" @@ -7710,6 +7711,7 @@ #include "monkestation\code\modules\mob\living\carbon\human\species_type\tundra_moths\tundramoths.dm" #include "monkestation\code\modules\mob\living\silicon\death.dm" #include "monkestation\code\modules\mob\living\simple_animal\bot\secbot.dm" +#include "monkestation\code\modules\mob\living\simple_animal\friendly\cat.dm" #include "monkestation\code\modules\mob\living\simple_animal\hostile\feral.dm" #include "monkestation\code\modules\mob\living\simple_animal\hostile\syndicat.dm" #include "monkestation\code\modules\mob\living\simple_animal\megafauna\wendigo.dm" @@ -8235,6 +8237,7 @@ #include "monkestation\code\modules\spells\spell_types\conjure_item\summon_mjollnir.dm" #include "monkestation\code\modules\spells\spell_types\pointed\fire_ball.dm" #include "monkestation\code\modules\spells\spell_types\pointed\smite.dm" +#include "monkestation\code\modules\spells\spell_types\shapeshift\_shapeshift.dm" #include "monkestation\code\modules\spells\spell_types\touch\_touch.dm" #include "monkestation\code\modules\store\admin\admin_coin_modification.dm" #include "monkestation\code\modules\store\atm\_atm.dm"