Files
Bubberstation/code/datums/components/pet_commands/fetch.dm
Bloop fd82421286 Fixes throwing hard del (#80551)
## About The Pull Request

Fixes https://github.com/tgstation/tgstation/issues/80472

## Why It's Good For The Game

Less CI failures

## Changelog

🆑
fix: fixes a hard del with thrown items
/🆑
2023-12-25 13:00:50 +01:00

118 lines
4.8 KiB
Plaintext

/**
* # Pet Command: Fetch
* Watch for someone throwing or pointing at something and then go get it and bring it back.
* If it's food we might eat it instead.
*/
/datum/pet_command/point_targeting/fetch
command_name = "Fetch"
command_desc = "Command your pet to retrieve something you throw or point at."
radial_icon = 'icons/mob/actions/actions_spells.dmi'
radial_icon_state = "summons"
speech_commands = list("fetch")
command_feedback = "bounces"
pointed_reaction = "with great interest"
/// If true, this command will trigger if the pet sees a friend throw any item, if they're not doing anything else
var/trigger_on_throw = TRUE
/// If true, this is a poorly trained pet who will eat food you throw instead of bringing it back
var/will_eat_targets = TRUE
/datum/pet_command/point_targeting/fetch/New(mob/living/parent)
. = ..()
if(isnull(parent))
return
parent.AddElement(/datum/element/ai_held_item) // We don't remove this on destroy because they might still be holding something
/datum/pet_command/point_targeting/fetch/add_new_friend(mob/living/tamer)
. = ..()
RegisterSignal(tamer, COMSIG_MOB_THROW, PROC_REF(listened_throw))
/datum/pet_command/point_targeting/fetch/remove_friend(mob/living/unfriended)
. = ..()
UnregisterSignal(unfriended, COMSIG_MOB_THROW)
/// A friend has thrown something, if we're listening or at least not busy then go get it
/datum/pet_command/point_targeting/fetch/proc/listened_throw(mob/living/carbon/thrower)
SIGNAL_HANDLER
var/mob/living/parent = weak_parent.resolve()
if (!parent)
return
var/list/blackboard = parent.ai_controller.blackboard
if (!trigger_on_throw && !blackboard[BB_ACTIVE_PET_COMMAND])
return // We don't have a command and we only listen to commands
if (blackboard[BB_ACTIVE_PET_COMMAND] && blackboard[BB_ACTIVE_PET_COMMAND] != src)
return // We have a command and it's not this one
if (blackboard[BB_CURRENT_PET_TARGET] || blackboard[BB_FETCH_DELIVER_TO])
return // We're already very fetching
if (!can_see(parent, thrower, length = sense_radius))
return // Can't see it
var/obj/item/thrown_thing = thrower.get_active_held_item()
if (!isitem(thrown_thing))
return
if (blackboard[BB_FETCH_IGNORE_LIST]?[thrown_thing])
return // We're ignoring it already
RegisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED, PROC_REF(listen_throw_land))
/// A throw we were listening to has finished, see if it's in range for us to try grabbing it
/datum/pet_command/point_targeting/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwingdatum)
SIGNAL_HANDLER
UnregisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED)
var/mob/living/parent = weak_parent.resolve()
if (!parent)
return
if (!isturf(thrown_thing.loc))
return
if (!can_see(parent, thrown_thing, length = sense_radius))
return
var/mob/thrower = throwingdatum?.get_thrower()
if(thrower)
try_activate_command(thrower)
set_command_target(parent, thrown_thing)
parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, thrower)
// Don't try and fetch turfs or anchored objects if someone points at them
/datum/pet_command/point_targeting/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom)
if (!istype(pointed_atom))
return FALSE
if (pointed_atom.anchored)
return FALSE
. = ..()
if (!.)
return FALSE
var/mob/living/parent = weak_parent.resolve()
parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, pointing_friend)
// Finally, plan our actions
/datum/pet_command/point_targeting/fetch/execute_action(datum/ai_controller/controller)
controller.queue_behavior(/datum/ai_behavior/forget_failed_fetches)
var/atom/target = controller.blackboard[BB_CURRENT_PET_TARGET]
// We got something to fetch so go fetch it
if (!QDELETED(target))
if (get_dist(controller.pawn, target) > 1) // We're not there yet
controller.queue_behavior(/datum/ai_behavior/fetch_seek, BB_CURRENT_PET_TARGET, BB_FETCH_DELIVER_TO)
return SUBTREE_RETURN_FINISH_PLANNING
// If mobs could attack food you would branch here to call `eat_fetched_snack`, however that's a task for the future
controller.queue_behavior(/datum/ai_behavior/pick_up_item, BB_CURRENT_PET_TARGET, BB_SIMPLE_CARRY_ITEM)
return SUBTREE_RETURN_FINISH_PLANNING
var/obj/item/carried_item = controller.blackboard[BB_SIMPLE_CARRY_ITEM]
if (QDELETED(carried_item))
return
var/atom/delivery_target = controller.blackboard[BB_FETCH_DELIVER_TO]
if (QDELETED(delivery_target) || !can_see(controller.pawn, delivery_target, sense_radius))
// We don't know where to return this to so we're just going to keep it
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
return
// We got something to deliver and someone to deliver it to
controller.queue_behavior(/datum/ai_behavior/deliver_fetched_item, BB_FETCH_DELIVER_TO, BB_SIMPLE_CARRY_ITEM)
return SUBTREE_RETURN_FINISH_PLANNING