Files
Bubberstation/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
SkyratBot 81ca11b95a [MIRROR] Basic Mob Carp: Retaliate Element [MDB IGNORE] (#18030)
* Basic Mob Carp: Retaliate Element (#71593)

## About The Pull Request

Adds an Element and AI behaviour intended to replicate the "retaliate"
behaviour which made up an entire widely-populated subtype of simple
mobs.
The behaviour is pretty simply "If you fuck with me I fuck with you".
Mobs with the component will "remember" being attacked and will try to
attack people who attacked them, until they lose sight of those people.
They don't have very long memories so breaking line of sight is enough
to remove you from their grudge list.
The implementation unfortunately requires registering to 600 different
"I have been attacked by X" signals but c'est la vie.

It will still be cleaner than
`/mob/living/simple_animal/hostile/retaliate/clown/clownhulk/honcmunculus`
and `mob/living/simple_animal/hostile/retaliate/bat/sgt_araneus`.

I attached it to the pig for testing and left it there because out of
all the farm animals we have right now, a pig would probably get pissed
off if you tried to kill it. Unfortunately it's got a sausage's chance
in hell of ever killing anyone.

## Why It's Good For The Game

It doesn't have much purpose yet but as we make more basic mobs this is
going to see a **lot** of use.

## Changelog

🆑
add: Basic mobs have the capability of being upset that you kicked and
punched them.
add: Pigs destined for slaughter will now ineffectually attempt to
resist their fate, at least until they lose sight of you.
balance: Bar bots are better at noticing that you're trying to kill
them.
/🆑

* Basic Mob Carp: Retaliate Element

Co-authored-by: Jacquerel <hnevard@gmail.com>
Co-authored-by: tastyfish <crazychris32@gmail.com>
2022-12-12 18:02:47 -05:00

70 lines
3.0 KiB
Plaintext

/// Sets the BB target to a mob which you can see and who has recently attacked you
/datum/ai_planning_subtree/target_retaliate
/datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, delta_time)
. = ..()
controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
/**
* Picks a target from a provided list of atoms who have been pissing you off
* You will probably need /datum/element/ai_retaliate to take advantage of this unless you're populating the blackboard yourself
*/
/datum/ai_behavior/target_from_retaliate_list
action_cooldown = 2 SECONDS
/// How far can we see stuff?
var/vision_range = 9
/datum/ai_behavior/target_from_retaliate_list/perform(delta_time, datum/ai_controller/controller, shitlist_key, target_key, targetting_datum_key, hiding_location_key)
. = ..()
var/mob/living/living_mob = controller.pawn
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
if(!targetting_datum)
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
var/list/enemy_refs = controller.blackboard[shitlist_key]
if (!length(enemy_refs))
finish_action(controller, succeeded = FALSE)
return
var/list/enemies_list = list()
for (var/datum/weakref/enemy_ref as anything in enemy_refs)
var/atom/enemy = enemy_ref.resolve()
if (!can_attack_target(living_mob, enemy, targetting_datum))
controller.blackboard[shitlist_key] -= enemy_ref
continue
enemies_list += enemy
if (!length(enemies_list))
finish_action(controller, succeeded = FALSE)
return
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/target = weak_target?.resolve()
if (target && (locate(target) in enemies_list)) // Don't bother changing
finish_action(controller, succeeded = FALSE)
return
var/atom/new_target = pick_final_target(controller, enemies_list)
controller.blackboard[target_key] = WEAKREF(new_target)
var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, new_target)
if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially.
controller.blackboard[hiding_location_key] = WEAKREF(potential_hiding_location)
finish_action(controller, succeeded = TRUE)
/// Returns true if this target is valid for attacking based on current conditions
/datum/ai_behavior/target_from_retaliate_list/proc/can_attack_target(mob/living/living_mob, atom/target, datum/targetting_datum/targetting_datum)
if (!target)
return FALSE
if (target == living_mob)
return FALSE
if (!can_see(living_mob, target, vision_range))
return FALSE
return targetting_datum.can_attack(living_mob, target)
/// Returns the desired final target from the filtered list of enemies
/datum/ai_behavior/target_from_retaliate_list/proc/pick_final_target(datum/ai_controller/controller, list/enemies_list)
return pick(enemies_list)