mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-14 08:34:16 +01:00
Ports deer to basic mobs and adds some behaviors (#29270)
* ports deer to basic mobs and adds some behaviors * update updatepaths script number * whitespace * Apply suggestions from code review Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Signed-off-by: warriorstar-orion <orion@snowfrost.garden> --------- Signed-off-by: warriorstar-orion <orion@snowfrost.garden> Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
9cabc380b4
commit
dfacf83e18
@@ -0,0 +1,27 @@
|
||||
/mob/living/basic/deer
|
||||
name = "deer"
|
||||
desc = "A strong, brave deer."
|
||||
icon_state = "deer"
|
||||
icon_living = "deer"
|
||||
icon_dead = "deer_dead"
|
||||
faction = list("neutral", "jungle")
|
||||
see_in_dark = 0 //I'm so funny
|
||||
butcher_results = list(/obj/item/food/meat = 4)
|
||||
mob_biotypes = MOB_ORGANIC | MOB_BEAST
|
||||
gold_core_spawnable = FRIENDLY_SPAWN
|
||||
ai_controller = /datum/ai_controller/basic_controller/deer
|
||||
/// Things that will scare us into being stationary. Vehicles are scary to deers because they might have headlights.
|
||||
var/static/list/stationary_scary_things = list(
|
||||
/obj/vehicle,
|
||||
/obj/tgvehicle,
|
||||
)
|
||||
|
||||
/mob/living/basic/deer/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/wears_collar)
|
||||
AddElement(/datum/element/ai_retaliate)
|
||||
AddComponent(/datum/component/footstep, FOOTSTEP_MOB_SHOE)
|
||||
var/time_to_freeze_for = (rand(5, 10) SECONDS)
|
||||
ai_controller.set_blackboard_key(BB_STATIONARY_SECONDS, time_to_freeze_for)
|
||||
ai_controller.set_blackboard_key(BB_STATIONARY_COOLDOWN, (time_to_freeze_for * (rand(3, 5))))
|
||||
ai_controller.set_blackboard_key(BB_STATIONARY_TARGETS, typecacheof(stationary_scary_things))
|
||||
@@ -0,0 +1,147 @@
|
||||
/datum/ai_planning_subtree/random_speech/deer
|
||||
speech_chance = 2
|
||||
speak_verbs = list("grunts", "snorts", "bleats")
|
||||
emote_hear = list("grunts.", "snorts.", "bleats.")
|
||||
emote_see = list("shakes its head.")
|
||||
|
||||
/datum/ai_controller/basic_controller/deer
|
||||
blackboard = list(
|
||||
BB_STATIONARY_MOVE_TO_TARGET = TRUE,
|
||||
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
||||
)
|
||||
ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
idle_behavior = /datum/idle_behavior/idle_random_walk
|
||||
planning_subtrees = list(
|
||||
/datum/ai_planning_subtree/random_speech/deer,
|
||||
/datum/ai_planning_subtree/stare_at_thing,
|
||||
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee,
|
||||
/datum/ai_planning_subtree/flee_target,
|
||||
/datum/ai_planning_subtree/rest_at_home,
|
||||
/datum/ai_planning_subtree/play_with_friends,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/mark_territory,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/graze,
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/drink_water,
|
||||
)
|
||||
|
||||
/// subtree to go around drinking water
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/drink_water
|
||||
target_key = BB_DEER_WATER_TARGET
|
||||
finding_behavior = /datum/ai_behavior/find_and_set/in_list/turf_types
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/drink_water
|
||||
hunt_targets = list(
|
||||
/turf/simulated/floor/beach/away/water,
|
||||
)
|
||||
hunt_range = 7
|
||||
hunt_chance = 5
|
||||
|
||||
/datum/ai_behavior/hunt_target/drink_water
|
||||
always_reset_target = TRUE
|
||||
hunt_cooldown = 20 SECONDS
|
||||
|
||||
/datum/ai_behavior/hunt_target/drink_water/target_caught(mob/living/hunter, atom/hunted)
|
||||
var/static/list/possible_emotes = list("drinks the water!", "dances in the water!", "splashes around happily!")
|
||||
hunter.custom_emote(EMOTE_VISIBLE, pick(possible_emotes))
|
||||
|
||||
/// subtree to go around grazing
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/graze
|
||||
target_key = BB_DEER_GRASS_TARGET
|
||||
finding_behavior = /datum/ai_behavior/find_and_set/in_list/turf_types
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/eat_grass
|
||||
hunt_targets = list(
|
||||
/turf/simulated/floor/grass,
|
||||
)
|
||||
hunt_range = 7
|
||||
hunt_chance = 45
|
||||
|
||||
/datum/ai_behavior/hunt_target/eat_grass
|
||||
always_reset_target = TRUE
|
||||
hunt_cooldown = 15 SECONDS
|
||||
|
||||
/datum/ai_behavior/hunt_target/eat_grass/target_caught(mob/living/hunter, atom/hunted)
|
||||
var/static/list/possible_emotes = list("eats the grass!", "munches down the grass!", "chews on the grass!")
|
||||
hunter.custom_emote(EMOTE_VISIBLE, pick(possible_emotes))
|
||||
|
||||
/// subtree to go around playing with other deers
|
||||
/datum/ai_planning_subtree/play_with_friends
|
||||
|
||||
/datum/ai_planning_subtree/play_with_friends/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/static/list/emote_list = list("plays with", "dances with", "celebrates with")
|
||||
var/static/list/friend_types = typecacheof(list(/mob/living/basic/deer))
|
||||
if(controller.blackboard_key_exists(BB_DEER_PLAYFRIEND))
|
||||
controller.queue_behavior(/datum/ai_behavior/emote_on_target, BB_DEER_PLAYFRIEND, emote_list)
|
||||
if(SPT_PROB(3, seconds_per_tick))
|
||||
controller.queue_behavior(/datum/ai_behavior/find_hunt_target/valid_deer, BB_DEER_PLAYFRIEND, friend_types)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
|
||||
/datum/ai_behavior/emote_on_target/deer_play
|
||||
|
||||
/datum/ai_behavior/emote_on_target/deer_play/run_emote(mob/living/living_pawn, atom/target, list/emote_list)
|
||||
. = ..()
|
||||
living_pawn.spin(spintime = 4, speed = 1)
|
||||
|
||||
/datum/ai_behavior/find_hunt_target/valid_deer/valid_dinner(mob/living/source, mob/living/deer, radius, datum/ai_controller/controller, seconds_per_tick)
|
||||
if(deer.stat == DEAD)
|
||||
return FALSE
|
||||
if(!can_see(source, deer, radius))
|
||||
return FALSE
|
||||
deer.ai_controller?.set_blackboard_key(BB_DEER_PLAYFRIEND, source)
|
||||
return can_see(source, deer, radius)
|
||||
|
||||
/// subtree to mark trees as territories
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/mark_territory
|
||||
target_key = BB_DEER_TREE_TARGET
|
||||
finding_behavior = /datum/ai_behavior/find_hunt_target
|
||||
hunting_behavior = /datum/ai_behavior/hunt_target/mark_territory
|
||||
hunt_targets = list(/obj/structure/flora/tree)
|
||||
hunt_range = 7
|
||||
hunt_chance = 75
|
||||
|
||||
/datum/ai_behavior/hunt_target/mark_territory
|
||||
always_reset_target = TRUE
|
||||
hunt_cooldown = 15 SECONDS
|
||||
|
||||
/datum/ai_behavior/hunt_target/mark_territory/target_caught(mob/living/hunter, atom/hunted)
|
||||
hunter.custom_emote(EMOTE_VISIBLE, "marks [hunted] with its hooves!")
|
||||
hunter.ai_controller.set_blackboard_key(BB_DEER_TREEHOME, hunted)
|
||||
|
||||
/datum/ai_planning_subtree/find_and_hunt_target/mark_territory/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(controller.blackboard_key_exists(BB_DEER_TREEHOME)) // already found our home, abort!
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/ai_planning_subtree/rest_at_home/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
if(controller.blackboard[BB_DEER_RESTING] > world.time) // we're resting for now, nothing more to do
|
||||
return SUBTREE_RETURN_FINISH_PLANNING
|
||||
if(!controller.blackboard_key_exists(BB_DEER_TREEHOME) || controller.blackboard[BB_DEER_NEXT_REST_TIMER] > world.time)
|
||||
return
|
||||
controller.queue_behavior(/datum/ai_behavior/return_home, BB_DEER_TREEHOME)
|
||||
|
||||
/datum/ai_behavior/return_home
|
||||
required_distance = 0
|
||||
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
||||
/// minimum time till next rest
|
||||
var/minimum_time = 2 MINUTES
|
||||
/// maximum time till next rest
|
||||
var/maximum_time = 4 MINUTES
|
||||
|
||||
/datum/ai_behavior/return_home/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
var/list/possible_turfs = get_adjacent_open_turfs(target)
|
||||
shuffle_inplace(possible_turfs)
|
||||
for(var/turf/possible_turf as anything in possible_turfs)
|
||||
if(!is_blocked_turf(possible_turf))
|
||||
set_movement_target(controller, possible_turf)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/ai_behavior/return_home/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
var/static/list/possible_emotes = list("rests its legs...", "yawns and naps...", "curls up and rests...")
|
||||
living_pawn.custom_emote(EMOTE_VISIBLE, pick(possible_emotes))
|
||||
controller.set_blackboard_key(BB_DEER_RESTING, world.time + 15 SECONDS)
|
||||
controller.set_blackboard_key(BB_DEER_NEXT_REST_TIMER, world.time + rand(minimum_time, maximum_time))
|
||||
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
|
||||
Reference in New Issue
Block a user