Files
Bubberstation/code/datums/components/nuclear_bomb_operator.dm
Bloop 4c870f71ca Fixes a bunch of callbacks that were being qdeleted, and code cleanup (#77904)
## About The Pull Request


![image](https://github.com/tgstation/tgstation/assets/13398309/559eb50a-461c-4220-b628-55412baaffc3)

Continuing the work of
https://github.com/tgstation/tgstation/pull/77850.

it started with finding one that was being missed and causing a
runtime...then I noticed a whole lot more. While I was doing this I
found callbacks that weren't being nulled in `Destroy()`, so I added
that wherever I found these spots as well as some general code cleanup.

There were a lot more of these than I initially hoped to encounter so
I'm labeling it as a refactor.

## Why It's Good For The Game

Fixes lots of runtimes, improves code resiliency.

## Changelog

🆑
refactor: fixed a bunch of instances of callbacks being qdeleted and
cleaned up related code
/🆑
2023-08-25 16:03:27 -06:00

144 lines
5.6 KiB
Plaintext

/**
* # Nuclear Bomb Operator
*
* Component applied to handless non-carbon mobs to allow them to perform the function of a nuclear operative.
* Effectively this means they need to be able to:
* * Strip people
* * Pick up the nuke disc, without having hands
* * Place the nuke disc into the nuke
* * Activate the nuke
*
* Human mobs do not need this component because they can already do all of those things.
*/
/datum/component/nuclear_bomb_operator
/// A weak reference to a held nuclear disk, in place of holding it in our inventory, because we don't have one
var/datum/weakref/disky
/// Something to call when we collect the disk
var/datum/callback/on_disk_collected
/// Should return some overlays to display on the mob to show they're carrying a disk
var/datum/callback/add_disk_overlays
/datum/component/nuclear_bomb_operator/Initialize(datum/callback/on_disk_collected, datum/callback/add_disk_overlays)
if (!ismob(parent))
return COMPONENT_INCOMPATIBLE
if (iscarbon(parent)) // Redundant
return COMPONENT_INCOMPATIBLE
src.on_disk_collected = on_disk_collected
src.add_disk_overlays = add_disk_overlays
/datum/component/nuclear_bomb_operator/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignals(parent, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_death))
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(owner_attacked_atom)) // This only works for players, but I am not sure this should have AI anyway
RegisterSignal(parent, COMSIG_ATOM_EXITED, PROC_REF(atom_exited_owner))
RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays))
parent.add_traits(list(TRAIT_DISK_VERIFIER, TRAIT_CAN_STRIP, TRAIT_CAN_USE_NUKE), NUKE_OP_MINION_TRAIT)
/datum/component/nuclear_bomb_operator/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(
COMSIG_ATOM_EXAMINE,
COMSIG_LIVING_DEATH,
COMSIG_QDELETING,
COMSIG_ATOM_ATTACK_HAND,
COMSIG_ATOM_EXITED,
COMSIG_ATOM_UPDATE_OVERLAYS,
))
parent.remove_traits(list(TRAIT_DISK_VERIFIER, TRAIT_CAN_STRIP, TRAIT_CAN_USE_NUKE), NUKE_OP_MINION_TRAIT)
/datum/component/nuclear_bomb_operator/Destroy(force, silent)
QDEL_NULL(disky)
on_disk_collected = null
add_disk_overlays = null
return ..()
/// Drop the disk on the floor, if we have it
/datum/component/nuclear_bomb_operator/proc/drop_disky()
var/obj/item/disk/nuclear/held_disk = disky?.resolve()
if (!held_disk)
return
var/mob/mob_parent = parent
held_disk.forceMove(mob_parent.drop_location())
mob_parent.visible_message(span_danger("[mob_parent] drops [held_disk] onto the ground!"))
disky = null
mob_parent.update_appearance(updates = UPDATE_ICON)
/// Add details about carrying the nuke disc to examination.
/datum/component/nuclear_bomb_operator/proc/on_examine(atom/parent_atom, mob/examiner, list/examine_list)
SIGNAL_HANDLER
var/obj/item/disk/nuclear/held_disk = disky?.resolve()
if (!held_disk)
return
var/mob/mob_parent = parent
examine_list += span_notice("Wait... [mob_parent.p_are()] [mob_parent.p_they()] holding [held_disk]?")
/// Drop the disk when we are killed
/datum/component/nuclear_bomb_operator/proc/on_death(atom/parent_atom)
SIGNAL_HANDLER
drop_disky()
/// Try to pick up the disk, put it down, or open the nuke panel
/datum/component/nuclear_bomb_operator/proc/owner_attacked_atom(atom/parent_atom, atom/attacked_target, proximity, modifiers)
SIGNAL_HANDLER
if (!proximity)
return
if (!LAZYACCESS(modifiers, LEFT_CLICK))
return
var/obj/item/disk/nuclear/held_disk = disky?.resolve()
if (held_disk)
return try_put_down_disk(held_disk, attacked_target)
if (istype(attacked_target, /obj/item/disk/nuclear))
return try_pick_up_disk(attacked_target)
if (istype(attacked_target, /obj/machinery/nuclearbomb))
attacked_target.ui_interact(parent)
return COMPONENT_CANCEL_ATTACK_CHAIN
/// Picks up the nuke disk, if it can be picked up
/datum/component/nuclear_bomb_operator/proc/try_pick_up_disk(obj/item/disk/nuclear/potential_disky)
if(potential_disky.anchored)
return
var/mob/mob_parent = parent
potential_disky.forceMove(mob_parent)
disky = WEAKREF(potential_disky)
mob_parent.update_appearance(updates = UPDATE_ICON)
mob_parent.balloon_alert(mob_parent, "disk secured!")
on_disk_collected?.InvokeAsync(potential_disky)
/// Uses the disk on clicked atom, or places it on the ground
/datum/component/nuclear_bomb_operator/proc/try_put_down_disk(obj/item/disk/nuclear/held_disk, atom/attacked_target)
var/mob/mob_parent = parent
if(!isopenturf(attacked_target))
INVOKE_ASYNC(held_disk, TYPE_PROC_REF(/obj/item, melee_attack_chain), mob_parent, attacked_target)
mob_parent.do_item_attack_animation(attacked_target, used_item = held_disk)
return COMPONENT_CANCEL_ATTACK_CHAIN
held_disk.forceMove(attacked_target)
disky = null
mob_parent.balloon_alert(mob_parent, "disk dropped!")
mob_parent.update_appearance(updates = UPDATE_ICON)
return COMPONENT_CANCEL_ATTACK_CHAIN
/// Don't hold onto the reference if we lose the disk somehow
/datum/component/nuclear_bomb_operator/proc/atom_exited_owner(atom/parent_atom, atom/movable/gone)
SIGNAL_HANDLER
var/obj/item/disk/nuclear/held_disk = disky?.resolve()
if (held_disk != gone)
return
disky = null
var/mob/mob_parent = parent
mob_parent.update_appearance(updates = UPDATE_ICON)
/// Display any disk-related overlays which need displaying
/datum/component/nuclear_bomb_operator/proc/on_update_overlays(atom/parent_atom, list/overlays)
SIGNAL_HANDLER
if (!disky?.resolve())
return
var/mob/mob_parent = parent
if (!istype(mob_parent) || mob_parent.stat == DEAD)
return
add_disk_overlays?.InvokeAsync(overlays)