From 8f3d1036c8f4f7b51acc6bad8b28009a81e20ac4 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sun, 19 Nov 2023 20:56:37 +0100 Subject: [PATCH] [MIRROR] Refactor icemoon wolves into basic mobs and add taming + pack behavior [MDB IGNORE] (#25126) * Refactor icemoon wolves into basic mobs and add taming + pack behavior (#79736) ## About The Pull Request Ports icemoon wolves over to the basic mob framework with a bit of extra stuff: - Wolves call for help when attacked within a decently large radius. Because you know, pack animals. - Wolves can now be tamed with a slab of meat - When tamed, wolves can be ridden like goliath mounts. Ride wolf, life good. Pretend you're playing ARK and start shivering to death in thatch huts for that High Roleplay experience. - Tamed wolves have access to a bunch of pet commands (following, point fetching, point attacking, play dead, etc) and will also defend their owners vehemently if they're attacked. You can probably tame multiple if you wanted to. ## Why It's Good For The Game What part about riding wolves isn't entertaining? I don't really play /tg/ that much so I can't argue too much about the balance implications this might pose, but it's undoubtedly a stupid little gimmick and is likely to be used by bored assistants and miners with too much time on their hands. Especially robust individuals will probably find a million things to do with a basic mob capable of fetching, attacking on command and generally being able to defend themselves decently well. ## Changelog :cl: yooriss refactor: Icemoon wolves now use the basic mob framework and should act more intelligently, defending their pack. add: Icemoon wolves can be tamed with slabs of meat and can be ridden as mounts once friendly. Being rather large dogs, they also have access to most of the pet commands you'd expect, such as fetching things, and violently mauling people their owners point at. /:cl: --------- Co-authored-by: san7890 * Refactor icemoon wolves into basic mobs and add taming + pack behavior --------- Co-authored-by: Ephemeralis Co-authored-by: san7890 --- ..._underground_abandoned_plasma_facility.dmm | 8 +- .../icemoon_underground_frozen_comms.dmm | 8 +- .../pet_commands/pet_commands_basic.dm | 3 +- code/datums/mapgen/Cavegens/IcemoonCaves.dm | 4 +- .../structures/icemoon/cave_entrance.dm | 2 +- .../mob/living/basic/icemoon/wolf/wolf.dm | 91 +++++++++++++++++++ .../mob/living/basic/icemoon/wolf/wolf_ai.dm | 36 ++++++++ .../living/basic/icemoon/wolf/wolf_extras.dm | 18 ++++ tgstation.dme | 3 + .../Scripts/79736_icemoon_wolf_basic.txt | 1 + 10 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 code/modules/mob/living/basic/icemoon/wolf/wolf.dm create mode 100644 code/modules/mob/living/basic/icemoon/wolf/wolf_ai.dm create mode 100644 code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm create mode 100644 tools/UpdatePaths/Scripts/79736_icemoon_wolf_basic.txt diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm index 84b10a3457b..865695e5b33 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm @@ -358,7 +358,7 @@ /turf/open/lava/plasma/ice_moon, /area/icemoon/underground/explored) "gd" = ( -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) "gj" = ( @@ -1263,7 +1263,7 @@ /obj/effect/turf_decal/box/corners{ dir = 4 }, -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/floor/iron/smooth{ initial_gas_mix = "ICEMOON_ATMOS" }, @@ -1819,7 +1819,7 @@ /turf/open/floor/plating/icemoon, /area/ruin/plasma_facility/commons) "Hz" = ( -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) "HA" = ( @@ -2655,7 +2655,7 @@ id = "fire_facility_car"; name = "Garage Door" }, -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/floor/plating/icemoon, /area/ruin/plasma_facility/operations) "VD" = ( diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_frozen_comms.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_frozen_comms.dmm index beab0026e91..25f29890f45 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_frozen_comms.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_frozen_comms.dmm @@ -7,7 +7,7 @@ /turf/open/genturf, /area/icemoon/underground/unexplored/rivers) "bh" = ( -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) "cv" = ( @@ -69,7 +69,7 @@ }, /area/ruin/powered/shuttle) "oD" = ( -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/floor/iron/showroomfloor{ initial_gas_mix = "ICEMOON_ATMOS" }, @@ -99,7 +99,7 @@ }, /area/ruin/powered/shuttle) "rn" = ( -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /turf/open/floor/plating/icemoon, /area/ruin/powered/shuttle) "rS" = ( @@ -249,7 +249,7 @@ /turf/open/floor/plating/icemoon, /area/ruin/powered/shuttle) "FK" = ( -/mob/living/simple_animal/hostile/asteroid/wolf, +/mob/living/basic/mining/wolf, /obj/machinery/light/small/broken/directional/north, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/ruin/powered/shuttle) diff --git a/code/datums/components/pet_commands/pet_commands_basic.dm b/code/datums/components/pet_commands/pet_commands_basic.dm index f77dad1d8bb..9941f83e8b1 100644 --- a/code/datums/components/pet_commands/pet_commands_basic.dm +++ b/code/datums/components/pet_commands/pet_commands_basic.dm @@ -235,7 +235,8 @@ var/mob/living/victim = controller.blackboard[BB_CURRENT_PET_TARGET] if(QDELETED(victim)) return - if(victim.stat > controller.blackboard[BB_TARGET_MINIMUM_STAT]) + // cancel the action if they're below our given crit stat, OR if we're trying to attack ourselves (this can happen on tamed mobs w/ protect subtree rarely) + if(victim.stat > controller.blackboard[BB_TARGET_MINIMUM_STAT] || victim == controller.pawn) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return controller.queue_behavior(protect_behavior, BB_CURRENT_PET_TARGET, BB_PET_TARGETING_STRATEGY) diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm index b0fcd471db2..96d30fbd359 100644 --- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm +++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm @@ -4,11 +4,11 @@ weighted_mob_spawn_list = list( + /mob/living/basic/mining/goldgrub = 10, /mob/living/basic/mining/legion/snow = 50, /mob/living/basic/mining/lobstrosity = 15, - /mob/living/basic/mining/goldgrub = 10, + /mob/living/basic/mining/wolf = 50, /mob/living/simple_animal/hostile/asteroid/polarbear = 30, - /mob/living/simple_animal/hostile/asteroid/wolf = 50, /obj/structure/spawner/ice_moon = 3, /obj/structure/spawner/ice_moon/polarbear = 3, ) diff --git a/code/game/objects/structures/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index add1f278569..20f14844c12 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -17,7 +17,7 @@ GLOBAL_LIST_INIT(ore_probability, list( faction = list(FACTION_MINING) max_mobs = 3 max_integrity = 250 - mob_types = list(/mob/living/simple_animal/hostile/asteroid/wolf) + mob_types = list(/mob/living/basic/mining/wolf) move_resist = INFINITY anchored = TRUE scanner_taggable = TRUE diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm new file mode 100644 index 00000000000..c657fa42843 --- /dev/null +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm @@ -0,0 +1,91 @@ +/mob/living/basic/mining/wolf + name = "white wolf" + desc = "Pack hunters of the Icemoon wastes. While a mere nuisance individually, they become fearsome foes in larger groups." + icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi' + icon_state = "whitewolf" + icon_living = "whitewolf" + icon_dead = "whitewolf_dead" + mob_biotypes = MOB_ORGANIC|MOB_BEAST + mouse_opacity = MOUSE_OPACITY_ICON + speak_emote = list("howls") + friendly_verb_continuous = "howls at" + friendly_verb_simple = "howl at" + + butcher_results = list( + /obj/item/food/meat/slab = 2, + /obj/item/stack/sheet/sinew/wolf = 2, + /obj/item/stack/sheet/bone = 2 + ) + crusher_loot = /obj/item/crusher_trophy/wolf_ear + + maxHealth = 130 + health = 130 + obj_damage = 15 + melee_damage_lower = 7.5 + melee_damage_upper = 7.5 + attack_vis_effect = ATTACK_EFFECT_BITE + melee_attack_cooldown = 1.2 SECONDS + + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + death_message = "snarls its last and perishes." + + attack_sound = 'sound/weapons/bite.ogg' + move_force = MOVE_FORCE_WEAK + move_resist = MOVE_FORCE_WEAK + pull_force = MOVE_FORCE_WEAK + + ai_controller = /datum/ai_controller/basic_controller/wolf + + //can we tame this wolf? + var/can_tame = TRUE + + //commands to give when tamed + var/static/list/pet_commands = list( + /datum/pet_command/idle, + /datum/pet_command/free, + /datum/pet_command/good_boy/wolf, + /datum/pet_command/follow/wolf, + /datum/pet_command/point_targeting/attack, + /datum/pet_command/point_targeting/fetch, + /datum/pet_command/play_dead, + /datum/pet_command/protect_owner, + ) + +/mob/living/basic/mining/wolf/Initialize(mapload) + . = ..() + + AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) + AddElement(/datum/element/ai_flee_while_injured) + AddElement(/datum/element/ai_retaliate) + AddComponent(/datum/component/basic_mob_ability_telegraph) + AddComponent(/datum/component/basic_mob_attack_telegraph, telegraph_duration = 0.6 SECONDS) + + if(can_tame) + make_tameable() + +/mob/living/basic/mining/wolf/proc/make_tameable() + AddComponent(\ + /datum/component/tameable,\ + food_types = list(/obj/item/food/meat/slab),\ + tame_chance = 15,\ + bonus_tame_chance = 5,\ + after_tame = CALLBACK(src, PROC_REF(tame_wolf)),\ + ) + +/mob/living/basic/mining/wolf/proc/tame_wolf() + new /obj/effect/temp_visual/heart(src.loc) + // ride wolf, life good + AddElement(/datum/element/ridable, /datum/component/riding/creature/wolf) + AddComponent(/datum/component/obeys_commands, pet_commands) + // this is purely a convenience thing once tamed so you can drag them away from shit + ai_controller.ai_traits = STOP_MOVING_WHEN_PULLED + // makes tamed wolves run away far less + ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEE_DISTANCE, 7) + +//port the faction fix from goliath basicmob to make the wildlife hostile when tamed (and also help defuckulate reinforcements ai) +//this should also produce interesting behavior where tamed wolves defend other tamed wolves. +/mob/living/basic/mining/wolf/befriend(mob/living/new_friend) + . = ..() + faction = new_friend.faction.Copy() + visible_message(span_notice("[src] lowers [src.p_their()] snout at [new_friend]'s offering and begins to wag [src.p_their()] tail.")) diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf_ai.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf_ai.dm new file mode 100644 index 00000000000..f0809d2ec86 --- /dev/null +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf_ai.dm @@ -0,0 +1,36 @@ +//This mimicks the old simple_animal wolf behavior fairly closely. +//The 30 tiles fleeing is pretty wild and may need toning back under basicmob behavior, we'll have to see. +/datum/ai_controller/basic_controller/wolf + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items, + BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends, + BB_BASIC_MOB_FLEE_DISTANCE = 30, + BB_VISION_RANGE = 9, + BB_TARGET_MINIMUM_STAT = HARD_CRIT, + BB_REINFORCEMENTS_EMOTE = "unleashes a chilling howl, calling for aid!" + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + + //reinforcements needs to be skipped over entirely on tamed wolves because it causes them to attack their owner and then themselves + planning_subtrees = list( + /datum/ai_planning_subtree/pet_planning, + /datum/ai_planning_subtree/call_reinforcements/wolf, + /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, + /datum/ai_planning_subtree/flee_target, + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_planning_subtree/call_reinforcements/wolf + +/datum/ai_planning_subtree/call_reinforcements/wolf/decide_to_call(datum/ai_controller/controller) + //only call reinforcements if the person who just smacked us isn't a friend to avoid hitting them once, then killing ourselves if we've been tamed + if (controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET) && istype(controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET], /mob)) + return !(controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] in controller.blackboard[BB_FRIENDS_LIST]) + else + return FALSE + diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm new file mode 100644 index 00000000000..7765ec896a1 --- /dev/null +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm @@ -0,0 +1,18 @@ +// Some flavor additions for wolf-related pet commands +/datum/pet_command/good_boy/wolf + speech_commands = list("good wolf") + +/datum/pet_command/follow/wolf + // Nordic-themed for a bit of extra flavor + speech_commands = list("heel", "follow", "fylgja", "fyl") + +// Contains pixel offset data for sprites riding wolves +/datum/component/riding/creature/wolf + +/datum/component/riding/creature/wolf/handle_specials() + . = ..() + set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(1, 9), TEXT_SOUTH = list(1, 9), TEXT_EAST = list(0, 9), TEXT_WEST = list(2, 9))) + set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) + set_vehicle_dir_layer(NORTH, OBJ_LAYER) + set_vehicle_dir_layer(EAST, OBJ_LAYER) + set_vehicle_dir_layer(WEST, OBJ_LAYER) diff --git a/tgstation.dme b/tgstation.dme index e111bcf9012..066c6ec7d2c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4611,6 +4611,9 @@ #include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp.dm" #include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_abilities.dm" #include "code\modules\mob\living\basic\icemoon\ice_whelp\ice_whelp_ai.dm" +#include "code\modules\mob\living\basic\icemoon\wolf\wolf.dm" +#include "code\modules\mob\living\basic\icemoon\wolf\wolf_ai.dm" +#include "code\modules\mob\living\basic\icemoon\wolf\wolf_extras.dm" #include "code\modules\mob\living\basic\jungle\venus_human_trap.dm" #include "code\modules\mob\living\basic\jungle\leaper\leaper.dm" #include "code\modules\mob\living\basic\jungle\leaper\leaper_abilities.dm" diff --git a/tools/UpdatePaths/Scripts/79736_icemoon_wolf_basic.txt b/tools/UpdatePaths/Scripts/79736_icemoon_wolf_basic.txt new file mode 100644 index 00000000000..cb4497537ff --- /dev/null +++ b/tools/UpdatePaths/Scripts/79736_icemoon_wolf_basic.txt @@ -0,0 +1 @@ +/mob/living/simple_animal/hostile/asteroid/wolf : /mob/living/basic/mining/wolf{@OLD}