Files
b4a124e557 [IDB IGNORE] cyborg refactor: icons, chassis, modules base (#6929)
- separates the composition of cyborgs into modules, iconsets, chassis,
upgrades
- modules / chassis atm can provide items, so can upgrades; in the
future we will want to probably generalize the item API a bit so
components can work
- chassis now can (unimplemented) easily be made to give different stats
- reorganizes all the cyborg sprites
- adds generalized item mounts with redirection support and tears out
legacy cyborg items
- entirely rebalances modules & writes some new lawsets in for future
use

---------

Co-authored-by: silicons <silicons@silicons.dev>
2026-01-13 18:39:38 +00:00

350 lines
10 KiB
Plaintext

//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station Developers *//
/**
* Arbitrary provider for resources, management, etc.
*
* * Used to allow things like cyborgs to provide water to things
* that would usually require internal tanks; this is just an example.
* * Usage procs have 'item' and 'key'. This is so you can route things like air
* around.
* * Items don't actually need to be mounted to use things. That's why
* there's minimally stateful procs. Some stateful procs just gracefully
* reject the usage / check if an item isn't mounted.
*
* ## Relaying
*
* Item mounts have an inbuilt relay system as 'mount an item that will be used in a module in a cyborg
* or rigsuit or mech' is a common patern.
*
* * Please know what you're doing if you use it. For performance reasons, there's no infinite loop guards.
* * If you use this system, it's on you to unlink it as needed and not cause GC issues.
*/
/datum/item_mount
/// mounted items; lazy list
var/list/obj/item/mounted_items
/// relay to other item mount by default
var/datum/item_mount/relay_to_other
/// item mounts relaying to us
var/list/datum/item_mount/relay_to_self
/datum/item_mount/Destroy()
for(var/obj/item/mounted as anything in mounted_items)
unmount(mounted)
relay_unlink_all()
relay_clear()
return ..()
/datum/item_mount/proc/relay_to(datum/item_mount/other)
relay_to_other = other
LAZYADD(relay_to_other.relay_to_self, src)
/datum/item_mount/proc/relay_clear()
if(!relay_to_other)
return
LAZYREMOVE(relay_to_other.relay_to_self, src)
relay_to_other = null
/datum/item_mount/proc/relay_unlink_all()
for(var/datum/item_mount/mount as anything in relay_to_self)
mount.relay_clear()
/datum/item_mount/proc/mount(obj/item/item)
if(item.item_mount)
if(item.item_mount == src)
return TRUE
item.item_mount.unmount(item)
LAZYADD(mounted_items, item)
item.item_mount = src
on_item_mount(item)
return TRUE
/datum/item_mount/proc/unmount(obj/item/item)
if(item.item_mount != src)
return TRUE
LAZYREMOVE(mounted_items, item)
item.item_mount = null
on_item_unmount(item)
return TRUE
/datum/item_mount/proc/is_mounted(obj/item/item)
return item in mounted_items
/**
* Called when a mounted item is deleted.
*/
/datum/item_mount/proc/on_item_del(obj/item/being_deleted)
unmount(being_deleted)
/datum/item_mount/proc/on_item_mount(obj/item/item)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(TRUE)
/datum/item_mount/proc/on_item_unmount(obj/item/item)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_CALL_PARENT(TRUE)
//* Gas *//
/**
* Get estimated gas pressure.
*
* @return null, or number
*/
/datum/item_mount/proc/gas_get_pressure(obj/item/item, key)
return relay_to_other?.gas_get_pressure(item, key)
/**
* Unsafe: Directly references a gas_mixture for a channel.
*
* @return null, or ref
*/
/datum/item_mount/proc/gas_mixture_ref(obj/item/item, key)
return relay_to_other?.gas_mixture_ref(item, key)
/**
* Returns a gas mixture by pulling a given liter amount.
*
* @return null, or ref
*/
/datum/item_mount/proc/gas_pull_volume(obj/item/item, key, liters)
return relay_to_other?.gas_pull_volume(item, key)
/**
* Fast: erases a given liter amount of gas. Usually used with [gas_mixture_ref]
* being used to check first.
*
* @return null, or moles deleted
*/
/datum/item_mount/proc/gas_erase_volume(obj/item/item, key, liters)
return relay_to_other?.gas_pull_volume(item, key)
//* Materials *//
/**
* Get the name of the provider.
* * Material is any resolvable material, so ID, path, or instance.
*
* @return null, or name
*/
/datum/item_mount/proc/material_get_provider_name(obj/item/item, key, material_id)
return relay_to_other?.material_get_provider_name(item, key, material_id)
/**
* * Material is any resolvable material, so ID, path, or instance.
* * Amount is in cm3
*
* @return null, or amount in cm3
*/
/datum/item_mount/proc/material_get_amount(obj/item/item, key, material_id)
return relay_to_other?.material_get_amount(item, key, material_id)
/**
* * Material is any resolvable material, so ID, path, or instance.
* * Amount is in cm3
*
* @return null, or TRUE / FALSE.
*/
/datum/item_mount/proc/material_has_amount(obj/item/item, key, material_id, amount)
return relay_to_other?.material_has_amount(item, key, material_id, amount)
/**
* * Material is any resolvable material, so ID, path, or instance.
* * Amount is in cm3.
*
* @return null, or amount used in cm3.
*/
/datum/item_mount/proc/material_use_amount(obj/item/item, key, material_id, amount)
return relay_to_other?.material_use_amount(item, key, material_id, amount)
/**
* * Material is any resolvable material, so ID, path, or instance.
* * Amount is in cm3.
*
* @return null, or amount used.
*/
/datum/item_mount/proc/material_use_checked_amount(obj/item/item, key, material_id, amount)
return material_has_amount(item, key, material_id, amount) && material_use_amount(item, key, material_id, amount)
/**
* * Material is any resolvable material, so ID, path, or instance.
* * Amount is in cm3.
*
* @return null, or amount given.
*/
/datum/item_mount/proc/material_give_amount(obj/item/item, key, material_id, amount, force)
return relay_to_other?.material_give_amount(item, key, material_id, amount, force)
/**
* * Material is any resolvable material, so ID, path, or instance.
* * Amount is in cm3.
*
* @return null, or max amount.
*/
/datum/item_mount/proc/material_get_capacity(obj/item/item, key, material_id)
return relay_to_other?.material_get_capacity(item, key, material_id)
//* Power *//
/**
* Lazy use-power-oneoff style thing
*
* @return null, or TRUE / FALSE for has that amount of energy
*/
/datum/item_mount/proc/lazy_energy_check(obj/item/item, key, joules)
return relay_to_other?.lazy_energy_check(item, key, joules)
/**
* Lazy use-power-oneoff style thing
*
* @return null, or joules supplied
*/
/datum/item_mount/proc/lazy_energy_use(obj/item/item, key, joules, minimum_reserve)
return relay_to_other?.lazy_energy_use(item, key, joules, minimum_reserve)
/**
* Lazy use-power-oneoff style thing
*
* @return null, or joules supplied
*/
/datum/item_mount/proc/lazy_energy_checked_use(obj/item/item, key, joules, minimum_reserve)
return lazy_energy_check(joules + minimum_reserve) && lazy_energy_use(joules, minimum_reserve)
//* Reagents - Direct *//
// TODO: notice how 'erase' and 'spawn' exists, but not 'push', and 'pull'?
// this is because reagents have data; they are not just described by the ID alone.
// thus an optimized uniform API for push/pull doesn't actually necessarily make sense,
// and as such implementation of such is left for when we need it (ergo mechs / rigsuits reagent routing).
/**
* Gets if an item mount has a reagent, and if it does, its amount.
* * Semantically, null means 'we can't store this'.
*
* @return null, or amount the item mount has
*/
/datum/item_mount/proc/reagent_get_amount(obj/item/item, key, datum/reagent/reagent)
return relay_to_other?.reagent_get_amount(item, key, reagent)
/**
* Checks if the item mount has a given amount of a reagent
* @return null, or TRUE / FALSE
*/
/datum/item_mount/proc/reagent_has_amount(obj/item/item, key, datum/reagent/reagent, amount)
. = reagent_get_amount(reagent)
if(.)
return . >= amount
/**
* @return null, or amount the item mount could to erase
*/
/datum/item_mount/proc/reagent_erase_amount(obj/item/item, key, datum/reagent/reagent, amount)
return relay_to_other?.reagent_erase_amount(item, key, reagent, amount)
/**
* @return null, or amount the item mount could give to erase
*/
/datum/item_mount/proc/reagent_erase_checked_amount(obj/item/item, key, datum/reagent/reagent, amount)
return reagent_has_amount(item, key, reagent, amount) && reagent_erase_amount(item, key, reagent, amount)
/**
* @return null, or amount the item mount could accept
*/
/datum/item_mount/proc/reagent_spawn_amount(obj/item/item, key, datum/reagent/reagent, amount, force)
return relay_to_other?.reagent_spawn_amount(item, key, reagent, amount, force)
//* Stacks *//
/**
* Get the name of the provider.
*
* @return null, or name
*/
/datum/item_mount/proc/stack_get_provider_name(obj/item/item, key, path)
return relay_to_other?.stack_get_provider_name(item, key, path)
/**
* Material stacks are invalid here.
*
* * Amount is in stack amount.
*
* @return null, or amount used.
*/
/datum/item_mount/proc/stack_use_checked_amount(obj/item/item, key, path, amount)
return stack_has_amount(item, key, path, amount) && stack_use_amount(item, key, path, amount)
/**
* Material stacks are invalid here.
*
* * Amount is in stack amount.
*
* @return null, or amount given.
*/
/datum/item_mount/proc/stack_give_amount(obj/item/item, key, path, amount, force)
return relay_to_other?.stack_give_amount(item, key, path, amount, force)
/**
* Material stacks are invalid here.
*
* @return null, or max amount.
*/
/datum/item_mount/proc/stack_get_capacity(obj/item/item, key, path)
return relay_to_other?.stack_get_capacity(item, key, path)
/**
* Material stacks are invalid here.
*
* * Amount is in stack amount.
*
* @return null, or amount remaining.
*/
/datum/item_mount/proc/stack_get_amount(obj/item/item, key, path)
return relay_to_other?.stack_get_amount(item, key, path)
/**
* Material stacks are invalid here.
*
* * Amount is in stack amount.
*
* @return null, or TRUE / FALSE.
*/
/datum/item_mount/proc/stack_has_amount(obj/item/item, key, path, amount)
. = stack_get_amount(item, key, path)
if(.)
return . >= amount
/**
* Material stacks are invalid here.
*
* * Amount is in stack amount.
*
* @return null, or amount used.
*/
/datum/item_mount/proc/stack_use_amount(obj/item/item, key, path, amount)
return relay_to_other?.stack_use_amount(item, key, path, amount)
//* ------ MISC BELOW HERE ------ *//
//* Misc - Extinguisher *//
/**
* @return null, or volume remaining
*/
/datum/item_mount/proc/extinguisher_get_volume(obj/item/extinguisher/extinguisher, key)
return relay_to_other?.extinguisher_get_volume(extinguisher, key)
/**
* @return null ,or TRUE / FALSE on if there's that much left
*/
/datum/item_mount/proc/extinguisher_has_volume(obj/item/extinguisher/extinguisher, key, requested)
. = extinguisher_get_volume(extinguisher)
if(.)
return . >= requested
/**
* @return null, or volume pulled
*/
/datum/item_mount/proc/extinguisher_transfer_volume(obj/item/extinguisher/extinguisher, key, requested, datum/reagent_holder/into_holder)
return relay_to_other?.extinguisher_transfer_volume(extinguisher, key, requested, into_holder)