mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-17 18:13:34 +01:00
Basic mobs targeting, attacks, and pig migration. (#28987)
* Basic mobs targeting, attacks, and pig migration. * run updatepaths * fix duplicate macro def * Update code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> Signed-off-by: warriorstar-orion <orion@snowfrost.garden> --------- Signed-off-by: warriorstar-orion <orion@snowfrost.garden> Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5da3694877
commit
efc8adb6dd
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Attached to a mob with an AI controller, simply sets a flag on whether or not to run away based on current health values.
|
||||
*/
|
||||
/datum/element/ai_flee_while_injured
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
argument_hash_start_idx = 2
|
||||
/// Health value to end fleeing if at or above
|
||||
var/stop_fleeing_at
|
||||
/// Health value to start fleeing if at or below
|
||||
var/start_fleeing_below
|
||||
|
||||
/datum/element/ai_flee_while_injured/Attach(datum/target, stop_fleeing_at = 1, start_fleeing_below = 0.5)
|
||||
. = ..()
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
var/mob/living/living_target = target
|
||||
if(!living_target.ai_controller)
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
src.stop_fleeing_at = stop_fleeing_at
|
||||
src.start_fleeing_below = start_fleeing_below
|
||||
RegisterSignal(target, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_health_changed))
|
||||
on_health_changed(target)
|
||||
|
||||
/datum/element/ai_flee_while_injured/Detach(datum/source)
|
||||
. = ..()
|
||||
UnregisterSignal(source, COMSIG_LIVING_HEALTH_UPDATE)
|
||||
|
||||
/// When the mob's health changes, check what the blackboard state should be
|
||||
/datum/element/ai_flee_while_injured/proc/on_health_changed(mob/living/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(isnull(source.ai_controller))
|
||||
return
|
||||
|
||||
var/current_health_percentage = source.health / source.maxHealth
|
||||
if(source.ai_controller.blackboard[BB_BASIC_MOB_STOP_FLEEING])
|
||||
if(current_health_percentage > start_fleeing_below)
|
||||
return
|
||||
source.ai_controller.cancel_actions()
|
||||
source.ai_controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, FALSE)
|
||||
return
|
||||
|
||||
if(current_health_percentage < stop_fleeing_at)
|
||||
return
|
||||
source.ai_controller.cancel_actions() // Stop fleeing go back to whatever you were doing
|
||||
source.ai_controller.set_blackboard_key(BB_BASIC_MOB_STOP_FLEEING, TRUE)
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Attached to a mob with an AI controller, passes things which have damaged it to a blackboard.
|
||||
* The AI controller is responsible for doing anything with that information.
|
||||
*/
|
||||
/datum/element/ai_retaliate
|
||||
|
||||
/datum/element/ai_retaliate/Attach(datum/target)
|
||||
. = ..()
|
||||
if(!ismob(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
target.AddElement(/datum/element/relay_attackers)
|
||||
RegisterSignal(target, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked))
|
||||
|
||||
ADD_TRAIT(target, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type)
|
||||
|
||||
/datum/element/ai_retaliate/Detach(datum/source, ...)
|
||||
. = ..()
|
||||
UnregisterSignal(source, COMSIG_ATOM_WAS_ATTACKED)
|
||||
|
||||
/// Add an attacking atom to a blackboard list of things which attacked us
|
||||
/datum/element/ai_retaliate/proc/on_attacked(mob/victim, atom/attacker)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(victim == attacker)
|
||||
return
|
||||
victim.ai_controller?.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, attacker)
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* This element registers to a shitload of signals which can signify "someone attacked me".
|
||||
* If anyone does it sends a single "someone attacked me" signal containing details about who done it.
|
||||
* This prevents other components and elements from having to register to the same list of a million signals, should be more maintainable in one place.
|
||||
*/
|
||||
/datum/element/relay_attackers
|
||||
|
||||
/datum/element/relay_attackers/Attach(datum/target)
|
||||
. = ..()
|
||||
if(!HAS_TRAIT(target, TRAIT_RELAYING_ATTACKER)) // Little bit gross but we want to just apply this shit from a bunch of places
|
||||
// Boy this sure is a lot of ways to tell us that someone tried to attack us
|
||||
RegisterSignal(target, COMSIG_AFTER_ATTACKED_BY, PROC_REF(on_after_attacked_by))
|
||||
RegisterSignals(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW), PROC_REF(on_attack_generic))
|
||||
RegisterSignals(target, list(COMSIG_ATOM_ATTACK_BASIC_MOB, COMSIG_ATOM_ATTACK_ANIMAL), PROC_REF(on_attack_npc))
|
||||
RegisterSignal(target, COMSIG_ATOM_BULLET_ACT, PROC_REF(on_bullet_act))
|
||||
RegisterSignal(target, COMSIG_ATOM_HITBY, PROC_REF(on_hitby))
|
||||
RegisterSignal(target, COMSIG_ATOM_HULK_ATTACK, PROC_REF(on_attack_hulk))
|
||||
ADD_TRAIT(target, TRAIT_RELAYING_ATTACKER, UID())
|
||||
|
||||
/datum/element/relay_attackers/Detach(datum/source, ...)
|
||||
. = ..()
|
||||
UnregisterSignal(source, list(
|
||||
COMSIG_AFTER_ATTACKED_BY,
|
||||
COMSIG_ATOM_ATTACK_HAND,
|
||||
COMSIG_ATOM_ATTACK_PAW,
|
||||
COMSIG_ATOM_ATTACK_BASIC_MOB,
|
||||
COMSIG_ATOM_BULLET_ACT,
|
||||
COMSIG_ATOM_HITBY,
|
||||
COMSIG_ATOM_HULK_ATTACK,
|
||||
))
|
||||
REMOVE_TRAIT(source, TRAIT_RELAYING_ATTACKER, UID())
|
||||
|
||||
/datum/element/relay_attackers/proc/on_after_attacked_by(atom/target, obj/item/weapon, mob/attacker, proximity_flag, click_parameters)
|
||||
SIGNAL_HANDLER // COMSIG_AFTER_ATTACKED_BY
|
||||
if(!proximity_flag) // we don't care about someone clicking us with a piece of metal from across the room
|
||||
return
|
||||
if(weapon.force)
|
||||
relay_attacker(target, attacker, weapon.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK)
|
||||
|
||||
/datum/element/relay_attackers/proc/on_attack_generic(atom/target, mob/living/attacker, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
// Check for a shove.
|
||||
if(attacker.a_intent == INTENT_DISARM)
|
||||
relay_attacker(target, attacker, ATTACKER_SHOVING)
|
||||
return
|
||||
|
||||
// Else check for harm intent.
|
||||
if(attacker.a_intent == INTENT_HARM)
|
||||
relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK)
|
||||
return
|
||||
|
||||
/datum/element/relay_attackers/proc/on_attack_npc(atom/target, mob/living/attacker)
|
||||
SIGNAL_HANDLER // COMSIG_ATOM_ATTACK_BASIC_MOB + COMSIG_ATOM_ATTACK_ANIMAL
|
||||
// both simple animals and basic mobs have the same var name here but we have to check both types
|
||||
if(isanimal(attacker))
|
||||
var/mob/living/simple_animal/SA = attacker
|
||||
if(SA.melee_damage_upper > 0)
|
||||
relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK)
|
||||
return
|
||||
if(isbasicmob(attacker))
|
||||
var/mob/living/basic/B = attacker
|
||||
if(B.melee_damage_upper > 0)
|
||||
relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK)
|
||||
return
|
||||
|
||||
/// Even if another component blocked this hit, someone still shot at us
|
||||
/datum/element/relay_attackers/proc/on_bullet_act(atom/target, obj/item/projectile/hit_projectile)
|
||||
SIGNAL_HANDLER // COMSIG_ATOM_BULLET_ACT
|
||||
if(!hit_projectile.is_hostile_projectile())
|
||||
return
|
||||
if(!ismob(hit_projectile.firer))
|
||||
return
|
||||
relay_attacker(target, hit_projectile.firer, hit_projectile.damage_type == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK)
|
||||
|
||||
/// Even if another component blocked this hit, someone still threw something
|
||||
/datum/element/relay_attackers/proc/on_hitby(atom/target, atom/movable/hit_atom, datum/thrownthing/throwingdatum)
|
||||
SIGNAL_HANDLER // COMSIG_ATOM_HITBY
|
||||
if(!isitem(hit_atom))
|
||||
return
|
||||
var/obj/item/hit_item = hit_atom
|
||||
if(!hit_item.throwforce)
|
||||
return
|
||||
var/mob/thrown_by = locateUID(hit_item.thrownby)
|
||||
if(!ismob(thrown_by))
|
||||
return
|
||||
relay_attacker(target, thrown_by, hit_item.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK)
|
||||
|
||||
/datum/element/relay_attackers/proc/on_attack_hulk(atom/target, mob/attacker)
|
||||
SIGNAL_HANDLER
|
||||
relay_attacker(target, attacker, ATTACKER_DAMAGING_ATTACK)
|
||||
|
||||
/// Send out a signal identifying whoever just attacked us (usually a mob but sometimes a mech or turret)
|
||||
/datum/element/relay_attackers/proc/relay_attacker(atom/victim, atom/attacker, attack_flags)
|
||||
SEND_SIGNAL(victim, COMSIG_ATOM_WAS_ATTACKED, attacker, attack_flags)
|
||||
Reference in New Issue
Block a user