mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-14 09:35:30 +01:00
31d4eb04f1
## About The Pull Request Two main things. Multiple instances of use of a proc in AI controllers seemingly assuming the default behaviour will work for them, but what ends up happening is `search_tactic` gets redefined and redefined with no defaut search range parameter, so nothing ends up passed to the `search_tactic` child procs, so they all call `oview` with `null` and this... somehow doesn't runtime? Has behaviour that works some of the time??? I hate this fucking language. Anyway. Stoat steal items behaviour was completely broken and apparently was not tested once since it was merged in. I've made the corrections I can, but I haven't figured out why stoat AI never enters idle, so we have a behaviour that leads to the stoat running up to an item, grabbing it, and then just staying there, unmoving. I've sunk too many hours into this, I'm just going to call it fixed and let someone else figure out what exciting additions there need to be to a behaviour that was never functional in the first place. ## Why It's Good For The Game i don't know man i just want the pain to stop okay, generally speaking, when people write AI behaviours, they want those AI behaviours to do something and not just silently fail for six months or longer ## Changelog 🆑 fix: Stoats have a chance to try and grab items like they always should have. /🆑
226 lines
9.1 KiB
Plaintext
226 lines
9.1 KiB
Plaintext
#define BOT_CLEAN_PATH_LIMIT 15
|
|
#define POST_CLEAN_COOLDOWN 5 SECONDS
|
|
|
|
/datum/ai_controller/basic_controller/bot/cleanbot
|
|
blackboard = list(
|
|
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/allow_items,
|
|
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
|
|
BB_UNREACHABLE_LIST_COOLDOWN = 3 MINUTES,
|
|
BB_SALUTE_MESSAGES = list(
|
|
"salutes",
|
|
"nods in appreciation towards",
|
|
"mops the dirt away in the path of",
|
|
),
|
|
BB_FRIENDLY_MESSAGE = "empathetically acknowledges your hardwork and tough circumstances",
|
|
)
|
|
planning_subtrees = list(
|
|
/datum/ai_planning_subtree/escape_captivity/pacifist,
|
|
/datum/ai_planning_subtree/respond_to_summon,
|
|
/datum/ai_planning_subtree/pet_planning/cleanbot,
|
|
/datum/ai_planning_subtree/cleaning_subtree,
|
|
/datum/ai_planning_subtree/befriend_janitors,
|
|
/datum/ai_planning_subtree/acid_spray,
|
|
/datum/ai_planning_subtree/use_mob_ability/foam_area,
|
|
/datum/ai_planning_subtree/salute_authority,
|
|
/datum/ai_planning_subtree/find_patrol_beacon/cleanbot,
|
|
)
|
|
reset_keys = list(
|
|
BB_ACTIVE_PET_COMMAND,
|
|
BB_CLEAN_TARGET,
|
|
BB_BEACON_TARGET,
|
|
BB_PREVIOUS_BEACON_TARGET,
|
|
BB_BOT_SUMMON_TARGET,
|
|
)
|
|
///list that ties each flag to its list key
|
|
var/static/list/clean_flags = list(
|
|
BB_CLEANABLE_BLOOD = CLEANBOT_CLEAN_BLOOD,
|
|
BB_HUNTABLE_PESTS = CLEANBOT_CLEAN_PESTS,
|
|
BB_CLEANABLE_DRAWINGS = CLEANBOT_CLEAN_DRAWINGS,
|
|
BB_HUNTABLE_TRASH = CLEANBOT_CLEAN_TRASH,
|
|
)
|
|
|
|
/datum/ai_planning_subtree/pet_planning/cleanbot/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
|
var/mob/living/basic/bot/bot_pawn = controller.pawn
|
|
//we are DONE listening to orders
|
|
if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
|
|
return
|
|
return ..()
|
|
|
|
|
|
/datum/ai_planning_subtree/cleaning_subtree
|
|
|
|
/datum/ai_planning_subtree/cleaning_subtree/SelectBehaviors(datum/ai_controller/basic_controller/bot/cleanbot/controller, seconds_per_tick)
|
|
if(controller.blackboard_key_exists(BB_CLEAN_TARGET))
|
|
controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_CLEAN_TARGET)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
var/list/final_hunt_list = list()
|
|
|
|
final_hunt_list += controller.blackboard[BB_CLEANABLE_DECALS]
|
|
var/list/flag_list = controller.clean_flags
|
|
var/mob/living/basic/bot/cleanbot/bot_pawn = controller.pawn
|
|
for(var/list_key in flag_list)
|
|
if(!(bot_pawn.janitor_mode_flags & flag_list[list_key]))
|
|
continue
|
|
final_hunt_list += controller.blackboard[list_key]
|
|
|
|
controller.queue_behavior(/datum/ai_behavior/find_and_set/in_list/clean_targets, BB_CLEAN_TARGET, final_hunt_list)
|
|
|
|
/datum/ai_behavior/find_and_set/in_list/clean_targets
|
|
action_cooldown = 3 SECONDS
|
|
|
|
/datum/ai_behavior/find_and_set/in_list/clean_targets/search_tactic(datum/ai_controller/basic_controller/bot/controller, locate_paths, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
|
|
var/list/found = typecache_filter_list(oview(search_range, controller.pawn), locate_paths)
|
|
var/list/ignore_list = controller.blackboard[BB_TEMPORARY_IGNORE_LIST]
|
|
for(var/atom/found_item in found)
|
|
if(QDELETED(controller.pawn))
|
|
break
|
|
if(LAZYACCESS(ignore_list, found_item))
|
|
continue
|
|
if(get_turf(found_item) == get_turf(controller.pawn))
|
|
return found_item
|
|
var/list/path = get_path_to(controller.pawn, found_item, max_distance = BOT_CLEAN_PATH_LIMIT, access = controller.get_access())
|
|
if(!length(path))
|
|
controller.add_to_blacklist(found_item)
|
|
continue
|
|
return found_item
|
|
|
|
/datum/ai_planning_subtree/acid_spray
|
|
|
|
/datum/ai_planning_subtree/acid_spray/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
|
var/mob/living/basic/bot/cleanbot/bot_pawn = controller.pawn
|
|
if(!(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED))
|
|
return
|
|
if(controller.blackboard_key_exists(BB_ACID_SPRAY_TARGET))
|
|
controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_ACID_SPRAY_TARGET)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
controller.queue_behavior(/datum/ai_behavior/find_and_set/spray_target, BB_ACID_SPRAY_TARGET, /mob/living/carbon/human, 5)
|
|
|
|
/datum/ai_behavior/find_and_set/spray_target
|
|
action_cooldown = 30 SECONDS
|
|
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
|
|
|
/datum/ai_behavior/find_and_set/spray_target/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
|
|
var/list/ignore_list = controller.blackboard[BB_TEMPORARY_IGNORE_LIST]
|
|
for(var/mob/living/carbon/human/human_target in oview(search_range, controller.pawn))
|
|
if(LAZYACCESS(ignore_list, human_target))
|
|
continue
|
|
if(human_target.stat != CONSCIOUS || isnull(human_target.mind))
|
|
continue
|
|
return human_target
|
|
return null
|
|
|
|
/datum/ai_behavior/execute_clean
|
|
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION | AI_BEHAVIOR_REQUIRE_REACH
|
|
|
|
/datum/ai_behavior/execute_clean/setup(datum/ai_controller/controller, target_key)
|
|
. = ..()
|
|
var/turf/target = controller.blackboard[target_key]
|
|
if(isnull(target))
|
|
return FALSE
|
|
set_movement_target(controller, target)
|
|
|
|
/datum/ai_behavior/execute_clean/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
|
|
var/mob/living/basic/living_pawn = controller.pawn
|
|
var/atom/target = controller.blackboard[target_key]
|
|
|
|
if(QDELETED(target))
|
|
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
|
|
|
|
living_pawn.UnarmedAttack(target, proximity_flag = TRUE)
|
|
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
|
|
|
|
/datum/ai_behavior/execute_clean/finish_action(datum/ai_controller/basic_controller/bot/controller, succeeded, target_key, targeting_strategy_key, hiding_location_key)
|
|
. = ..()
|
|
controller.set_blackboard_key(BB_POST_CLEAN_COOLDOWN, POST_CLEAN_COOLDOWN + world.time)
|
|
var/atom/target = controller.blackboard[target_key]
|
|
if(!succeeded && !isnull(target))
|
|
controller.clear_blackboard_key(target_key)
|
|
controller.add_to_blacklist(target)
|
|
return
|
|
if(QDELETED(target) || is_type_in_typecache(target, controller.blackboard[BB_HUNTABLE_TRASH]))
|
|
return
|
|
if(!iscarbon(target))
|
|
controller.clear_blackboard_key(target_key)
|
|
return
|
|
var/list/speech_list = controller.blackboard[BB_CLEANBOT_EMAGGED_PHRASES]
|
|
if(length(speech_list))
|
|
var/mob/living/living_pawn = controller.pawn
|
|
if(!QDELETED(living_pawn)) // pawn can be null at this point
|
|
living_pawn.say(pick(speech_list), forced = "ai controller")
|
|
controller.clear_blackboard_key(target_key)
|
|
|
|
/datum/ai_planning_subtree/use_mob_ability/foam_area
|
|
ability_key = BB_CLEANBOT_FOAM
|
|
finish_planning = FALSE
|
|
|
|
/datum/ai_planning_subtree/use_mob_ability/foam_area/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
|
var/mob/living/basic/bot/bot_pawn = controller.pawn
|
|
if(!(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED))
|
|
return
|
|
return ..()
|
|
|
|
/datum/ai_planning_subtree/befriend_janitors
|
|
|
|
/datum/ai_planning_subtree/befriend_janitors/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
|
var/mob/living/basic/bot/bot_pawn = controller.pawn
|
|
//we are now evil. dont befriend the janitors
|
|
if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
|
|
return
|
|
if(controller.blackboard_key_exists(BB_FRIENDLY_JANITOR))
|
|
controller.queue_behavior(/datum/ai_behavior/befriend_target, BB_FRIENDLY_JANITOR, BB_FRIENDLY_MESSAGE)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
controller.queue_behavior(/datum/ai_behavior/find_and_set/friendly_janitor, BB_FRIENDLY_JANITOR, /mob/living/carbon/human, 5)
|
|
|
|
/datum/ai_behavior/find_and_set/friendly_janitor
|
|
action_cooldown = 30 SECONDS
|
|
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
|
|
|
|
/datum/ai_behavior/find_and_set/friendly_janitor/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
|
|
var/mob/living/living_pawn = controller.pawn
|
|
for(var/mob/living/carbon/human/human_target in oview(search_range, living_pawn))
|
|
if(human_target.stat != CONSCIOUS || isnull(human_target.mind))
|
|
continue
|
|
if(!HAS_TRAIT(human_target, TRAIT_CLEANBOT_WHISPERER))
|
|
continue
|
|
if((living_pawn.faction.Find(REF(human_target))))
|
|
continue
|
|
return human_target
|
|
return null
|
|
|
|
/datum/ai_planning_subtree/find_patrol_beacon/cleanbot
|
|
|
|
/datum/ai_planning_subtree/find_patrol_beacon/cleanbot/SelectBehaviors(datum/ai_controller/basic_controller/bot/controller, seconds_per_tick)
|
|
if(controller.blackboard[BB_POST_CLEAN_COOLDOWN] >= world.time)
|
|
return
|
|
return ..()
|
|
|
|
/datum/pet_command/clean
|
|
command_name = "Clean"
|
|
command_desc = "Command a cleanbot to clean the mess."
|
|
requires_pointing = TRUE
|
|
radial_icon = 'icons/obj/service/janitor.dmi'
|
|
radial_icon_state = "mop"
|
|
speech_commands = list("clean", "mop")
|
|
|
|
/datum/pet_command/clean/set_command_target(mob/living/parent, atom/target)
|
|
if(isnull(target) || !istype(target, /obj/effect/decal/cleanable))
|
|
return FALSE
|
|
if(isnull(parent.ai_controller))
|
|
return FALSE
|
|
if(LAZYACCESS(parent.ai_controller.blackboard[BB_TEMPORARY_IGNORE_LIST], target))
|
|
return FALSE
|
|
return ..()
|
|
|
|
/datum/pet_command/clean/execute_action(datum/ai_controller/basic_controller/bot/controller)
|
|
if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET))
|
|
controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_CURRENT_PET_TARGET)
|
|
return SUBTREE_RETURN_FINISH_PLANNING
|
|
|
|
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
|
|
|
|
#undef BOT_CLEAN_PATH_LIMIT
|
|
#undef POST_CLEAN_COOLDOWN
|