[MIRROR] Experiment with replacing weakrefs in AI blackboard with deleting signals, ideally making it easier to work with and harder to cause hard deletes [MDB IGNORE] (#20719)

* 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
/🆑

* Experiment with replacing weakrefs in AI blackboard with deleting signals, ideally making it easier to work with and harder to cause hard deletes

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-04-26 21:17:15 +01:00
committed by GitHub
co-authored by MrMelbert
parent 6435018ba7
commit e6f66d3a4a
92 changed files with 688 additions and 592 deletions
@@ -55,7 +55,7 @@
continue
// This gives all mobs in view "5" haunt level
// For reference picking one up gives "2"
haunted_item.ai_controller.blackboard[BB_TO_HAUNT_LIST][WEAKREF(victim)] = 5
haunted_item.ai_controller.add_blackboard_key_assoc(BB_TO_HAUNT_LIST, victim, 5)
if(haunted_item.throwforce < throw_force_max)
pre_haunt_throwforce = haunted_item.throwforce
@@ -81,7 +81,7 @@
if(prob(10))
switch(rand(1,4))
if(1) //blood rage
magnification.ai_controller.blackboard[BB_MONKEY_AGGRESSIVE] = TRUE
magnification.ai_controller.set_blackboard_key(BB_MONKEY_AGGRESSIVE, TRUE)
if(2) //brain death
magnification.apply_damage(500,BRAIN,BODY_ZONE_HEAD,FALSE,FALSE,FALSE)
if(3) //primal gene (gorilla)
@@ -153,7 +153,7 @@
restaurant_portal.update_icon()
STOP_PROCESSING(SSobj, src)
for(var/mob/living/simple_animal/robot_customer as anything in current_visitors)
robot_customer.ai_controller.blackboard[BB_CUSTOMER_LEAVING] = TRUE //LEAVEEEEEE
robot_customer.ai_controller.set_blackboard_key(BB_CUSTOMER_LEAVING, TRUE) //LEAVEEEEEE
/obj/machinery/restaurant_portal
name = "restaurant portal"
@@ -45,7 +45,7 @@
udder_component()
setup_eating()
. = ..()
ai_controller.blackboard[BB_BASIC_FOODS] = food_types
ai_controller.set_blackboard_key(BB_BASIC_FOODS, food_types)
///wrapper for the udder component addition so you can have uniquely uddered cow subtypes
/mob/living/basic/cow/proc/udder_component()
@@ -86,5 +86,5 @@
/mob/living/basic/cow/proc/set_tip_react_blackboard(mob/living/carbon/tipper)
if(!HAS_TRAIT_FROM(src, TRAIT_IMMOBILIZED, TIPPED_OVER) || !ai_controller)
return
ai_controller.blackboard[BB_BASIC_MOB_TIP_REACTING] = TRUE
ai_controller.blackboard[BB_BASIC_MOB_TIPPER] = tipper
ai_controller.set_blackboard_key(BB_BASIC_MOB_TIP_REACTING, TRUE)
ai_controller.set_blackboard_key(BB_BASIC_MOB_TIPPER, tipper)
@@ -28,9 +28,9 @@
. = ..()
AddElement(/datum/element/footstep, footstep_type = FOOTSTEP_MOB_SHOE)
var/time_to_freeze_for = (rand(5, 10) SECONDS)
ai_controller.blackboard[BB_STATIONARY_SECONDS] = time_to_freeze_for
ai_controller.blackboard[BB_STATIONARY_COOLDOWN] = (time_to_freeze_for * (rand(3, 5)))
ai_controller.blackboard[BB_STATIONARY_TARGETS] = stationary_scary_things
ai_controller.set_blackboard_key(BB_STATIONARY_SECONDS, time_to_freeze_for)
ai_controller.set_blackboard_key(BB_STATIONARY_COOLDOWN, (time_to_freeze_for * (rand(3, 5))))
ai_controller.set_blackboard_key(BB_STATIONARY_TARGETS, stationary_scary_things)
/datum/ai_controller/basic_controller/deer
blackboard = list(
@@ -45,7 +45,7 @@
AddElement(/datum/element/death_drops, list(/obj/item/stack/rods))
var/datum/action/cooldown/mob_cooldown/charge_apc/charge_ability = new(src)
charge_ability.Grant(src)
ai_controller.blackboard[BB_FESTIVE_APC] = WEAKREF(charge_ability)
ai_controller.set_blackboard_key(BB_FESTIVE_APC, charge_ability)
/datum/ai_controller/basic_controller/festivus_pole
blackboard = list(
@@ -98,8 +98,7 @@
always_reset_target = TRUE
/datum/ai_behavior/hunt_target/apcs/target_caught(mob/living/basic/hunter, obj/machinery/power/apc/hunted)
var/datum/weakref/ability_weakref = hunter.ai_controller.blackboard[BB_FESTIVE_APC]
var/datum/action/cooldown/mob_cooldown/charge_ability = ability_weakref?.resolve()
var/datum/action/cooldown/mob_cooldown/charge_ability = hunter.ai_controller.blackboard[BB_FESTIVE_APC]
if(isnull(charge_ability))
return
charge_ability.Activate(hunted)
@@ -86,8 +86,7 @@
/datum/ai_behavior/basic_melee_attack/star_gazer/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
. = ..()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/target = weak_target?.resolve()
var/atom/target = controller.blackboard[target_key]
var/mob/living/living_pawn = controller.pawn
if(!isliving(target))
@@ -56,6 +56,6 @@
devour.Grant(src)
var/datum/action/adjust_vision/bileworm/adjust_vision = new(src)
adjust_vision.Grant(src)
ai_controller.blackboard[BB_BILEWORM_SPEW_BILE] = WEAKREF(spew_bile)
ai_controller.blackboard[BB_BILEWORM_RESURFACE] = WEAKREF(resurface)
ai_controller.blackboard[BB_BILEWORM_DEVOUR] = WEAKREF(devour)
ai_controller.set_blackboard_key(BB_BILEWORM_SPEW_BILE, spew_bile)
ai_controller.set_blackboard_key(BB_BILEWORM_RESURFACE, resurface)
ai_controller.set_blackboard_key(BB_BILEWORM_DEVOUR, devour)
@@ -15,7 +15,7 @@
to_chat(burrower, span_warning("Couldn't burrow anywhere near the target!"))
if(burrower.ai_controller?.ai_status == AI_STATUS_ON)
//this is a valid reason to give up on a target
burrower.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] = null
burrower.ai_controller.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET)
return
playsound(burrower, 'sound/effects/break_stone.ogg', 50, TRUE)
new /obj/effect/temp_visual/mook_dust(get_turf(burrower))
@@ -13,17 +13,15 @@
/datum/ai_planning_subtree/bileworm_attack/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
var/mob/living/target = weak_target?.resolve()
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
if(QDELETED(target))
return
var/datum/weakref/weak_action = controller.blackboard[BB_BILEWORM_RESURFACE]
var/datum/action/cooldown/mob_cooldown/resurface = weak_action?.resolve()
var/datum/action/cooldown/mob_cooldown/resurface = controller.blackboard[BB_BILEWORM_RESURFACE]
//because one ability is always INFINITY cooldown, this actually works to check which ability should be used
//sometimes it will try to spew bile on infinity cooldown, but that's okay because as soon as resurface is ready it will attempt that
if(resurface && resurface.next_use_time <= world.time)
if(!QDELETED(resurface) && resurface.next_use_time <= world.time)
controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_plan_execute, BB_BILEWORM_RESURFACE, BB_BASIC_MOB_CURRENT_TARGET)
else
controller.queue_behavior(/datum/ai_behavior/targeted_mob_ability/and_plan_execute, BB_BILEWORM_SPEW_BILE, BB_BASIC_MOB_CURRENT_TARGET)
@@ -33,8 +31,7 @@
/datum/ai_planning_subtree/bileworm_execute/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_EXECUTION_TARGET]
var/mob/living/target = weak_target?.resolve()
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_EXECUTION_TARGET]
if(QDELETED(target) || target.stat < UNCONSCIOUS)
return
+3 -3
View File
@@ -14,7 +14,7 @@
/datum/pet_command/point_targetting/attack/dog/set_command_active(mob/living/parent, mob/living/commander)
. = ..()
parent.ai_controller.blackboard[BB_DOG_HARASS_HARM] = TRUE
parent.ai_controller.set_blackboard_key(BB_DOG_HARASS_HARM, TRUE)
/mob/living/basic/pet/dog
mob_biotypes = MOB_ORGANIC|MOB_BEAST
@@ -159,7 +159,7 @@
/mob/living/basic/pet/dog/corgi/proc/stop_deadchat_plays()
var/controller_type = initial(ai_controller)
ai_controller = new controller_type(src)
ai_controller?.blackboard[BB_DOG_IS_SLOW] = is_slow
ai_controller?.set_blackboard_key(BB_DOG_IS_SLOW, is_slow)
/mob/living/basic/pet/dog/corgi/handle_atom_del(atom/A)
if(A == inventory_head)
@@ -556,7 +556,7 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list(
held_state = "old_corgi"
icon_dead = "old_corgi_dead"
desc = "At a ripe old age of [record_age], Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
ai_controller?.blackboard[BB_DOG_IS_SLOW] = TRUE
ai_controller?.set_blackboard_key(BB_DOG_IS_SLOW, TRUE)
is_slow = TRUE
speed = 2
@@ -118,8 +118,9 @@
teleport = new(src)
teleport.Grant(src)
ai_controller.blackboard[BB_CARP_RIFT] = WEAKREF(teleport)
ai_controller.blackboard[BB_OBSTACLE_TARGETTING_WHITELIST] = allowed_obstacle_targets
ai_controller.set_blackboard_key(BB_CARP_RIFT, teleport)
ai_controller.set_blackboard_key(BB_OBSTACLE_TARGETTING_WHITELIST, allowed_obstacle_targets)
/mob/living/basic/carp/Destroy()
QDEL_NULL(teleport)
@@ -129,7 +130,7 @@
/mob/living/basic/carp/proc/setup_eating()
AddElement(/datum/element/basic_eating, 10, 0, null, desired_food)
AddElement(/datum/element/basic_eating, 0, 10, BRUTE, desired_trash) // We are killing our planet
ai_controller.blackboard[BB_BASIC_FOODS] = desired_food + desired_trash
ai_controller.set_blackboard_key(BB_BASIC_FOODS, desired_food + desired_trash)
/// Set a random colour on the carp, override to do something else
/mob/living/basic/carp/proc/apply_colour()
@@ -151,9 +152,16 @@
/mob/living/basic/carp/ranged_secondary_attack(atom/atom_target, modifiers)
teleport.Trigger(target = atom_target)
/// Gives the carp a list of destinations to try and travel between when it has nothing better to do
/mob/living/basic/carp/proc/migrate_to(list/migration_points)
ai_controller.blackboard[BB_CARP_MIGRATION_PATH] = migration_points
/// Gives the carp a list of weakrefs of destinations to try and travel between when it has nothing better to do
/mob/living/basic/carp/proc/migrate_to(list/datum/weakref/migration_points)
var/list/actual_points = list()
for(var/datum/weakref/point_ref as anything in migration_points)
var/turf/point_resolved = point_ref.resolve()
if(QDELETED(point_resolved))
return // invalid list, we can't migrate to this
actual_points += point_resolved
ai_controller.set_blackboard_key(BB_CARP_MIGRATION_PATH, actual_points)
/**
* Holographic carp from the holodeck
@@ -42,8 +42,7 @@
/datum/ai_planning_subtree/find_nearest_magicarp_spell_target
/datum/ai_planning_subtree/find_nearest_magicarp_spell_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/weak_action = controller.blackboard[BB_MAGICARP_SPELL]
var/datum/action/cooldown/using_action = weak_action?.resolve()
var/datum/action/cooldown/using_action = controller.blackboard[BB_MAGICARP_SPELL]
if (QDELETED(using_action))
return
if (!using_action.IsAvailable())
@@ -22,8 +22,7 @@
if (!length(migration_points))
return
var/datum/weakref/weak_target = controller.blackboard[BB_CARP_MIGRATION_TARGET]
var/turf/moving_to = weak_target?.resolve()
var/turf/moving_to = controller.blackboard[BB_CARP_MIGRATION_TARGET]
// If we don't have a target or are close enough to it, pick a new one
if (isnull(moving_to) || get_dist(controller.pawn, moving_to) <= CARP_DESTINATION_SEARCH_RANGE)
@@ -48,13 +47,12 @@
var/list/blackboard_points = controller.blackboard[path_key]
var/list/potential_migration_points = blackboard_points.Copy()
while (length(potential_migration_points))
var/datum/weakref/weak_destination = popleft(potential_migration_points)
var/turf/potential_destination = weak_destination.resolve()
var/turf/potential_destination = popleft(potential_migration_points)
if (!isnull(potential_destination) && get_dist(controller.pawn, potential_destination) > CARP_DESTINATION_SEARCH_RANGE)
controller.blackboard[target_key] = weak_destination
controller.set_blackboard_key(target_key, potential_destination)
finish_action(controller, succeeded = TRUE)
return
controller.blackboard[path_key] = potential_migration_points.Copy()
controller.set_blackboard_key(path_key, potential_migration_points.Copy())
finish_action(controller, succeeded = FALSE)
@@ -12,14 +12,9 @@
if (!rift_behaviour)
CRASH("Forgot to specify rift behaviour for [src]")
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
var/mob/living/target = weak_target?.resolve()
if (!target)
return
var/datum/weakref/weak_action = controller.blackboard[BB_CARP_RIFT]
var/datum/action/cooldown/using_action = weak_action?.resolve()
if (isnull(using_action) || !using_action.IsAvailable())
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
var/datum/action/cooldown/using_action = controller.blackboard[BB_CARP_RIFT]
if (QDELETED(target) || QDELETED(using_action) || !using_action.IsAvailable())
return
controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, BB_BASIC_MOB_CURRENT_TARGET)
@@ -53,20 +48,12 @@
/datum/ai_behavior/make_carp_rift
/datum/ai_behavior/make_carp_rift/setup(datum/ai_controller/controller, ability_key, target_key)
var/datum/weakref/weak_action = controller.blackboard[ability_key]
var/datum/action/cooldown/mob_cooldown/lesser_carp_rift/ability = weak_action?.resolve()
if (!ability)
return FALSE
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/target = weak_target?.resolve()
return target
return controller.blackboard[ability_key] && controller.blackboard[target_key]
/datum/ai_behavior/make_carp_rift/perform(seconds_per_tick, datum/ai_controller/controller, ability_key, target_key)
. = ..()
var/datum/weakref/weak_action = controller.blackboard[ability_key]
var/datum/action/cooldown/mob_cooldown/lesser_carp_rift/ability = weak_action?.resolve()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/target = weak_target?.resolve()
var/datum/action/cooldown/mob_cooldown/lesser_carp_rift/ability = controller.blackboard[ability_key]
var/atom/target = controller.blackboard[target_key]
if (!validate_target(controller, target, ability))
finish_action(controller, FALSE, ability_key, target_key)
@@ -187,9 +174,8 @@
var/minimum_distance = 2
/datum/ai_planning_subtree/shortcut_to_target_through_carp_rift/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
var/mob/living/target = weak_target?.resolve()
if (isnull(target))
var/mob/living/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
if (QDELETED(target))
return
var/distance_to_target = get_dist(controller.pawn, target)
@@ -88,7 +88,7 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list(
spell.projectile_type = spell_type
spell.button_icon_state = initial(spell_type.icon_state)
spell.Grant(src)
ai_controller.blackboard[BB_MAGICARP_SPELL] = WEAKREF(spell)
ai_controller.set_blackboard_key(BB_MAGICARP_SPELL, spell)
assign_spell_ai(spell_type)
/// If you have certain spells, use a different targetting datum
@@ -99,7 +99,7 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list(
/obj/projectile/magic/resurrection = MAGICARP_SPELL_CORPSES,
)
ai_controller.blackboard[BB_MAGICARP_SPELL_SPECIAL_TARGETTING] = spell_special_targetting[spell_type]
ai_controller.set_blackboard_key(BB_MAGICARP_SPELL_SPECIAL_TARGETTING, spell_special_targetting[spell_type])
/// Shoot when you click away from you
/mob/living/basic/carp/magic/RangedAttack(atom/atom_target, modifiers)
@@ -123,7 +123,7 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list(
chaos_bolt.permitted_projectiles = allowed_projectile_types
chaos_bolt.Grant(src)
spell = chaos_bolt
ai_controller.blackboard[BB_MAGICARP_SPELL] = spell
ai_controller.set_blackboard_key(BB_MAGICARP_SPELL, spell)
RegisterSignal(spell, COMSIG_ACTION_TRIGGER, PROC_REF(apply_colour))
/// Has a more limited spell pool but can appear from gold slime cores
@@ -67,8 +67,7 @@
/datum/ai_behavior/basic_melee_attack/faithless/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
. = ..()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/atom/target = weak_target?.resolve()
var/atom/target = controller.blackboard[target_key]
var/mob/living/living_pawn = controller.pawn
if(!isliving(target))
@@ -119,13 +119,8 @@
/mob/living/basic/garden_gnome/proc/ai_retaliate_behaviour(mob/living/attacker)
if (!istype(attacker))
return
var/list/enemy_refs
for (var/mob/living/basic/garden_gnome/potential_gnome in oview(src, 7))
enemy_refs = potential_gnome.ai_controller.blackboard[BB_BASIC_MOB_RETALIATE_LIST]
if (!enemy_refs)
enemy_refs = list()
enemy_refs |= WEAKREF(attacker)
potential_gnome.ai_controller.blackboard[BB_BASIC_MOB_RETALIATE_LIST] = enemy_refs
potential_gnome.ai_controller.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, attacker)
/datum/ai_controller/basic_controller/garden_gnome
blackboard = list(
@@ -73,7 +73,7 @@
var/datum/action/cooldown/lay_web/webbing = new web_type(src)
webbing.webbing_time *= web_speed
webbing.Grant(src)
ai_controller.blackboard[BB_SPIDER_WEB_ACTION] = WEAKREF(webbing)
ai_controller.set_blackboard_key(BB_SPIDER_WEB_ACTION, webbing)
/mob/living/basic/giant_spider/Login()
. = ..()
@@ -15,16 +15,15 @@
/datum/ai_behavior/find_unwebbed_turf/perform(seconds_per_tick, datum/ai_controller/controller)
. = ..()
var/mob/living/spider = 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 (current_target && !(locate(/obj/structure/spider/stickyweb) in current_target))
finish_action(controller, succeeded = FALSE) // Already got a target
return
controller.blackboard[target_key] = null
controller.clear_blackboard_key(target_key)
var/turf/our_turf = get_turf(spider)
if (is_valid_web_turf(our_turf))
controller.blackboard[target_key] = WEAKREF(our_turf)
controller.set_blackboard_key(target_key, our_turf)
finish_action(controller, succeeded = TRUE)
return
@@ -38,7 +37,7 @@
finish_action(controller, succeeded = FALSE)
return
controller.blackboard[target_key] = WEAKREF(get_closest_atom(/turf/, potential_turfs, our_turf))
controller.set_blackboard_key(target_key, get_closest_atom(/turf/, potential_turfs, our_turf))
finish_action(controller, succeeded = TRUE)
/datum/ai_behavior/find_unwebbed_turf/proc/is_valid_web_turf(turf/target_turf, mob/living/spider)
@@ -54,11 +53,9 @@
var/target_key = BB_SPIDER_WEB_TARGET
/datum/ai_planning_subtree/spin_web/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/weak_action = controller.blackboard[action_key]
var/datum/action/cooldown/using_action = weak_action?.resolve()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/turf/target_turf = weak_target?.resolve()
if (!using_action || !target_turf)
var/datum/action/cooldown/using_action = controller.blackboard[action_key]
var/turf/target_turf = controller.blackboard[target_key]
if (QDELETED(using_action) || QDELETED(target_turf))
return
controller.queue_behavior(/datum/ai_behavior/spin_web, action_key, target_key)
return SUBTREE_RETURN_FINISH_PLANNING
@@ -70,10 +67,8 @@
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/spin_web/setup(datum/ai_controller/controller, action_key, target_key)
var/datum/weakref/weak_action = controller.blackboard[action_key]
var/datum/action/cooldown/web_action = weak_action?.resolve()
var/datum/weakref/weak_target = controller.blackboard[target_key]
var/turf/target_turf = weak_target?.resolve()
var/datum/action/cooldown/web_action = controller.blackboard[action_key]
var/turf/target_turf = controller.blackboard[target_key]
if (!web_action || !target_turf)
return FALSE
@@ -82,10 +77,9 @@
/datum/ai_behavior/spin_web/perform(seconds_per_tick, datum/ai_controller/controller, action_key, target_key)
. = ..()
var/datum/weakref/weak_action = controller.blackboard[action_key]
var/datum/action/cooldown/web_action = weak_action?.resolve()
var/datum/action/cooldown/web_action = controller.blackboard[action_key]
finish_action(controller, succeeded = web_action?.Trigger(), action_key = action_key, target_key = target_key)
/datum/ai_behavior/spin_web/finish_action(datum/ai_controller/controller, succeeded, action_key, target_key)
controller.blackboard[target_key] = null
controller.clear_blackboard_key(target_key)
return ..()
@@ -40,11 +40,11 @@
spikes = new(src)
spikes.Grant(src)
ai_controller.blackboard[BB_METEOR_HEART_GROUND_SPIKES] = WEAKREF(spikes)
ai_controller.set_blackboard_key(BB_METEOR_HEART_GROUND_SPIKES, spikes)
traps = new(src)
traps.Grant(src)
ai_controller.blackboard[BB_METEOR_HEART_SPINE_TRAPS] = WEAKREF(traps)
ai_controller.set_blackboard_key(BB_METEOR_HEART_SPINE_TRAPS, traps)
ai_controller.set_ai_status(AI_STATUS_OFF)
@@ -65,7 +65,7 @@
fugu.melee_damage_upper = 20
fugu.status_flags |= GODMODE
fugu.obj_damage = 60
fugu.ai_controller.blackboard[BB_BASIC_MOB_FLEEING] = FALSE
fugu.ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEEING, FALSE)
fugu.ai_controller.CancelActions()
/datum/status_effect/inflated/on_remove()
@@ -84,7 +84,7 @@
if (fugu.stat != DEAD)
fugu.icon_state = "Fugu0"
fugu.obj_damage = 0
fugu.ai_controller.blackboard[BB_BASIC_MOB_FLEEING] = TRUE
fugu.ai_controller.set_blackboard_key(BB_BASIC_MOB_FLEEING, TRUE)
fugu.ai_controller.CancelActions()
/// Remove status effect if we die
@@ -53,7 +53,7 @@
add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE), ROUNDSTART_TRAIT)
expand = new(src)
expand.Grant(src)
ai_controller.blackboard[BB_FUGU_INFLATE] = WEAKREF(expand)
ai_controller.set_blackboard_key(BB_FUGU_INFLATE, expand)
/mob/living/basic/wumborian_fugu/Destroy()
QDEL_NULL(expand)
@@ -380,8 +380,7 @@
/datum/ai_planning_subtree/flee_target/mouse
/datum/ai_planning_subtree/flee_target/mouse/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/datum/weakref/hunting_weakref = controller.blackboard[BB_CURRENT_HUNTING_TARGET]
var/atom/hunted_cheese = hunting_weakref?.resolve()
var/atom/hunted_cheese = controller.blackboard[BB_CURRENT_HUNTING_TARGET]
if (!isnull(hunted_cheese))
return // We see some cheese, which is more important than our life
return ..()
+4 -12
View File
@@ -2517,12 +2517,8 @@ GLOBAL_LIST_EMPTY(fire_appearances)
if (faction.Find(friend_ref))
return FALSE
faction |= friend_ref
if (ai_controller)
var/list/friends = ai_controller.blackboard[BB_FRIENDS_LIST]
if (!friends)
friends = list()
friends[WEAKREF(new_friend)] = TRUE
ai_controller.blackboard[BB_FRIENDS_LIST] = friends
ai_controller?.insert_blackboard_key_lazylist(BB_FRIENDS_LIST, new_friend)
SEND_SIGNAL(src, COMSIG_LIVING_BEFRIENDED, new_friend)
return TRUE
@@ -2533,12 +2529,8 @@ GLOBAL_LIST_EMPTY(fire_appearances)
if (!faction.Find(friend_ref))
return FALSE
faction -= friend_ref
if (ai_controller)
var/list/friends = ai_controller.blackboard[BB_FRIENDS_LIST]
if (!friends)
return
friends[WEAKREF(old_friend)] = FALSE
ai_controller.blackboard[BB_FRIENDS_LIST] = friends
ai_controller?.remove_thing_from_blackboard_key(BB_FRIENDS_LIST, old_friend)
SEND_SIGNAL(src, COMSIG_LIVING_UNFRIENDED, old_friend)
return TRUE
@@ -29,9 +29,9 @@
clothes_set = pick(customer_info.clothing_sets)
ai_controller = customer_info.ai_controller_used
. = ..()
ai_controller.blackboard[BB_CUSTOMER_CUSTOMERINFO] = customer_info
ai_controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE] = attending_venue
ai_controller.blackboard[BB_CUSTOMER_PATIENCE] = customer_info.total_patience
ai_controller.set_blackboard_key(BB_CUSTOMER_CUSTOMERINFO, customer_info)
ai_controller.set_blackboard_key(BB_CUSTOMER_ATTENDING_VENUE, attending_venue)
ai_controller.set_blackboard_key(BB_CUSTOMER_PATIENCE, customer_info.total_patience)
icon = customer_info.base_icon
icon_state = customer_info.base_icon_state
name = "[pick(customer_info.name_prefixes)]-bot"
@@ -41,9 +41,8 @@
///Clean up on the mobs seat etc when its deleted (Either by murder or because it left)
/mob/living/simple_animal/robot_customer/Destroy()
var/datum/venue/attending_venue = ai_controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE]
var/obj/structure/holosign/robot_seat/our_seat = ai_controller.blackboard[BB_CUSTOMER_MY_SEAT]
attending_venue.current_visitors -= src
var/datum/weakref/seat_ref = ai_controller.blackboard[BB_CUSTOMER_MY_SEAT]
var/obj/structure/holosign/robot_seat/our_seat = seat_ref?.resolve()
if(attending_venue.linked_seats[our_seat])
attending_venue.linked_seats[our_seat] = null
QDEL_NULL(hud_to_show_on_hover)
@@ -90,6 +89,7 @@
/mob/living/simple_animal/robot_customer/examine(mob/user)
. = ..()
// this should be handled by the ai controller
if(ai_controller.blackboard[BB_CUSTOMER_CURRENT_ORDER])
var/datum/venue/attending_venue = ai_controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE]
var/wanted_item = ai_controller.blackboard[BB_CUSTOMER_CURRENT_ORDER]
@@ -110,8 +110,8 @@
var/datum/ai_controller/mod_ai = new /datum/ai_controller/mod(module.mod)
module.mod.ai_controller = mod_ai
mod_ai.set_movement_target(type, imp_in)
mod_ai.blackboard[BB_MOD_TARGET] = imp_in
mod_ai.blackboard[BB_MOD_IMPLANT] = src
mod_ai.set_blackboard_key(BB_MOD_TARGET, imp_in)
mod_ai.set_blackboard_key(BB_MOD_IMPLANT, src)
module.mod.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP
module.mod.AddElement(/datum/element/movetype_handler)
ADD_TRAIT(module.mod, TRAIT_MOVE_FLYING, MOD_TRAIT)
@@ -44,6 +44,7 @@
desc = "These cybernetic eye implants will display a security HUD over everything you see."
HUD_type = DATA_HUD_SECURITY_ADVANCED
HUD_trait = TRAIT_SECURITY_HUD
organ_flags = ALL
/obj/item/organ/internal/cyberimp/eyes/hud/diagnostic
name = "Diagnostic HUD implant"
+1 -1
View File
@@ -22,5 +22,5 @@
new /datum/ai_controller/monkey/angry(monkey)
else
new /datum/ai_controller/monkey(monkey)
monkey.ai_controller.blackboard[BB_MONKEY_TARGET_MONKEYS] = TRUE
monkey.ai_controller.set_blackboard_key(BB_MONKEY_TARGET_MONKEYS, TRUE)
sleep(monkey_timer)
+1 -1
View File
@@ -24,7 +24,7 @@
// Process behavior - this will execute the "locate the cable" behavior
biter.ai_controller.process(fake_dt)
// Check that the cable was found
TEST_ASSERT(biter.ai_controller.blackboard[BB_LOW_PRIORITY_HUNTING_TARGET] == WEAKREF(wire), "Mouse, after executing find, did not set the cable as a target.")
TEST_ASSERT(biter.ai_controller.blackboard[BB_LOW_PRIORITY_HUNTING_TARGET] == wire, "Mouse, after executing find, did not set the cable as a target.")
// Select behavior - this will queue hunting
biter.ai_controller.SelectBehaviors(fake_dt)
// Process behavior - this will execute the hunt for the cable and cause a bite (as we're in the min range)