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}