Files
Bubberstation/code/modules/mob/living/basic/bots/bot_ai.dm
T
MrMelbertandGitHub b0459944d9 Baisc Bot "Commission Emote" Tweak (#82549)
## About The Pull Request

1. Simple bots use Manual Emotes like Basic Bots
2. Re-ups the CD for emoting to commission bots to 60 seconds, as it was
originally with Simple Bots
3. Punctuates the manual emotes
4. Deletes the fist bump message

## Why It's Good For The Game

1. Consistency. 
2. These messages get a little... a lot spammy when walking around the
halls, especially if Robotics has made a few additional bots. The
original implementation had a CD of 60 seconds, which the AI behavior
halved. Upping it back up for consistency + less spam.
3. Looks a little less shoddy. 
4. It's a cute message, but it's completely out of character for what
the bots are supposed to be "doing". They're "saluting" their
"commissioned officer", not meeting up with the bros. Also they don't
have fists! I understand saluting with their "robot appendage" but they
don't punch people!

## Changelog

🆑 Melbert
qol: Basic Bots will use their "salute" emotes less often. 
del: Basic bot fists. 
/🆑
2024-04-10 17:24:07 -07:00

240 lines
9.0 KiB
Plaintext

/datum/ai_controller/basic_controller/bot
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_SALUTE_MESSAGES = list(
"performs an elaborate salute for",
"nods in appreciation towards",
),
BB_UNREACHABLE_LIST_COOLDOWN = 45 SECONDS,
)
ai_movement = /datum/ai_movement/jps/bot
idle_behavior = /datum/idle_behavior/idle_random_walk/less_walking
planning_subtrees = list(
/datum/ai_planning_subtree/respond_to_summon,
/datum/ai_planning_subtree/salute_authority,
/datum/ai_planning_subtree/find_patrol_beacon,
/datum/ai_planning_subtree/manage_unreachable_list,
)
max_target_distance = AI_BOT_PATH_LENGTH
///keys to be reset when the bot is reseted
var/list/reset_keys = list(
BB_BEACON_TARGET,
BB_PREVIOUS_BEACON_TARGET,
BB_BOT_SUMMON_TARGET,
)
///how many times we tried to reach the target
var/current_pathing_attempts = 0
///if we cant reach it after this many attempts, add it to our ignore list
var/max_pathing_attempts = 25
/datum/ai_controller/basic_controller/bot/TryPossessPawn(atom/new_pawn)
. = ..()
if(. & AI_CONTROLLER_INCOMPATIBLE)
return
RegisterSignal(new_pawn, COMSIG_BOT_RESET, PROC_REF(reset_bot))
/datum/ai_controller/basic_controller/bot/able_to_run()
var/mob/living/basic/bot/bot_pawn = pawn
if(!(bot_pawn.bot_mode_flags & BOT_MODE_ON))
return FALSE
return ..()
/datum/ai_controller/basic_controller/bot/get_access()
var/mob/living/basic/bot/basic_bot = pawn
return basic_bot.access_card?.access
/datum/ai_controller/basic_controller/bot/proc/reset_bot()
SIGNAL_HANDLER
if(!length(reset_keys))
return
for(var/key in reset_keys)
clear_blackboard_key(key)
///set the target if we can reach them
/datum/ai_controller/basic_controller/bot/proc/set_if_can_reach(key, target, distance = 10, bypass_add_to_blacklist = FALSE)
if(can_reach_target(target, distance))
set_blackboard_key(key, target)
return TRUE
if(!bypass_add_to_blacklist)
set_blackboard_key_assoc_lazylist(BB_TEMPORARY_IGNORE_LIST, REF(target), TRUE)
return FALSE
/datum/ai_controller/basic_controller/bot/proc/can_reach_target(target, distance = 10)
if(!isdatum(target)) //we dont need to check if its not a datum!
return TRUE
if(get_turf(pawn) == get_turf(target))
return TRUE
var/list/path = get_path_to(pawn, target, max_distance = distance, access = get_access())
if(!length(path))
return FALSE
return TRUE
/// subtree to manage our list of unreachables, we reset it every 15 seconds
/datum/ai_planning_subtree/manage_unreachable_list
/datum/ai_planning_subtree/manage_unreachable_list/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
if(isnull(controller.blackboard[BB_UNREACHABLE_LIST_COOLDOWN]) || controller.blackboard[BB_CLEAR_LIST_READY] > world.time)
return
controller.queue_behavior(/datum/ai_behavior/manage_unreachable_list, BB_TEMPORARY_IGNORE_LIST)
/datum/ai_behavior/manage_unreachable_list
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/manage_unreachable_list/perform(seconds_per_tick, datum/ai_controller/controller, list_key)
. = ..()
if(!isnull(controller.blackboard[list_key]))
controller.clear_blackboard_key(list_key)
finish_action(controller, TRUE)
/datum/ai_behavior/manage_unreachable_list/finish_action(datum/ai_controller/controller, succeeded)
. = ..()
controller.set_blackboard_key(BB_CLEAR_LIST_READY, controller.blackboard[BB_UNREACHABLE_LIST_COOLDOWN] + world.time)
/datum/ai_planning_subtree/find_patrol_beacon
///travel towards beacon behavior
var/travel_behavior = /datum/ai_behavior/travel_towards/beacon
/datum/ai_planning_subtree/find_patrol_beacon/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/basic/bot/bot_pawn = controller.pawn
if(!(bot_pawn.bot_mode_flags & BOT_MODE_AUTOPATROL) || bot_pawn.mode == BOT_SUMMON)
return
if(controller.blackboard_key_exists(BB_BEACON_TARGET))
bot_pawn.update_bot_mode(new_mode = BOT_PATROL)
controller.queue_behavior(travel_behavior, BB_BEACON_TARGET)
return
if(controller.blackboard_key_exists(BB_PREVIOUS_BEACON_TARGET))
controller.queue_behavior(/datum/ai_behavior/find_next_beacon_target, BB_BEACON_TARGET)
return
controller.queue_behavior(/datum/ai_behavior/find_first_beacon_target, BB_BEACON_TARGET)
/datum/ai_behavior/find_first_beacon_target
/datum/ai_behavior/find_first_beacon_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
. = ..()
var/closest_distance = INFINITY
var/mob/living/basic/bot/bot_pawn = controller.pawn
var/atom/final_target
var/atom/previous_target = controller.blackboard[BB_PREVIOUS_BEACON_TARGET]
for(var/obj/machinery/navbeacon/beacon as anything in GLOB.navbeacons["[bot_pawn.z]"])
var/dist = get_dist(bot_pawn, beacon)
if(beacon == previous_target || dist <= 1)
continue
if(dist > closest_distance)
continue
closest_distance = dist
final_target = beacon
if(isnull(final_target))
finish_action(controller, FALSE)
return
controller.set_blackboard_key(BB_BEACON_TARGET, final_target)
finish_action(controller, TRUE)
/datum/ai_behavior/find_next_beacon_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
. = ..()
var/mob/living/basic/bot/bot_pawn = controller.pawn
var/atom/final_target
var/obj/machinery/navbeacon/prev_beacon = controller.blackboard[BB_PREVIOUS_BEACON_TARGET]
if(QDELETED(prev_beacon))
finish_action(controller, FALSE)
return
for(var/obj/machinery/navbeacon/beacon as anything in GLOB.navbeacons["[bot_pawn.z]"])
if(beacon.location == prev_beacon.codes[NAVBEACON_PATROL_NEXT])
final_target = beacon
break
if(isnull(final_target))
controller.clear_blackboard_key(BB_PREVIOUS_BEACON_TARGET)
finish_action(controller, FALSE)
controller.set_blackboard_key(BB_BEACON_TARGET, final_target)
finish_action(controller, TRUE)
/datum/ai_behavior/travel_towards/beacon
clear_target = TRUE
new_movement_type = /datum/ai_movement/jps/bot/travel_to_beacon
/datum/ai_behavior/travel_towards/beacon/finish_action(datum/ai_controller/controller, succeeded, target_key)
var/atom/target = controller.blackboard[target_key]
controller.set_blackboard_key(BB_PREVIOUS_BEACON_TARGET, target)
return ..()
/datum/ai_planning_subtree/respond_to_summon
/datum/ai_planning_subtree/respond_to_summon/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
if(!controller.blackboard_key_exists(BB_BOT_SUMMON_TARGET))
return
controller.clear_blackboard_key(BB_PREVIOUS_BEACON_TARGET)
controller.clear_blackboard_key(BB_BEACON_TARGET)
controller.queue_behavior(/datum/ai_behavior/travel_towards/bot_summon, BB_BOT_SUMMON_TARGET)
return SUBTREE_RETURN_FINISH_PLANNING
/datum/ai_behavior/travel_towards/bot_summon
clear_target = TRUE
new_movement_type = /datum/ai_movement/jps/bot/travel_to_beacon
/datum/ai_behavior/travel_towards/bot_summon/finish_action(datum/ai_controller/controller, succeeded, target_key)
var/mob/living/basic/bot/bot_pawn = controller.pawn
if(QDELETED(bot_pawn)) // pawn can be null at this point
return ..()
bot_pawn.calling_ai_ref = null
bot_pawn.update_bot_mode(new_mode = BOT_IDLE)
return ..()
/datum/ai_planning_subtree/salute_authority
/datum/ai_planning_subtree/salute_authority/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/basic/bot/bot_pawn = controller.pawn
//we are criminals, dont salute the dirty pigs
if(bot_pawn.bot_access_flags & BOT_COVER_EMAGGED)
return
if(controller.blackboard_key_exists(BB_SALUTE_TARGET))
controller.queue_behavior(/datum/ai_behavior/salute_authority, BB_SALUTE_TARGET, BB_SALUTE_MESSAGES)
return SUBTREE_RETURN_FINISH_PLANNING
controller.queue_behavior(/datum/ai_behavior/find_and_set/valid_authority, BB_SALUTE_TARGET)
/datum/ai_behavior/find_and_set/valid_authority
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
action_cooldown = BOT_COMMISSIONED_SALUTE_DELAY
/datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range)
for(var/mob/living/nearby_mob in oview(search_range, controller.pawn))
if(!HAS_TRAIT(nearby_mob, TRAIT_COMMISSIONED))
continue
return nearby_mob
return null
/datum/ai_behavior/salute_authority
/datum/ai_behavior/salute_authority/perform(seconds_per_tick, datum/ai_controller/controller, target_key, salute_keys)
. = ..()
if(!controller.blackboard_key_exists(target_key))
finish_action(controller, FALSE, target_key)
return
var/list/salute_list = controller.blackboard[salute_keys]
if(!length(salute_list))
finish_action(controller, FALSE, target_key)
return
var/mob/living/basic/bot/bot_pawn = controller.pawn
//special interaction if we are wearing a fedora
var/obj/item/our_hat = (locate(/obj/item/clothing/head) in bot_pawn)
if(our_hat)
salute_list += "tips [our_hat] at "
bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]!")
finish_action(controller, TRUE, target_key)
return
/datum/ai_behavior/salute_authority/finish_action(datum/ai_controller/controller, succeeded, target_key)
. = ..()
controller.clear_blackboard_key(target_key)