mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-18 19:44:58 +01:00
Experiment with replacing weakrefs in AI blackboard with deleting signals, ideally making it easier to work with and harder to cause hard deletes (#74791)
## About The Pull Request Replaces weakref usage in AI blackboards with deleting signals All blackboard var setting must go through setters rather than directly ## Why It's Good For The Game This both makes it a ton easier to develop AI for, and also makes it harder for hard deletes to sneak in, as has been seen with recent 515 prs showing hard deletes in AI blackboards (To quantify "making it easier to develop AI", I found multiple bugs in existing AI code due to the usage of weakrefs.) I'm looking for `@Jacquerel` `@tralezab` 's opinions on the matter, also maybe `@LemonInTheDark` if they're interested ## Changelog 🆑 Melbert refactor: Mob ai refactored once again /🆑
This commit is contained in:
@@ -4,22 +4,22 @@
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
//Hiding location is priority
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target)
|
||||
return FALSE
|
||||
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
|
||||
if (!targetting_datum)
|
||||
return
|
||||
if(isnull(targetting_datum))
|
||||
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
|
||||
|
||||
//Hiding location is priority
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
var/mob/living/basic/basic_mob = controller.pawn
|
||||
//targetting datum will kill the action if not real anymore
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
|
||||
|
||||
if(!targetting_datum.can_attack(basic_mob, target))
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
var/hiding_target = targetting_datum.find_hidden_mobs(basic_mob, target) //If this is valid, theyre hidden in something!
|
||||
|
||||
controller.blackboard[hiding_location_key] = hiding_target
|
||||
controller.set_blackboard_key(hiding_location_key, hiding_target)
|
||||
|
||||
if(hiding_target) //Slap it!
|
||||
basic_mob.melee_attack(hiding_target)
|
||||
@@ -39,7 +39,7 @@
|
||||
/datum/ai_behavior/basic_melee_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
if(!succeeded)
|
||||
controller.blackboard -= target_key
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/datum/ai_behavior/basic_melee_attack/average_speed
|
||||
action_cooldown = 1 SECONDS
|
||||
@@ -55,9 +55,8 @@
|
||||
|
||||
/datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target)
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
@@ -65,8 +64,7 @@
|
||||
. = ..()
|
||||
var/mob/living/basic/basic_mob = controller.pawn
|
||||
//targetting datum will kill the action if not real anymore
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
var/datum/targetting_datum/targetting_datum = controller.blackboard[targetting_datum_key]
|
||||
|
||||
if(!targetting_datum.can_attack(basic_mob, target))
|
||||
@@ -80,7 +78,7 @@
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
|
||||
controller.blackboard[hiding_location_key] = WEAKREF(hiding_target)
|
||||
controller.set_blackboard_key(hiding_location_key, hiding_target)
|
||||
|
||||
if(shots>1)
|
||||
var/atom/burst_target = final_target
|
||||
@@ -94,4 +92,4 @@
|
||||
/datum/ai_behavior/basic_ranged_attack/finish_action(datum/ai_controller/controller, succeeded, target_key, targetting_datum_key, hiding_location_key)
|
||||
. = ..()
|
||||
if(!succeeded)
|
||||
controller.blackboard -= target_key
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -7,18 +7,16 @@
|
||||
|
||||
/datum/ai_behavior/pick_up_item/setup(datum/ai_controller/controller, target_key, storage_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/obj/item/target = weak_target?.resolve()
|
||||
var/obj/item/target = controller.blackboard[target_key]
|
||||
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/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/obj/item/target = weak_target?.resolve()
|
||||
if(!isturf(target?.loc)) // Someone picked it up or it got deleted
|
||||
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
|
||||
if(!in_range(controller.pawn, target)) // It teleported
|
||||
if(!controller.pawn.Adjacent(target)) // It teleported
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
pickup_item(controller, target, storage_key)
|
||||
@@ -26,22 +24,21 @@
|
||||
|
||||
/datum/ai_behavior/pick_up_item/finish_action(datum/ai_controller/controller, success, target_key, storage_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/datum/ai_behavior/pick_up_item/proc/pickup_item(datum/ai_controller/controller, obj/item/target, storage_key)
|
||||
var/atom/pawn = controller.pawn
|
||||
drop_existing_item(controller, storage_key)
|
||||
pawn.visible_message(span_notice("[pawn] picks up [target]."))
|
||||
target.forceMove(pawn)
|
||||
controller.blackboard[storage_key] = WEAKREF(target)
|
||||
controller.set_blackboard_key(storage_key, target)
|
||||
return TRUE
|
||||
|
||||
/datum/ai_behavior/pick_up_item/proc/drop_existing_item(datum/ai_controller/controller, storage_key)
|
||||
var/datum/weakref/carried_ref = controller.blackboard[storage_key]
|
||||
var/obj/item/carried_item = carried_ref?.resolve()
|
||||
var/obj/item/carried_item = controller.blackboard[storage_key]
|
||||
if(!carried_item)
|
||||
return
|
||||
controller.blackboard[storage_key] = null
|
||||
controller.clear_blackboard_key(storage_key)
|
||||
var/atom/pawn = controller.pawn
|
||||
if(carried_item.loc != pawn)
|
||||
return
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
var/run_distance = 9
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/setup(datum/ai_controller/controller, target_key, hiding_location_key)
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target)
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
if(!plot_path_away_from(controller, target))
|
||||
return FALSE
|
||||
@@ -17,9 +16,8 @@
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/escaped = !target || !can_see(controller.pawn, target, run_distance) // If we can't see it we got away
|
||||
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
|
||||
var/escaped = QDELETED(target) || !can_see(controller.pawn, target, run_distance) // If we can't see it we got away
|
||||
if (escaped)
|
||||
finish_action(controller, succeeded = TRUE, target_key = target_key, hiding_location_key = hiding_location_key)
|
||||
return
|
||||
@@ -43,4 +41,4 @@
|
||||
|
||||
/datum/ai_behavior/run_away_from_target/finish_action(datum/ai_controller/controller, succeeded, target_key, hiding_location_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -11,13 +11,12 @@
|
||||
var/step_distance = 3
|
||||
|
||||
/datum/ai_behavior/step_towards_turf/setup(datum/ai_controller/controller, turf_key)
|
||||
var/datum/weakref/weak_turf = controller.blackboard[turf_key]
|
||||
var/turf/target_turf = weak_turf?.resolve()
|
||||
if (!target_turf || target_turf.is_blocked_turf(exclude_mobs = TRUE))
|
||||
var/turf/target_turf = controller.blackboard[turf_key]
|
||||
if (QDELETED(target_turf) || target_turf.is_blocked_turf(exclude_mobs = TRUE))
|
||||
target_turf = find_destination_turf(args)
|
||||
if (!target_turf)
|
||||
return FALSE
|
||||
controller.blackboard[turf_key] = WEAKREF(target_turf)
|
||||
controller.set_blackboard_key(turf_key, target_turf)
|
||||
|
||||
if (target_turf.z != controller.pawn.z)
|
||||
return FALSE
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
|
||||
/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()
|
||||
var/atom/movable/target = controller.blackboard[target_key]
|
||||
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()
|
||||
var/atom/movable/target = controller.blackboard[target_key]
|
||||
if(!ismovable(target) || !isturf(target.loc)) // just to make sure that nothing funky happened between setup and perform
|
||||
return
|
||||
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
/datum/ai_behavior/targeted_mob_ability
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key)
|
||||
var/datum/weakref/weak_ability = controller.blackboard[ability_key]
|
||||
var/datum/action/cooldown/ability = weak_ability?.resolve()
|
||||
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/mob/living/target = weak_target?.resolve()
|
||||
if(!ability || QDELETED(target))
|
||||
var/datum/action/cooldown/ability = controller.blackboard[ability_key]
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
if(QDELETED(ability) || QDELETED(target))
|
||||
finish_action(controller, FALSE, ability_key, target_key)
|
||||
return
|
||||
var/mob/pawn = controller.pawn
|
||||
@@ -19,16 +16,15 @@
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target))
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
return
|
||||
if (!isliving(target))
|
||||
return
|
||||
var/mob/living/living_target = target
|
||||
if(living_target.stat >= UNCONSCIOUS)
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
/**
|
||||
* # Try Mob Ability and plan execute
|
||||
@@ -38,7 +34,7 @@
|
||||
/datum/ai_behavior/targeted_mob_ability/and_plan_execute
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/and_plan_execute/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
controller.blackboard[BB_BASIC_MOB_EXECUTION_TARGET] = controller.blackboard[target_key]
|
||||
controller.set_blackboard_key(BB_BASIC_MOB_EXECUTION_TARGET, controller.blackboard[target_key])
|
||||
return ..()
|
||||
|
||||
/**
|
||||
@@ -49,4 +45,4 @@
|
||||
|
||||
/datum/ai_behavior/targeted_mob_ability/and_clear_target/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
if(!targetting_datum)
|
||||
CRASH("No target datum was supplied in the blackboard for [controller.pawn]")
|
||||
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/current_target = weak_target?.resolve()
|
||||
var/atom/current_target = controller.blackboard[target_key]
|
||||
if (targetting_datum.can_attack(living_mob, current_target))
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
var/list/potential_targets = hearers(vision_range, controller.pawn) - living_mob //Remove self, so we don't suicide
|
||||
|
||||
for(var/HM in typecache_filter_list(range(vision_range, living_mob), hostile_machines)) //Can we see any hostile machines?
|
||||
@@ -42,12 +41,12 @@
|
||||
return
|
||||
|
||||
var/atom/target = pick_final_target(controller, filtered_targets)
|
||||
controller.blackboard[target_key] = WEAKREF(target)
|
||||
controller.set_blackboard_key(target_key, target)
|
||||
|
||||
var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, 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)
|
||||
controller.set_blackboard_key(hiding_location_key, potential_hiding_location)
|
||||
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
|
||||
@@ -33,5 +33,5 @@
|
||||
/datum/ai_behavior/tipped_reaction/finish_action(datum/ai_controller/controller, succeeded, tipper_key, reacting_key)
|
||||
. = ..()
|
||||
//I'VE SAID MY PEACE...
|
||||
controller.blackboard[reacting_key] = FALSE
|
||||
controller.blackboard[tipper_key] = null
|
||||
controller.set_blackboard_key(reacting_key, FALSE)
|
||||
controller.clear_blackboard_key(tipper_key)
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
|
||||
/datum/ai_behavior/travel_towards/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(isnull(target))
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
|
||||
/datum/ai_planning_subtree/attack_obstacle_in_path/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
|
||||
if(isnull(target))
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
|
||||
var/turf/next_step = get_step_towards(controller.pawn, target)
|
||||
@@ -31,10 +29,9 @@
|
||||
/datum/ai_behavior/attack_obstructions/perform(seconds_per_tick, 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()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
|
||||
if (!target)
|
||||
if (QDELETED(target))
|
||||
finish_action(controller, succeeded = FALSE)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/// similar to finding a target but looks for food types in the
|
||||
/// similar to finding a target but looks for food types in the // the what?
|
||||
/datum/ai_planning_subtree/find_food
|
||||
|
||||
/datum/ai_planning_subtree/find_food/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(target && !QDELETED(target))
|
||||
if(!QDELETED(target))
|
||||
// Busy with something
|
||||
return
|
||||
var/list/wanted = controller.blackboard[BB_BASIC_FOODS]
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/in_list, BB_BASIC_MOB_CURRENT_TARGET, wanted)
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/find_and_set/in_list, BB_BASIC_MOB_CURRENT_TARGET, controller.blackboard[BB_BASIC_FOODS])
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
. = ..()
|
||||
if (!controller.blackboard[BB_BASIC_MOB_FLEEING])
|
||||
return
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target || QDELETED(target))
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
controller.queue_behavior(flee_behaviour, target_key, hiding_place_key)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here.
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
|
||||
/datum/ai_planning_subtree/basic_melee_attack_subtree/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
|
||||
if(!target || QDELETED(target))
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
controller.queue_behavior(melee_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions.
|
||||
@@ -20,9 +18,8 @@
|
||||
|
||||
/datum/ai_planning_subtree/basic_ranged_attack_subtree/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if(!target || QDELETED(target))
|
||||
var/atom/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
|
||||
if(QDELETED(target))
|
||||
return
|
||||
controller.queue_behavior(ranged_attack_behavior, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
|
||||
return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions.
|
||||
|
||||
@@ -15,16 +15,15 @@
|
||||
var/time_to_wait = 10
|
||||
|
||||
/datum/ai_behavior/sleep_after_targetless_time/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
finish_action(controller, succeeded = !target, seconds_per_tick = seconds_per_tick)
|
||||
|
||||
/datum/ai_behavior/sleep_after_targetless_time/finish_action(datum/ai_controller/controller, succeeded, seconds_per_tick)
|
||||
. = ..()
|
||||
if (!succeeded)
|
||||
controller.blackboard[BB_TARGETLESS_TIME] = 0
|
||||
controller.set_blackboard_key(BB_TARGETLESS_TIME, 0)
|
||||
return
|
||||
controller.blackboard[BB_TARGETLESS_TIME] += seconds_per_tick
|
||||
controller.add_blackboard_key(BB_TARGETLESS_TIME, seconds_per_tick)
|
||||
if (controller.blackboard[BB_TARGETLESS_TIME] > time_to_wait)
|
||||
enter_sleep(controller)
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
/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()
|
||||
var/atom/target = controller.blackboard[BB_STATIONARY_CAUSE]
|
||||
|
||||
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]
|
||||
@@ -11,4 +10,3 @@
|
||||
return
|
||||
|
||||
controller.queue_behavior(/datum/ai_behavior/stop_and_stare, BB_STATIONARY_CAUSE)
|
||||
|
||||
|
||||
@@ -35,36 +35,22 @@
|
||||
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
|
||||
|
||||
var/list/enemies_list = controller.blackboard[shitlist_key]
|
||||
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
|
||||
if (controller.blackboard[target_key] 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)
|
||||
controller.set_blackboard_key(target_key, 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)
|
||||
controller.set_blackboard_key(hiding_location_key, potential_hiding_location)
|
||||
|
||||
finish_action(controller, succeeded = TRUE)
|
||||
|
||||
|
||||
@@ -13,14 +13,9 @@
|
||||
if (!ability_key)
|
||||
CRASH("You forgot to tell this mob where to find its ability")
|
||||
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/mob/living/target = weak_target?.resolve()
|
||||
if (QDELETED(target))
|
||||
return
|
||||
|
||||
var/datum/weakref/weak_ability = controller.blackboard[ability_key]
|
||||
var/datum/action/cooldown/using_action = weak_ability?.resolve()
|
||||
if (!using_action || !using_action.IsAvailable())
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[ability_key]
|
||||
if (QDELETED(target) || QDELETED(using_action) || !using_action.IsAvailable())
|
||||
return
|
||||
|
||||
controller.queue_behavior(use_ability_behaviour, ability_key, target_key)
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
if (!ability_key)
|
||||
CRASH("You forgot to tell this mob where to find its ability")
|
||||
|
||||
var/datum/weakref/weak_ability = controller.blackboard[ability_key]
|
||||
var/datum/action/cooldown/using_action = weak_ability?.resolve()
|
||||
if (!using_action || !using_action.IsAvailable())
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[ability_key]
|
||||
if (QDELETED(using_action) || !using_action.IsAvailable())
|
||||
return
|
||||
|
||||
controller.queue_behavior(use_ability_behaviour, ability_key)
|
||||
@@ -26,9 +25,8 @@
|
||||
/datum/ai_behavior/use_mob_ability
|
||||
|
||||
/datum/ai_behavior/use_mob_ability/perform(seconds_per_tick, datum/ai_controller/controller, ability_key)
|
||||
var/datum/weakref/weak_ability = controller.blackboard[ability_key]
|
||||
var/datum/action/cooldown/using_action = weak_ability?.resolve()
|
||||
if (!using_action)
|
||||
var/datum/action/cooldown/using_action = controller.blackboard[ability_key]
|
||||
if (QDELETED(using_action))
|
||||
finish_action(controller, FALSE, ability_key)
|
||||
return
|
||||
var/result = using_action.Trigger()
|
||||
|
||||
@@ -7,21 +7,18 @@
|
||||
|
||||
/datum/ai_behavior/fetch_seek/setup(datum/ai_controller/controller, target_key, delivery_key)
|
||||
. = ..()
|
||||
var/datum/weakref/thing_ref = controller.blackboard[target_key]
|
||||
var/obj/item/fetch_thing = thing_ref?.resolve()
|
||||
|
||||
var/obj/item/fetch_thing = controller.blackboard[target_key]
|
||||
// It stopped existing
|
||||
if (!fetch_thing)
|
||||
if (QDELETED(fetch_thing))
|
||||
return FALSE
|
||||
set_movement_target(controller, fetch_thing)
|
||||
|
||||
/datum/ai_behavior/fetch_seek/perform(seconds_per_tick, datum/ai_controller/controller, target_key, delivery_key)
|
||||
. = ..()
|
||||
var/datum/weakref/thing_ref = controller.blackboard[target_key]
|
||||
var/obj/item/fetch_thing = thing_ref?.resolve()
|
||||
var/obj/item/fetch_thing = controller.blackboard[target_key]
|
||||
|
||||
// It stopped existing
|
||||
if (!fetch_thing)
|
||||
if (QDELETED(fetch_thing))
|
||||
finish_action(controller, FALSE, target_key, delivery_key)
|
||||
return
|
||||
var/mob/living/living_pawn = controller.pawn
|
||||
@@ -37,12 +34,11 @@
|
||||
if (success)
|
||||
return
|
||||
// Blacklist item if we failed
|
||||
var/datum/weakref/thing_ref = controller.blackboard[target_key]
|
||||
var/obj/item/target = thing_ref?.resolve()
|
||||
var/obj/item/target = controller.blackboard[target_key]
|
||||
if (target)
|
||||
controller.blackboard[BB_FETCH_IGNORE_LIST][thing_ref] = TRUE
|
||||
controller.blackboard[target_key] = null
|
||||
controller.blackboard[delivery_key] = null
|
||||
controller.set_blackboard_key_assoc_lazylist(BB_FETCH_IGNORE_LIST, target, TRUE)
|
||||
controller.clear_blackboard_key(target_key)
|
||||
controller.clear_blackboard_key(delivery_key)
|
||||
|
||||
/**
|
||||
* The second half of fetching, deliver the item to a target.
|
||||
@@ -52,17 +48,15 @@
|
||||
|
||||
/datum/ai_behavior/deliver_fetched_item/setup(datum/ai_controller/controller, delivery_key, storage_key)
|
||||
. = ..()
|
||||
var/datum/weakref/return_ref = controller.blackboard[delivery_key]
|
||||
var/mob/living/return_target = return_ref?.resolve()
|
||||
if(!return_target) // Guess it's mine now
|
||||
var/mob/living/return_target = controller.blackboard[delivery_key]
|
||||
if(QDELETED(return_target)) // Guess it's mine now
|
||||
return FALSE
|
||||
set_movement_target(controller, return_target)
|
||||
|
||||
/datum/ai_behavior/deliver_fetched_item/perform(seconds_per_tick, datum/ai_controller/controller, delivery_key, storage_key)
|
||||
. = ..()
|
||||
var/datum/weakref/return_ref = controller.blackboard[delivery_key]
|
||||
var/mob/living/return_target = return_ref?.resolve()
|
||||
if(!return_target)
|
||||
var/mob/living/return_target = controller.blackboard[delivery_key]
|
||||
if(QDELETED(return_target))
|
||||
finish_action(controller, FALSE, delivery_key)
|
||||
return
|
||||
|
||||
@@ -71,22 +65,21 @@
|
||||
|
||||
/datum/ai_behavior/deliver_fetched_item/finish_action(datum/ai_controller/controller, success, delivery_key)
|
||||
. = ..()
|
||||
controller.blackboard[delivery_key] = null
|
||||
controller.blackboard[BB_ACTIVE_PET_COMMAND] = null
|
||||
controller.clear_blackboard_key(delivery_key)
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
/// Actually deliver the fetched item to the target, if we still have it
|
||||
/datum/ai_behavior/deliver_fetched_item/proc/deliver_item(datum/ai_controller/controller, return_target, storage_key)
|
||||
var/mob/pawn = controller.pawn
|
||||
var/datum/weakref/carried_ref = controller.blackboard[storage_key]
|
||||
var/obj/item/carried_item = carried_ref?.resolve()
|
||||
if(!carried_item || carried_item.loc != pawn)
|
||||
var/obj/item/carried_item = controller.blackboard[storage_key]
|
||||
if(QDELETED(carried_item) || carried_item.loc != pawn)
|
||||
pawn.visible_message(span_notice("[pawn] looks around as if [pawn.p_they()] [pawn.p_have()] lost something."))
|
||||
finish_action(controller, FALSE)
|
||||
return
|
||||
|
||||
pawn.visible_message(span_notice("[pawn] delivers [carried_item] to [return_target]."))
|
||||
carried_item.forceMove(get_turf(return_target))
|
||||
controller.blackboard[storage_key] = null
|
||||
controller.clear_blackboard_key(storage_key)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
@@ -101,19 +94,15 @@
|
||||
|
||||
/datum/ai_behavior/eat_fetched_snack/setup(datum/ai_controller/controller, target_key, delivery_key)
|
||||
. = ..()
|
||||
var/datum/weakref/thing_ref = controller.blackboard[target_key]
|
||||
var/obj/item/snack = thing_ref?.resolve()
|
||||
|
||||
var/obj/item/snack = controller.blackboard[target_key]
|
||||
if(!istype(snack) || !IS_EDIBLE(snack) || !(isturf(snack.loc) || ishuman(snack.loc)))
|
||||
return FALSE // This isn't food at all!
|
||||
set_movement_target(controller, snack)
|
||||
|
||||
/datum/ai_behavior/eat_fetched_snack/perform(seconds_per_tick, datum/ai_controller/controller, target_key, delivery_key)
|
||||
. = ..()
|
||||
var/datum/weakref/thing_ref = controller.blackboard[target_key]
|
||||
var/obj/item/snack = thing_ref?.resolve()
|
||||
|
||||
if(!(isturf(snack.loc) || ishuman(snack.loc)))
|
||||
var/obj/item/snack = controller.blackboard[target_key]
|
||||
if(QDELETED(snack) || !isturf(snack.loc) || ishuman(snack.loc))
|
||||
finish_action(controller, FALSE) // Where did it go?
|
||||
|
||||
var/mob/living/basic/basic_pawn = controller.pawn
|
||||
@@ -130,9 +119,9 @@
|
||||
|
||||
/datum/ai_behavior/eat_fetched_snack/finish_action(datum/ai_controller/controller, succeeded, target_key, delivery_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.blackboard[delivery_key] = null
|
||||
controller.blackboard[BB_ACTIVE_PET_COMMAND] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
controller.clear_blackboard_key(delivery_key)
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
/**
|
||||
* Clear our failed fetch list every so often
|
||||
@@ -153,5 +142,5 @@
|
||||
/datum/ai_behavior/forget_failed_fetches/perform(seconds_per_tick, datum/ai_controller/controller)
|
||||
. = ..()
|
||||
COOLDOWN_START(src, reset_ignore_cooldown, cooldown_duration)
|
||||
controller.blackboard[BB_FETCH_IGNORE_LIST] = list()
|
||||
controller.clear_blackboard_key(BB_FETCH_IGNORE_LIST)
|
||||
finish_action(controller, TRUE)
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
/datum/ai_planning_subtree/pet_planning
|
||||
|
||||
/datum/ai_planning_subtree/pet_planning/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
|
||||
var/datum/weakref/weak_command = controller.blackboard[BB_ACTIVE_PET_COMMAND]
|
||||
var/datum/pet_command/command = weak_command?.resolve()
|
||||
var/datum/pet_command/command = controller.blackboard[BB_ACTIVE_PET_COMMAND]
|
||||
if (!command)
|
||||
return // Do something else
|
||||
return command.execute_action(controller)
|
||||
|
||||
@@ -4,16 +4,14 @@
|
||||
|
||||
/datum/ai_behavior/pet_follow_friend/setup(datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if (!target)
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/pet_follow_friend/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/atom/target = weak_target?.resolve()
|
||||
if (!target)
|
||||
var/atom/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target))
|
||||
finish_action(controller, FALSE, target_key)
|
||||
return
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
|
||||
/datum/ai_behavior/pet_use_ability/setup(datum/ai_controller/controller, ability_key, target_key)
|
||||
. = ..()
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/mob/living/target = weak_target?.resolve()
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
if (QDELETED(target))
|
||||
return FALSE
|
||||
set_movement_target(controller, target)
|
||||
|
||||
/datum/ai_behavior/pet_use_ability/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key)
|
||||
var/datum/action/cooldown/mob_cooldown/ability = controller.blackboard[ability_key]
|
||||
var/datum/weakref/weak_target = controller.blackboard[target_key]
|
||||
var/mob/living/target = weak_target?.resolve()
|
||||
if (!ability || QDELETED(target))
|
||||
var/mob/living/target = controller.blackboard[target_key]
|
||||
if (QDELETED(ability) || QDELETED(target))
|
||||
finish_action(controller, FALSE, ability_key, target_key)
|
||||
return
|
||||
var/mob/pawn = controller.pawn
|
||||
@@ -23,4 +21,4 @@
|
||||
|
||||
/datum/ai_behavior/pet_use_ability/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
|
||||
. = ..()
|
||||
controller.blackboard[target_key] = null
|
||||
controller.clear_blackboard_key(target_key)
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
return
|
||||
basic_pawn.visible_message(span_notice("[basic_pawn] miraculously springs back to life!"))
|
||||
basic_pawn.look_alive()
|
||||
controller.blackboard[BB_ACTIVE_PET_COMMAND] = null
|
||||
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
||||
|
||||
@@ -30,11 +30,10 @@
|
||||
if (!living_mob.ai_controller) // How did you get here?
|
||||
return FALSE
|
||||
|
||||
var/list/friends_list = living_mob.ai_controller.blackboard[BB_FRIENDS_LIST]
|
||||
if (!friends_list)
|
||||
return TRUE // We don't have any friends, anything's fair game
|
||||
if (!friends_list[WEAKREF(target)])
|
||||
return TRUE // This is not our friend, fire at will
|
||||
if (!(target in living_mob.ai_controller.blackboard[BB_FRIENDS_LIST]))
|
||||
// We don't have any friends, anything's fair game
|
||||
// OR This is not our friend, fire at will
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user