mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-10 06:34:45 +01:00
24845b238a
* Initial commit - FLOCKMIND - Probably has like a billion things to fix * Do after conversions * Config * Moved the files, icon fixes * Tick everything, language work, event, spawn landmark, role prefs, beginning mob port * Spans and some other fixes. Also the tickening * More tickening * More fixes. Lots of fixes. * More Fixes * A whole lot more. Also flock TGUI. * Fixes fixes fixes fixes fixes * FIXES * More fixes - PR ready, still needs a fuckton of testing * Fixes * fix incomplete upstream merge * fix FlockPanel + sort button name * TGUI review * Fixes tealprint list * Fixes * More fixes * Incapacitator Fix * Filenames * Linters * Interceptor range buff * Reagent counts * Linters * Fabricator vendor fix * Keybinds and HUD - Flockdrones, Fixes Vendor Conversion, Cube Materials * Reworks reagent, adds flock grilles, fixes compute node overlays * Intent-based flockdrone parts * Intent based drone parts * Radial control panel for controlling drones manually, phasing through windows/grilles * Movement fixes * Radio talk power, stare fix * Flock health HUD * Fixes flock lights, linters * Unit tests * Adds countdown to relay * Relay improvements * Small fix * Logic Schmogic * Relay overlay and looping sound effect * Ignore air when converting turfs * Cage fixes and improvements * Improved flock bolt * Turret conversions * Flock bolts taze simple or basic mobs * Sentience type * Fixe * Linter * tgui review stage 2 * Concentrated Repair Burst * Improves radio detection * Removes extra space * Adds healing visual effect * Cube tech levels * Ghooost * Excess * Flock doors, chairs, lattices. Centralizes conversion code. Crafting with Gnesis * Update code/modules/antagonists/flockmind/ai_behaviors/flock_wander.dm Co-authored-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> * Fixes the fix * Astar movement detection * Fix, extraneous code, language stuff * Language fixes and wander fix * Fixes * Another fix * Lints * Another linter * Language improvement * More language improvements * Time requirement and appearing in orbit menu as an antag * Cube glow * TGUI * Minicache * Linters * Grammar * Material ID fix * Lid fix * Reagent turf reaction * Reagent fix * Butcher results * Conversion rates * Flock stare fix * Fixes stare behavior * Staring * Flock mob blood * Flock mobs gibs and blood. Also some runtime fixes * Flock mobs now resist out of grabs, buckles, lockers, and more * Fixes flock orbit, fixes a runtime I think, * Target mechs, damage mechs, other bug fixes * Cage fix * Cage resist change * Some mind changes, gatecrash buff * Drones now shoot mechs, stare improvement * Cut down on spam a little * Nest fix * No more resist spam * Fixed drone death control * Resist statement * Makes the relay alarm scarier * Fixes dead flock camera mobs having no ghost sprite, something with ghosting * Enhanced flockphasing * Improved flockmob pathing * Added required turf restriction to relay * Increased needed bandwidth for relay construction * Nerfed drone substrate rate * Added new status tab items for relay progress * Another relay cost adjustment * Improves drone AI responsiveness * Computer frames now become flock computers * Improves target finding for conversion, building, and replicating * Reduced flock event pop requirements * Adjusts flock protection on structures. Adjusts overlays. * Relay unlock tweak * Fixwes flock being able to gib mech'd AIs with one button * Map conflict * Flock can no longer be outed by merely existing * Fied bug causing drones to shoot themselves * Prevents mobs from attacking while in a cage * Converter tool can now open closets and crates. * Adds descriptions to flockdrone tools. * More informatic blurbs * Adds xenobiology organs * Organ lint * TGUI merge * bundle and mm --------- Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com> Co-authored-by: Toastical <20125180+Toastical@users.noreply.github.com> Co-authored-by: Kapu1178 <75460809+Kapu1178@users.noreply.github.com> Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
201 lines
8.3 KiB
Plaintext
201 lines
8.3 KiB
Plaintext
/// Abstract class for an action an AI can take. Can range from movement to grabbing a nearby weapon.
|
|
/datum/ai_behavior
|
|
/// What distance you need to be from the target to perform the action.
|
|
var/required_distance = 1
|
|
/// If >0, overrides controller.target_search_radius
|
|
var/search_radius_override = null
|
|
/// Flags for extra behavior
|
|
var/behavior_flags = NONE
|
|
/// Cooldown between actions performances, defaults to the value of
|
|
/// CLICK_CD_MELEE because that seemed like a nice standard for the speed of
|
|
/// AI behavior
|
|
var/action_cooldown = CLICK_CD_MELEE
|
|
/// A multiplier applied to the behavior's goap_score().
|
|
var/goap_weight = 1
|
|
|
|
/// Behaviors to add upon a successful setup
|
|
var/list/sub_behaviors
|
|
|
|
/// Called by the AI controller when first being added. Additional arguments
|
|
/// depend on the behavior type. For example, if the behavior involves attacking
|
|
/// a mob, you may require an argument naming the blackboard key which points to
|
|
/// the target. Return FALSE to cancel.
|
|
/datum/ai_behavior/proc/setup(datum/ai_controller/controller, ...)
|
|
return TRUE
|
|
|
|
/// Returns the delay to use for this behavior in the moment. The default
|
|
/// behavior cooldown is `CLICK_CD_MELEE`, but can be customized; for example,
|
|
/// you may want a mob crawling through vents to move slowly and at a random
|
|
/// pace between pipes.
|
|
/datum/ai_behavior/proc/get_cooldown(datum/ai_controller/cooldown_for)
|
|
return action_cooldown
|
|
|
|
/// Called by the AI controller when this action is performed. This will
|
|
/// typically require consulting the blackboard for information on the specific
|
|
/// actions desired from this behavior, by passing the relevant blackboard data
|
|
/// keys to this proc. Returns a combination of [AI_BEHAVIOR_DELAY] or
|
|
/// [AI_BEHAVIOR_INSTANT], determining whether or not a cooldown occurs, and
|
|
/// [AI_BEHAVIOR_SUCCEEDED] or [AI_BEHAVIOR_FAILED]. The behavior's
|
|
/// `finish_action` proc is given TRUE or FALSE depending on whether or not the
|
|
/// return value of `perform` is marked as successful or unsuccessful.
|
|
/datum/ai_behavior/proc/perform(seconds_per_tick, datum/ai_controller/controller, ...)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
controller.behavior_cooldowns[src] = world.time + action_cooldown
|
|
|
|
/// Called when the action is finished. This needs the same args as `perform`
|
|
/// besides the default ones. This should be used to clear up the blackboard of
|
|
/// any unnecessary or obsolete data, and update the state of the pawn if
|
|
/// necessary once we know whether or not the AI action was successful.
|
|
/// `succeeded` is `TRUE` or `FALSE` depending on whether
|
|
/// [/datum/ai_behavior/proc/perform] returns [AI_BEHAVIOR_SUCCEEDED] or
|
|
/// [AI_BEHAVIOR_FAILED].
|
|
/datum/ai_behavior/proc/finish_action(datum/ai_controller/controller, succeeded, ...)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
controller.dequeue_behavior(src)
|
|
controller.behavior_args -= type
|
|
// If this was a movement task, reset our movement target if necessary
|
|
if(!(behavior_flags & AI_BEHAVIOR_REQUIRE_MOVEMENT))
|
|
next_behavior(controller, succeeded)
|
|
return
|
|
if(behavior_flags & AI_BEHAVIOR_KEEP_MOVE_TARGET_ON_FINISH)
|
|
return
|
|
clear_movement_target(controller)
|
|
controller.ai_movement.stop_moving_towards(controller)
|
|
|
|
/// Helper proc to ensure consistency in setting the source of the movement target
|
|
/datum/ai_behavior/proc/set_movement_target(datum/ai_controller/controller, atom/target, datum/ai_movement/new_movement)
|
|
controller.set_movement_target(type, target, new_movement)
|
|
|
|
/// Clear the controller's movement target only if it was us who last set it
|
|
/datum/ai_behavior/proc/clear_movement_target(datum/ai_controller/controller)
|
|
if(controller.movement_target_source != type)
|
|
return
|
|
controller.set_movement_target(type, null)
|
|
|
|
/// Returns a behavior to perform after this one, or null if continuing this one
|
|
/datum/ai_behavior/proc/next_behavior(datum/ai_controller/controller, success)
|
|
return null
|
|
|
|
/// Executed before goap_score(), to see if the behavior should even be considered.
|
|
/datum/ai_behavior/proc/goap_precondition(datum/ai_controller/controller)
|
|
return TRUE
|
|
|
|
/// Returns a numerical value that is essentially a priority for planner behaviors.
|
|
/datum/ai_behavior/proc/goap_score(datum/ai_controller/controller)
|
|
return score_distance(controller, goap_get_ideal_target(controller))
|
|
|
|
/// Returns the ideal target for this behavior.
|
|
/datum/ai_behavior/proc/goap_get_ideal_target(datum/ai_controller/controller, set_path = FALSE)
|
|
var/list/options = goap_filter_targets(controller)
|
|
return get_best_target_by_distance_score(controller, options, set_path)
|
|
|
|
/// Filter through potential targets to find real targets.
|
|
/datum/ai_behavior/proc/goap_filter_targets(datum/ai_controller/controller)
|
|
var/list/options = list()
|
|
for(var/atom/potential_target as anything in goap_get_potential_targets(controller))
|
|
if(goap_is_valid_target(controller, potential_target))
|
|
options += potential_target
|
|
return options
|
|
|
|
/// Returns a list of potential targets to filter through.
|
|
/datum/ai_behavior/proc/goap_get_potential_targets(datum/ai_controller/controller)
|
|
return list()
|
|
|
|
/// Returns TRUE if the given atom is a valid target for this behavior.
|
|
/datum/ai_behavior/proc/goap_is_valid_target(datum/ai_controller/controller, atom/target)
|
|
return TRUE
|
|
|
|
#define BINARY_INSERT_TARGET(target_list, target, score) \
|
|
do { \
|
|
var/length = length(target_list); \
|
|
if(!length) { \
|
|
target_list[target] = score; \
|
|
} else { \
|
|
var/left = 1; \
|
|
var/right = length; \
|
|
var/middle = (left + right) >> 1; \
|
|
while(left < right) { \
|
|
if(target_list[target_list[middle]] <= score) { \
|
|
left = middle + 1; \
|
|
} else { \
|
|
right = middle; \
|
|
}; \
|
|
middle = (left + right) >> 1; \
|
|
}; \
|
|
middle = target_list[target_list[middle]] > score ? middle : middle + 1; \
|
|
target_list.Insert(middle, target); \
|
|
target_list[target] = score; \
|
|
}; \
|
|
} while(FALSE)
|
|
|
|
|
|
/// Returns the best target by scoring the distance of each possible target.
|
|
/// Takes a list to insert the path into, so it can be handed back and re-used.
|
|
/datum/ai_behavior/proc/get_best_target_by_distance_score(datum/ai_controller/controller, list/targets, set_path = FALSE)
|
|
if(!length(targets))
|
|
return null
|
|
|
|
var/atom/movable/pawn = controller.pawn
|
|
var/list/access = controller.get_access()
|
|
|
|
var/list/targets_by_score = list()
|
|
var/list/reachable_targets = list()
|
|
|
|
// Sort targets by their estimated score. The last element in the lists has the highest score.
|
|
while(length(targets))
|
|
var/index = rand(1, length(targets))
|
|
var/atom/A = targets[index]
|
|
targets.Cut(index, index + 1)
|
|
|
|
var/score = score_distance(controller, A)
|
|
|
|
BINARY_INSERT_TARGET(targets_by_score, A, score)
|
|
|
|
// WEE WOO WEE WOO BEHAVIOR-CHANGING MICRO-OPT: we assume turfs further than 1 tile aren't reachable
|
|
// Because this is true in 99.9999999999999999% of cases
|
|
if(get_dist(pawn, A) <= 1 && A.Adjacent(pawn))
|
|
BINARY_INSERT_TARGET(reachable_targets, A, score)
|
|
|
|
// Go through our sorted target list until we find a path to one.
|
|
// Note: This does mean that the found target might not be the ideal one, as it's operating on the estimate
|
|
// This is a performance thing. We cannot actually use the true best target.
|
|
var/atom/ideal_atom
|
|
var/list/ideal_path
|
|
if(length(reachable_targets))
|
|
ideal_atom = reachable_targets[length(reachable_targets)]
|
|
else
|
|
while(length(targets_by_score))
|
|
var/atom/candidate = targets_by_score[length(targets_by_score)]
|
|
targets_by_score.len--
|
|
|
|
var/list/path = SSpathfinder.astar_pathfind_now(
|
|
controller.pawn,
|
|
candidate,
|
|
controller.max_target_distance,
|
|
required_distance,
|
|
access,
|
|
HAS_TRAIT(controller.pawn, TRAIT_FLYING),
|
|
)
|
|
|
|
if(path)
|
|
ideal_atom = candidate
|
|
ideal_path = path
|
|
break
|
|
|
|
if(set_path && length(ideal_path))
|
|
controller.clear_blackboard_key(BB_PATH_TO_USE)
|
|
controller.set_blackboard_key(BB_PATH_TO_USE, ideal_path)
|
|
return ideal_atom
|
|
|
|
#undef BINARY_INSERT_TARGET
|
|
|
|
/// Helper for scoring something based on the distance between it and the pawn.
|
|
/// By default, returns a value between 100 and -INFINITY, where 100 is a distance of 0 steps.
|
|
/// A distance equal to target_search_radius is zero.
|
|
/// A distance greater than target_search_radius is negative.
|
|
/datum/ai_behavior/proc/score_distance(datum/ai_controller/controller, atom/target)
|
|
var/search_radius = search_radius_override || controller.target_search_radius
|
|
if(isnull(target))
|
|
return -INFINITY
|
|
return 100 * (search_radius - get_dist_manhattan(get_turf(controller.pawn), get_turf(target))) / search_radius
|