Files
Bubberstation/code/modules/unit_tests/leash.dm
SkyratBot cab87c97e5 [MIRROR] Add leash component to pAIs that keeps them within range instead of directly teleporting them back, increases default range to max range [MDB IGNORE] (#22745)
* Add leash component to pAIs that keeps them within range instead of directly teleporting them back, increases default range to max range (#77030)

## About The Pull Request

Tries to keep pAIs in range of their owner by moving them closer when
the owner moves, rather than jarringly teleporting every time the owner
gets out of range. Does this by calculating the closest path a nearby
tile and forcefully moving you there. Still a bit janky at times but is
better than teleporting directly onto the owner 100% of the time I feel.
Also prevents you from moving out of range, rather than forcefully
teleporting you back.

Increases the default pAI range to the maximum (9 tiles)

## Why It's Good For The Game

New leashing makes being a leashed pAI significantly less jarring and
obvious. Ideally we would also have a visible max range too.

Default pAI range was pretty small in my testing and I think it's not
unreasonable to think a lot of people won't bother changing it. That
they are leashed at all is the important part.

## Changelog

🆑
qol: pAIs now try to stay within range of their owner, and teleport back
only when necessary
qol: Default max pAI range has been changed to the maximum range you can
choose (9 tiles)
/🆑

---------

Co-authored-by: Jacquerel <hnevard@ gmail.com>

* Add leash component to pAIs that keeps them within range instead of directly teleporting them back, increases default range to max range

* Fixes the leash enable/disable

* A workaround because the procs are private.

* Update card.dm

* Update card.dm

what I get for rushing

* Update card.dm

---------

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Co-authored-by: Jacquerel <hnevard@ gmail.com>
Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
2023-07-30 16:24:44 -04:00

103 lines
3.0 KiB
Plaintext

/datum/unit_test/leash
abstract_type = /datum/unit_test/leash
var/atom/movable/owner
var/atom/movable/pet
var/max_distance = 3
var/forcibly_teleported = FALSE
var/datum/leash_wait/leash_wait
/datum/unit_test/leash/New()
. = ..()
owner = allocate(/obj/item/pen)
pet = allocate(/obj/item/pen)
pet.AddComponent(/datum/component/leash, owner, max_distance)
RegisterSignal(pet, COMSIG_LEASH_FORCE_TELEPORT, PROC_REF(on_leash_force_teleport))
RegisterSignal(pet, COMSIG_LEASH_PATH_STARTED, PROC_REF(on_leash_path_started))
RegisterSignal(pet, COMSIG_LEASH_PATH_COMPLETE, PROC_REF(on_leash_path_complete))
/datum/unit_test/leash/Destroy()
QDEL_NULL(owner)
QDEL_NULL(pet)
return ..()
/datum/unit_test/leash/proc/on_leash_force_teleport()
SIGNAL_HANDLER
forcibly_teleported = TRUE
/datum/unit_test/leash/proc/on_leash_path_complete()
SIGNAL_HANDLER
leash_wait?.completed()
/datum/unit_test/leash/proc/on_leash_path_started()
SIGNAL_HANDLER
leash_wait?.started()
/datum/unit_test/leash/proc/move_away(atom/movable/mover, distance)
RETURN_TYPE(/datum/leash_wait)
leash_wait = new
for (var/_ in 1 to distance)
mover.Move(get_step(mover, EAST))
return leash_wait
/datum/leash_wait
var/completed = FALSE
var/started = FALSE
var/timed_out = FALSE
/datum/leash_wait/New()
addtimer(VARSET_CALLBACK(src, timed_out, TRUE), 1 SECONDS)
/datum/leash_wait/proc/completed()
completed = TRUE
/datum/leash_wait/proc/started()
started = TRUE
/datum/leash_wait/proc/assert_unmoved()
ASSERT(!started, "Leash started to move when it should not have")
/datum/leash_wait/proc/wait()
ASSERT(started, "Leash doesn't plan on moving")
UNTIL(completed || timed_out)
ASSERT(!timed_out, "Waiting for leash movement timed out, it didn't want to move")
/// Validates the leash component will keep its parent within range without teleporting
/// when possible.
/datum/unit_test/leash/no_teleport
/datum/unit_test/leash/no_teleport/Run()
move_away(owner, 1).assert_unmoved()
TEST_ASSERT_EQUAL(get_dist(owner, pet), 1, "Pet should not have moved")
move_away(owner, max_distance).wait() // max_distance + 1 = we move closer, but don't teleport
TEST_ASSERT_EQUAL(get_dist(owner, pet), max_distance, "Pet should have stayed directly outside range of owner")
TEST_ASSERT(!forcibly_teleported, "Pet should not have been forcibly teleported")
/// Validates that the leash component will forcibly teleport when necessary
/datum/unit_test/leash/will_teleport
/datum/unit_test/leash/will_teleport/Run()
leash_wait = new
owner.forceMove(locate(1, 1, 1))
leash_wait.wait()
TEST_ASSERT(forcibly_teleported, "Pet should have been forcibly teleported, since they are too far away with no valid path")
/// Validates that the leashed object cannot move outside of the max distance from owner
/datum/unit_test/leash/limit_range
/datum/unit_test/leash/limit_range/Run()
move_away(pet, max_distance + 1)
TEST_ASSERT_EQUAL(get_dist(owner, pet), max_distance, "Pet should not have moved farther than max_distance")