Skip to content

Commit

Permalink
[MIRROR] Refactors how basic ais do their success/failures (#2131)
Browse files Browse the repository at this point in the history
* Refactors how basic ais do their success/failures (#82643)

* Refactors how basic ais do their success/failures

---------

Co-authored-by: LemonInTheDark <[email protected]>
  • Loading branch information
2 people authored and StealsThePRs committed Apr 23, 2024
1 parent df3285b commit 7dee38e
Show file tree
Hide file tree
Showing 76 changed files with 453 additions and 664 deletions.
10 changes: 10 additions & 0 deletions code/__DEFINES/ai/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
///Flags for ai_behavior new()
#define AI_CONTROLLER_INCOMPATIBLE (1<<0)

//Return flags for ai_behavior/perform()
///Update this behavior's cooldown
#define AI_BEHAVIOR_DELAY (1<<0)
///Finish the behavior successfully
#define AI_BEHAVIOR_SUCCEEDED (1<<1)
///Finish the behavior unsuccessfully
#define AI_BEHAVIOR_FAILED (1<<1)

#define AI_BEHAVIOR_INSTANT (NONE)

///Does this task require movement from the AI before it can be performed?
#define AI_BEHAVIOR_REQUIRE_MOVEMENT (1<<0)
///Does this require the current_movement_target to be adjacent and in reach?
Expand Down
2 changes: 1 addition & 1 deletion code/datums/ai/_ai_behavior.dm
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
return TRUE

///Called by the AI controller when this action is performed
///Returns a set of flags defined in [code/__DEFINES/ai/ai.dm]
/datum/ai_behavior/proc/perform(seconds_per_tick, datum/ai_controller/controller, ...)
controller.behavior_cooldowns[src] = world.time + get_cooldown(controller)
return

///Called when the action is finished. This needs the same args as perform besides the default ones
Expand Down
24 changes: 16 additions & 8 deletions code/datums/ai/_ai_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,12 @@ multiple modular subtrees with behaviors
break

SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_PICKED_BEHAVIORS, current_behaviors, planned_behaviors)
for(var/datum/ai_behavior/current_behavior as anything in current_behaviors)
if(LAZYACCESS(planned_behaviors, current_behavior))
continue
for(var/datum/ai_behavior/forgotten_behavior as anything in current_behaviors - planned_behaviors)
var/list/arguments = list(src, FALSE)
var/list/stored_arguments = behavior_args[type]
if(stored_arguments)
arguments += stored_arguments
current_behavior.finish_action(arglist(arguments))
forgotten_behavior.finish_action(arglist(arguments))

///This proc handles changing ai status, and starts/stops processing if required.
/datum/ai_controller/proc/set_ai_status(new_ai_status)
Expand All @@ -389,7 +387,7 @@ multiple modular subtrees with behaviors
paused_until = world.time + time

/datum/ai_controller/proc/modify_cooldown(datum/ai_behavior/behavior, new_cooldown)
behavior_cooldowns[behavior.type] = new_cooldown
behavior_cooldowns[behavior] = new_cooldown

///Call this to add a behavior to the stack.
/datum/ai_controller/proc/queue_behavior(behavior_type, ...)
Expand Down Expand Up @@ -419,13 +417,23 @@ multiple modular subtrees with behaviors
var/list/stored_arguments = behavior_args[behavior.type]
if(stored_arguments)
arguments += stored_arguments
behavior.perform(arglist(arguments))

var/process_flags = behavior.perform(arglist(arguments))
if(process_flags & AI_BEHAVIOR_DELAY)
behavior_cooldowns[behavior] = world.time + behavior.get_cooldown(src)
if(process_flags & AI_BEHAVIOR_FAILED)
arguments[1] = src
arguments[2] = FALSE
behavior.finish_action(arglist(arguments))
else if (process_flags & AI_BEHAVIOR_SUCCEEDED)
arguments[1] = src
arguments[2] = TRUE
behavior.finish_action(arglist(arguments))

/datum/ai_controller/proc/CancelActions()
if(!LAZYLEN(current_behaviors))
return
for(var/i in current_behaviors)
var/datum/ai_behavior/current_behavior = i
for(var/datum/ai_behavior/current_behavior as anything in current_behaviors)
var/list/arguments = list(src, FALSE)
var/list/stored_arguments = behavior_args[current_behavior.type]
if(stored_arguments)
Expand Down
10 changes: 5 additions & 5 deletions code/datums/ai/_item_behaviors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
/datum/ai_behavior/item_escape_grasp

/datum/ai_behavior/item_escape_grasp/perform(seconds_per_tick, datum/ai_controller/controller)
. = ..()
var/obj/item/item_pawn = controller.pawn
var/mob/item_holder = item_pawn.loc
if(!istype(item_holder))
finish_action(controller, FALSE) //We're no longer being held. abort abort!!
//We're no longer being held. abort abort!!
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
item_pawn.visible_message(span_warning("[item_pawn] slips out of the hands of [item_holder]!"))
item_holder.dropItemToGround(item_pawn, TRUE)
finish_action(controller, TRUE)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED


///This behavior is for obj/items, it is used to move closer to a target and throw themselves towards them.
Expand All @@ -30,7 +30,6 @@
set_movement_target(controller, target)

/datum/ai_behavior/item_move_close_and_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, throw_count_key)
. = ..()
var/obj/item/item_pawn = controller.pawn
var/atom/throw_target = controller.blackboard[target_key]

Expand All @@ -39,7 +38,8 @@
playsound(item_pawn.loc, attack_sound, 100, TRUE)
controller.add_blackboard_key(throw_count_key, 1)
if(controller.blackboard[throw_count_key] >= max_attempts)
finish_action(controller, TRUE, target_key, throw_count_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
return AI_BEHAVIOR_DELAY

/datum/ai_behavior/item_move_close_and_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, throw_count_key)
. = ..()
Expand Down
18 changes: 6 additions & 12 deletions code/datums/ai/babies/babies_behaviors.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
var/max_children = 3

/datum/ai_behavior/find_partner/perform(seconds_per_tick, datum/ai_controller/controller, target_key, partner_types_key, child_types_key)
. = ..()
max_children = controller.blackboard[BB_MAX_CHILDREN] || max_children
var/mob/pawn_mob = controller.pawn
var/list/partner_types = controller.blackboard[partner_types_key]
Expand All @@ -18,12 +17,10 @@
var/children = 0
for(var/mob/living/other in oview(range, pawn_mob))
if(!pawn_mob.faction_check_atom(other))
finish_action(controller, FALSE)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

if(children >= max_children)
finish_action(controller, FALSE)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

if(other.stat != CONSCIOUS) //Check if it's conscious FIRST.
continue
Expand All @@ -40,10 +37,9 @@

if(other.gender != living_pawn.gender && !(other.flags_1 & HOLOGRAM_1)) //Better safe than sorry ;_;
controller.set_blackboard_key(target_key, other)
finish_action(controller, TRUE)

finish_action(controller, FALSE)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

/**
* Reproduce.
Expand All @@ -59,15 +55,13 @@
set_movement_target(controller, target)

/datum/ai_behavior/make_babies/perform(seconds_per_tick, datum/ai_controller/controller, target_key, child_types_key)
. = ..()
var/mob/target = controller.blackboard[target_key]
if(QDELETED(target) || target.stat != CONSCIOUS)
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/mob/living/basic/living_pawn = controller.pawn
living_pawn.set_combat_mode(FALSE)
living_pawn.melee_attack(target)
finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

/datum/ai_behavior/make_babies/finish_action(datum/ai_controller/controller, succeeded, target_key)
. = ..()
Expand Down
18 changes: 8 additions & 10 deletions code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,15 @@
if (isliving(controller.pawn))
var/mob/living/pawn = controller.pawn
if (world.time < pawn.next_move)
return
return AI_BEHAVIOR_INSTANT

. = ..()
var/mob/living/basic/basic_mob = controller.pawn
//targeting strategy will kill the action if not real anymore
var/atom/target = controller.blackboard[target_key]
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])

if(!targeting_strategy.can_attack(basic_mob, target))
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

var/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!

Expand All @@ -43,7 +41,8 @@
basic_mob.melee_attack(target)

if(terminate_after_action)
finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
return AI_BEHAVIOR_DELAY

/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
Expand Down Expand Up @@ -82,22 +81,21 @@
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])

if(!targeting_strategy.can_attack(basic_mob, target, chase_range))
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_FAILED

var/atom/hiding_target = targeting_strategy.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
var/atom/final_target = hiding_target ? hiding_target : target

if(!can_see(basic_mob, final_target, required_distance))
return
return AI_BEHAVIOR_INSTANT

if(avoid_friendly_fire && check_friendly_in_path(basic_mob, target, targeting_strategy))
adjust_position(basic_mob, target)
return ..()
return AI_BEHAVIOR_DELAY

controller.set_blackboard_key(hiding_location_key, hiding_target)
basic_mob.RangedAttack(final_target)
return ..() //only start the cooldown when the shot is shot
return AI_BEHAVIOR_DELAY //only start the cooldown when the shot is shot

/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
. = ..()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
/datum/ai_behavior/befriend_target

/datum/ai_behavior/befriend_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, befriend_message)
. = ..()
var/mob/living/living_pawn = controller.pawn
var/mob/living/living_target = controller.blackboard[target_key]
if(QDELETED(living_target))
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

living_pawn.befriend(living_target)
var/befriend_text = controller.blackboard[befriend_message]
if(befriend_text)
to_chat(living_target, span_nicegreen("[living_pawn] [befriend_text]"))

finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

/datum/ai_behavior/befriend_target/finish_action(datum/ai_controller/controller, succeeded, target_key)
. = ..()
Expand Down
3 changes: 1 addition & 2 deletions code/datums/ai/basic_mobs/basic_ai_behaviors/climb_tree.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@
set_movement_target(controller, target)

/datum/ai_behavior/climb_tree/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
. = ..()
var/obj/structure/flora/target_tree = controller.blackboard[target_key]
var/mob/living/basic/living_pawn = controller.pawn
if(QDELETED(living_pawn)) // pawn can be null at this point
return
SEND_SIGNAL(living_pawn, COMSIG_LIVING_CLIMB_TREE, target_tree)
finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

/datum/ai_behavior/climb_tree/finish_action(datum/ai_controller/controller, succeeded, target_key)
. = ..()
Expand Down
10 changes: 3 additions & 7 deletions code/datums/ai/basic_mobs/basic_ai_behaviors/find_parent.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@
var/look_range = 7

/datum/ai_behavior/find_mom/perform(seconds_per_tick, datum/ai_controller/controller, mom_key, ignore_mom_key, found_mom)
. = ..()

var/mob/living_pawn = controller.pawn
var/list/mom_types = controller.blackboard[mom_key]
var/list/all_moms = list()
var/list/ignore_types = controller.blackboard[ignore_mom_key]

if(!length(mom_types))
finish_action(controller, FALSE)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

for(var/mob/mother in oview(look_range, living_pawn))
if(!is_type_in_list(mother, mom_types))
Expand All @@ -23,6 +20,5 @@

if(length(all_moms))
controller.set_blackboard_key(found_mom, pick(all_moms))
finish_action(controller, TRUE)
return
finish_action(controller, FALSE)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
9 changes: 3 additions & 6 deletions code/datums/ai/basic_mobs/basic_ai_behaviors/pick_up_item.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@
return isitem(target) && isturf(target.loc) && !target.anchored

/datum/ai_behavior/pick_up_item/perform(seconds_per_tick, datum/ai_controller/controller, target_key, storage_key)
. = ..()
var/obj/item/target = controller.blackboard[target_key]
if(QDELETED(target) || !isturf(target.loc)) // Someone picked it up or it got deleted
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
if(!controller.pawn.Adjacent(target)) // It teleported
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
pickup_item(controller, target, storage_key)
finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

/datum/ai_behavior/pick_up_item/finish_action(datum/ai_controller/controller, success, target_key, storage_key)
. = ..()
Expand Down
7 changes: 2 additions & 5 deletions code/datums/ai/basic_mobs/basic_ai_behaviors/pull_target.dm
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@
set_movement_target(controller, target)

/datum/ai_behavior/pull_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
. = ..()

var/atom/movable/target = controller.blackboard[target_key]
if(QDELETED(target) || target.anchored || target.pulledby)
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/mob/living/our_mob = controller.pawn
our_mob.start_pulling(target)
finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

/datum/ai_behavior/pull_target/finish_action(datum/ai_controller/controller, succeeded, target_key)
. = ..()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,16 @@
return ..()

/datum/ai_behavior/run_away_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
. = ..()
if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING])
return
return AI_BEHAVIOR_DELAY
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
if (QDELETED(target) || !can_see(controller.pawn, target, run_distance))
finish_action(controller, succeeded = TRUE, target_key = target_key, hiding_location_key = hiding_location_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
if (get_dist(controller.pawn, controller.current_movement_target) > required_distance)
return // Still heading over
return AI_BEHAVIOR_DELAY // Still heading over
if (plot_path_away_from(controller, target))
return
finish_action(controller, succeeded = FALSE, target_key = target_key, hiding_location_key = hiding_location_key)
return AI_BEHAVIOR_DELAY
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

/datum/ai_behavior/run_away_from_target/proc/plot_path_away_from(datum/ai_controller/controller, atom/target)
var/turf/target_destination = get_turf(controller.pawn)
Expand Down Expand Up @@ -71,7 +69,7 @@
/datum/ai_behavior/run_away_from_target/run_and_shoot/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
var/atom/target = controller.blackboard[target_key]
if(QDELETED(target))
finish_action(controller, succeeded = FALSE, target_key = target_key, hiding_location_key = hiding_location_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/mob/living/living_pawn = controller.pawn
living_pawn.RangedAttack(target)
return ..()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
/datum/ai_behavior/set_travel_destination

/datum/ai_behavior/set_travel_destination/perform(seconds_per_tick, datum/ai_controller/controller, target_key, location_key)
. = ..()
var/atom/target = controller.blackboard[target_key]

if(QDELETED(target))
finish_action(controller, FALSE, target_key)
return
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED

controller.set_blackboard_key(location_key, target)

finish_action(controller, TRUE, target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@

// We actually only wanted the movement so if we've arrived we're done
/datum/ai_behavior/step_towards_turf/perform(seconds_per_tick, datum/ai_controller/controller, area_key, turf_key)
. = ..()
finish_action(controller, succeeded = TRUE)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED

/**
* # Step towards turf in area
Expand Down
Loading

0 comments on commit 7dee38e

Please sign in to comment.