# SS13 Mob AI Overhaul ###### tags: `Ideas Guy` `Development` `Design` ## Key Goals To provide performant, intelligent AI to SS13, such that players are actually significantly challenged by organized groups of NPCs. ## Concepts - Flocking Behavior - "Trend towards center of herd" - Group moves in concert, does single pathing as a group with basic cellular behaviors for local collision avoidance. - Center isn't necessarily on a mob, more the directed center of the group - Shared state about targeting - Raycasting algo based off of the atom density field around the flock - Shares pathfinding knowledge by using each individual mob as an outer edge in the pathfinding algo for other mobs. - Mobs share their optimal path to target - Splitting/Flanking behaviors for "intelligent" flocks - "Crowded" paths are treated as high-cost movement, will repath around targets if possible. - Chokepoint exploitation - instead of filing into the fatal funnel to be killed, can call mob specific behaivors based on flock capabilities - Individuals providing capabilities to the flock like demolitions/breaching/anti-personnel/anti-mech attacks as options. - Checks to determine when the behavior should be used are provided by the capabilities, but the flock AI chooses when to actually execute the order. - Leader unit that, when killed, disorganizes the flock temporarily until a re-election is performed. ## Algorithm Details Psuedocode in some places like yield Note: Not necessarily needed to be implemented in DM, great candidate for C++/Rust implementation. ``` #define FLOCK_BEHAVIOR_STARTING 0x1 #define FLOCK_BEHAVIOR_RUNNING 0x2 #define FLOCK_BEHAVIOR_COMPLETE 0x3 /datum/flock_behavior var/behavior_state = 0x0 /datum/flock_behavior/bind(/datum/flock_controller/flock) flock.set_active_behavior(src) /datum/flock_behavior/pathfind_behavior/Initialize(/turf/origin, /turf/dest) /datum/flock_behavior/pathfind_behavior/bind(/datum/flock_controller/flock) /datum/flock_decision_tree/Initialize() /datum/flock_decision_tree/basic/Initialize() /datum/flock_decision_tree/basic/step(flock) if (flock.has_target() && flock.aggresive_state() && !flock.not_engaged()) var/datum/flock_behavior/pathfind_behavior/P = flock.get_pathfind_from_cache( astar.path(WEAKREF(flock.center), WEAKREF(flock.target.loc)) ) if (P.behavior_state & FLOCK_BEHAVIOR_COMPLETE) var/datum/flock_behavior/engage_behavior/E = flock.engage_target() return E.bind(flock) if (P.behavior_state & FLOCK_BEHAVIOR_RUNNING) return P.step(flock) else return P.bind(flock) else if (flock.aggressive_state()) var/datum/flock_behavior/seek_behavior/S = flock.seek_target() return S.bind(flock) else var/datum/flock_behavior/idle_behavior/B = flock.select_idle_behavior() return B.bind(flock) /datum/flock_controller var/state = 0x0 /datum/flock_controller/Initialize(decision_tree, list_of_mobs) for var/m in list_of_mobs m.set_flock(src) src.elect_leader() /datum/flock_controller/get_pathfind_from_cache(/turf/origin, /turf/dest) var/hash = loc_merge_hash(origin, dest) if (src.pathfind_cache[hash] != NULL) return src.pathfind_cache[hash] else return new /datum/flock_behavior/pathfind_behavior(origin, dest)