diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 7f335afed04..c93cb22246a 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1462,6 +1462,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BEAST_EMPATHY "beast_empathy" // you're good with animals, such as with taming them #define TRAIT_STURDY_FRAME "sturdy_frame" // you suffer much lesser effects from equipment that slows you down +/// Has this mob been tamed? +#define TRAIT_TAMED "tamed" + /// This item cannot be selected for or used by a theft objective (Spies, Traitors, etc.) #define TRAIT_ITEM_OBJECTIVE_BLOCKED "item_objective_blocked" /// This trait lets you attach limbs to any player without surgery. diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 8fff1e9688e..6fffe7203f4 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -587,6 +587,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_TACKLING_WINGED_ATTACKER" = TRAIT_TACKLING_WINGED_ATTACKER, "TRAIT_TACTICALLY_CAMOUFLAGED" = TRAIT_TACTICALLY_CAMOUFLAGED, "TRAIT_TAGGER" = TRAIT_TAGGER, + "TRAIT_TAMED" = TRAIT_TAMED, "TRAIT_TEMPORARY_BODY" = TRAIT_TEMPORARY_BODY, "TRAIT_TENACIOUS" = TRAIT_TENACIOUS, "TRAIT_TENTACLE_IMMUNE" = TRAIT_TENTACLE_IMMUNE, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 3bb5fc532f1..508334bab3f 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -308,6 +308,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_TACKLING_TAILED_DEFENDER" = TRAIT_TACKLING_TAILED_DEFENDER, "TRAIT_TACKLING_TAILED_POUNCE" = TRAIT_TACKLING_TAILED_POUNCE, "TRAIT_TAGGER" = TRAIT_TAGGER, + "TRAIT_TAMED" = TRAIT_TAMED, "TRAIT_TENTACLE_IMMUNE" = TRAIT_TENTACLE_IMMUNE, "TRAIT_TESLA_SHOCKIMMUNE" = TRAIT_TESLA_SHOCKIMMUNE, "TRAIT_TETRODOTOXIN_HEALING" = TRAIT_TETRODOTOXIN_HEALING, diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index c515df2cdd0..ba6153aa77f 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -739,3 +739,23 @@ TEXT_EAST = list(0, 5), TEXT_WEST = list(0, 5), ) + +/datum/component/riding/creature/spider + rider_traits = list(TRAIT_WEB_SURFER, TRAIT_FENCE_CLIMBER) + ride_check_flags = RIDER_NEEDS_ARM | UNBUCKLE_DISABLED_RIDER + +/datum/component/riding/creature/spider/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 10), + TEXT_SOUTH = list( 0, 10), + TEXT_EAST = list(-5, 10), + TEXT_WEST = list( 5, 10), + ) + +/datum/component/riding/creature/spider/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), + TEXT_EAST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_WEST = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), + ) diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index cdaa2ea434c..73a29c11eca 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -799,6 +799,8 @@ ///Called after the atom is 'tamed' for type-specific operations, Usually called by the tameable component but also other things. /atom/proc/tamed(mob/living/tamer, obj/item/food) + SHOULD_CALL_PARENT(TRUE) + ADD_TRAIT(src, TRAIT_TAMED, INNATE_TRAIT) return /** diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index 7a135e74317..5b230a6605d 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -481,6 +481,7 @@ flick("glutton_mouth", src) /mob/living/basic/clown/mutant/glutton/tamed(mob/living/tamer, atom/food) + . = ..() buckle_lying = 0 AddElement(/datum/element/ridable, /datum/component/riding/creature/glutton) diff --git a/code/modules/mob/living/basic/cytology/vatbeast.dm b/code/modules/mob/living/basic/cytology/vatbeast.dm index 84eb8e1fcd4..a52411f0d82 100644 --- a/code/modules/mob/living/basic/cytology/vatbeast.dm +++ b/code/modules/mob/living/basic/cytology/vatbeast.dm @@ -51,6 +51,7 @@ ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(enjoyed_food)) /mob/living/basic/vatbeast/tamed(mob/living/tamer, obj/item/food) + . = ..() buckle_lying = 0 AddElement(/datum/element/ridable, /datum/component/riding/creature/vatbeast) set_faction(list(FACTION_NEUTRAL)) diff --git a/code/modules/mob/living/basic/farm_animals/cow/_cow.dm b/code/modules/mob/living/basic/farm_animals/cow/_cow.dm index d55869f751d..3c6b1e81422 100644 --- a/code/modules/mob/living/basic/farm_animals/cow/_cow.dm +++ b/code/modules/mob/living/basic/farm_animals/cow/_cow.dm @@ -79,6 +79,7 @@ AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15) /mob/living/basic/cow/tamed(mob/living/tamer, atom/food) + . = ..() visible_message("[src] [tame_message] as it seems to bond with [tamer].", "You [self_tame_message], recognizing [tamer] as your new pal.") AddElement(/datum/element/ridable, /datum/component/riding/creature/cow) diff --git a/code/modules/mob/living/basic/farm_animals/pig.dm b/code/modules/mob/living/basic/farm_animals/pig.dm index 784e1bfb221..0ef58faca89 100644 --- a/code/modules/mob/living/basic/farm_animals/pig.dm +++ b/code/modules/mob/living/basic/farm_animals/pig.dm @@ -55,6 +55,7 @@ AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15) /mob/living/basic/pig/tamed(mob/living/tamer, atom/food) + . = ..() AddElement(/datum/element/ridable, /datum/component/riding/creature/pig) visible_message(span_notice("[src] snorts respectfully.")) diff --git a/code/modules/mob/living/basic/farm_animals/pony.dm b/code/modules/mob/living/basic/farm_animals/pony.dm index 0989fabae0f..a44d042809c 100644 --- a/code/modules/mob/living/basic/farm_animals/pony.dm +++ b/code/modules/mob/living/basic/farm_animals/pony.dm @@ -60,6 +60,7 @@ AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 15, unique = unique_tamer) /mob/living/basic/pony/tamed(mob/living/tamer, atom/food) + . = ..() playsound(src, 'sound/mobs/non-humanoids/pony/snort.ogg', 50) AddElement(/datum/element/ridable, /datum/component/riding/creature/pony) visible_message(span_notice("[src] snorts happily.")) diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm index c50c56c38c3..9d1393fbc3b 100644 --- a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm @@ -68,6 +68,7 @@ AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 15, bonus_tame_chance = 5) /mob/living/basic/mining/wolf/tamed(mob/living/tamer, atom/food) + . = ..() new /obj/effect/temp_visual/heart(src.loc) // ride wolf, life good AddElement(/datum/element/ridable, /datum/component/riding/creature/wolf) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index 9a531a7bb45..b20f29364bd 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -118,6 +118,7 @@ AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 5) /mob/living/basic/mining/goldgrub/tamed(mob/living/tamer, atom/food) + . = ..() new /obj/effect/temp_visual/heart(src.loc) AddElement(/datum/element/ridable, /datum/component/riding/creature/goldgrub) AddComponent(/datum/component/obeys_commands, pet_commands) diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm index c2c597dfd31..6aef2570060 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath.dm @@ -36,8 +36,6 @@ var/tentacle_warning_state = "goliath_preattack" /// Can this kind of goliath be tamed? var/tameable = TRUE - /// Has this particular goliath been tamed? - var/tamed = FALSE /// Can someone ride us around like a horse? var/saddled = FALSE /// Slight cooldown to prevent double-dipping if we use both abilities at once @@ -112,7 +110,7 @@ if (saddled) balloon_alert(user, "already saddled!") return - if (!tamed) + if (!HAS_TRAIT(src, TRAIT_TAMED)) balloon_alert(user, "too rowdy!") return balloon_alert(user, "affixing saddle...") @@ -150,10 +148,6 @@ return icon_state = tentacle_warning_state -/// Get ready for mounting -/mob/living/basic/mining/goliath/tamed(mob/living/tamer, atom/food) - tamed = TRUE - // Copy entire faction rather than just placing user into faction, to avoid tentacle peril on station /mob/living/basic/mining/goliath/befriend(mob/living/new_friend) . = ..() diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index 5c5107162cf..1801d2dc189 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -74,6 +74,7 @@ charge.Trigger(target = atom_target) /mob/living/basic/mining/lobstrosity/tamed(mob/living/tamer, obj/item/food) + . = ..() new /obj/effect/temp_visual/heart(loc) /// Pet commands for this mob, however you'll have to tame juvenile lobstrosities to a trained adult one. var/list/pet_commands = list( @@ -167,8 +168,6 @@ base_fishing_level = SKILL_LEVEL_NOVICE /// What do we become when we grow up? var/mob/living/basic/mining/lobstrosity/grow_type = /mob/living/basic/mining/lobstrosity - /// Were we tamed? If yes, tame the mob we become when we grow up too. - var/was_tamed = FALSE /datum/emote/lobstrosity_juvenile abstract_type = /datum/emote/lobstrosity_juvenile @@ -226,7 +225,6 @@ /mob/living/basic/mining/lobstrosity/juvenile/tamed(mob/living/tamer, obj/item/food) . = ..() - was_tamed = TRUE // They are more pettable I guess AddElement(/datum/element/pet_bonus, "chitter") REMOVE_TRAIT(src, TRAIT_MOB_HIDE_HAPPINESS, INNATE_TRAIT) @@ -237,7 +235,7 @@ /mob/living/basic/mining/lobstrosity/juvenile/proc/grow_up() var/name_to_use = name == initial(name) ? grow_type::name : name var/mob/living/basic/mining/lobstrosity/grown = change_mob_type(grow_type, get_turf(src), name_to_use) - if(was_tamed) + if(HAS_TRAIT(src, TRAIT_TAMED)) grown.tamed() for(var/friend in ai_controller?.blackboard?[BB_FRIENDS_LIST]) grown.befriend(friend) diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index ce10ab89525..0db8b036eee 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -91,6 +91,7 @@ ///Proc to run on a successful taming attempt /mob/living/basic/pet/dog/tamed(mob/living/tamer, atom/food) + . = ..() 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. diff --git a/code/modules/mob/living/basic/pets/parrot/_parrot.dm b/code/modules/mob/living/basic/pets/parrot/_parrot.dm index 5f667857f40..8e338d7bf60 100644 --- a/code/modules/mob/living/basic/pets/parrot/_parrot.dm +++ b/code/modules/mob/living/basic/pets/parrot/_parrot.dm @@ -447,6 +447,7 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( return returnable_list /mob/living/basic/parrot/tamed(mob/living/tamer, atom/food) + . = ..() new /obj/effect/temp_visual/heart(drop_location()) /mob/living/basic/parrot/proc/drop_item_on_signal(mob/living/user) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index ea679a38235..6f1ff9e864f 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -142,6 +142,7 @@ /// Called when another mob has forged a bond of friendship with this one, passed the taming mob as 'tamer' /mob/living/basic/carp/tamed(mob/living/tamer, atom/food, feedback = TRUE) + . = ..() AddElement(/datum/element/ridable, ridable_data) AddComponent(/datum/component/obeys_commands, tamed_commands) if (!feedback) diff --git a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm index fd549c92ffe..26bb5548e80 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm @@ -117,6 +117,7 @@ COOLDOWN_START(src, eye_healing, 15 SECONDS) /mob/living/basic/eyeball/tamed(mob/living/tamer, atom/food) + . = ..() spin(spintime = 2 SECONDS, speed = 1) //become passive to the humens APPLY_FACTION_AND_ALLIES_FROM(src, tamer) diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider.dm b/code/modules/mob/living/basic/space_fauna/spider/spider.dm index 8cf80569766..1399e5e1b0a 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/spider.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/spider.dm @@ -53,6 +53,13 @@ var/menu_description = "Tanky and strong for the defense of the nest and other spiders." /// If true then you shouldn't be told that you're a spider antagonist as soon as you are placed into this mob var/apply_spider_antag = TRUE + /// Commands you can give this spider once it is tamed + var/static/list/tamed_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/follow, + /datum/pet_command/attack, + ) /datum/emote/spider abstract_type = /datum/emote/spider @@ -85,6 +92,17 @@ webbing.Grant(src) ai_controller?.set_blackboard_key(BB_SPIDER_WEB_ACTION, webbing) + var/static/list/food_types = list( + /obj/item/food/meat/slab/human/mutant/lizard, + /obj/item/food/meat/slab/human/mutant/fly, + /obj/item/food/meat/slab/human/mutant/moth, + /obj/item/food/meat/slab/mouse, + /obj/item/food/meat/slab/mothroach, + /obj/item/food/meat/slab/blood_worm, + /obj/item/food/deadmouse, + ) + AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 20, bonus_tame_chance = 10) + /mob/living/basic/spider/Login() . = ..() if(!. || !client) @@ -92,6 +110,8 @@ GLOB.spidermobs[src] = TRUE add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/player_spider_modifier, multiplicative_slowdown = player_speed_modifier) + AddElement(/datum/element/ridable, /datum/component/riding/creature/spider) + /mob/living/basic/spider/Logout() . = ..() remove_movespeed_modifier(/datum/movespeed_modifier/player_spider_modifier) @@ -100,6 +120,12 @@ GLOB.spidermobs -= src return ..() +/mob/living/basic/spider/tamed(mob/living/tamer, atom/food, feedback = TRUE) + . = ..() + new /obj/effect/temp_visual/heart(src.loc) + AddElement(/datum/element/ridable, /datum/component/riding/creature/spider) + AddComponent(/datum/component/obeys_commands, tamed_commands) + /mob/living/basic/spider/mob_negates_gravity() if(locate(/obj/structure/spider/stickyweb) in loc) return TRUE @@ -158,6 +184,12 @@ grown.set_name() grown.set_brute_loss(get_brute_loss()) grown.set_fire_loss(get_fire_loss()) + + if(HAS_TRAIT(src, TRAIT_TAMED)) + grown.tamed() + else if(istype(grown, /mob/living/basic/spider/giant)) // Adults cannot be tamed via snacks + qdel(grown.GetComponent(/datum/component/tameable)) + qdel(src) /** diff --git a/code/modules/mob/living/basic/vermin/mouse.dm b/code/modules/mob/living/basic/vermin/mouse.dm index 698eb30c752..67cae390295 100644 --- a/code/modules/mob/living/basic/vermin/mouse.dm +++ b/code/modules/mob/living/basic/vermin/mouse.dm @@ -28,8 +28,6 @@ ai_controller = /datum/ai_controller/basic_controller/mouse - /// Whether this rat is friendly to players - var/tame = FALSE /// What color our mouse is. Brown, gray and white - leave blank for random. var/body_color /// Does this mouse contribute to the ratcap? @@ -63,7 +61,8 @@ SSmobs.cheeserats |= src ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) - src.tame = tame + if(tame) + ADD_TRAIT(src, TRAIT_TAMED, INNATE_TRAIT) if(!isnull(new_body_color)) body_color = new_body_color if(isnull(body_color)) @@ -81,7 +80,7 @@ AddComponent(/datum/component/swarming, 16, 16) //max_x, max_y /mob/living/basic/mouse/proc/make_tameable() - if (tame) + if (HAS_TRAIT(src, TRAIT_TAMED)) add_faction(FACTION_NEUTRAL) else var/static/list/food_types = list(/obj/item/food/cheese) @@ -196,9 +195,9 @@ /// Called when a mouse is hand-fed some cheese, it will stop being afraid of humans /mob/living/basic/mouse/tamed(mob/living/tamer, obj/item/food/cheese/cheese) + . = ..() new /obj/effect/temp_visual/heart(loc) add_faction(FACTION_NEUTRAL) - tame = TRUE try_consume_cheese(cheese) ai_controller.CancelActions() // Interrupt any current fleeing @@ -248,7 +247,7 @@ /// Creates a new mouse based on this mouse's subtype. /mob/living/basic/mouse/proc/create_a_new_rat() - new /mob/living/basic/mouse(loc, /* tame = */ tame) + new /mob/living/basic/mouse(loc, HAS_TRAIT(src, TRAIT_TAMED)) /// Biting into a cable will cause a mouse to get shocked and die if applicable. Or do nothing if they're lucky. /mob/living/basic/mouse/proc/try_bite_cable(obj/structure/cable/cable) @@ -302,7 +301,7 @@ contributes_to_ratcap = FALSE /mob/living/basic/mouse/brown/tom/make_tameable() - tame = TRUE + ADD_TRAIT(src, TRAIT_TAMED, INNATE_TRAIT) return ..() /mob/living/basic/mouse/brown/tom/Initialize(mapload) @@ -312,7 +311,7 @@ AddElement(/datum/element/pet_bonus, "squeak") /mob/living/basic/mouse/brown/tom/create_a_new_rat() - new /mob/living/basic/mouse/brown(loc, /* tame = */ tame) // dominant gene + new /mob/living/basic/mouse/brown(loc, HAS_TRAIT(src, TRAIT_TAMED)) // dominant gene /mob/living/basic/mouse/rat name = "rat"