The Divine Flock - DaedalusDock Flockmind Port (#31984)

* 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>
This commit is contained in:
PollardTheDragon
2026-07-08 21:31:28 +00:00
committed by GitHub
co-authored by Kapu1178 Toastical Burzah
parent ab05a4ee3a
commit 24845b238a
228 changed files with 9724 additions and 49 deletions
+135
View File
@@ -2,12 +2,19 @@
/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
@@ -48,6 +55,7 @@
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
@@ -63,3 +71,130 @@
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