Reduce carp migration devastation (#74608)

## About The Pull Request

I'm not totally satisfied with the amount of random destruction caused
by space carp wandering around, they should certainly be dangerous and
annoying but the random nature of their spawning and pathfinding means
that they would trap themselves in random rooms and then smash all of
the machinery in there.
Because they could attack any dense object they perceived as being in
their way that could result in venting random gas canisters, breaking
terminals, or I even once saw them destroy the supermatter cooling loop
by eating the thermomachines.
While the latter is pretty funny, arbitrary destruction of machines
simply caused because a fish teleported into a room without you knowing
isn't really very engaging and doesn't create very interesting stories.
This ultimately isn't meant to be a heavily destructive event and its
probability to run isn't tuned as if it is.

So, a couple of changes:

I reduced both the range and cooldown of the carp teleporting ability.
This means that AI carp can use it to pathfind past obstacles pretty
reliably and don't spend so much time smashing things, and also reduces
the chances of them getting the drop on you from a location you can't
see.
I also added a short click cooldown to carp travelling through other
carp rifts so people being teleported _to_ have more of an advantage
over people ambushing them (this was already true for the carp creating
the rift).

Additionally I added an optional whitelist to the "attack obstacles to
your pathfinding" AI script, and heavily culled the kind of obstacles
that carp will attack to be ones which are mostly replaceable. They will
still cause a mess and might even vent a room, but they won't smash
vital infrastructure.

Finally I replaced a couple of instances of `get_ranged_target_turf`
with `get_ranged_target_turf_direct` for better precision, and player
carp using the ability can now just click anywhere on the screen and it
will jaunt in that rough direction. With the reduced range, having to
click within its radius was pretty annoying.

With these changes I ran the event 10 times in a row on kilo and then
watched JoJo's bizzarre adventure for 90 minutes and when I came back
the level of destruction seemed pretty reasonable (aside from the big
hole where one of them ran into the supermatter and delaminated it, but
if there were players around that wouldn't happen).

## Why It's Good For The Game

This event was still just a little bit _too_ annoying.
If something destroys important machines it should have happened on
purpose via an event which was supposed to do that, rather than through
chance. Or preferably just be player-driven.

## Changelog

🆑
balance: Carp can't teleport as far, but can do it more frequently.
People who piggyback through their rifts will be blocked from attacking
for a short duration (the same as the normal attack cooldown).
balance: AI controlled carp will now be more selective about which
objects they smash. Player controlled carp (or carp directly instructed
to attack objects by people who have tamed them) can still attack
whatever they like.
/🆑
This commit is contained in:
Jacquerel
2023-04-09 16:50:14 -06:00
committed by GitHub
parent 2225629319
commit 17e8000c8e
6 changed files with 38 additions and 14 deletions
@@ -63,6 +63,21 @@
var/static/list/desired_food = list(/obj/item/food/meat/slab, /obj/item/food/meat/rawcutlet)
/// Carp want to eat delicious six pack plastic rings
var/static/list/desired_trash = list(/obj/item/storage/cans)
/// Structures that AI carp are willing to attack. This prevents them from deconstructing supermatter cooling equipment.
var/static/list/allowed_obstacle_targets = typecacheof(list(
/obj/structure/closet,
/obj/machinery/door,
/obj/structure/door_assembly,
/obj/structure/filingcabinet,
/obj/structure/frame,
/obj/structure/grille,
/obj/structure/plasticflaps,
/obj/structure/rack,
/obj/structure/reagent_dispensers, // Carp can have a little welding fuel, as a treat
/obj/structure/table,
/obj/machinery/vending,
/obj/structure/window,
))
/// Weighted list of colours a carp can be
/// Weighted list of usual carp colors
var/static/list/carp_colors = list(
@@ -104,6 +119,7 @@
teleport = new(src)
teleport.Grant(src)
ai_controller.blackboard[BB_CARP_RIFT] = WEAKREF(teleport)
ai_controller.blackboard[BB_OBSTACLE_TARGETTING_WHITELIST] = allowed_obstacle_targets
/mob/living/basic/carp/Destroy()
QDEL_NULL(teleport)
@@ -37,12 +37,14 @@
button_icon = 'icons/effects/effects.dmi'
button_icon_state = "rift"
desc = "Open a rift through the carp stream, allowing passage to somewhere close by."
cooldown_time = 1 MINUTES
melee_cooldown_time = 2 SECONDS
cooldown_time = 15 SECONDS
melee_cooldown_time = 0 SECONDS // Handled by rift
/// How far away can you place a rift?
var/max_range = 6
var/max_range = 3
/datum/action/cooldown/mob_cooldown/lesser_carp_rift/Activate(atom/target_atom)
if (get_dist(get_turf(owner), target_atom) > max_range)
target_atom = get_ranged_target_turf_direct(owner, target_atom, range = max_range)
if (!make_rift(target_atom))
return FALSE
StartCooldown()
@@ -58,10 +60,6 @@
if (!target_turf)
return FALSE
if (get_dist(owner_turf, target_turf) > max_range)
owner.balloon_alert(owner, "too far!")
return FALSE
if (!target_turf)
return FALSE
@@ -107,6 +105,8 @@
/obj/effect/temp_visual/lesser_carp_rift/entrance
/// Where you get teleported to
var/list/exit_locs
/// Click CD to apply after teleporting
var/disorient_time = CLICK_CD_MELEE
/obj/effect/temp_visual/lesser_carp_rift/entrance/Initialize(mapload)
. = ..()
@@ -129,6 +129,10 @@
if (isobserver(entered_atom))
return
if (isliving(entered_atom))
var/mob/living/teleported_mob = entered_atom
teleported_mob.changeNext_move(disorient_time)
var/turf/destination = pick(exit_locs)
do_teleport(entered_atom, destination, channel = TELEPORT_CHANNEL_MAGIC)
playsound(src, 'sound/magic/wand_teleport.ogg', 50)
@@ -99,8 +99,7 @@
/datum/ai_behavior/make_carp_rift/away
/datum/ai_behavior/make_carp_rift/away/find_target_turf(datum/ai_controller/controller, atom/target, datum/action/cooldown/mob_cooldown/lesser_carp_rift/ability)
var/run_direction = get_dir(controller.pawn, get_step_away(controller.pawn, target))
return get_ranged_target_turf(controller.pawn, run_direction, ability.max_range)
return get_ranged_target_turf_direct(controller.pawn, target, range = ability.max_range, offset = 180)
/**
* # Make carp rift forwards
@@ -161,7 +160,7 @@
* Make a rift towards your target if you are blocked from moving or if it is far away
*/
/datum/ai_behavior/make_carp_rift/towards/aggressive
teleport_buffer_distance = 2 // Don't aggressively drop carps directly on top of a target mob
teleport_buffer_distance = 1 // Don't aggressively drop carps directly on top of a target mob
/**
* # Make carp rift forwards (unvalidated)
@@ -183,9 +182,9 @@
*/
/datum/ai_planning_subtree/shortcut_to_target_through_carp_rift
/// How far away do we look for rifts?
var/search_distance = 2
var/search_distance = 3
/// Minimum distance we should be from the target before we bother performing this action
var/minimum_distance = 3
var/minimum_distance = 2
/datum/ai_planning_subtree/shortcut_to_target_through_carp_rift/SelectBehaviors(datum/ai_controller/controller, delta_time)
var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]