[MIRROR] Dog wit the butter (feat. a bunch of dog-related code improvements) [MDB IGNORE] (#22728)

* Dog wit the butter (feat. a bunch of dog-related code improvements)

* Delete dog.dm

* Update dogs.dm

---------

Co-authored-by: Sealed101 <cool.bullseye@yandex.ru>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-07-30 20:43:07 -04:00
committed by nevimer
co-authored by Sealed101 Bloop
parent c26d24b402
commit b50a6c7ddb
15 changed files with 1000 additions and 937 deletions
@@ -0,0 +1,4 @@
/// Sent from /mob/living/basic/proc/look_dead() : ()
#define COMSIG_BASICMOB_LOOK_DEAD "basicmob_look_dead"
/// Sent from /mob/living/basic/proc/look_alive() : ()
#define COMSIG_BASICMOB_LOOK_ALIVE "basicmob_look_alive"
@@ -7,6 +7,7 @@
if(!istype(basic_pawn) || basic_pawn.stat) // Can't act dead if you're dead
return
basic_pawn.emote("deathgasp", intentional=FALSE)
ADD_TRAIT(basic_pawn, TRAIT_FAKEDEATH, BASIC_MOB_DEATH_TRAIT)
basic_pawn.look_dead()
/datum/ai_behavior/play_dead/perform(seconds_per_tick, datum/ai_controller/controller)
@@ -20,5 +21,6 @@
if(!istype(basic_pawn) || basic_pawn.stat) // imagine actually dying while playing dead. hell, imagine being the kid waiting for your pup to get back up :(
return
basic_pawn.visible_message(span_notice("[basic_pawn] miraculously springs back to life!"))
REMOVE_TRAIT(basic_pawn, TRAIT_FAKEDEATH, BASIC_MOB_DEATH_TRAIT)
basic_pawn.look_alive()
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
+86 -61
View File
@@ -1,41 +1,65 @@
/datum/dog_fashion
var/name
var/desc
var/emote_see
var/emote_hear
var/speak
var/speak_emote
///Name modifier for the dog that we're dressing up
var/name = null
///Description modifier for the dog that we're dressing up
var/desc = null
///Hearable emotes modifier for the dog that we're dressing up
var/list/emote_hear = list()
///Visible emotes modifier for the dog that we're dressing up
var/list/emote_see = list()
///Speech modifier for the dog that we're dressing up
var/list/speak = list()
///Speech verb modifier for the dog that we're dressing up
var/list/speak_emote = list()
// This isn't applied to the dog, but stores the icon_state of the
// sprite that the associated item uses
var/icon_file
var/obj_icon_state
///Icon path for the fashion item
var/icon_file = null
///Icon state for the fashion item
var/obj_icon_state = null
///Alpha level (opacity) modifier of the fashion item
var/obj_alpha
///Color modifier of the fasion item
var/obj_color
/datum/dog_fashion/New(mob/M)
name = replacetext(name, "REAL_NAME", M.real_name)
desc = replacetext(desc, "NAME", name)
/datum/dog_fashion/New(mob/fashionable_mob)
//replace the placeholder for the real unmodified name in the name of the dog
name = replacetext(name, "%REAL_NAME%", fashionable_mob.real_name)
//replace the placeholder for the capitalized real unmodified name in the name of the dog
name = replacetext(name, "%CAPITAL_REAL_NAME%", capitalize(fashionable_mob.real_name))
//replace the placeholder for the current full name, which includes our name modifiers
desc = replacetext(desc, "%NAME%", name)
//replace the placeholder for the real unmodified name in the description of the dog
desc = replacetext(desc, "%REAL_NAME%", fashionable_mob.real_name)
//replace the placeholder for the capitalized real unmodified name in the description of the dog
desc = replacetext(desc, "%CAPITAL_REAL_NAME%", capitalize(fashionable_mob.real_name))
/datum/dog_fashion/proc/apply(mob/living/basic/pet/dog/D)
///Applies the name, description and speak emote modifiers to the dog
/datum/dog_fashion/proc/apply(mob/living/basic/pet/dog/dressup_doggy)
if(name)
D.name = name
dressup_doggy.name = name
if(desc)
D.desc = desc
if(speak_emote)
D.speak_emote = string_list(speak_emote)
dressup_doggy.desc = desc
if(length(speak_emote))
dressup_doggy.speak_emote = string_list(speak_emote)
///Applies random speech modifiers to the dog
/datum/dog_fashion/proc/apply_to_speech(datum/ai_planning_subtree/random_speech/speech)
if(emote_see)
if(length(emote_see))
speech.emote_see = string_list(emote_see)
if(emote_hear)
if(length(emote_hear))
speech.emote_hear = string_list(emote_hear)
if(speak)
if(length(speak))
speech.speak = string_list(speak)
/**
* Generates the icon overlay for the equipped item
* dir: passed direction for the sprite, e.g. to apply to a dead dog, we use the EAST dir and just flip it 180.
*/
/datum/dog_fashion/proc/get_overlay(dir)
if(icon_file && obj_icon_state)
var/image/corgI = image(icon_file, obj_icon_state, dir = dir)
var/image/corgI = image(icon_file, icon_state = obj_icon_state, dir = dir)
corgI.alpha = obj_alpha
corgI.color = obj_color
return corgI
@@ -51,33 +75,32 @@
obj_icon_state = "armor"
/datum/dog_fashion/back/deathsquad
name = "Trooper REAL_NAME"
name = "Trooper %REAL_NAME%"
desc = "That's not red paint. That's real corgi blood."
/datum/dog_fashion/head/helmet
name = "Sergeant REAL_NAME"
name = "Sergeant %REAL_NAME%"
desc = "The ever-loyal, the ever-vigilant."
/datum/dog_fashion/head/chef
name = "Sous chef REAL_NAME"
name = "Sous chef %REAL_NAME%"
desc = "Your food will be taste-tested. All of it."
/datum/dog_fashion/head/captain
name = "Captain REAL_NAME"
name = "Captain %REAL_NAME%"
desc = "Probably better than the last captain."
/datum/dog_fashion/head/kitty
name = "Runtime"
desc = "They're a cute little kitty-cat! ... wait ... what the hell?"
emote_see = list("coughs up a furball", "stretches")
emote_hear = list("purrs")
speak = list("Purrr", "Meow!", "MAOOOOOW!", "HISSSSS", "MEEEEEEW")
desc = "They're a cute little kitty-cat! ... wait ... what the hell?"
/datum/dog_fashion/head/rabbit
name = "Hoppy"
emote_see = list("twitches their nose", "hops around a bit")
desc = "This is Hoppy. They're a corgi-...urmm... bunny rabbit."
emote_see = list("twitches their nose", "hops around a bit")
/datum/dog_fashion/head/beret
name = "Yann"
@@ -85,16 +108,14 @@
speak = list("le woof!", "le bark!", "JAPPE!!")
emote_see = list("cowers in fear.", "surrenders.", "plays dead.","looks as though there is a wall in front of them.")
/datum/dog_fashion/head/detective
name = "Detective REAL_NAME"
desc = "NAME sees through your lies..."
name = "Detective %REAL_NAME%"
desc = "%NAME% sees through your lies..."
emote_see = list("investigates the area.","sniffs around for clues.","searches for scooby snacks.","takes a candycorn from the hat.")
/datum/dog_fashion/head/nurse
name = "Nurse REAL_NAME"
desc = "NAME needs 100cc of beef jerky... STAT!"
name = "Nurse %REAL_NAME%"
desc = "%NAME% needs 100cc of beef jerky... STAT!"
/datum/dog_fashion/head/pirate
name = "Pirate-title Pirate-name"
@@ -104,7 +125,7 @@
speak = list("Arrrrgh!!","Grrrrrr!")
/datum/dog_fashion/head/pirate/New(mob/M)
..()
. = ..()
name = "[pick("Ol'","Scurvy","Black","Rum","Gammy","Bloody","Gangrene","Death","Long-John")] [pick("kibble","leg","beard","tooth","poop-deck","Threepwood","Le Chuck","corsair","Silver","Crusoe")]"
/datum/dog_fashion/head/ushanka
@@ -113,85 +134,81 @@
emote_see = list("contemplates the failings of the capitalist economic model.", "ponders the pros and cons of vanguardism.")
/datum/dog_fashion/head/ushanka/New(mob/M)
..()
name = "[pick("Comrade","Commissar","Glorious Leader")] [M.real_name]"
name = "[pick("Comrade","Commissar","Glorious Leader")] %REAL_NAME%"
return ..()
/datum/dog_fashion/head/warden
name = "Officer REAL_NAME"
emote_see = list("drools.","looks for donuts.")
name = "Officer %REAL_NAME%"
desc = "Stop right there criminal scum!"
emote_see = list("drools.","looks for donuts.")
/datum/dog_fashion/head/warden_red
name = "Officer REAL_NAME"
emote_see = list("drools.","looks for donuts.")
name = "Officer %REAL_NAME%"
desc = "Stop right there criminal scum!"
emote_see = list("drools.","looks for donuts.")
/datum/dog_fashion/head/blue_wizard
name = "Grandwizard REAL_NAME"
name = "Grandwizard %REAL_NAME%"
speak = list("YAP", "Woof!", "Bark!", "AUUUUUU", "EI NATH!")
/datum/dog_fashion/head/red_wizard
name = "Pyromancer REAL_NAME"
name = "Pyromancer %REAL_NAME%"
speak = list("YAP", "Woof!", "Bark!", "AUUUUUU", "ONI SOMA!")
/datum/dog_fashion/head/cardborg
name = "Borgi"
desc = "Result of robotics budget cuts."
speak = list("Ping!","Beep!","Woof!")
emote_see = list("goes rogue.", "sniffs out non-humans.")
desc = "Result of robotics budget cuts."
/datum/dog_fashion/head/ghost
name = "\improper Ghost"
desc = "Spooky!"
obj_icon_state = "sheet"
speak = list("WoooOOOooo~","AUUUUUUUUUUUUUUUUUU")
emote_see = list("stumbles around.", "shivers.")
emote_hear = list("howls!","groans.")
desc = "Spooky!"
obj_icon_state = "sheet"
/datum/dog_fashion/head/santa
name = "Santa's Corgi Helper"
desc = "They're very fond of milk and cookies."
emote_hear = list("barks Christmas songs.", "yaps merrily!")
emote_see = list("looks for presents.", "checks their list.")
desc = "They're very fond of milk and cookies."
/datum/dog_fashion/head/cargo_tech
name = "Corgi Tech REAL_NAME"
name = "Corgi Tech %REAL_NAME%"
desc = "The reason your yellow gloves have chew-marks."
/datum/dog_fashion/head/reindeer
name = "REAL_NAME the red-nosed Corgi"
emote_hear = list("lights the way!", "illuminates.", "yaps!")
name = "%REAL_NAME% the red-nosed Corgi"
desc = "They have a very shiny nose."
emote_hear = list("lights the way!", "illuminates.", "yaps!")
/datum/dog_fashion/head/sombrero
name = "Segnor REAL_NAME"
desc = "You must respect Elder Dogname"
/datum/dog_fashion/head/sombrero/New(mob/M)
..()
desc = "You must respect Elder [M.real_name]."
name = "Segnor %REAL_NAME%"
desc = "You must respect Elder %REAL_NAME%."
/datum/dog_fashion/head/hop
name = "Lieutenant REAL_NAME"
name = "Lieutenant %REAL_NAME%"
desc = "Can actually be trusted to not run off on their own."
/datum/dog_fashion/head/deathsquad
name = "Trooper REAL_NAME"
name = "Trooper %REAL_NAME%"
desc = "That's not red paint. That's real corgi blood."
/datum/dog_fashion/head/clown
name = "REAL_NAME the Clown"
name = "%REAL_NAME% the Clown"
desc = "Honkman's best friend."
speak = list("HONK!", "Honk!")
emote_see = list("plays tricks.", "slips.")
/datum/dog_fashion/head/festive
name = "Festive REAL_NAME"
name = "Festive %REAL_NAME%"
desc = "Ready to party!"
obj_icon_state = "festive"
/datum/dog_fashion/head/pumpkin/unlit
name = "Headless HoP-less REAL_NAME"
name = "Headless HoP-less %REAL_NAME%"
desc = "A spooky dog spirit of a beloved pet who lost their owner."
obj_icon_state = "pumpkin0"
speak = list("BOO!", "AUUUUUUU", "RAAARGH!")
@@ -202,7 +219,7 @@
obj_icon_state = "pumpkin1"
/datum/dog_fashion/head/blumpkin/unlit
name = "Hue-less Headless HoP-less REAL_NAME"
name = "Hue-less Headless HoP-less %REAL_NAME%"
desc = "An evil dog spirit of a beloved pet that haunts your treats pantries!"
obj_icon_state = "blumpkin0"
speak = list("BOO!", "AUUUUUUU", "RAAARGH!")
@@ -211,3 +228,11 @@
/datum/dog_fashion/head/blumpkin/lit
obj_icon_state = "blumpkin1"
/datum/dog_fashion/head/butter
name = "Butter %REAL_NAME%"
desc = "%NAME%. %CAPITAL_REAL_NAME% with the butter. %NAME%. %CAPITAL_REAL_NAME% with a butter on 'em."
obj_icon_state = "butter"
speak = list() //they're very patient and focused on holding the butter on 'em
emote_see = list("shakes a little.", "looks around.")
emote_hear = list("licks a trickle of the butter up.", "smiles.")
+1
View File
@@ -238,6 +238,7 @@
tastes = list("butter" = 1)
foodtypes = DAIRY
w_class = WEIGHT_CLASS_SMALL
dog_fashion = /datum/dog_fashion/head/butter
/obj/item/food/butter/examine(mob/user)
. = ..()
+2
View File
@@ -151,6 +151,7 @@
transform = transform.Turn(180)
if(!(basic_mob_flags & REMAIN_DENSE_WHILE_DEAD))
ADD_TRAIT(src, TRAIT_UNDENSE, BASIC_MOB_DEATH_TRAIT)
SEND_SIGNAL(src, COMSIG_BASICMOB_LOOK_DEAD)
/mob/living/basic/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
. = ..()
@@ -165,6 +166,7 @@
transform = transform.Turn(180)
if(!(basic_mob_flags & REMAIN_DENSE_WHILE_DEAD))
REMOVE_TRAIT(src, TRAIT_UNDENSE, BASIC_MOB_DEATH_TRAIT)
SEND_SIGNAL(src, COMSIG_BASICMOB_LOOK_ALIVE)
/mob/living/basic/update_sight()
lighting_color_cutoffs = list(lighting_cutoff_red, lighting_cutoff_green, lighting_cutoff_blue)
-870
View File
@@ -1,870 +0,0 @@
//Dogs.
// Add 'walkies' as valid input
/datum/pet_command/follow/dog
speech_commands = list("heel", "follow", "walkies")
// Add 'good dog' as valid input
/datum/pet_command/good_boy/dog
speech_commands = list("good dog")
// Set correct attack behaviour
/datum/pet_command/point_targetting/attack/dog
attack_behaviour = /datum/ai_behavior/basic_melee_attack/dog
/datum/pet_command/point_targetting/attack/dog/set_command_active(mob/living/parent, mob/living/commander)
. = ..()
parent.ai_controller.set_blackboard_key(BB_DOG_HARASS_HARM, TRUE)
/mob/living/basic/pet/dog
mob_biotypes = MOB_ORGANIC|MOB_BEAST
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
speak_emote = list("barks", "woofs")
faction = list(FACTION_NEUTRAL)
can_be_held = TRUE
ai_controller = /datum/ai_controller/basic_controller/dog
// The dog attack pet command can raise melee attack above 0
attack_verb_continuous = "bites"
attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
attack_vis_effect = ATTACK_EFFECT_BITE
/// Instructions you can give to dogs
var/static/list/pet_commands = list(
/datum/pet_command/idle,
/datum/pet_command/free,
/datum/pet_command/good_boy/dog,
/datum/pet_command/follow/dog,
/datum/pet_command/point_targetting/attack/dog,
/datum/pet_command/point_targetting/fetch,
/datum/pet_command/play_dead,
)
/mob/living/basic/pet/dog/Initialize(mapload)
. = ..()
AddElement(/datum/element/pet_bonus, "woofs happily!")
AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/unfriend_attacker, untamed_reaction = "%SOURCE% fixes %TARGET% with a look of betrayal.")
AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/meat/slab/human/mutant/skeleton, /obj/item/stack/sheet/bone), tame_chance = 30, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)), unique = FALSE)
AddComponent(/datum/component/obeys_commands, pet_commands)
/mob/living/basic/pet/dog/proc/update_dog_speech(datum/ai_planning_subtree/random_speech/speech)
speech.speak = string_list(list("YAP", "Woof!", "Bark!", "AUUUUUU"))
speech.emote_hear = string_list(list("barks!", "woofs!", "yaps.","pants."))
speech.emote_see = string_list(list("shakes [p_their()] head.", "chases [p_their()] tail.","shivers."))
/mob/living/basic/pet/dog/proc/tamed(mob/living/tamer)
visible_message(span_notice("[src] licks at [tamer] in a friendly manner!"))
//Corgis and pugs are now under one dog subtype
/mob/living/basic/pet/dog/corgi
name = "\improper corgi"
real_name = "corgi"
desc = "They're a corgi."
icon_state = "corgi"
icon_living = "corgi"
icon_dead = "corgi_dead"
held_state = "corgi"
butcher_results = list(/obj/item/food/meat/slab/corgi = 3, /obj/item/stack/sheet/animalhide/corgi = 1)
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "corgi"
ai_controller = /datum/ai_controller/basic_controller/dog/corgi
var/obj/item/inventory_head
var/obj/item/inventory_back
/// Access card for Ian.
var/obj/item/card/id/access_card = null
var/shaved = FALSE
var/nofur = FALSE //Corgis that have risen past the material plane of existence.
/// Is this corgi physically slow due to age, etc?
var/is_slow = FALSE
/mob/living/basic/pet/dog/corgi/examine(mob/user)
. = ..()
if(access_card)
. += "There appears to be [icon2html(access_card, user)] \a [access_card] pinned to [p_them()]."
/mob/living/basic/pet/dog/corgi/Destroy()
QDEL_NULL(inventory_head)
QDEL_NULL(inventory_back)
QDEL_NULL(access_card)
return ..()
/mob/living/basic/pet/dog/corgi/gib()
if(inventory_head)
inventory_head.forceMove(drop_location())
inventory_head = null
if(inventory_back)
inventory_back.forceMove(drop_location())
inventory_back = null
if(access_card)
access_card.forceMove(drop_location())
access_card = null
return ..()
/mob/living/basic/pet/dog/corgi/deadchat_plays(mode = ANARCHY_MODE, cooldown = 12 SECONDS)
. = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, list(
"speak" = CALLBACK(src, PROC_REF(bork)),
"wear_hat" = CALLBACK(src, PROC_REF(find_new_hat)),
"drop_hat" = CALLBACK(src, PROC_REF(drop_hat)),
"spin" = CALLBACK(src, TYPE_PROC_REF(/mob, emote), "spin")), cooldown, CALLBACK(src, PROC_REF(stop_deadchat_plays)))
if(. == COMPONENT_INCOMPATIBLE)
return
// Stop all automated behavior.
QDEL_NULL(ai_controller)
///Deadchat bark.
/mob/living/basic/pet/dog/corgi/proc/bork()
var/emote = pick("barks!", "woofs!", "yaps.","pants.")
manual_emote(emote)
///Deadchat plays command that picks a new hat for Ian.
/mob/living/basic/pet/dog/corgi/proc/find_new_hat()
if(!isturf(loc))
return
var/list/possible_headwear = list()
for(var/obj/item/item in loc)
if(ispath(item.dog_fashion, /datum/dog_fashion/head))
possible_headwear += item
if(!length(possible_headwear))
for(var/obj/item/item in orange(1))
if(ispath(item.dog_fashion, /datum/dog_fashion/head) && CanReach(item))
possible_headwear += item
if(!length(possible_headwear))
return
if(inventory_head)
inventory_head.forceMove(drop_location())
inventory_head = null
place_on_head(pick(possible_headwear))
visible_message(span_notice("[src] puts [inventory_head] on [p_their()] own head, somehow."))
///Deadchat plays command that drops the current hat off Ian.
/mob/living/basic/pet/dog/corgi/proc/drop_hat()
if(!inventory_head)
return
visible_message(span_notice("[src] vigorously shakes [p_their()] head, dropping [inventory_head] to the ground."))
inventory_head.forceMove(drop_location())
inventory_head = null
update_corgi_fluff()
regenerate_icons()
///Turn AI back on.
/mob/living/basic/pet/dog/corgi/proc/stop_deadchat_plays()
var/controller_type = initial(ai_controller)
ai_controller = new controller_type(src)
ai_controller?.set_blackboard_key(BB_DOG_IS_SLOW, is_slow)
/mob/living/basic/pet/dog/corgi/handle_atom_del(atom/A)
if(A == inventory_head)
inventory_head = null
update_corgi_fluff()
regenerate_icons()
if(A == inventory_back)
inventory_back = null
update_corgi_fluff()
regenerate_icons()
return ..()
/mob/living/basic/pet/dog/pug
name = "\improper pug"
real_name = "pug"
desc = "They're a pug."
icon = 'icons/mob/simple/pets.dmi'
icon_state = "pug"
icon_living = "pug"
icon_dead = "pug_dead"
butcher_results = list(/obj/item/food/meat/slab/pug = 3)
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "pug"
held_state = "pug"
/mob/living/basic/pet/dog/pug/Initialize(mapload)
. = ..()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_PUG, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
/mob/living/basic/pet/dog/pug/mcgriff
name = "McGriff"
desc = "This dog can tell something smells around here, and that something is CRIME!"
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
/mob/living/basic/pet/dog/bullterrier
name = "\improper bull terrier"
real_name = "bull terrier"
desc = "They're a bull terrier."
icon = 'icons/mob/simple/pets.dmi'
icon_state = "bullterrier"
icon_living = "bullterrier"
icon_dead = "bullterrier_dead"
butcher_results = list(/obj/item/food/meat/slab/corgi = 3) // Would feel redundant to add more new dog meats.
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "bullterrier"
held_state = "bullterrier"
/mob/living/basic/pet/dog/corgi/exoticcorgi
name = "Exotic Corgi"
desc = "As cute as they are colorful!"
icon = 'icons/mob/simple/pets.dmi'
icon_state = "corgigrey"
icon_living = "corgigrey"
icon_dead = "corgigrey_dead"
nofur = TRUE
/mob/living/basic/pet/dog/Initialize(mapload)
. = ..()
var/dog_area = get_area(src)
for(var/obj/structure/bed/dogbed/D in dog_area)
if(D.update_owner(src)) //No muscling in on my turf you fucking parrot
break
/mob/living/basic/pet/dog/corgi/Initialize(mapload)
. = ..()
regenerate_icons()
AddElement(/datum/element/strippable, GLOB.strippable_corgi_items)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CORGI, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(on_tried_access))
/**
* Handler for COMSIG_MOB_TRIED_ACCESS
*/
/mob/living/basic/pet/dog/corgi/proc/on_tried_access(mob/accessor, obj/locked_thing)
SIGNAL_HANDLER
return locked_thing?.check_access(access_card) ? ACCESS_ALLOWED : ACCESS_DISALLOWED
/mob/living/basic/pet/dog/corgi/exoticcorgi/Initialize(mapload)
. = ..()
var/newcolor = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
/mob/living/basic/pet/dog/corgi/death(gibbed)
..(gibbed)
regenerate_icons()
GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list(
/datum/strippable_item/corgi_head,
/datum/strippable_item/corgi_back,
/datum/strippable_item/pet_collar,
/datum/strippable_item/corgi_id,
)))
/datum/strippable_item/corgi_head
key = STRIPPABLE_ITEM_HEAD
/datum/strippable_item/corgi_head/get_item(atom/source)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
return corgi_source.inventory_head
/datum/strippable_item/corgi_head/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
corgi_source.place_on_head(equipping, user)
/datum/strippable_item/corgi_head/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
user.put_in_hands(corgi_source.inventory_head)
corgi_source.inventory_head = null
corgi_source.update_corgi_fluff()
corgi_source.regenerate_icons()
/datum/strippable_item/pet_collar
key = STRIPPABLE_ITEM_PET_COLLAR
/datum/strippable_item/pet_collar/get_item(atom/source)
var/mob/living/basic/pet/pet_source = source
if (!istype(pet_source))
return
return pet_source.collar
/datum/strippable_item/pet_collar/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if (!.)
return FALSE
if (!istype(equipping, /obj/item/clothing/neck/petcollar))
to_chat(user, span_warning("That's not a collar."))
return FALSE
return TRUE
/datum/strippable_item/pet_collar/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/pet_source = source
if (!istype(pet_source))
return
pet_source.add_collar(equipping, user)
/datum/strippable_item/pet_collar/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/pet_source = source
if (!istype(pet_source))
return
var/obj/collar = pet_source.remove_collar(user.drop_location())
user.put_in_hands(collar)
/datum/strippable_item/corgi_back
key = STRIPPABLE_ITEM_BACK
/datum/strippable_item/corgi_back/get_item(atom/source)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
return corgi_source.inventory_back
/datum/strippable_item/corgi_back/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if (!.)
return FALSE
if (!ispath(equipping.dog_fashion, /datum/dog_fashion/back))
to_chat(user, span_warning("You set [equipping] on [source]'s back, but it falls off!"))
equipping.forceMove(source.drop_location())
if (prob(25))
step_rand(equipping)
dance_rotate(source, set_original_dir = TRUE)
return FALSE
return TRUE
/datum/strippable_item/corgi_back/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
equipping.forceMove(corgi_source)
corgi_source.inventory_back = equipping
corgi_source.update_corgi_fluff()
corgi_source.regenerate_icons()
/datum/strippable_item/corgi_back/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
user.put_in_hands(corgi_source.inventory_back)
corgi_source.inventory_back = null
corgi_source.update_corgi_fluff()
corgi_source.regenerate_icons()
/datum/strippable_item/corgi_id
key = STRIPPABLE_ITEM_ID
/datum/strippable_item/corgi_id/get_item(atom/source)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
return corgi_source.access_card
/datum/strippable_item/corgi_id/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if (!.)
return FALSE
if (!isidcard(equipping))
to_chat(user, span_warning("You can't pin [equipping] to [source]!"))
return FALSE
return TRUE
/datum/strippable_item/corgi_id/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
equipping.forceMove(source)
corgi_source.access_card = equipping
/datum/strippable_item/corgi_id/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if (!istype(corgi_source))
return
user.put_in_hands(corgi_source.access_card)
corgi_source.access_card = null
corgi_source.update_corgi_fluff()
corgi_source.regenerate_icons()
/mob/living/basic/pet/dog/corgi/getarmor(def_zone, type)
var/armorval = 0
if(def_zone)
if(def_zone == BODY_ZONE_HEAD)
if(inventory_head)
armorval = inventory_head.get_armor_rating(type)
else
if(inventory_back)
armorval = inventory_back.get_armor_rating(type)
return armorval
else
if(inventory_head)
armorval += inventory_head.get_armor_rating(type)
if(inventory_back)
armorval += inventory_back.get_armor_rating(type)
return armorval*0.5
/mob/living/basic/pet/dog/corgi/attackby(obj/item/O, mob/user, params)
if (istype(O, /obj/item/razor))
if (shaved)
to_chat(user, span_warning("You can't shave this corgi, [p_they()] has already been shaved!"))
return
if (nofur)
to_chat(user, span_warning("You can't shave this corgi, [p_they()] [p_do()]n't have a fur coat!"))
return
user.visible_message(span_notice("[user] starts to shave [src] using \the [O]."), span_notice("You start to shave [src] using \the [O]..."))
if(do_after(user, 50, target = src))
user.visible_message(span_notice("[user] shaves [src]'s hair using \the [O]."))
playsound(loc, 'sound/items/welder2.ogg', 20, TRUE)
shaved = TRUE
icon_living = "[initial(icon_living)]_shaved"
icon_dead = "[initial(icon_living)]_shaved_dead"
if(stat == CONSCIOUS)
icon_state = icon_living
else
icon_state = icon_dead
return
..()
update_corgi_fluff()
//Corgis are supposed to be simpler, so only a select few objects can actually be put
//to be compatible with them. The objects are below.
//Many hats added, Some will probably be removed, just want to see which ones are popular.
// > some will probably be removed
/mob/living/basic/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/living/user)
if(inventory_head)
if(user)
to_chat(user, span_warning("You can't put more than one hat on [src]!"))
return
if(!item_to_add)
user.visible_message(span_notice("[user] pets [src]."), span_notice("You rest your hand on [src]'s head for a moment."))
if(flags_1 & HOLOGRAM_1)
return
user.add_mood_event(REF(src), /datum/mood_event/pet_animal, src)
return
if(user && !user.temporarilyRemoveItemFromInventory(item_to_add))
to_chat(user, span_warning("\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!"))
return
var/valid = FALSE
if(ispath(item_to_add.dog_fashion, /datum/dog_fashion/head))
valid = TRUE
//Various hats and items (worn on his head) change Ian's behaviour. His attributes are reset when a hat is removed.
if(valid)
if(health <= 0)
to_chat(user, span_notice("There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()]."))
else if(user)
user.visible_message(span_notice("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once."),
span_notice("You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks."),
span_hear("You hear a friendly-sounding bark."))
item_to_add.forceMove(src)
src.inventory_head = item_to_add
update_corgi_fluff()
regenerate_icons()
else
to_chat(user, span_warning("You set [item_to_add] on [src]'s head, but it falls off!"))
item_to_add.forceMove(drop_location())
if(prob(25))
step_rand(item_to_add)
dance_rotate(src, set_original_dir=TRUE)
return valid
/mob/living/basic/pet/dog/corgi/proc/update_corgi_fluff()
// First, change back to defaults
name = real_name
desc = initial(desc)
// BYOND/DM doesn't support the use of initial on lists.
speak_emote = list("barks", "woofs")
desc = initial(desc)
set_light(0)
if(inventory_head?.dog_fashion)
var/datum/dog_fashion/DF = new inventory_head.dog_fashion(src)
DF.apply(src)
if(inventory_back?.dog_fashion)
var/datum/dog_fashion/DF = new inventory_back.dog_fashion(src)
DF.apply(src)
/mob/living/basic/pet/dog/corgi/update_dog_speech(datum/ai_planning_subtree/random_speech/speech)
..()
if(inventory_head?.dog_fashion)
var/datum/dog_fashion/DF = new inventory_head.dog_fashion(src)
DF.apply_to_speech(speech)
if(inventory_back?.dog_fashion)
var/datum/dog_fashion/DF = new inventory_back.dog_fashion(src)
DF.apply_to_speech(speech)
//IAN! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/ian
name = "Ian"
real_name = "Ian" //Intended to hold the name without altering it.
gender = MALE
desc = "He's the HoP's beloved corgi."
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
var/age = 0
var/record_age = 1
var/memory_saved = FALSE
var/saved_head //path
/mob/living/basic/pet/dog/corgi/ian/Initialize(mapload)
. = ..()
// Ensure Ian exists
REGISTER_REQUIRED_MAP_ITEM(1, 1)
//parent call must happen first to ensure IAN
//is not in nullspace when child puppies spawn
Read_Memory()
if(age == 0)
var/turf/target = get_turf(loc)
if(target)
new /mob/living/basic/pet/dog/corgi/puppy/ian(target)
Write_Memory(FALSE)
return INITIALIZE_HINT_QDEL
else if(age == record_age)
icon_state = "old_corgi"
icon_living = "old_corgi"
held_state = "old_corgi"
icon_dead = "old_corgi_dead"
desc = "At a ripe old age of [record_age], Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
ai_controller?.set_blackboard_key(BB_DOG_IS_SLOW, TRUE)
is_slow = TRUE
speed = 2
/mob/living/basic/pet/dog/corgi/ian/Life(seconds_per_tick = SSMOBS_DT, times_fired)
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
Write_Memory(FALSE)
memory_saved = TRUE
..()
/mob/living/basic/pet/dog/corgi/ian/death()
if(!memory_saved)
Write_Memory(TRUE)
..()
/mob/living/basic/pet/dog/corgi/ian/proc/Read_Memory()
if(fexists("data/npc_saves/Ian.sav")) //legacy compatability to convert old format to new
var/savefile/S = new /savefile("data/npc_saves/Ian.sav")
S["age"] >> age
S["record_age"] >> record_age
S["saved_head"] >> saved_head
fdel("data/npc_saves/Ian.sav")
else
var/json_file = file("data/npc_saves/Ian.json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
age = json["age"]
record_age = json["record_age"]
saved_head = json["saved_head"]
if(isnull(age))
age = 0
if(isnull(record_age))
record_age = 1
if(saved_head)
place_on_head(new saved_head)
/mob/living/basic/pet/dog/corgi/ian/Write_Memory(dead, gibbed)
. = ..()
if(!.)
return
var/json_file = file("data/npc_saves/Ian.json")
var/list/file_data = list()
if(!dead)
file_data["age"] = age + 1
if((age + 1) > record_age)
file_data["record_age"] = record_age + 1
else
file_data["record_age"] = record_age
if(inventory_head)
file_data["saved_head"] = inventory_head.type
else
file_data["saved_head"] = null
else
file_data["age"] = 0
file_data["record_age"] = record_age
file_data["saved_head"] = null
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
/mob/living/basic/pet/dog/corgi/ian/narsie_act()
playsound(src, 'sound/magic/demon_dies.ogg', 75, TRUE)
var/mob/living/basic/pet/dog/corgi/narsie/N = new(loc)
N.setDir(dir)
investigate_log("has been gibbed by Nar'Sie.", INVESTIGATE_DEATHS)
gib()
/mob/living/basic/pet/dog/corgi/narsie
name = "Nars-Ian"
desc = "Ia! Ia!"
icon_state = "narsian"
icon_living = "narsian"
icon_dead = "narsian_dead"
faction = list(FACTION_NEUTRAL, FACTION_CULT)
gold_core_spawnable = NO_SPAWN
nofur = TRUE
unique_pet = TRUE
held_state = "narsian"
/mob/living/basic/pet/dog/corgi/narsie/Life(seconds_per_tick = SSMOBS_DT, times_fired)
..()
for(var/mob/living/simple_animal/pet/P in range(1, src))
if(P != src && !istype(P,/mob/living/basic/pet/dog/corgi/narsie))
visible_message(span_warning("[src] devours [P]!"), \
"<span class='cult big bold'>DELICIOUS SOULS</span>")
playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE)
narsie_act()
P.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
P.gib()
for(var/mob/living/basic/pet/P in range(1, src))
if(P != src && !istype(P,/mob/living/basic/pet/dog/corgi/narsie))
visible_message(span_warning("[src] devours [P]!"), \
"<span class='cult big bold'>DELICIOUS SOULS</span>")
playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE)
narsie_act()
P.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
P.gib()
/mob/living/basic/pet/dog/corgi/narsie/update_corgi_fluff()
..()
speak_emote = list("growls", "barks ominously")
/mob/living/basic/pet/dog/corgi/narsie/update_dog_speech(datum/ai_planning_subtree/random_speech/speech)
speech.speak = string_list(list("Tari'karat-pasnar!", "IA! IA!", "BRRUUURGHGHRHR"))
speech.emote_hear = string_list(list("barks echoingly!", "woofs hauntingly!", "yaps in an eldritch manner.", "mutters something unspeakable."))
speech.emote_see = string_list(list("communes with the unnameable.", "ponders devouring some souls.", "shakes."))
/mob/living/basic/pet/dog/corgi/narsie/narsie_act()
adjustBruteLoss(-maxHealth)
/mob/living/basic/pet/dog/corgi/regenerate_icons()
..()
cut_overlays() //we are redrawing the mob after all
if(inventory_head)
var/image/head_icon
var/datum/dog_fashion/DF = new inventory_head.dog_fashion(src)
if(!DF.obj_icon_state)
DF.obj_icon_state = inventory_head.icon_state
if(!DF.obj_alpha)
DF.obj_alpha = inventory_head.alpha
if(!DF.obj_color)
DF.obj_color = inventory_head.color
if(health <= 0)
head_icon = DF.get_overlay(dir = EAST)
head_icon.pixel_y = -8
head_icon.transform = turn(head_icon.transform, 180)
else
head_icon = DF.get_overlay()
add_overlay(head_icon)
if(inventory_back)
var/image/back_icon
var/datum/dog_fashion/DF = new inventory_back.dog_fashion(src)
if(!DF.obj_icon_state)
DF.obj_icon_state = inventory_back.icon_state
if(!DF.obj_alpha)
DF.obj_alpha = inventory_back.alpha
if(!DF.obj_color)
DF.obj_color = inventory_back.color
if(health <= 0)
back_icon = DF.get_overlay(dir = EAST)
back_icon.pixel_y = -11
back_icon.transform = turn(back_icon.transform, 180)
else
back_icon = DF.get_overlay()
add_overlay(back_icon)
return
/mob/living/basic/pet/dog/corgi/puppy
name = "\improper corgi puppy"
real_name = "corgi"
desc = "They're a corgi puppy!"
icon_state = "puppy"
icon_living = "puppy"
icon_dead = "puppy_dead"
density = FALSE
pass_flags = PASSMOB
mob_size = MOB_SIZE_SMALL
collar_icon_state = "puppy"
//puppies cannot wear anything.
/mob/living/basic/pet/dog/corgi/puppy/Topic(href, href_list)
if(href_list["remove_inv"] || href_list["add_inv"])
to_chat(usr, span_warning("You can't fit this on [src], [p_they()] [p_are()] too small!"))
return
..()
//PUPPY IAN! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/puppy/ian
name = "Ian"
real_name = "Ian"
gender = MALE
desc = "He's the HoP's beloved corgi puppy."
/mob/living/basic/pet/dog/corgi/puppy/void //Tribute to the corgis born in nullspace
name = "\improper void puppy"
real_name = "voidy"
desc = "A corgi puppy that has been infused with deep space energy. It's staring back..."
gender = NEUTER
icon_state = "void_puppy"
icon_living = "void_puppy"
icon_dead = "void_puppy_dead"
nofur = TRUE
held_state = "void_puppy"
unsuitable_atmos_damage = 0
minimum_survivable_temperature = TCMB
maximum_survivable_temperature = T0C + 40
/mob/living/basic/pet/dog/corgi/puppy/void/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_AI_BAGATTACK, INNATE_TRAIT)
/mob/living/basic/pet/dog/corgi/puppy/void/Process_Spacemove(movement_dir = 0, continuous_move = FALSE)
return 1 //Void puppies can navigate space.
//LISA! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/lisa
name = "Lisa"
real_name = "Lisa"
gender = FEMALE
desc = "She's tearing you apart."
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
icon_state = "lisa"
icon_living = "lisa"
icon_dead = "lisa_dead"
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
held_state = "lisa"
var/puppies = 0
//Lisa already has a cute bow!
/mob/living/basic/pet/dog/corgi/lisa/Topic(href, href_list)
if(href_list["remove_inv"] || href_list["add_inv"])
to_chat(usr, span_warning("[src] already has a cute bow!"))
return
..()
/mob/living/basic/pet/dog/breaddog //Most of the code originates from Cak
name = "Kobun"
desc = "It is a dog made out of bread. 'The universe is definitely half full'."
icon_state = "breaddog"
icon_living = "breaddog"
icon_dead = "breaddog_dead"
head_icon = 'icons/mob/clothing/head/pets_head.dmi'
health = 50
maxHealth = 50
gender = NEUTER
damage_coeff = list(BRUTE = 3, BURN = 3, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
butcher_results = list(/obj/item/organ/internal/brain = 1, /obj/item/organ/internal/heart = 1, /obj/item/food/breadslice/plain = 3, \
/obj/item/food/meat/slab = 2)
response_harm_continuous = "takes a bite out of"
response_harm_simple = "take a bite out of"
attacked_sound = 'sound/items/eatfood.ogg'
held_state = "breaddog"
worn_slot_flags = ITEM_SLOT_HEAD
/mob/living/basic/pet/dog/breaddog/CheckParts(list/parts)
..()
var/obj/item/organ/internal/brain/candidate = locate(/obj/item/organ/internal/brain) in contents
if(!candidate || !candidate.brainmob || !candidate.brainmob.mind)
return
candidate.brainmob.mind.transfer_to(src)
to_chat(src, "[span_boldbig("You are a bread dog!")]<b> You're a harmless dog/bread hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
free bread to the station! 'Im not alone, and you arent either'</b>")
var/default_name = "Kobun"
var/new_name = sanitize_name(reject_bad_text(tgui_input_text(src, "You are the [name]. Would you like to change your name to something else?", "Name change", default_name, MAX_NAME_LEN)), cap_after_symbols = FALSE)
if(new_name)
to_chat(src, span_notice("Your name is now <b>[new_name]</b>!"))
name = new_name
/mob/living/basic/pet/dog/breaddog/Life(seconds_per_tick = SSMOBS_DT, times_fired)
..()
if(stat)
return
if(health < maxHealth)
adjustBruteLoss(-4 * seconds_per_tick) //Fast life regen
for(var/mob/living/carbon/humanoid_entities in view(3, src)) //Mood aura which stay as long you do not wear Sanallite as hat or carry(I will try to make it work with hat someday(obviously weaker than normal one))
humanoid_entities.add_mood_event("kobun", /datum/mood_event/kobun)
/mob/living/basic/pet/dog/breaddog/attack_hand(mob/living/user, list/modifiers)
..()
if(user.combat_mode && user.reagents && !stat)
user.reagents.add_reagent(/datum/reagent/consumable/nutriment, 0.4)
user.reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 0.4)
/// A dog bone fully heals a dog, and befriends it if it's not your friend.
/obj/item/dog_bone
name = "jumbo dog bone"
desc = "A tasty femur full of juicy marrow, the perfect gift for your best friend."
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/food/meat.dmi'
icon_state = "skeletonmeat"
custom_materials = list(/datum/material/bone = SHEET_MATERIAL_AMOUNT * 4)
force = 3
throwforce = 5
attack_verb_continuous = list("attacks", "bashes", "batters", "bludgeons", "whacks")
attack_verb_simple = list("attack", "bash", "batter", "bludgeon", "whack")
/obj/item/dog_bone/pre_attack(atom/target, mob/living/user, params)
if (!isdog(target) || user.combat_mode)
return ..()
var/mob/living/basic/pet/dog/dog_target = target
if (dog_target.stat != CONSCIOUS)
return ..()
dog_target.emote("spin")
dog_target.fully_heal()
if (dog_target.befriend(user))
dog_target.tamed(user)
new /obj/effect/temp_visual/heart(target.loc)
qdel(src)
return TRUE
@@ -0,0 +1,94 @@
// Add 'walkies' as valid input
/datum/pet_command/follow/dog
speech_commands = list("heel", "follow", "walkies")
// Add 'good dog' as valid input
/datum/pet_command/good_boy/dog
speech_commands = list("good dog")
// Set correct attack behaviour
/datum/pet_command/point_targetting/attack/dog
attack_behaviour = /datum/ai_behavior/basic_melee_attack/dog
/datum/pet_command/point_targetting/attack/dog/set_command_active(mob/living/parent, mob/living/commander)
. = ..()
parent.ai_controller.set_blackboard_key(BB_DOG_HARASS_HARM, TRUE)
//Dogs.
/mob/living/basic/pet/dog
mob_biotypes = MOB_ORGANIC|MOB_BEAST
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
speak_emote = list("barks", "woofs")
faction = list(FACTION_NEUTRAL)
can_be_held = TRUE
ai_controller = /datum/ai_controller/basic_controller/dog
// The dog attack pet command can raise melee attack above 0
attack_verb_continuous = "bites"
attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
attack_vis_effect = ATTACK_EFFECT_BITE
/// Instructions you can give to dogs
var/static/list/pet_commands = list(
/datum/pet_command/idle,
/datum/pet_command/free,
/datum/pet_command/good_boy/dog,
/datum/pet_command/follow/dog,
/datum/pet_command/point_targetting/attack/dog,
/datum/pet_command/point_targetting/fetch,
/datum/pet_command/play_dead,
)
/mob/living/basic/pet/dog/Initialize(mapload)
. = ..()
AddElement(/datum/element/pet_bonus, "woofs happily!")
AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/unfriend_attacker, untamed_reaction = "%SOURCE% fixes %TARGET% with a look of betrayal.")
AddComponent(/datum/component/tameable, food_types = list(/obj/item/food/meat/slab/human/mutant/skeleton, /obj/item/stack/sheet/bone), tame_chance = 30, bonus_tame_chance = 15, after_tame = CALLBACK(src, PROC_REF(tamed)), unique = FALSE)
AddComponent(/datum/component/obeys_commands, pet_commands)
var/dog_area = get_area(src)
for(var/obj/structure/bed/dogbed/dog_bed in dog_area)
if(dog_bed.update_owner(src)) //No muscling in on my turf you fucking parrot
break
///Updates dog speech and emotes
/mob/living/basic/pet/dog/proc/update_dog_speech(datum/ai_planning_subtree/random_speech/speech)
speech.speak = string_list(list("YAP", "Woof!", "Bark!", "AUUUUUU"))
speech.emote_hear = string_list(list("barks!", "woofs!", "yaps.","pants."))
speech.emote_see = string_list(list("shakes [p_their()] head.", "chases [p_their()] tail.","shivers."))
///Proc to run on a successful taming attempt
/mob/living/basic/pet/dog/proc/tamed(mob/living/tamer)
visible_message(span_notice("[src] licks at [tamer] in a friendly manner!"))
/// A dog bone fully heals a dog, and befriends it if it's not your friend.
/obj/item/dog_bone
name = "jumbo dog bone"
desc = "A tasty femur full of juicy marrow, the perfect gift for your best friend."
w_class = WEIGHT_CLASS_SMALL
icon = 'icons/obj/food/meat.dmi'
icon_state = "skeletonmeat"
custom_materials = list(/datum/material/bone = SHEET_MATERIAL_AMOUNT * 4)
force = 3
throwforce = 5
attack_verb_continuous = list("attacks", "bashes", "batters", "bludgeons", "whacks")
attack_verb_simple = list("attack", "bash", "batter", "bludgeon", "whack")
/obj/item/dog_bone/pre_attack(atom/target, mob/living/user, params)
if (!isdog(target) || user.combat_mode)
return ..()
var/mob/living/basic/pet/dog/dog_target = target
if (dog_target.stat != CONSCIOUS)
return ..()
dog_target.emote("spin")
dog_target.fully_heal()
if (dog_target.befriend(user))
dog_target.tamed(user)
new /obj/effect/temp_visual/heart(target.loc)
qdel(src)
return TRUE
@@ -0,0 +1,555 @@
//CORGIS!
/mob/living/basic/pet/dog/corgi
name = "\improper corgi"
real_name = "corgi"
desc = "They're a corgi."
icon_state = "corgi"
icon_living = "corgi"
icon_dead = "corgi_dead"
held_state = "corgi"
butcher_results = list(/obj/item/food/meat/slab/corgi = 3, /obj/item/stack/sheet/animalhide/corgi = 1)
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "corgi"
ai_controller = /datum/ai_controller/basic_controller/dog/corgi
///Access card for the corgi.
var/obj/item/card/id/access_card = null
///Can this corgi be shaved by an electric razor?
var/can_be_shaved = TRUE
///Did this corgi get mutilated and has had their fur shaved by an electric razor, oh the humanity?
var/shaved = FALSE
///Currently worn item on the head slot
var/obj/item/inventory_head = null
///Currently worn item on the back slot
var/obj/item/inventory_back = null
///Is this corgi physically slow due to age, etc?
var/is_slow = FALSE
///Item slots that are available for this corgi to equip stuff into
var/list/strippable_inventory_slots = list()
/mob/living/basic/pet/dog/corgi/Initialize(mapload)
. = ..()
update_appearance()
AddElement(/datum/element/strippable, length(strippable_inventory_slots) ? create_strippable_list(strippable_inventory_slots) : GLOB.strippable_corgi_items)
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CORGI, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
RegisterSignal(src, COMSIG_MOB_TRIED_ACCESS, PROC_REF(on_tried_access))
RegisterSignals(src, list(COMSIG_BASICMOB_LOOK_ALIVE, COMSIG_BASICMOB_LOOK_DEAD), PROC_REF(on_appearance_change))
/mob/living/basic/pet/dog/corgi/Destroy()
QDEL_NULL(inventory_head)
QDEL_NULL(inventory_back)
QDEL_NULL(access_card)
UnregisterSignal(src, list(COMSIG_BASICMOB_LOOK_ALIVE, COMSIG_BASICMOB_LOOK_DEAD))
return ..()
/mob/living/basic/pet/dog/corgi/handle_atom_del(atom/deleting_atom)
if(deleting_atom == inventory_head)
inventory_head = null
update_corgi_fluff()
update_appearance(UPDATE_OVERLAYS)
if(deleting_atom == inventory_back)
inventory_back = null
update_corgi_fluff()
update_appearance(UPDATE_OVERLAYS)
return ..()
/mob/living/basic/pet/dog/corgi/gib()
if(inventory_head)
inventory_head.forceMove(drop_location())
inventory_head = null
if(inventory_back)
inventory_back.forceMove(drop_location())
inventory_back = null
if(access_card)
access_card.forceMove(drop_location())
access_card = null
return ..()
/mob/living/basic/pet/dog/corgi/examine(mob/user)
. = ..()
if(access_card)
. += "There appears to be [icon2html(access_card, user)] \a [access_card] pinned to [p_them()]."
/**
* Corgis get full protection from their equipped fashion items if attacked in a way that passes def_zone,
* which usually means any direct attack like melee or gunshot. Anything abstract like a bomb or acid or something
* will instead give half the armor value.
*/
/mob/living/basic/pet/dog/corgi/getarmor(def_zone, type)
var/armorval = 0
if(def_zone)
if(def_zone == BODY_ZONE_HEAD)
if(inventory_head)
armorval = inventory_head.get_armor_rating(type)
else
if(inventory_back)
armorval = inventory_back.get_armor_rating(type)
return armorval
else
if(inventory_head)
armorval += inventory_head.get_armor_rating(type)
if(inventory_back)
armorval += inventory_back.get_armor_rating(type)
return armorval * 0.5
/mob/living/basic/pet/dog/corgi/attackby(obj/item/attacking_item, mob/user, params)
if(istype(attacking_item, /obj/item/razor))
if(shaved)
to_chat(user, span_warning("You can't shave this corgi, [p_they()] has already been shaved!"))
return
if(!can_be_shaved)
to_chat(user, span_warning("You can't shave this corgi, [p_they()] [p_do()]n't have a fur coat!"))
return
user.visible_message(span_notice("[user] starts to shave [src] using \the [attacking_item]."), span_notice("You start to shave [src] using \the [attacking_item]..."))
if(do_after(user, 5 SECONDS, target = src))
user.visible_message(span_notice("[user] shaves [src]'s hair using \the [attacking_item]."))
playsound(get_turf(src), 'sound/items/welder2.ogg', 20, TRUE)
shaved = TRUE
icon_living = "[icon_living]_shaved"
icon_dead = "[icon_living]_shaved_dead"
if(stat == CONSCIOUS)
icon_state = icon_living
else
icon_state = icon_dead
return TRUE
return ..()
/mob/living/basic/pet/dog/corgi/update_dog_speech(datum/ai_planning_subtree/random_speech/speech)
. = ..()
if(inventory_head?.dog_fashion)
var/datum/dog_fashion/equipped_head_fashion_item = new inventory_head.dog_fashion(src)
equipped_head_fashion_item.apply_to_speech(speech)
if(inventory_back?.dog_fashion)
var/datum/dog_fashion/equipped_back_fashion_item = new inventory_back.dog_fashion(src)
equipped_back_fashion_item.apply_to_speech(speech)
/mob/living/basic/pet/dog/corgi/deadchat_plays(mode = ANARCHY_MODE, cooldown = 12 SECONDS)
. = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, list(
"speak" = CALLBACK(src, PROC_REF(bork)),
"wear_hat" = CALLBACK(src, PROC_REF(find_new_hat)),
"drop_hat" = CALLBACK(src, PROC_REF(drop_hat)),
"spin" = CALLBACK(src, TYPE_PROC_REF(/mob, emote), "spin")), cooldown, CALLBACK(src, PROC_REF(stop_deadchat_plays)))
if(. == COMPONENT_INCOMPATIBLE)
return
// Stop all automated behavior.
QDEL_NULL(ai_controller)
/mob/living/basic/pet/dog/corgi/update_overlays()
. = ..()
if(inventory_head)
var/image/head_icon
var/datum/dog_fashion/equipped_head_fashion_item = new inventory_head.dog_fashion(src)
if(!equipped_head_fashion_item.obj_icon_state)
equipped_head_fashion_item.obj_icon_state = inventory_head.icon_state
if(!equipped_head_fashion_item.obj_alpha)
equipped_head_fashion_item.obj_alpha = inventory_head.alpha
if(!equipped_head_fashion_item.obj_color)
equipped_head_fashion_item.obj_color = inventory_head.color
if(stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH))
head_icon = equipped_head_fashion_item.get_overlay(dir = EAST)
head_icon.pixel_y = -8
head_icon.transform = head_icon.transform.Turn(180)
else
head_icon = equipped_head_fashion_item.get_overlay()
. += head_icon
if(inventory_back)
var/image/back_icon
var/datum/dog_fashion/equipped_back_fashion_item = new inventory_back.dog_fashion(src)
if(!equipped_back_fashion_item.obj_icon_state)
equipped_back_fashion_item.obj_icon_state = inventory_back.icon_state
if(!equipped_back_fashion_item.obj_alpha)
equipped_back_fashion_item.obj_alpha = inventory_back.alpha
if(!equipped_back_fashion_item.obj_color)
equipped_back_fashion_item.obj_color = inventory_back.color
if(stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH))
back_icon = equipped_back_fashion_item.get_overlay(dir = EAST)
back_icon.pixel_y = -11
back_icon.transform = back_icon.transform.Turn(180)
else
back_icon = equipped_back_fashion_item.get_overlay()
. += back_icon
//Corgis are supposed to be simpler, so only a select few objects can actually be put
//to be compatible with them. The objects are below.
//Many hats added, Some will probably be removed, just want to see which ones are popular.
// > some will probably be removed
/**
* Places an item on the corgi's head, handling updating the corgi's appearance and the item's dog fashion modifiers
* to the name, description, speech etc. Doesn't need the user to complete, and is also used in station traits/events/persistence reading.
*/
/mob/living/basic/pet/dog/corgi/proc/place_on_head(obj/item/item_to_add, mob/living/user)
if(inventory_head)
if(user)
to_chat(user, span_warning("You can't put more than one hat on [src]!"))
return
if(!item_to_add)
user.visible_message(span_notice("[user] pets [src]."), span_notice("You rest your hand on [src]'s head for a moment."))
if(flags_1 & HOLOGRAM_1)
return
user.add_mood_event(REF(src), /datum/mood_event/pet_animal, src)
return
if(user && !user.temporarilyRemoveItemFromInventory(item_to_add))
to_chat(user, span_warning("\The [item_to_add] is stuck to your hand, you cannot put it on [src]'s head!"))
return
var/valid = FALSE
if(ispath(item_to_add.dog_fashion, /datum/dog_fashion/head))
valid = TRUE
//Various hats and items (worn on his head) change Ian's behaviour. His attributes are reset when a hat is removed.
if(valid)
if(user && (stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH)))
to_chat(user, span_notice("There is merely a dull, lifeless look in [real_name]'s eyes as you put \the [item_to_add] on [p_them()]."))
else if(user)
user.visible_message(span_notice("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once."),
span_notice("You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks."),
span_hear("You hear a friendly-sounding bark."))
item_to_add.forceMove(src)
inventory_head = item_to_add
update_corgi_fluff()
update_appearance(UPDATE_OVERLAYS)
else
to_chat(user, span_warning("You set [item_to_add] on [src]'s head, but it falls off!"))
item_to_add.forceMove(drop_location())
if(prob(25))
step_rand(item_to_add)
dance_rotate(src, set_original_dir = TRUE)
return valid
/mob/living/basic/pet/dog/corgi/proc/update_corgi_fluff()
// First, change back to defaults
name = real_name
desc = initial(desc)
// BYOND/DM doesn't support the use of initial on lists.
speak_emote = list("barks", "woofs")
desc = initial(desc)
set_light(0)
if(inventory_head?.dog_fashion)
var/datum/dog_fashion/equipped_head_fashion_item = new inventory_head.dog_fashion(src)
equipped_head_fashion_item.apply(src)
if(inventory_back?.dog_fashion)
var/datum/dog_fashion/equipped_back_fashion_item = new inventory_back.dog_fashion(src)
equipped_back_fashion_item.apply(src)
///Handler for COMSIG_MOB_TRIED_ACCESS
/mob/living/basic/pet/dog/corgi/proc/on_tried_access(mob/accessor, obj/locked_thing)
SIGNAL_HANDLER
return locked_thing?.check_access(access_card) ? ACCESS_ALLOWED : ACCESS_DISALLOWED
///Handles updating any existing overlays for the corgi (such as fashion items) when it changes how it appears, as in, dead or alive.
/mob/living/basic/pet/dog/corgi/proc/on_appearance_change()
SIGNAL_HANDLER
update_appearance(UPDATE_OVERLAYS)
///Deadchat plays bark.
/mob/living/basic/pet/dog/corgi/proc/bork()
var/emote = pick("barks!", "woofs!", "yaps.", "pants.")
manual_emote(emote)
///Deadchat plays command that picks a new hat for Ian.
/mob/living/basic/pet/dog/corgi/proc/find_new_hat()
if(!isturf(loc))
return
var/list/possible_headwear = list()
for(var/obj/item/item in loc)
if(ispath(item.dog_fashion, /datum/dog_fashion/head))
possible_headwear += item
if(!length(possible_headwear))
for(var/obj/item/item in orange(1))
if(ispath(item.dog_fashion, /datum/dog_fashion/head) && CanReach(item))
possible_headwear += item
if(!length(possible_headwear))
return
if(inventory_head)
inventory_head.forceMove(drop_location())
inventory_head = null
place_on_head(pick(possible_headwear))
visible_message(span_notice("[src] puts [inventory_head] on [p_their()] own head, somehow."))
///Deadchat plays command that drops the current hat off Ian.
/mob/living/basic/pet/dog/corgi/proc/drop_hat()
if(!inventory_head)
return
visible_message(span_notice("[src] vigorously shakes [p_their()] head, dropping [inventory_head] to the ground."))
inventory_head.forceMove(drop_location())
inventory_head = null
update_corgi_fluff()
update_appearance(UPDATE_OVERLAYS)
///Turn AI back on.
/mob/living/basic/pet/dog/corgi/proc/stop_deadchat_plays()
var/controller_type = initial(ai_controller)
ai_controller = new controller_type(src)
ai_controller?.set_blackboard_key(BB_DOG_IS_SLOW, is_slow)
//SUBTYPES!
/mob/living/basic/pet/dog/corgi/exoticcorgi
name = "Exotic Corgi"
desc = "As cute as they are colorful!"
icon = 'icons/mob/simple/pets.dmi'
icon_state = "corgigrey"
icon_living = "corgigrey"
icon_dead = "corgigrey_dead"
can_be_shaved = FALSE
/mob/living/basic/pet/dog/corgi/exoticcorgi/Initialize(mapload)
. = ..()
var/newcolor = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
//IAN! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/ian
name = "Ian"
real_name = "Ian" //Intended to hold the name without altering it.
gender = MALE
desc = "He's the HoP's beloved corgi."
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
///Tracks how many rounds did Ian survive from start to finish
var/age = 0
///Callback to execute upon roundend to check whether Ian has survived the round or not
var/datum/callback/i_will_survive
///Highest achieved consecutive rounds that Ian survived from start to finish
var/record_age = 1
///Whether we have already recorded this Ian's achievements(survival and equipped hat) to the database
var/memory_saved = FALSE
///Path of the item Ian was wearing in a previous shift, if he survived through it
var/saved_head = null
/mob/living/basic/pet/dog/corgi/ian/Initialize(mapload)
. = ..()
// Ensure Ian exists
REGISTER_REQUIRED_MAP_ITEM(1, 1)
//parent call must happen first to ensure IAN
//is not in nullspace when child puppies spawn
Read_Memory()
if(age == 0)
var/turf/target = get_turf(loc)
if(target)
new /mob/living/basic/pet/dog/corgi/puppy/ian(target)
Write_Memory(FALSE)
return INITIALIZE_HINT_QDEL
else if(age == record_age)
icon_state = "old_corgi"
icon_living = "old_corgi"
held_state = "old_corgi"
icon_dead = "old_corgi_dead"
desc = "At a ripe old age of [record_age], Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
ai_controller?.set_blackboard_key(BB_DOG_IS_SLOW, TRUE)
is_slow = TRUE
speed = 2
//setup roundend check for Ian's whereabouts
i_will_survive = CALLBACK(src, PROC_REF(check_ian_survival))
SSticker.OnRoundend(i_will_survive)
/mob/living/basic/pet/dog/corgi/ian/Destroy()
LAZYREMOVE(SSticker.round_end_events, i_will_survive) //cleanup the survival callback
QDEL_NULL(i_will_survive)
return ..()
/mob/living/basic/pet/dog/corgi/ian/death()
if(!memory_saved)
Write_Memory(TRUE)
return ..()
/mob/living/basic/pet/dog/corgi/ian/narsie_act()
playsound(src, 'sound/magic/demon_dies.ogg', 75, TRUE)
var/mob/living/basic/pet/dog/corgi/narsie/narsIan = new(loc)
narsIan.setDir(dir)
investigate_log("has been gibbed and replaced with Nars-Ian by Nar'Sie.", INVESTIGATE_DEATHS)
gib()
/mob/living/basic/pet/dog/corgi/ian/Write_Memory(dead, gibbed)
. = ..()
if(!.)
return
memory_saved = TRUE
var/json_file = file("data/npc_saves/Ian.json")
var/list/file_data = list()
if(!dead)
file_data["age"] = age + 1
if((age + 1) > record_age)
file_data["record_age"] = record_age + 1
else
file_data["record_age"] = record_age
if(inventory_head)
file_data["saved_head"] = inventory_head.type
else
file_data["saved_head"] = null
else
file_data["age"] = 0
file_data["record_age"] = record_age
file_data["saved_head"] = null
fdel(json_file)
WRITE_FILE(json_file, json_encode(file_data))
///Reads the database's persistence json file and applies age, record_age and saved_head to Ian.
/mob/living/basic/pet/dog/corgi/ian/proc/Read_Memory()
if(fexists("data/npc_saves/Ian.sav")) //legacy compatability to convert old format to new
var/savefile/S = new /savefile("data/npc_saves/Ian.sav")
S["age"] >> age
S["record_age"] >> record_age
S["saved_head"] >> saved_head
fdel("data/npc_saves/Ian.sav")
else
var/json_file = file("data/npc_saves/Ian.json")
if(!fexists(json_file))
return
var/list/json = json_decode(file2text(json_file))
age = json["age"]
record_age = json["record_age"]
saved_head = json["saved_head"]
if(isnull(age))
age = 0
if(isnull(record_age))
record_age = 1
if(saved_head)
place_on_head(new saved_head)
///Checks whether Ian has survived the round or not
/mob/living/basic/pet/dog/corgi/ian/proc/check_ian_survival()
if(!stat && !memory_saved)
Write_Memory(FALSE)
//NARS-IAN! SQ-Q-QooEglor-r'EEn-nl-luEEEf-f-fth-h
/mob/living/basic/pet/dog/corgi/narsie
name = "Nars-Ian"
real_name = "Nars-Ian"
desc = "Ia! Ia!"
icon_state = "narsian"
icon_living = "narsian"
icon_dead = "narsian_dead"
faction = list(FACTION_NEUTRAL, FACTION_CULT)
speak_emote = list("growls", "barks ominously")
gold_core_spawnable = NO_SPAWN
can_be_shaved = FALSE
unique_pet = TRUE
held_state = "narsian"
//this could maybe be turned into an element
/mob/living/basic/pet/dog/corgi/narsie/Life(seconds_per_tick = SSMOBS_DT, times_fired)
. = ..()
//consume simple_animal pets
for(var/mob/living/simple_animal/pet/simple_pet in range(1, src))
if(simple_pet != src && !istype(simple_pet, /mob/living/basic/pet/dog/corgi/narsie))
visible_message(span_warning("Dark magic resonating from [src] devours [simple_pet]!"), \
"<span class='cult big bold'>DELICIOUS SOULS</span>")
playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE)
new /obj/effect/temp_visual/cult/sac(get_turf(simple_pet))
narsie_act()
simple_pet.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
simple_pet.gib()
//consume basic pets
for(var/mob/living/basic/pet/basic_pet in range(1, src))
if(basic_pet != src && !istype(basic_pet, /mob/living/basic/pet/dog/corgi/narsie))
visible_message(span_warning("Dark magic resonating from [src] devours [basic_pet]!"), \
"<span class='cult big bold'>DELICIOUS SOULS</span>")
playsound(src, 'sound/magic/demon_attack1.ogg', 75, TRUE)
new /obj/effect/temp_visual/cult/sac(get_turf(basic_pet))
narsie_act()
basic_pet.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
basic_pet.gib()
/mob/living/basic/pet/dog/corgi/narsie/update_corgi_fluff()
. = ..()
speak_emote = list("growls", "barks ominously")
/mob/living/basic/pet/dog/corgi/narsie/update_dog_speech(datum/ai_planning_subtree/random_speech/speech)
speech.speak = string_list(list("Tari'karat-pasnar!", "IA! IA!", "BRRUUURGHGHRHR"))
speech.emote_hear = string_list(list("barks echoingly!", "woofs hauntingly!", "yaps in an eldritch manner.", "mutters something unspeakable."))
speech.emote_see = string_list(list("communes with the unnameable.", "ponders devouring some souls.", "shakes."))
/mob/living/basic/pet/dog/corgi/narsie/narsie_act()
if(stat == DEAD) //Nar'Sie loves her doggy
visible_message(span_warning("[src] arises again, revived by the dark magicks!"), \
span_cultlarge("RISE"))
revive(ADMIN_HEAL_ALL) //also means that a dead Nars-Ian can consume a pet and revive
adjustBruteLoss(-maxHealth)
//LISA! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/lisa
name = "Lisa"
real_name = "Lisa"
gender = FEMALE
desc = "She's tearing you apart."
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
icon_state = "lisa"
icon_living = "lisa"
icon_dead = "lisa_dead"
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "bops"
response_disarm_simple = "bop"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
held_state = "lisa"
strippable_inventory_slots = list(/datum/strippable_item/corgi_back, /datum/strippable_item/pet_collar, /datum/strippable_item/corgi_id) //Lisa already has a cute bow!
//PUPPIES! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/puppy
name = "\improper corgi puppy"
real_name = "corgi"
desc = "They're a corgi puppy!"
icon_state = "puppy"
icon_living = "puppy"
icon_dead = "puppy_dead"
density = FALSE
pass_flags = PASSMOB
mob_size = MOB_SIZE_SMALL
collar_icon_state = "puppy"
strippable_inventory_slots = list(/datum/strippable_item/pet_collar, /datum/strippable_item/corgi_id) //puppies are too small to handle hats and back slot items
//PUPPY IAN! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/puppy/ian
name = "Ian"
real_name = "Ian"
gender = MALE
desc = "He's the HoP's beloved corgi puppy."
/mob/living/basic/pet/dog/corgi/puppy/void //Tribute to the corgis born in nullspace
name = "\improper void puppy"
real_name = "voidy"
desc = "A corgi puppy that has been infused with deep space energy. It's staring back..."
gender = NEUTER
icon_state = "void_puppy"
icon_living = "void_puppy"
icon_dead = "void_puppy_dead"
can_be_shaved = FALSE
held_state = "void_puppy"
unsuitable_atmos_damage = 0
minimum_survivable_temperature = TCMB
maximum_survivable_temperature = T0C + 40
/mob/living/basic/pet/dog/corgi/puppy/void/Initialize(mapload)
. = ..()
//void puppies can spacewalk and can harass people from within a container because they're void puppies
add_traits(list(TRAIT_AI_BAGATTACK, TRAIT_SPACEWALK), INNATE_TRAIT)
@@ -0,0 +1,91 @@
//Less exciting dog breeds
/mob/living/basic/pet/dog/pug
name = "\improper pug"
real_name = "pug"
desc = "They're a pug."
icon = 'icons/mob/simple/pets.dmi'
icon_state = "pug"
icon_living = "pug"
icon_dead = "pug_dead"
butcher_results = list(/obj/item/food/meat/slab/pug = 3)
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "pug"
held_state = "pug"
/mob/living/basic/pet/dog/pug/Initialize(mapload)
. = ..()
AddElement(/datum/element/swabable, CELL_LINE_TABLE_PUG, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
/mob/living/basic/pet/dog/pug/mcgriff
name = "McGriff"
real_name = "McGriff"
desc = "This dog can tell something smells around here, and that something is CRIME!"
gold_core_spawnable = NO_SPAWN
unique_pet = TRUE
/mob/living/basic/pet/dog/bullterrier
name = "\improper bull terrier"
real_name = "bull terrier"
desc = "They're a bull terrier."
icon = 'icons/mob/simple/pets.dmi'
icon_state = "bullterrier"
icon_living = "bullterrier"
icon_dead = "bullterrier_dead"
butcher_results = list(/obj/item/food/meat/slab/corgi = 3) // Would feel redundant to add more new dog meats.
gold_core_spawnable = FRIENDLY_SPAWN
collar_icon_state = "bullterrier"
held_state = "bullterrier"
/mob/living/basic/pet/dog/breaddog //Most of the code originates from Cak
name = "Kobun"
real_name = "Kobun"
desc = "It is a dog made out of bread. 'The universe is definitely half full'."
icon_state = "breaddog"
icon_living = "breaddog"
icon_dead = "breaddog_dead"
head_icon = 'icons/mob/clothing/head/pets_head.dmi'
health = 50
maxHealth = 50
gender = NEUTER
damage_coeff = list(BRUTE = 3, BURN = 3, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
butcher_results = list(/obj/item/organ/internal/brain = 1, /obj/item/organ/internal/heart = 1, /obj/item/food/breadslice/plain = 3, \
/obj/item/food/meat/slab = 2)
response_harm_continuous = "takes a bite out of"
response_harm_simple = "take a bite out of"
attacked_sound = 'sound/items/eatfood.ogg'
held_state = "breaddog"
worn_slot_flags = ITEM_SLOT_HEAD
/mob/living/basic/pet/dog/breaddog/CheckParts(list/parts)
. = ..()
var/obj/item/organ/internal/brain/candidate = locate(/obj/item/organ/internal/brain) in contents
if(!candidate || !candidate.brainmob || !candidate.brainmob.mind)
return
candidate.brainmob.mind.transfer_to(src)
to_chat(src, "[span_boldbig("You are a bread dog!")]<b> You're a harmless dog/bread hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
free bread to the station! 'Im not alone, and you arent either'</b>")
var/default_name = "Kobun"
var/new_name = sanitize_name(reject_bad_text(tgui_input_text(src, "You are the [name]. Would you like to change your name to something else?", "Name change", default_name, MAX_NAME_LEN)), cap_after_symbols = FALSE)
if(new_name)
to_chat(src, span_notice("Your name is now <b>[new_name]</b>!"))
name = new_name
real_name = new_name
/mob/living/basic/pet/dog/breaddog/Life(seconds_per_tick = SSMOBS_DT, times_fired)
. = ..()
if(stat)
return
if(health < maxHealth)
adjustBruteLoss(-4 * seconds_per_tick) //Fast life regen
for(var/mob/living/carbon/humanoid_entities in view(3, src)) //Mood aura which stay as long you do not wear Sanallite as hat or carry(I will try to make it work with hat someday(obviously weaker than normal one))
humanoid_entities.add_mood_event("kobun", /datum/mood_event/kobun)
/mob/living/basic/pet/dog/breaddog/attack_hand(mob/living/user, list/modifiers)
. = ..()
if(user.combat_mode && user.reagents && !stat)
user.reagents.add_reagent(/datum/reagent/consumable/nutriment, 0.4)
user.reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 0.4)
@@ -0,0 +1,156 @@
//corgi's stippable items
GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list(
/datum/strippable_item/corgi_head,
/datum/strippable_item/corgi_back,
/datum/strippable_item/pet_collar,
/datum/strippable_item/corgi_id,
)))
/datum/strippable_item/corgi_head
key = STRIPPABLE_ITEM_HEAD
/datum/strippable_item/corgi_head/get_item(atom/source)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
return corgi_source.inventory_head
/datum/strippable_item/corgi_head/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
corgi_source.place_on_head(equipping, user)
/datum/strippable_item/corgi_head/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
user.put_in_hands(corgi_source.inventory_head)
corgi_source.inventory_head = null
corgi_source.update_corgi_fluff()
corgi_source.update_appearance(UPDATE_OVERLAYS)
/datum/strippable_item/pet_collar
key = STRIPPABLE_ITEM_PET_COLLAR
/datum/strippable_item/pet_collar/get_item(atom/source)
var/mob/living/basic/pet/pet_source = source
if(!istype(pet_source))
return
return pet_source.collar
/datum/strippable_item/pet_collar/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if(!.)
return FALSE
if(!istype(equipping, /obj/item/clothing/neck/petcollar))
to_chat(user, span_warning("That's not a collar."))
return FALSE
return TRUE
/datum/strippable_item/pet_collar/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/pet_source = source
if(!istype(pet_source))
return
pet_source.add_collar(equipping, user)
/datum/strippable_item/pet_collar/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/pet_source = source
if(!istype(pet_source))
return
var/obj/collar = pet_source.remove_collar(user.drop_location())
user.put_in_hands(collar)
/datum/strippable_item/corgi_back
key = STRIPPABLE_ITEM_BACK
/datum/strippable_item/corgi_back/get_item(atom/source)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
return corgi_source.inventory_back
/datum/strippable_item/corgi_back/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if(!.)
return FALSE
if(!ispath(equipping.dog_fashion, /datum/dog_fashion/back))
to_chat(user, span_warning("You set [equipping] on [source]'s back, but it falls off!"))
equipping.forceMove(source.drop_location())
if(prob(25))
step_rand(equipping)
dance_rotate(source, set_original_dir = TRUE)
return FALSE
return TRUE
/datum/strippable_item/corgi_back/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
equipping.forceMove(corgi_source)
corgi_source.inventory_back = equipping
corgi_source.update_corgi_fluff()
corgi_source.update_appearance(UPDATE_OVERLAYS)
/datum/strippable_item/corgi_back/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
user.put_in_hands(corgi_source.inventory_back)
corgi_source.inventory_back = null
corgi_source.update_corgi_fluff()
corgi_source.update_appearance(UPDATE_OVERLAYS)
/datum/strippable_item/corgi_id
key = STRIPPABLE_ITEM_ID
/datum/strippable_item/corgi_id/get_item(atom/source)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
return corgi_source.access_card
/datum/strippable_item/corgi_id/try_equip(atom/source, obj/item/equipping, mob/user)
. = ..()
if(!.)
return FALSE
if(!isidcard(equipping))
to_chat(user, span_warning("You can't pin [equipping] to [source]!"))
return FALSE
return TRUE
/datum/strippable_item/corgi_id/finish_equip(atom/source, obj/item/equipping, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
equipping.forceMove(source)
corgi_source.access_card = equipping
/datum/strippable_item/corgi_id/finish_unequip(atom/source, mob/user)
var/mob/living/basic/pet/dog/corgi/corgi_source = source
if(!istype(corgi_source))
return
user.put_in_hands(corgi_source.access_card)
corgi_source.access_card = null
corgi_source.update_corgi_fluff()
corgi_source.update_appearance(UPDATE_OVERLAYS)
+2 -3
View File
@@ -47,7 +47,7 @@
return
// Determine which status tag to add to the middle of the icon state.
var/dead_tag = stat == DEAD ? "_dead" : null
var/dead_tag = (stat == DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH)) ? "_dead" : null
var/rest_tag = has_collar_resting_icon_state && resting ? "_rest" : null
var/stat_tag = dead_tag || rest_tag || ""
@@ -55,9 +55,8 @@
. += mutable_appearance(icon, "[collar_icon_state][stat_tag]tag")
/mob/living/basic/pet/gib()
. = ..()
remove_collar(drop_location(), update_visuals = FALSE)
return ..()
/mob/living/basic/pet/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
. = ..()
@@ -45,7 +45,7 @@ Slimecrossing Mobs
icon_state = "slime_puppy"
icon_living = "slime_puppy"
icon_dead = "slime_puppy_dead"
nofur = TRUE
can_be_shaved = FALSE
gold_core_spawnable = NO_SPAWN
speak_emote = list("blorbles", "bubbles", "borks")
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

@@ -67,7 +67,7 @@
)
death_message = "beeps, its mechanical parts hissing before the chassis collapses in a loud thud."
gold_core_spawnable = NO_SPAWN
nofur = TRUE
can_be_shaved = FALSE
ai_controller = /datum/ai_controller/basic_controller/dog/borgi
unsuitable_atmos_damage = 0
minimum_survivable_temperature = 0
+5 -1
View File
@@ -334,6 +334,7 @@
#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_x_act.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_ai.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_arcade.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_basic.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_carbon.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_living.dm"
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm"
@@ -4156,10 +4157,13 @@
#include "code\modules\mob\living\basic\lavaland\goliath\goliath_actions.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\goliath_ai.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\tentacle.dm"
#include "code\modules\mob\living\basic\pets\dog.dm"
#include "code\modules\mob\living\basic\pets\fox.dm"
#include "code\modules\mob\living\basic\pets\penguin.dm"
#include "code\modules\mob\living\basic\pets\pet.dm"
#include "code\modules\mob\living\basic\pets\dog\_dog.dm"
#include "code\modules\mob\living\basic\pets\dog\corgi.dm"
#include "code\modules\mob\living\basic\pets\dog\dog_subtypes.dm"
#include "code\modules\mob\living\basic\pets\dog\strippable_items.dm"
#include "code\modules\mob\living\basic\ruin_defender\stickman.dm"
#include "code\modules\mob\living\basic\space_fauna\ant.dm"
#include "code\modules\mob\living\basic\space_fauna\cat_surgeon.dm"