Skip to content

Commit

Permalink
[MIRROR] Turns Deer into Basic Mob - They Freeze At The Sight of Vehi…
Browse files Browse the repository at this point in the history
…cles [MDB IGNORE] (Skyrat-SS13#20711)

* Turns Deer into Basic Mob - They Freeze At The Sight of Vehicles (#74784)

## About The Pull Request

deers only show up in the BEPIS but i decided that they would be easy
enough to turn into a basic mob (they were). it was so easy in fact that
i decided to dip my toes into coding AI behavior, and made them freeze
up whenever they see a vehicle. this required a lot of code in a bunch
of places that i was quite unfamiliar with before starting this project,
so do let me know if i glonked up anywhere and i can work on smoothing
it out.
## Why It's Good For The Game

one less simple animal on the list. deers staring at headlights is
pretty cool i think, neato interaction for when you do get them beyond
the joke the bepis makes

i'm also amenable to dropping the whole "deer in headlights" code if you
don't like that for w/e reason- just wanted to make them basic at the
very least
## Changelog
:cl:
add: If you ever happen upon a wild deer, try not to ride your fancy
vehicles too close to it as it'll freeze up like a... you know where I'm
going with this.
/:cl:

---------

Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>

* Turns Deer into Basic Mob - They Freeze At The Sight of Vehicles

---------

Co-authored-by: san7890 <the@san7890.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@ users.noreply.github.com>
  • Loading branch information
3 people authored Apr 23, 2023
1 parent 7ffa98e commit 8164175
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 32 deletions.
11 changes: 11 additions & 0 deletions code/__DEFINES/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,17 @@
///How long have we spent with no target?
#define BB_TARGETLESS_TIME "BB_targetless_time"

/// Is there something that scared us into being stationary? If so, hold the reference here
#define BB_STATIONARY_CAUSE "BB_thing_that_made_us_stationary"
///How long should we remain stationary for?
#define BB_STATIONARY_SECONDS "BB_stationary_time_in_seconds"
///Should we move towards the target that triggered us to be stationary?
#define BB_STATIONARY_MOVE_TO_TARGET "BB_stationary_move_to_target"
/// What targets will trigger us to be stationary? Must be a list.
#define BB_STATIONARY_TARGETS "BB_stationary_targets"
/// How often can we get spooked by a target?
#define BB_STATIONARY_COOLDOWN "BB_stationary_cooldown"

///List of mobs who have damaged us
#define BB_BASIC_MOB_RETALIATE_LIST "BB_basic_mob_shitlist"

Expand Down
22 changes: 22 additions & 0 deletions code/controllers/subsystem/movement/movement_types.dm
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,28 @@
moving.Move(target_turf, get_dir(moving, target_turf))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE

/**
* Assigns a target to a move loop that immediately freezes for a set duration of time.
*
* Returns TRUE if the loop sucessfully started, or FALSE if it failed
*
* Arguments:
* moving - The atom we want to move
* halted_turf - The turf we want to freeze on. This should typically be the loc of moving.
* delay - How many deci-seconds to wait between fires. Defaults to the lowest value, 0.1
* timeout - Time in deci-seconds until the moveloop self expires. This should be considered extremely non-optional as it will completely stun out the movement loop <i>forever</i> if unset.
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
*/
/datum/controller/subsystem/move_manager/proc/freeze(moving, halted_turf, delay, timeout, subsystem, priority, flags, datum/extra_info)
return add_to_loop(moving, subsystem, /datum/move_loop/freeze, priority, flags, extra_info, delay, timeout, halted_turf)

/// As close as you can get to a "do-nothing" move loop, the pure intention of this is to absolutely resist all and any automated movement until the move loop times out.
/datum/move_loop/freeze

/datum/move_loop/freeze/move()
return MOVELOOP_SUCCESS // it's successful because it's not moving. we autoclear outselves when `timeout` is reached

/**
* Helper proc for the move_rand datum
Expand Down
28 changes: 28 additions & 0 deletions code/datums/ai/basic_mobs/basic_ai_behaviors/stop_and_stare.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// Makes a mob simply stop and stare at a movable... yea...
/datum/ai_behavior/stop_and_stare
behavior_flags = AI_BEHAVIOR_MOVE_AND_PERFORM

/datum/ai_behavior/stop_and_stare/setup(datum/ai_controller/controller, target_key)
. = ..()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/movable/target = weak_target?.resolve()
return ismovable(target) && isturf(target.loc) && ismob(controller.pawn)

/datum/ai_behavior/stop_and_stare/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
// i don't really like doing this but we wanna make sure that the cooldown is pertinent to what we need for this specific controller before we invoke parent
action_cooldown = controller.blackboard[BB_STATIONARY_COOLDOWN]
. = ..()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/movable/target = weak_target?.resolve()
if(!ismovable(target) || !isturf(target.loc)) // just to make sure that nothing funky happened between setup and perform
return

var/mob/pawn_mob = controller.pawn
var/turf/pawn_turf = get_turf(pawn_mob)

pawn_mob.face_atom(target)
pawn_mob.balloon_alert_to_viewers("stops and stares...")
set_movement_target(controller, pawn_turf, /datum/ai_movement/complete_stop)

if(controller.blackboard[BB_STATIONARY_MOVE_TO_TARGET])
addtimer(CALLBACK(src, PROC_REF(set_movement_target), controller, target, initial(controller.ai_movement)), (controller.blackboard[BB_STATIONARY_SECONDS] + 1 SECONDS))
6 changes: 6 additions & 0 deletions code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@
speak = GLOB.wisdoms //Done here so it's setup properly
sound = list()

/datum/ai_planning_subtree/random_speech/deer
speech_chance = 1
speak = list("Weeeeeeee?", "Weeee", "WEOOOOOOOOOO")
emote_hear = list("brays.")
emote_see = list("shakes her head.")

/datum/ai_planning_subtree/random_speech/dog
speech_chance = 1

Expand Down
14 changes: 14 additions & 0 deletions code/datums/ai/basic_mobs/basic_subtrees/stare_at_thing.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// Locate a thing (practically any atom) to stop and stare at.
/datum/ai_planning_subtree/stare_at_thing

/datum/ai_planning_subtree/stare_at_thing/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/weak_target = controller.blackboard[BB_STATIONARY_CAUSE]
var/atom/target = weak_target?.resolve()

if(isnull(target)) // No target? Time to locate one using the list we set in this mob's blackboard.
var/list/potential_scares = controller.blackboard[BB_STATIONARY_TARGETS]
controller.queue_behavior(/datum/ai_behavior/find_and_set/in_list, BB_STATIONARY_CAUSE, potential_scares)
return

controller.queue_behavior(/datum/ai_behavior/stop_and_stare, BB_STATIONARY_CAUSE)

15 changes: 15 additions & 0 deletions code/datums/ai/movement/ai_movement_complete_stop.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// Come to a complete stop for a set amount of time.
/datum/ai_movement/complete_stop
max_pathing_attempts = INFINITE // path all you want, you can not escape your fate

/datum/ai_movement/complete_stop/start_moving_towards(datum/ai_controller/controller, atom/current_movement_target, min_distance)
. = ..()
var/atom/movable/moving = controller.pawn
var/stopping_time = controller.blackboard[BB_STATIONARY_SECONDS]
var/delay_time = (stopping_time * 0.5) // no real reason to fire any more often than this really
// assume that the current_movement_target is our location
var/datum/move_loop/loop = SSmove_manager.freeze(moving, current_movement_target, delay = delay_time, timeout = stopping_time, subsystem = SSai_movement, extra_info = controller)
RegisterSignal(loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(pre_move))

/datum/ai_movement/complete_stop/allowed_to_move(datum/move_loop/source)
return // no movement allowed
49 changes: 49 additions & 0 deletions code/modules/mob/living/basic/farm_animals/deer.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/mob/living/basic/deer
name = "doe"
desc = "A gentle, peaceful forest animal. How did this get into space?"
icon_state = "deer-doe"
icon_living = "deer-doe"
icon_dead = "deer-doe-dead"
gender = FEMALE
mob_biotypes = MOB_ORGANIC|MOB_BEAST
speak_emote = list("grunts", "grunts lowly")
butcher_results = list(/obj/item/food/meat/slab = 3)
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently nudges"
response_disarm_simple = "gently nudges aside"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
attack_verb_continuous = "bucks"
attack_verb_simple = "buck"
attack_sound = 'sound/weapons/punch1.ogg'
health = 75
maxHealth = 75
blood_volume = BLOOD_VOLUME_NORMAL
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)

/mob/living/basic/deer/Initialize(mapload)
. = ..()
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_SHOE)
var/time_to_freeze_for = (rand(5, 10) SECONDS)
ai_controller.blackboard[BB_STATIONARY_SECONDS] = time_to_freeze_for
ai_controller.blackboard[BB_STATIONARY_COOLDOWN] = (time_to_freeze_for * (rand(3, 5)))
ai_controller.blackboard[BB_STATIONARY_TARGETS] = stationary_scary_things

/datum/ai_controller/basic_controller/deer
blackboard = list(
BB_BASIC_MOB_FLEEING = TRUE,
BB_STATIONARY_MOVE_TO_TARGET = TRUE,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction,
)
ai_traits = 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,
)
29 changes: 0 additions & 29 deletions code/modules/mob/living/simple_animal/friendly/farm_animals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -250,32 +250,3 @@ GLOBAL_VAR_INIT(chicken_count, 0)
location_allowlist = typecacheof(list(/turf)),\
spoilable = TRUE,\
)

/mob/living/simple_animal/deer
name = "doe"
desc = "A gentle, peaceful forest animal. How did this get into space?"
icon_state = "deer-doe"
icon_living = "deer-doe"
icon_dead = "deer-doe-dead"
gender = FEMALE
mob_biotypes = MOB_ORGANIC|MOB_BEAST
speak = list("Weeeeeeee?","Weeee","WEOOOOOOOOOO")
speak_emote = list("grunts","grunts lowly")
emote_hear = list("brays.")
emote_see = list("shakes her head.")
speak_chance = 1
turns_per_move = 5
butcher_results = list(/obj/item/food/meat/slab = 3)
response_help_continuous = "pets"
response_help_simple = "pet"
response_disarm_continuous = "gently nudges"
response_disarm_simple = "gently nudges aside"
response_harm_continuous = "kicks"
response_harm_simple = "kick"
attack_verb_continuous = "bucks"
attack_verb_simple = "buck"
attack_sound = 'sound/weapons/punch1.ogg'
health = 75
maxHealth = 75
blood_volume = BLOOD_VOLUME_NORMAL
footstep_type = FOOTSTEP_MOB_SHOE
2 changes: 1 addition & 1 deletion code/modules/research/bepis.dm
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@
return
if(gauss_real <= -1) //Critical Failure
say("ERROR: CRITICAL MACHIME MALFUNCTI- ON. CURRENCY IS NOT CRASH. CANNOT COMPUTE COMMAND: 'make bucks'") //not a typo, for once.
new /mob/living/simple_animal/deer(dropturf, 1)
new /mob/living/basic/deer(dropturf, 1)
use_power(MACHINE_OVERLOAD * power_saver) //To prevent gambling at low cost and also prevent spamming for infinite deer.
return
//Minor Failure
Expand Down
1 change: 0 additions & 1 deletion code/modules/unit_tests/simple_animal_freeze.dm
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
/mob/living/simple_animal/crab/evil/kreb,
/mob/living/simple_animal/crab/jon,
/mob/living/simple_animal/crab/kreb,
/mob/living/simple_animal/deer,
/mob/living/simple_animal/drone,
/mob/living/simple_animal/drone/classic,
/mob/living/simple_animal/drone/derelict,
Expand Down
2 changes: 1 addition & 1 deletion code/modules/vehicles/cars/clowncar.dm
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@

/obj/vehicle/sealed/car/clowncar/Bump(atom/bumped)
. = ..()
if(isliving(bumped) && !istype(bumped, /mob/living/simple_animal/deer))
if(isliving(bumped) && !istype(bumped, /mob/living/basic/deer))
if(ismegafauna(bumped))
return
var/mob/living/hittarget_living = bumped
Expand Down
4 changes: 4 additions & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\pick_up_item.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\run_away_from_target.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\step_towards_turf.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\stop_and_stare.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\targeted_mob_ability.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\targetting.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm"
Expand All @@ -851,6 +852,7 @@
#include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_target.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\sleep_with_no_target.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\speech_subtree.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\stare_at_thing.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\target_retaliate.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\targeted_mob_ability.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\tipped_subtree.dm"
Expand Down Expand Up @@ -888,6 +890,7 @@
#include "code\datums\ai\monkey\punpun_subtrees.dm"
#include "code\datums\ai\movement\_ai_movement.dm"
#include "code\datums\ai\movement\ai_movement_basic_avoidance.dm"
#include "code\datums\ai\movement\ai_movement_complete_stop.dm"
#include "code\datums\ai\movement\ai_movement_dumb.dm"
#include "code\datums\ai\movement\ai_movement_jps.dm"
#include "code\datums\ai\objects\mod.dm"
Expand Down Expand Up @@ -3968,6 +3971,7 @@
#include "code\modules\mob\living\basic\festivus_pole.dm"
#include "code\modules\mob\living\basic\health_adjustment.dm"
#include "code\modules\mob\living\basic\tree.dm"
#include "code\modules\mob\living\basic\farm_animals\deer.dm"
#include "code\modules\mob\living\basic\farm_animals\pig.dm"
#include "code\modules\mob\living\basic\farm_animals\rabbit.dm"
#include "code\modules\mob\living\basic\farm_animals\sheep.dm"
Expand Down

0 comments on commit 8164175

Please sign in to comment.