Files
BatrachophrenoandGitHub 5277251959 Tool behaviors port (#21663)
For a robust crafting system, I need a new materials framework.
For a new materials framework, I need to clean up reagents.
To clean up reagents, I need to pare down foods from reagent holders.
To pare down foods from reagent holders, I need to port edibility
components.
To port edibility components, I need to port processing components.
To port processing components, I need to port tool behaviors.

This is all back-end code, no new features or functionality from this.
2026-01-27 08:44:49 +00:00

216 lines
7.1 KiB
Plaintext

/obj/machinery/chemical_dispenser
name = "chemical dispenser"
icon = 'icons/obj/chemical.dmi'
icon_state = "dispenser"
clicksound = SFX_BUTTON
idle_power_usage = 100
density = TRUE
anchored = TRUE
manufacturer = "zenghu"
/// Icon state when used.
var/icon_state_active = "dispenser_active"
/// Set to a list of types to spawn one of each on New().
var/list/spawn_cartridges
/// Associative, label -> cartridge.
var/list/cartridges = list()
///Current container.
var/obj/item/reagent_containers/container
/// Name of the dispenser on the UI.
var/ui_title = "Chemical Dispenser"
/// If set to FALSE, will only accept beakers.
var/accept_drinking = FALSE
/// Amount dispensed.
var/amount = 30
/// Preset amounts to dispense.
var/list/preset_dispense_amounts = list(5, 10, 15, 20, 30, 40)
/// If the user can select the amount to dispense.
var/can_select_dispense_amount = TRUE
/// For containers we don't want people to shove into the chem machine. Like buckets.
var/list/forbidden_containers = list(/obj/item/reagent_containers/glass/bucket)
/// Allow these cans/glasses/condiment bottles but forbid ACTUAL food.
var/list/drink_accepted = list(/obj/item/reagent_containers/food/drinks, /obj/item/reagent_containers/food/condiment)
/obj/machinery/chemical_dispenser/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
. += "It has [cartridges.len] cartridges installed, and has space for [DISPENSER_MAX_CARTRIDGES - cartridges.len] more."
/obj/machinery/chemical_dispenser/Initialize()
. = ..()
if(spawn_cartridges)
for(var/type in spawn_cartridges)
add_cartridge(new type(src))
/obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/reagent_containers/chem_disp_cartridge/C, mob/user)
if(!istype(C))
if(user)
to_chat(user, SPAN_WARNING("[C] will not fit in [src]!"))
return
if(cartridges.len >= DISPENSER_MAX_CARTRIDGES)
if(user)
to_chat(user, SPAN_WARNING("[src] does not have any slots open for [C] to fit into!"))
return
if(!C.label)
if(user)
to_chat(user, SPAN_WARNING("[C] does not have a label!"))
return
if(cartridges[C.label])
if(user)
to_chat(user, SPAN_WARNING("[src] already contains a cartridge with that label!"))
return
if(user)
user.drop_from_inventory(C,src)
to_chat(user, SPAN_NOTICE("You add [C] to [src]."))
else
C.forceMove(src)
cartridges[C.label] = C
sortTim(cartridges, GLOBAL_PROC_REF(cmp_text_asc))
SStgui.update_uis(src)
/obj/machinery/chemical_dispenser/proc/remove_cartridge(label)
. = cartridges[label]
cartridges -= label
SStgui.update_uis(src)
/obj/machinery/chemical_dispenser/proc/eject()
if(container && usr)
var/obj/item/reagent_containers/B = container
if(!use_check_and_message(usr))
usr.put_in_hands(B, TRUE)
else
B.loc = get_turf(src)
container = null
if(icon_state_active)
icon_state = initial(icon_state)
return TRUE
/obj/machinery/chemical_dispenser/AltClick(mob/user)
if(use_check_and_message(usr))
eject()
/obj/machinery/chemical_dispenser/attackby(obj/item/attacking_item, mob/user)
if(attacking_item.tool_behaviour == TOOL_WRENCH)
to_chat(user, SPAN_NOTICE("You begin to [anchored ? "un" : ""]fasten [src]."))
if(attacking_item.use_tool(src, user, 20, volume = 50))
user.visible_message(
SPAN_NOTICE("[user] [anchored ? "un" : ""]fastens [src]."),
SPAN_NOTICE("You have [anchored ? "un" : ""]fastened [src]."),
"You hear a ratchet.")
anchored = !anchored
else
to_chat(user, SPAN_NOTICE("You decide not to [anchored ? "un" : ""]fasten [src]."))
else if(istype(attacking_item, /obj/item/reagent_containers/chem_disp_cartridge))
add_cartridge(attacking_item, user)
else if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER)
var/label = tgui_input_list(user, "Which cartridge would you like to remove?", "Chemical Dispenser", cartridges)
if(!label)
return
var/obj/item/reagent_containers/chem_disp_cartridge/C = remove_cartridge(label)
if(C)
to_chat(user, SPAN_NOTICE("You remove [C] from [src]."))
C.forceMove(loc)
else if(istype(attacking_item, /obj/item/reagent_containers/glass) || is_type_in_list(attacking_item, drink_accepted))
if(container)
to_chat(user, SPAN_WARNING("There is already \a [container] on [src]!"))
return
var/obj/item/reagent_containers/RC = attacking_item
if(is_type_in_list(RC, forbidden_containers))
to_chat(user, SPAN_WARNING("There's no way to fit [RC] into \the [src]!"))
return
if(!accept_drinking && is_type_in_list(RC, drink_accepted))
to_chat(user, SPAN_WARNING("This machine only accepts beakers!"))
return
if(!RC.is_open_container())
to_chat(user, SPAN_WARNING("You don't see how [src] could dispense reagents into [RC]."))
return
container = RC
user.drop_from_inventory(RC,src)
to_chat(user, SPAN_NOTICE("You set [RC] on [src]."))
SStgui.update_uis(src)
if(icon_state_active)
icon_state = icon_state_active
else
return ..()
/obj/machinery/chemical_dispenser/ui_data(mob/user)
var/list/data = list()
data["manufacturer"] = manufacturer
data["amount"] = amount
data["preset_dispense_amounts"] = preset_dispense_amounts
data["can_select_dispense_amount"] = can_select_dispense_amount
data["accept_drinking"] = accept_drinking
data["is_beaker_loaded"] = !!container
data["beaker_max_volume"] = container?.reagents?.maximum_volume
data["beaker_current_volume"] = container?.reagents?.total_volume
var/list/beakerD = list()
for(var/_R in container?.reagents?.reagent_volumes)
var/singleton/reagent/R = GET_SINGLETON(_R)
beakerD += list(list("name" = R.name, "volume" = REAGENT_VOLUME(container.reagents, _R)))
data["beaker_contents"] = beakerD
var/list/chemicals = list()
for(var/label in cartridges)
var/obj/item/reagent_containers/chem_disp_cartridge/C = cartridges[label]
chemicals += list(list("label" = label, "amount" = C.reagents.total_volume))
data["chemicals"] = chemicals
return data
/obj/machinery/chemical_dispenser/ui_interact(mob/user, var/datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ChemicalDispenser", ui_title, 400, 680)
ui.open()
/obj/machinery/chemical_dispenser/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch(action)
if("amount")
amount = round(text2num(params["amount"]), 1) // round to nearest 1
amount = between(amount, 1, container?.reagents?.maximum_volume || 120) // Since the user can actually type the commands himself, some sanity checking
. = TRUE
if("dispense")
var/label = params["dispense"]
if(cartridges[label] && container?.is_open_container())
var/obj/item/reagent_containers/chem_disp_cartridge/C = cartridges[label]
playsound(src.loc, 'sound/machines/reagent_dispense.ogg', 25, 1)
C.reagents.trans_to(container, amount)
. = TRUE
if("ejectBeaker")
if(eject())
. = TRUE
add_fingerprint(usr)
/obj/machinery/chemical_dispenser/ui_status(mob/user, datum/ui_state/state)
if(!operable())
return UI_DISABLED
. = ..()
/obj/machinery/chemical_dispenser/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
ui_interact(user)
/obj/machinery/chemical_dispenser/attack_hand(mob/user as mob)
ui_interact(user)