mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 01:34:01 +00:00
…not idle) (#27470) * Reworks targeting behavior to fall back onto proximity monitors. Refactors ai cooldowns a bit (#82640) Nother bit ripped out of #79498 [Implements a get_cooldown() proc to get around dumb manual overrides and empower me to optimize the findtarget logic](7047d294dd) [Adds modify_cooldown, uses it to optimize find_potential_targets further](4ebc8cedce) No sense running the behavior if we're just waiting on its output, so let's run it once a minute just in case, then push an update instantly if we find something [Optimizes connect_range and promxity_monitors](bcf7d7c5b3) We know what turfs exist before and after a move We can use this information to prevent trying to update turfs we don't care about. This is important because post these changes mobs with fields will be moving a lot more, so it's gotta be cheap [Implements a special kind of field to handle ai targeting](80b63b3445) If we run targeting and don't like, find anything, we should setup a field that listens for things coming near us and then handle those things as we find them. This incurs a slight startup cost but saves so much time on the churn of constant costs Note: We should also work to figure out a way to avoid waking ais if none is near them/they aren't doing anything interesting We don't need to do that immediately this acts as somewhat of a stopgap (and would be good regardless) but it is worth keeping in mind) I am unsure whether this is worth it anymore since #82539 was merged. As I say it was done as a stopgap because ais didn't know how to idle. If not I'll rip er out and we'll keep the other refactoring/optimizations. Cleaner basic ai code, maybe? faster basic ai code, for sure faster proximity monitors (significantly) * ai controllers use cell trackers to know when to idle (#82691) this makes ai controllers use cell trackers and signals to determine when to idle might be better than looping over all clients for every controller 🆑 code: The way mobs idle has been refactored, please report any issues with non-reactive mobs /🆑 * makes slimes not idle (#82742) slimes should still be able to do their everyday routine without needing to be watched over makes xenobiologist's lives easier 🆑 qol: slimes will stay active without needing any one to watch over /🆑 --------- <!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request <!-- Describe The Pull Request. Please be sure every change is documented or this can delay review and even discourage maintainers from merging your PR! --> <!-- Please make sure to actually test your PRs. If you have not tested your PR mention it. --> ## Why It's Good For The Game <!-- Argue for the merits of your changes and how they benefit the game, especially if they are controversial and/or far reaching. If you can't actually explain WHY what you are doing will improve the game, then it probably isn't good for the game in the first place. --> ## Proof Of Testing <!-- Compile and run your code locally. Make sure it works. This is the place to show off your changes! We are not responsible for testing your features. --> ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 add: Added new mechanics or gameplay changes add: Added more things del: Removed old things qol: made something easier to use balance: rebalanced something fix: fixed a few things sound: added/modified/removed audio or sound effects image: added/modified/removed some icons or images spellcheck: fixed a few typos code: changed some code refactor: refactored some code config: changed some config setting admin: messed with admin stuff server: something server ops should know /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. --> <!-- By opening a pull request. You have read and understood the repository rules located on the main README.md on this project. --> --------- Co-authored-by: Waterpig <49160555+Majkl-J@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Iamgoofball <iamgoofball@gmail.com> Co-authored-by: Waterpig <wtryoutube@seznam.cz>
220 lines
8.0 KiB
Plaintext
220 lines
8.0 KiB
Plaintext
#define FIELD_TURFS_KEY "field_turfs"
|
|
#define EDGE_TURFS_KEY "edge_turfs"
|
|
|
|
/**
|
|
* Movable and easily code-modified fields! Allows for custom AOE effects that affect movement
|
|
* and anything inside of them, and can do custom turf effects!
|
|
* Supports automatic recalculation/reset on movement.
|
|
*
|
|
* "What do I gain from using advanced over standard prox monitors?"
|
|
* - You can set different effects on edge vs field entrance
|
|
* - You can set effects when the proximity monitor starts and stops tracking a turf
|
|
*/
|
|
/datum/proximity_monitor/advanced
|
|
/// If TRUE, edge turfs will be included as "in the field" for effects
|
|
/// Can be used in certain situations where you may have effects that trigger only at the edge,
|
|
/// while also wanting the field effect to trigger at edge turfs as well
|
|
var/edge_is_a_field = FALSE
|
|
/// All turfs on the inside of the proximity monitor - range - 1 turfs
|
|
var/list/turf/field_turfs = list()
|
|
/// All turfs on the very last tile of the proximity monitor's radius
|
|
var/list/turf/edge_turfs = list()
|
|
|
|
/datum/proximity_monitor/advanced/Destroy()
|
|
cleanup_field()
|
|
return ..()
|
|
|
|
/datum/proximity_monitor/advanced/proc/cleanup_field()
|
|
for(var/turf/turf as anything in edge_turfs)
|
|
cleanup_edge_turf(turf)
|
|
edge_turfs = list()
|
|
for(var/turf/turf as anything in field_turfs)
|
|
cleanup_field_turf(turf)
|
|
field_turfs = list()
|
|
|
|
//Call every time the field moves (done automatically if you use update_center) or a setup specification is changed.
|
|
/datum/proximity_monitor/advanced/proc/recalculate_field(full_recalc = FALSE)
|
|
var/list/new_turfs = update_new_turfs()
|
|
|
|
var/list/old_field_turfs = field_turfs
|
|
var/list/old_edge_turfs = edge_turfs
|
|
field_turfs = new_turfs[FIELD_TURFS_KEY]
|
|
edge_turfs = new_turfs[EDGE_TURFS_KEY]
|
|
if(!full_recalc)
|
|
field_turfs = list()
|
|
edge_turfs = list()
|
|
|
|
for(var/turf/old_turf as anything in old_field_turfs - field_turfs)
|
|
if(QDELETED(src))
|
|
return
|
|
cleanup_field_turf(old_turf)
|
|
for(var/turf/old_turf as anything in old_edge_turfs - edge_turfs)
|
|
if(QDELETED(src))
|
|
return
|
|
cleanup_edge_turf(old_turf)
|
|
|
|
if(full_recalc)
|
|
old_field_turfs = list()
|
|
old_edge_turfs = list()
|
|
field_turfs = new_turfs[FIELD_TURFS_KEY]
|
|
edge_turfs = new_turfs[EDGE_TURFS_KEY]
|
|
|
|
for(var/turf/new_turf as anything in field_turfs - old_field_turfs)
|
|
if(QDELETED(src))
|
|
return
|
|
field_turfs += new_turf
|
|
setup_field_turf(new_turf)
|
|
for(var/turf/new_turf as anything in edge_turfs - old_edge_turfs)
|
|
if(QDELETED(src))
|
|
return
|
|
edge_turfs += new_turf
|
|
setup_edge_turf(new_turf)
|
|
|
|
/datum/proximity_monitor/advanced/on_initialized(turf/location, atom/created, init_flags)
|
|
. = ..()
|
|
on_entered(location, created, null)
|
|
|
|
/datum/proximity_monitor/advanced/on_entered(turf/source, atom/movable/entered, turf/old_loc)
|
|
. = ..()
|
|
if(get_dist(source, host) == current_range)
|
|
field_edge_crossed(entered, old_loc, source)
|
|
else
|
|
field_turf_crossed(entered, old_loc, source)
|
|
|
|
/datum/proximity_monitor/advanced/on_moved(atom/movable/movable, atom/old_loc)
|
|
. = ..()
|
|
if(ignore_if_not_on_turf)
|
|
//Early return if it's not the host that has moved.
|
|
if(movable != host)
|
|
return
|
|
//Cleanup the field if the host was on a turf but isn't anymore.
|
|
if(!isturf(host.loc))
|
|
if(isturf(old_loc))
|
|
cleanup_field()
|
|
return
|
|
recalculate_field(full_recalc = FALSE)
|
|
|
|
/datum/proximity_monitor/advanced/on_uncrossed(turf/source, atom/movable/gone, direction)
|
|
if(get_dist(source, host) == current_range)
|
|
field_edge_uncrossed(gone, source, get_turf(gone))
|
|
else
|
|
field_turf_uncrossed(gone, source, get_turf(gone))
|
|
|
|
/// Called when a turf in the field of the monitor is linked
|
|
/datum/proximity_monitor/advanced/proc/setup_field_turf(turf/target)
|
|
return
|
|
|
|
/// Called when a turf in the field of the monitor is unlinked
|
|
/// Do NOT call this manually, requires management of the field_turfs list
|
|
/datum/proximity_monitor/advanced/proc/cleanup_field_turf(turf/target)
|
|
return
|
|
|
|
/// Called when a turf in the edge of the monitor is linked
|
|
/datum/proximity_monitor/advanced/proc/setup_edge_turf(turf/target)
|
|
if(edge_is_a_field) // If the edge is considered a field, set it up like one
|
|
setup_field_turf(target)
|
|
|
|
/// Called when a turf in the edge of the monitor is unlinked
|
|
/// Do NOT call this manually, requires management of the edge_turfs list
|
|
/datum/proximity_monitor/advanced/proc/cleanup_edge_turf(turf/target)
|
|
if(edge_is_a_field) // If the edge is considered a field, clean it up like one
|
|
cleanup_field_turf(target)
|
|
|
|
/datum/proximity_monitor/advanced/proc/update_new_turfs()
|
|
if(ignore_if_not_on_turf && !isturf(host.loc))
|
|
return list(FIELD_TURFS_KEY = list(), EDGE_TURFS_KEY = list())
|
|
var/list/local_field_turfs = list()
|
|
var/list/local_edge_turfs = list()
|
|
var/turf/center = get_turf(host)
|
|
if(current_range > 0)
|
|
local_field_turfs += RANGE_TURFS(current_range - 1, center)
|
|
if(current_range > 1)
|
|
local_edge_turfs = local_field_turfs - RANGE_TURFS(current_range, center)
|
|
return list(FIELD_TURFS_KEY = local_field_turfs, EDGE_TURFS_KEY = local_edge_turfs)
|
|
|
|
//Gets edge direction/corner, only works with square radius/WDH fields!
|
|
/datum/proximity_monitor/advanced/proc/get_edgeturf_direction(turf/T, turf/center_override = null)
|
|
var/turf/checking_from = get_turf(host)
|
|
if(istype(center_override))
|
|
checking_from = center_override
|
|
if(!(T in edge_turfs))
|
|
return
|
|
if(((T.x == (checking_from.x + current_range)) || (T.x == (checking_from.x - current_range))) && ((T.y == (checking_from.y + current_range)) || (T.y == (checking_from.y - current_range))))
|
|
return get_dir(checking_from, T)
|
|
if(T.x == (checking_from.x + current_range))
|
|
return EAST
|
|
if(T.x == (checking_from.x - current_range))
|
|
return WEST
|
|
if(T.y == (checking_from.y - current_range))
|
|
return SOUTH
|
|
if(T.y == (checking_from.y + current_range))
|
|
return NORTH
|
|
|
|
/datum/proximity_monitor/advanced/proc/field_turf_crossed(atom/movable/movable, turf/old_location, turf/new_location)
|
|
return
|
|
|
|
/datum/proximity_monitor/advanced/proc/field_turf_uncrossed(atom/movable/movable, turf/old_location, turf/new_location)
|
|
return
|
|
|
|
/datum/proximity_monitor/advanced/proc/field_edge_crossed(atom/movable/movable, turf/old_location, turf/new_location)
|
|
if(edge_is_a_field) // If the edge is considered a field, pass crossed to that
|
|
field_turf_crossed(movable, old_location, new_location)
|
|
|
|
/datum/proximity_monitor/advanced/proc/field_edge_uncrossed(atom/movable/movable, turf/old_location, turf/new_location)
|
|
if(edge_is_a_field) // If the edge is considered a field, pass uncrossed to that
|
|
field_turf_uncrossed(movable, old_location, new_location)
|
|
|
|
//DEBUG FIELD ITEM
|
|
/obj/item/multitool/field_debug
|
|
name = "strange multitool"
|
|
desc = "Seems to project a colored field!"
|
|
var/operating = FALSE
|
|
var/datum/proximity_monitor/advanced/debug/current = null
|
|
|
|
/obj/item/multitool/field_debug/Destroy()
|
|
QDEL_NULL(current)
|
|
return ..()
|
|
|
|
/obj/item/multitool/field_debug/proc/setup_debug_field()
|
|
current = new(src, 5, FALSE)
|
|
current.set_fieldturf_color = "#aaffff"
|
|
current.set_edgeturf_color = "#ffaaff"
|
|
current.recalculate_field(full_recalc = TRUE)
|
|
|
|
/obj/item/multitool/field_debug/attack_self(mob/user)
|
|
operating = !operating
|
|
to_chat(user, span_notice("You turn [src] [operating? "on":"off"]."))
|
|
if(!istype(current) && operating)
|
|
setup_debug_field()
|
|
else if(!operating)
|
|
QDEL_NULL(current)
|
|
|
|
/obj/item/multitool/field_debug/attack_self_secondary(mob/user, modifiers)
|
|
current.edge_is_a_field = !current.edge_is_a_field
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
//DEBUG FIELDS
|
|
/datum/proximity_monitor/advanced/debug
|
|
current_range = 5
|
|
var/set_fieldturf_color = "#aaffff"
|
|
var/set_edgeturf_color = "#ffaaff"
|
|
|
|
/datum/proximity_monitor/advanced/debug/setup_edge_turf(turf/target)
|
|
. = ..()
|
|
target.color = set_edgeturf_color
|
|
|
|
/datum/proximity_monitor/advanced/debug/cleanup_edge_turf(turf/target)
|
|
. = ..()
|
|
target.color = initial(target.color)
|
|
|
|
/datum/proximity_monitor/advanced/debug/setup_field_turf(turf/target)
|
|
. = ..()
|
|
target.color = set_fieldturf_color
|
|
|
|
/datum/proximity_monitor/advanced/debug/cleanup_field_turf(turf/target)
|
|
. = ..()
|
|
target.color = initial(target.color)
|
|
|
|
#undef FIELD_TURFS_KEY
|
|
#undef EDGE_TURFS_KEY
|