mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-19 03:55:11 +01:00
Rats can attack obstacles between them and their target (#71741)
## About The Pull Request Fixes #71568 I wrote this for basic mob carp but it will be needed in a lot of places. Rats used to be able to attack windows or dense objects between them and their target, but basic mobs didn't have this capability. Now they do. Behind the scenes, an important change is that this adds `AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION` to `/datum/ai_behavior/basic_melee_attack`. This is because `basic_melee_attack` essentially enters a loop which won't end until the target is dead or lost, but there are plenty of circumstances where we'll actually want to interrupt this to do something else. Such as attack windows. ## Why It's Good For The Game Restores accidentally removed behaviour. Will likely be required for future basic mob development. ## Changelog 🆑 fix: Rats will once again attempt to attack windows or other dense objects separating them from their targets. /🆑
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/// If there's something between us and our target then we need to queue a behaviour to make it not be there
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path
|
||||
/// Blackboard key containing current target
|
||||
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
|
||||
/// The action to execute, extend to add a different cooldown or something
|
||||
var/attack_behaviour = /datum/ai_behavior/attack_obstructions
|
||||
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/SelectBehaviors(datum/ai_controller/controller, delta_time)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
|
||||
if(QDELETED(target))
|
||||
return
|
||||
|
||||
var/turf/next_step = get_step_towards(controller.pawn, target)
|
||||
if (!next_step.is_blocked_turf(exclude_mobs = TRUE))
|
||||
return
|
||||
|
||||
controller.queue_behavior(attack_behaviour, target_key)
|
||||
// Don't cancel future planning, maybe we can move now
|
||||
|
||||
/// Something is in our way, get it outta here
|
||||
/datum/ai_behavior/attack_obstructions
|
||||
action_cooldown = 1 SECONDS
|
||||
/// If we should attack walls, be prepared for complaints about breaches
|
||||
var/can_attack_turfs = FALSE
|
||||
|
||||
/datum/ai_behavior/attack_obstructions/perform(delta_time, datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/mob/living/basic/basic_mob = controller.pawn
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
|
||||
if (!target)
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
|
||||
var/turf/next_step = get_step_towards(basic_mob, target)
|
||||
var/dir_to_next_step = get_dir(basic_mob, next_step)
|
||||
// If moving diagonally we need to punch both ways, or more accurately the one we are blocked in
|
||||
var/list/dirs_to_move = list()
|
||||
if (ISDIAGONALDIR(dir_to_next_step))
|
||||
for(var/direction in GLOB.cardinals)
|
||||
if(direction & dir_to_next_step)
|
||||
dirs_to_move += direction
|
||||
else
|
||||
dirs_to_move += dir_to_next_step
|
||||
|
||||
for (var/direction in dirs_to_move)
|
||||
if (attack_in_direction(controller, basic_mob, direction))
|
||||
return
|
||||
|
||||
/datum/ai_behavior/attack_obstructions/proc/attack_in_direction(datum/ai_controller/controller, mob/living/basic/basic_mob, direction)
|
||||
var/turf/next_step = get_step(basic_mob, direction)
|
||||
if (!next_step.is_blocked_turf(exclude_mobs = TRUE))
|
||||
return FALSE
|
||||
|
||||
for (var/obj/object as anything in next_step.contents)
|
||||
if (!can_smash_object(basic_mob, object))
|
||||
continue
|
||||
basic_mob.melee_attack(object)
|
||||
return TRUE
|
||||
|
||||
if (can_attack_turfs)
|
||||
basic_mob.melee_attack(next_step)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/ai_behavior/attack_obstructions/proc/can_smash_object(mob/living/basic/basic_mob, obj/object)
|
||||
if (!object.density)
|
||||
return FALSE
|
||||
if (object.IsObscured())
|
||||
return FALSE
|
||||
if (basic_mob.see_invisible < object.invisibility)
|
||||
return FALSE
|
||||
return TRUE // It's in our way, let's get it out of our way
|
||||
Reference in New Issue
Block a user