Files
Bubberstation/code/datums/components/material/remote_materials.dm
SkyratBot 99bf83f35d [MIRROR] Fixes for mat container & ORM [MDB IGNORE] (#25885)
* Fixes for mat container & ORM (#80573)

## About The Pull Request
- Fixes #80559

1) The ORM now hooks onto the local container only if off station. The
ui act if statement was also messed up but that's fixed now too.

2) Creates a dedicated signal for items inserted into the silo for
clarity & uses the helper proc defined inside remote materials for
inserting items so we don't have to specify the `context` manually.

3) Properly updates the auto Doc for the container signal defines

## Changelog
🆑
fix: Off station ORM's can redeem points again.
/🆑

* Fixes for mat container & ORM

---------

Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
2023-12-28 07:58:44 -08:00

290 lines
9.9 KiB
Plaintext

/*
This component allows machines to connect remotely to a material container
(namely an /obj/machinery/ore_silo) elsewhere. It offers optional graceful
fallback to a local material storage in case remote storage is unavailable, and
handles linking back and forth.
*/
/datum/component/remote_materials
// Three possible states:
// 1. silo exists, materials is parented to silo
// 2. silo is null, materials is parented to parent
// 3. silo is null, materials is null
///The silo machine this container is connected to
var/obj/machinery/ore_silo/silo
///Material container. the value is either the silo or local
var/datum/component/material_container/mat_container
///Should we create a local storage if we can't connect to silo
var/allow_standalone
///Local size of container when silo = null
var/local_size = INFINITY
///Flags used for the local material container(exceptions for item insert & intent flags)
var/mat_container_flags = NONE
///List of signals to hook onto the local container
var/list/mat_container_signals
/datum/component/remote_materials/Initialize(
mapload,
allow_standalone = TRUE,
force_connect = FALSE,
mat_container_flags = NONE,
list/mat_container_signals = null
)
if (!isatom(parent))
return COMPONENT_INCOMPATIBLE
src.allow_standalone = allow_standalone
src.mat_container_flags = mat_container_flags
src.mat_container_signals = mat_container_signals
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(OnMultitool))
var/turf/T = get_turf(parent)
var/connect_to_silo = FALSE
if(force_connect || (mapload && is_station_level(T.z)))
connect_to_silo = TRUE
if(!(mat_container_flags & MATCONTAINER_NO_INSERT))
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, TYPE_PROC_REF(/datum/component/remote_materials, SiloAttackBy))
if(mapload) // wait for silo to initialize during mapload
addtimer(CALLBACK(src, PROC_REF(_PrepareStorage), connect_to_silo))
else //directly register in round
_PrepareStorage(connect_to_silo)
/**
* Internal proc. prepares local storage if onnect_to_silo = FALSE
*
* Arguments
* connect_to_silo- if true connect to global silo. If not successfull then go to local storage
* only if allow_standalone = TRUE, else you a null mat_container
*/
/datum/component/remote_materials/proc/_PrepareStorage(connect_to_silo)
PRIVATE_PROC(TRUE)
if (connect_to_silo)
silo = GLOB.ore_silo_default
if (silo)
silo.ore_connected_machines += src
mat_container = silo.GetComponent(/datum/component/material_container)
if (!mat_container && allow_standalone)
_MakeLocal()
/datum/component/remote_materials/Destroy()
if (silo)
silo.ore_connected_machines -= src
silo.holds -= src
silo.updateUsrDialog()
silo = null
mat_container = null
return ..()
/datum/component/remote_materials/proc/_MakeLocal()
PRIVATE_PROC(TRUE)
silo = null
var/static/list/allowed_mats = list(
/datum/material/iron,
/datum/material/glass,
/datum/material/silver,
/datum/material/gold,
/datum/material/diamond,
/datum/material/plasma,
/datum/material/uranium,
/datum/material/bananium,
/datum/material/titanium,
/datum/material/bluespace,
/datum/material/plastic,
)
mat_container = parent.AddComponent( \
/datum/component/material_container, \
allowed_mats, \
local_size, \
mat_container_flags, \
container_signals = mat_container_signals, \
allowed_items = /obj/item/stack \
)
/datum/component/remote_materials/proc/toggle_holding(force_hold = FALSE)
if(isnull(silo))
return
if(force_hold)
silo.holds[src] = TRUE
else if(!silo.holds[src])
silo.holds[src] = TRUE
else
silo.holds -= src
/datum/component/remote_materials/proc/set_local_size(size)
local_size = size
if (!silo && mat_container)
mat_container.max_amount = size
/**
* Disconnect this component from the remote silo
*
* Arguments
* old_silo- The silo we are trying to disconnect from
*/
/datum/component/remote_materials/proc/disconnect_from(obj/machinery/ore_silo/old_silo)
if (!old_silo || silo != old_silo)
return
silo.ore_connected_machines -= src
silo = null
mat_container = null
if (allow_standalone)
_MakeLocal()
///Insert mats into silo
/datum/component/remote_materials/proc/SiloAttackBy(datum/source, obj/item/target, mob/living/user)
SIGNAL_HANDLER
//Allows you to attack the machine with iron sheets for e.g.
if(!(mat_container_flags & MATCONTAINER_ANY_INTENT) && user.combat_mode)
return
if(silo)
mat_container.user_insert(target, user, parent)
return COMPONENT_NO_AFTERATTACK
/datum/component/remote_materials/proc/OnMultitool(datum/source, mob/user, obj/item/I)
SIGNAL_HANDLER
if(!I.multitool_check_buffer(user, I))
return ITEM_INTERACT_BLOCKING
var/obj/item/multitool/M = I
if (!QDELETED(M.buffer) && istype(M.buffer, /obj/machinery/ore_silo))
if (silo == M.buffer)
to_chat(user, span_warning("[parent] is already connected to [silo]!"))
return ITEM_INTERACT_BLOCKING
if(!check_z_level(M.buffer))
to_chat(user, span_warning("[parent] is too far away to get a connection signal!"))
return ITEM_INTERACT_BLOCKING
var/obj/machinery/ore_silo/new_silo = M.buffer
var/datum/component/material_container/new_container = new_silo.GetComponent(/datum/component/material_container)
if (silo)
silo.ore_connected_machines -= src
silo.holds -= src
silo.updateUsrDialog()
else if (mat_container)
//transfer all mats to silo. whatever cannot be transfered is dumped out as sheets
if(mat_container.total_amount())
for(var/datum/material/mat as anything in mat_container.materials)
var/mat_amount = mat_container.materials[mat]
if(!mat_amount || !new_container.has_space(mat_amount) || !new_container.can_hold_material(mat))
continue
new_container.materials[mat] += mat_amount
mat_container.materials[mat] = 0
qdel(mat_container)
silo = new_silo
silo.ore_connected_machines += src
silo.updateUsrDialog()
mat_container = new_container
if(!(mat_container_flags & MATCONTAINER_NO_INSERT))
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, TYPE_PROC_REF(/datum/component/remote_materials, SiloAttackBy))
to_chat(user, span_notice("You connect [parent] to [silo] from the multitool's buffer."))
return ITEM_INTERACT_BLOCKING
/**
* Checks if the param silo is in the same level as this components parent i.e. connected machine, rcd, etc
*
* Arguments
* silo_to_check- Is this components parent in the same Z level as this param silo. If null
* then check this components connected silo
*
* Returns true if both are on the station or same z level
*/
/datum/component/remote_materials/proc/check_z_level(obj/silo_to_check = silo)
if(isnull(silo_to_check))
return FALSE
return is_valid_z_level(get_turf(silo_to_check), get_turf(parent))
/// returns TRUE if this connection put on hold by the silo
/datum/component/remote_materials/proc/on_hold()
return check_z_level() ? silo.holds[src] : FALSE
/**
* Internal proc to check if this connection can use any materials from the silo
* Returns true only if
* - The parent is of type movable atom
* - A mat container is actually present
* - The silo in not on hold
* Arguments
* * check_hold - should we check if the silo is on hold
*/
/datum/component/remote_materials/proc/_can_use_resource(check_hold = TRUE)
PRIVATE_PROC(TRUE)
var/atom/movable/movable_parent = parent
if (!istype(movable_parent))
return FALSE
if (!mat_container) //no silolink & local storage not supported
movable_parent.say("No access to material storage, please contact the quartermaster.")
return FALSE
if(check_hold && on_hold()) //silo on hold
movable_parent.say("Mineral access is on hold, please contact the quartermaster.")
return FALSE
return TRUE
/**
* Use materials from either the silo(if connected) or from the local storage. If silo then this action
* is logged else not e.g. action="build" & name="matter bin" means you are trying to build an matter bin
*
* Arguments
* [mats][list]- list of materials to use
* coefficient- each mat unit is scaled by this value then rounded. This value if usually your machine efficiency e.g. upgraded protolathe has reduced costs
* multiplier- each mat unit is scaled by this value then rounded after it is scaled by coefficient. This value is your print quatity e.g. printing multiple items
* action- For logging only. e.g. build, create, i.e. the action you are trying to perform
* name- For logging only. the design you are trying to build e.g. matter bin, etc.
*/
/datum/component/remote_materials/proc/use_materials(list/mats, coefficient = 1, multiplier = 1, action = "build", name = "design")
if(!_can_use_resource())
return 0
var/amount_consumed = mat_container.use_materials(mats, coefficient, multiplier)
if (silo)//log only if silo is linked
var/list/scaled_mats = list()
for(var/i in mats)
scaled_mats[i] = OPTIMAL_COST(OPTIMAL_COST(mats[i] * coefficient) * multiplier)
silo.silo_log(parent, action, -multiplier, name, scaled_mats)
return amount_consumed
/**
* Ejects the given material ref and logs it
*
* Arguments
* [material_ref][datum/material]- The material type you are trying to eject
* eject_amount- how many sheets to eject
* [drop_target][atom]- optional where to drop the sheets. null means it is dropped at this components parent location
*/
/datum/component/remote_materials/proc/eject_sheets(datum/material/material_ref, eject_amount, atom/drop_target = null)
if(!_can_use_resource())
return 0
var/atom/movable/movable_parent = parent
if(isnull(drop_target))
drop_target = movable_parent.drop_location()
return mat_container.retrieve_sheets(eject_amount, material_ref, target = drop_target, context = parent)
/**
* Insert an item into the mat container, helper proc to insert items with the correct context
*
* Arguments
* * obj/item/weapon - the item you are trying to insert
* * multiplier - the multiplier applied on the materials consumed
*/
/datum/component/remote_materials/proc/insert_item(obj/item/weapon, multiplier = 1)
if(!_can_use_resource(FALSE))
return MATERIAL_INSERT_ITEM_FAILURE
return mat_container.insert_item(weapon, multiplier, parent)