Files
Bubberstation/code/modules/wiremod/shell/dispenser.dm
Ghom 339616ae78 You can now interact with held mobs beside wearing them (feat: "minor" melee attack chain cleanup) (#90080)
## About The Pull Request
People can now pet held mothroaches and pugs if they want to, or use
items on them, hopefully without causing many issues. After all, it only
took about a couple dozen lines of code to make...

...Oh, did the 527 files changed or the 850~ lines added/removed perhaps
catch your eye? Made you wonder if I accidentally pushed the wrong
branch? or skewed something up big time? Well, nuh uh. I just happen to
be fed up with the melee attack chain still using stringized params
instead of an array/list. It was frankly revolting to see how I'd have
had to otherwise call `list2params` for what I'm trying to accomplish
here, and make this PR another tessera to the immense stupidity of our
attack chain procs calling `params2list` over and over and over instead
of just using that one call instance from `ClickOn` as an argument. It's
2025, honey, wake up!

I also tried to replace some of those single letter vars/args but there
are just way too many of them.

## Why It's Good For The Game
Improving old code. And I want to be able to pet mobroaches while
holding them too.

## Changelog

🆑
qol: You can now interact with held mobs in more ways beside wearing
them.
/🆑
2025-04-23 20:18:26 +00:00

210 lines
6.6 KiB
Plaintext

/**
* # Dispenser
*
* Immobile (but not dense) shell that can receive and dispense items.
*/
/obj/structure/dispenser_bot
name = "dispenser"
icon = 'icons/obj/science/circuits.dmi'
icon_state = "setup_drone_arms"
density = FALSE
light_system = OVERLAY_LIGHT
light_on = FALSE
var/max_weight = WEIGHT_CLASS_NORMAL
var/capacity = 20
var/list/obj/item/stored_items = list()
var/locked = FALSE
/obj/structure/dispenser_bot/atom_deconstruct(disassembled = TRUE)
for(var/obj/item/stored_item as anything in stored_items)
remove_item(stored_item)
/obj/structure/dispenser_bot/Destroy()
QDEL_LIST(stored_items)
return ..()
/obj/structure/dispenser_bot/proc/add_item(mob/user, obj/item/to_add)
balloon_alert(user, "inserted item")
stored_items += to_add
to_add.forceMove(src)
RegisterSignal(to_add, COMSIG_MOVABLE_MOVED, PROC_REF(handle_stored_item_moved))
RegisterSignal(to_add, COMSIG_QDELETING, PROC_REF(handle_stored_item_deleted))
SEND_SIGNAL(src, COMSIG_DISPENSERBOT_ADD_ITEM, to_add)
/obj/structure/dispenser_bot/proc/handle_stored_item_moved(obj/item/moving_item, atom/location)
SIGNAL_HANDLER
if(location != src)
remove_item(moving_item)
/obj/structure/dispenser_bot/proc/handle_stored_item_deleted(obj/item/deleting_item)
SIGNAL_HANDLER
remove_item(deleting_item)
/obj/structure/dispenser_bot/proc/remove_item(obj/item/to_remove)
UnregisterSignal(to_remove, list(
COMSIG_MOVABLE_MOVED,
COMSIG_QDELETING,
))
to_remove.forceMove(drop_location())
stored_items -= to_remove
SEND_SIGNAL(src, COMSIG_DISPENSERBOT_REMOVE_ITEM, to_remove)
/obj/structure/dispenser_bot/Initialize(mapload)
. = ..()
AddComponent(/datum/component/shell, list(
new /obj/item/circuit_component/dispenser_bot()
), SHELL_CAPACITY_LARGE)
/obj/structure/dispenser_bot/attackby(obj/item/item, mob/living/user, list/modifiers)
if(user.combat_mode)
return ..()
if(istype(item, /obj/item/wrench) || istype(item, /obj/item/multitool) || istype(item, /obj/item/integrated_circuit))
return ..()
if(item.w_class > max_weight && !istype(item, /obj/item/storage/bag))
balloon_alert(user, "item too big!")
return FALSE
if(length(stored_items) >= capacity)
balloon_alert(user, "at maximum capacity!")
return FALSE
if(istype(item, /obj/item/storage/bag))
for(var/obj/item/bag_item in item.contents)
if(length(stored_items) >= capacity)
break
if(bag_item.w_class > max_weight || istype(bag_item, /obj/item/storage/bag))
continue
add_item(user, bag_item)
return TRUE
add_item(user, item)
return TRUE
/obj/structure/dispenser_bot/wrench_act(mob/living/user, obj/item/tool)
if(locked)
return
set_anchored(!anchored)
tool.play_tool_sound(src)
balloon_alert(user, "[anchored? "secured" : "unsecured"]")
return TRUE
/obj/item/circuit_component/dispenser_bot
display_name = "Dispenser"
desc = "A dispenser bot that can dispense items "
/// The list of items
var/datum/port/output/item_list
/// The item that was added/removed.
var/datum/port/output/item
/// Called when an item is added.
var/datum/port/output/on_item_added
/// Called when an item is removed.
var/datum/port/output/on_item_removed
ui_buttons = list(
"plus" = "add_vend_component",
)
/// Vendor components attached to this dispenser bot
var/list/obj/item/circuit_component/vendor_component/vendor_components = list()
var/max_vendor_components = 20
/obj/item/circuit_component/dispenser_bot/populate_ports()
item_list = add_output_port("Items", PORT_TYPE_LIST(PORT_TYPE_ATOM))
item = add_output_port("Item", PORT_TYPE_ATOM)
on_item_added = add_output_port("On Item Added", PORT_TYPE_SIGNAL)
on_item_removed = add_output_port("On Item Removed", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/dispenser_bot/register_shell(atom/movable/shell)
. = ..()
RegisterSignal(shell, COMSIG_DISPENSERBOT_ADD_ITEM, PROC_REF(on_shell_add_item))
RegisterSignal(shell, COMSIG_DISPENSERBOT_REMOVE_ITEM, PROC_REF(on_shell_remove_item))
/obj/item/circuit_component/dispenser_bot/unregister_shell(atom/movable/shell)
UnregisterSignal(shell, list(
COMSIG_DISPENSERBOT_ADD_ITEM,
COMSIG_DISPENSERBOT_REMOVE_ITEM,
))
return ..()
/obj/item/circuit_component/dispenser_bot/proc/on_shell_add_item(obj/structure/dispenser_bot/source, obj/item/added_item)
SIGNAL_HANDLER
item.set_output(added_item)
item_list.set_output(source.stored_items)
on_item_added.set_output(COMPONENT_SIGNAL)
/obj/item/circuit_component/dispenser_bot/proc/on_shell_remove_item(obj/structure/dispenser_bot/source, obj/item/added_item)
SIGNAL_HANDLER
item.set_output(added_item)
item_list.set_output(source.stored_items)
on_item_added.set_output(COMPONENT_SIGNAL)
/obj/item/circuit_component/dispenser_bot/proc/remove_vendor_component(obj/item/circuit_component/vendor_component/vendor_component)
SIGNAL_HANDLER
UnregisterSignal(vendor_component, list(
COMSIG_QDELETING,
COMSIG_CIRCUIT_COMPONENT_REMOVED,
))
if(!QDELING(vendor_component))
qdel(vendor_component)
vendor_components -= vendor_component
/obj/item/circuit_component/dispenser_bot/ui_perform_action(mob/user, action)
switch(action)
if("add_vend_component")
if(length(vendor_components) >= max_vendor_components)
balloon_alert(user, "you have hit vendor component limit!")
return
var/obj/item/circuit_component/vendor_component/vendor_component = new(parent)
parent.add_component(vendor_component, user)
vendor_components += vendor_component
RegisterSignals(vendor_component, list(
COMSIG_QDELETING,
COMSIG_CIRCUIT_COMPONENT_REMOVED,
), PROC_REF(remove_vendor_component))
/obj/item/circuit_component/vendor_component
display_name = "Vend"
desc = "A component used to vend out specific objects from the dispenser bot."
circuit_flags = CIRCUIT_FLAG_OUTPUT_SIGNAL
var/obj/structure/dispenser_bot/attached_bot
/// The item this vendor component should vend
var/datum/port/input/item_to_vend
/// Used to vend the item
var/datum/port/input/vend_item
circuit_size = 0
/obj/item/circuit_component/vendor_component/register_shell(atom/movable/shell)
. = ..()
if(istype(shell, /obj/structure/dispenser_bot))
attached_bot = shell
/obj/item/circuit_component/vendor_component/unregister_shell(atom/movable/shell)
attached_bot = null
return ..()
/obj/item/circuit_component/vendor_component/populate_ports()
item_to_vend = add_input_port("Item", PORT_TYPE_ATOM, trigger = null)
vend_item = add_input_port("Vend Item", PORT_TYPE_SIGNAL, trigger = PROC_REF(vend_item))
/obj/item/circuit_component/vendor_component/proc/vend_item(datum/port/input/port, list/return_values)
CIRCUIT_TRIGGER
if(!attached_bot)
return
var/obj/item/vending_item = locate(item_to_vend.value) in attached_bot.stored_items
if(!vending_item)
return
attached_bot.remove_item(vending_item)