mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-14 03:32:00 +00:00
## About The Pull Request MODsuit modules now render on the part they're attached to, that being first part if required_slots is set, otherwise defaulting to the control module. Instead of using icon ops and a cache, module masking (used by armor boosters and insignias) will instead render the module on all parts, each overlay alpha filtered using the worn piece as the mask. To do this we also migrate modules to separate_worn_overlays, which fixes the issue where they'd always get painted the same color as the back piece, ignoring use_mod_colors's value (which is FALSE by default). So now modules that inherit MOD's color like armor booster will be painted accordingly to their piece. This also means that modules actually layer properly, and don't go ontop of items that they should be under. Additionally, whenever gloves or boots overslot an item, the overslotted item will still render underneath them if they're unsealed. Because it looks weird when your gloves disappear when you extend your MODsuit ones.  Look at that hip look, she'd have bare hands and ankles without this PR. Closes #90370 ## Why It's Good For The Game Fixes a bunch of visual jank that looks weird, and overslotting displaying overslotted item is just behavior you'd expect normally. ## Changelog 🆑 add: When a MODsuit piece overslots an item, it will now render beneath that piece as long as its unsealed. refactor: Refactored how MODsuit modules are rendered, report any bugs on GitHub! /🆑
304 lines
12 KiB
Plaintext
304 lines
12 KiB
Plaintext
/obj/item/mod/module/circuit
|
|
name = "MOD circuit adapter module"
|
|
desc = "A module shell that allows a circuit to be inserted into, and interface with, a MODsuit."
|
|
module_type = MODULE_USABLE
|
|
complexity = 1
|
|
idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
|
incompatible_modules = list(/obj/item/mod/module/circuit)
|
|
cooldown_time = 0.5 SECONDS
|
|
|
|
/// A reference to the shell component, used to access the shell and its attached circuit
|
|
var/datum/component/shell/shell
|
|
|
|
/// List of installed action components
|
|
var/list/obj/item/circuit_component/equipment_action/action_comps = list()
|
|
|
|
/obj/item/mod/module/circuit/Initialize(mapload)
|
|
. = ..()
|
|
|
|
RegisterSignal(src, COMSIG_CIRCUIT_ACTION_COMPONENT_REGISTERED, PROC_REF(action_comp_registered))
|
|
RegisterSignal(src, COMSIG_CIRCUIT_ACTION_COMPONENT_UNREGISTERED, PROC_REF(action_comp_unregistered))
|
|
|
|
shell = AddComponent(/datum/component/shell, \
|
|
list(new /obj/item/circuit_component/mod_adapter_core()), \
|
|
capacity = SHELL_CAPACITY_LARGE, \
|
|
)
|
|
|
|
/obj/item/mod/module/circuit/proc/override_power_usage(datum/source, amount)
|
|
SIGNAL_HANDLER
|
|
if(drain_power(amount))
|
|
. = COMPONENT_OVERRIDE_POWER_USAGE
|
|
|
|
/obj/item/mod/module/circuit/proc/action_comp_registered(datum/source, obj/item/circuit_component/equipment_action/action_comp)
|
|
SIGNAL_HANDLER
|
|
action_comps += action_comp
|
|
|
|
/obj/item/mod/module/circuit/proc/action_comp_unregistered(datum/source, obj/item/circuit_component/equipment_action/action_comp)
|
|
SIGNAL_HANDLER
|
|
action_comps -= action_comp
|
|
for(var/ref in action_comp.granted_to)
|
|
unpin_action(action_comp, locate(ref))
|
|
QDEL_LIST_ASSOC_VAL(action_comp.granted_to)
|
|
|
|
/obj/item/mod/module/circuit/on_install()
|
|
. = ..()
|
|
if(!shell?.attached_circuit)
|
|
return
|
|
RegisterSignal(shell?.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE, PROC_REF(override_power_usage))
|
|
|
|
/obj/item/mod/module/circuit/on_uninstall(deleting = FALSE)
|
|
. = ..()
|
|
if(!shell?.attached_circuit)
|
|
return
|
|
for(var/obj/item/circuit_component/equipment_action/action_comp in action_comps)
|
|
for(var/ref in action_comp.granted_to)
|
|
unpin_action(action_comp, locate(ref))
|
|
UnregisterSignal(shell?.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE)
|
|
|
|
/obj/item/mod/module/circuit/on_use()
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(!shell.attached_circuit)
|
|
return
|
|
shell.attached_circuit?.interact(mod.wearer)
|
|
|
|
/obj/item/mod/module/circuit/get_configuration(mob/user)
|
|
. = ..()
|
|
var/unnamed_action_index = 1
|
|
for(var/obj/item/circuit_component/equipment_action/action_comp in action_comps)
|
|
.[REF(action_comp)] = add_ui_configuration(action_comp.button_name.value || "Unnamed Action [unnamed_action_index++]", "pin", !!action_comp.granted_to[REF(user)])
|
|
|
|
/obj/item/mod/module/circuit/configure_edit(key, value)
|
|
. = ..()
|
|
var/obj/item/circuit_component/equipment_action/action_comp = locate(key) in action_comps
|
|
if(!istype(action_comp))
|
|
return
|
|
if(text2num(value))
|
|
pin_action(action_comp, usr)
|
|
else
|
|
unpin_action(action_comp, usr)
|
|
|
|
/obj/item/mod/module/circuit/proc/pin_action(obj/item/circuit_component/equipment_action/action_comp, mob/user)
|
|
if(!istype(user))
|
|
return
|
|
if(action_comp.granted_to[REF(user)]) // Sanity check - don't pin an action for a mob that has already pinned it
|
|
return
|
|
mod.add_item_action(new/datum/action/item_action/mod/pinnable/circuit(mod, user, src, action_comp))
|
|
|
|
/obj/item/mod/module/circuit/proc/unpin_action(obj/item/circuit_component/equipment_action/action_comp, mob/user)
|
|
var/datum/action/item_action/mod/pinnable/circuit/action = action_comp.granted_to[REF(user)]
|
|
if(!istype(action))
|
|
return
|
|
qdel(action)
|
|
|
|
/datum/action/item_action/mod/pinnable/circuit
|
|
button_icon = 'icons/mob/actions/actions_items.dmi'
|
|
button_icon_state = "bci_blank"
|
|
|
|
/// A reference to the module containing this action's component
|
|
var/obj/item/mod/module/circuit/module
|
|
|
|
/// A reference to the component this action triggers.
|
|
var/obj/item/circuit_component/equipment_action/circuit_component
|
|
|
|
/datum/action/item_action/mod/pinnable/circuit/New(Target, mob/user, obj/item/mod/module/circuit/linked_module, obj/item/circuit_component/equipment_action/action_comp)
|
|
. = ..()
|
|
module = linked_module
|
|
action_comp.granted_to[REF(user)] = src
|
|
circuit_component = action_comp
|
|
name = action_comp.button_name.value
|
|
button_icon_state = "bci_[replacetextEx(LOWER_TEXT(action_comp.icon_options.value), " ", "_")]"
|
|
|
|
/datum/action/item_action/mod/pinnable/circuit/Destroy()
|
|
circuit_component.granted_to -= REF(pinner)
|
|
circuit_component = null
|
|
|
|
return ..()
|
|
|
|
/datum/action/item_action/mod/pinnable/circuit/do_effect(trigger_flags)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
var/obj/item/mod/control/mod = module.mod
|
|
if(!istype(mod))
|
|
return FALSE
|
|
if(!mod.active || mod.activating)
|
|
if(mod.wearer)
|
|
module.balloon_alert(mod.wearer, "not active!")
|
|
return FALSE
|
|
circuit_component.user.set_output(owner)
|
|
circuit_component.signal.set_output(COMPONENT_SIGNAL)
|
|
|
|
/// If the guy whose UI we are pinned to got deleted
|
|
/datum/action/item_action/mod/pinnable/circuit/pinner_deleted()
|
|
module?.action_comps[circuit_component] -= REF(pinner)
|
|
. = ..()
|
|
|
|
/obj/item/circuit_component/mod_adapter_core
|
|
display_name = "MOD circuit adapter core"
|
|
desc = "Provides a reference to the MODsuit's occupant and allows the circuit to toggle the MODsuit."
|
|
|
|
/// The MODsuit module this circuit is associated with
|
|
var/obj/item/mod/module/attached_module
|
|
|
|
/// The name of the module to select
|
|
var/datum/port/input/option/module_to_select
|
|
|
|
/// The signal to toggle deployment of the modsuit
|
|
var/datum/port/input/toggle_deploy
|
|
|
|
/// The signal to toggle the suit
|
|
var/datum/port/input/toggle_suit
|
|
|
|
/// The signal to select a module
|
|
var/datum/port/input/select_module
|
|
|
|
/// A reference to the wearer of the MODsuit
|
|
var/datum/port/output/wearer
|
|
|
|
/// Whether or not the suit is deployed
|
|
var/datum/port/output/deployed
|
|
|
|
/// Whether or not the suit is activated
|
|
var/datum/port/output/activated
|
|
|
|
/// The name of the last selected module
|
|
var/datum/port/output/selected_module
|
|
|
|
/// A list of the names of all currently deployed parts
|
|
var/datum/port/output/deployed_parts
|
|
|
|
/// The signal that is triggered when a module is selected
|
|
var/datum/port/output/on_module_selected
|
|
|
|
/// The signal that is triggered when the suit is deployed by a signal
|
|
var/datum/port/output/on_deploy
|
|
|
|
/// The signal that is triggered when the suit has finished toggling itself after being activated by a signal
|
|
var/datum/port/output/on_toggle_finish
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/populate_options()
|
|
module_to_select = add_option_port("Module to Select", list())
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/populate_ports()
|
|
// Input Signals
|
|
toggle_deploy = add_input_port("Toggle Deployment", PORT_TYPE_SIGNAL)
|
|
toggle_suit = add_input_port("Toggle Suit", PORT_TYPE_SIGNAL)
|
|
select_module = add_input_port("Select Module", PORT_TYPE_SIGNAL)
|
|
// States
|
|
wearer = add_output_port("Wearer", PORT_TYPE_USER)
|
|
deployed = add_output_port("Deployed", PORT_TYPE_NUMBER)
|
|
activated = add_output_port("Activated", PORT_TYPE_NUMBER)
|
|
selected_module = add_output_port("Selected Module", PORT_TYPE_STRING)
|
|
deployed_parts = add_output_port("Deployed Parts", PORT_TYPE_LIST(PORT_TYPE_STRING))
|
|
// Output Signals
|
|
on_module_selected = add_output_port("On Module Selected", PORT_TYPE_SIGNAL)
|
|
on_deploy = add_output_port("On Deploy", PORT_TYPE_SIGNAL)
|
|
on_toggle_finish = add_output_port("Finished Toggling", PORT_TYPE_SIGNAL)
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/register_shell(atom/movable/shell)
|
|
. = ..()
|
|
if(istype(shell, /obj/item/mod/module))
|
|
attached_module = shell
|
|
RegisterSignal(attached_module, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/unregister_shell(atom/movable/shell)
|
|
if(attached_module)
|
|
UnregisterSignal(attached_module, COMSIG_MOVABLE_MOVED)
|
|
attached_module = null
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/input_received(datum/port/input/port)
|
|
if(!attached_module?.mod)
|
|
return
|
|
var/obj/item/mod/module/module
|
|
for(var/obj/item/mod/module/potential_module as anything in attached_module.mod.modules)
|
|
if(potential_module.name == module_to_select.value)
|
|
module = potential_module
|
|
if(COMPONENT_TRIGGERED_BY(toggle_suit, port))
|
|
INVOKE_ASYNC(attached_module.mod, TYPE_PROC_REF(/obj/item/mod/control, toggle_activate), attached_module.mod.wearer)
|
|
if(COMPONENT_TRIGGERED_BY(toggle_deploy, port))
|
|
INVOKE_ASYNC(attached_module.mod, TYPE_PROC_REF(/obj/item/mod/control, quick_deploy), attached_module.mod.wearer)
|
|
if(attached_module.mod.active && module && COMPONENT_TRIGGERED_BY(select_module, port))
|
|
INVOKE_ASYNC(module, TYPE_PROC_REF(/obj/item/mod/module, on_select))
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/proc/on_move(atom/movable/source, atom/old_loc, dir, forced)
|
|
SIGNAL_HANDLER
|
|
if(istype(source.loc, /obj/item/mod/control))
|
|
var/obj/item/mod/control/mod = source.loc
|
|
RegisterSignal(mod, COMSIG_MOD_MODULE_SELECTED, PROC_REF(on_module_select))
|
|
RegisterSignal(mod, COMSIG_MOD_DEPLOYED, PROC_REF(on_mod_part_toggled))
|
|
RegisterSignal(mod, COMSIG_MOD_RETRACTED, PROC_REF(on_mod_part_toggled))
|
|
RegisterSignal(mod, COMSIG_MOD_TOGGLED, PROC_REF(on_mod_toggled))
|
|
RegisterSignal(mod, COMSIG_MOD_MODULE_ADDED, PROC_REF(on_module_changed))
|
|
RegisterSignal(mod, COMSIG_MOD_MODULE_REMOVED, PROC_REF(on_module_changed))
|
|
RegisterSignal(mod, COMSIG_ITEM_EQUIPPED, PROC_REF(equip_check))
|
|
wearer.set_output(mod.wearer)
|
|
var/modules_list = list()
|
|
for(var/obj/item/mod/module/module in mod.modules)
|
|
if(module.module_type != MODULE_PASSIVE)
|
|
modules_list += module.name
|
|
module_to_select.possible_options = modules_list
|
|
if (module_to_select.possible_options.len)
|
|
module_to_select.set_value(module_to_select.possible_options[1])
|
|
else if(istype(old_loc, /obj/item/mod/control))
|
|
UnregisterSignal(old_loc, list(COMSIG_MOD_MODULE_SELECTED, COMSIG_ITEM_EQUIPPED))
|
|
UnregisterSignal(old_loc, COMSIG_MOD_DEPLOYED)
|
|
UnregisterSignal(old_loc, COMSIG_MOD_RETRACTED)
|
|
UnregisterSignal(old_loc, COMSIG_MOD_TOGGLED)
|
|
UnregisterSignal(old_loc, COMSIG_MOD_MODULE_ADDED)
|
|
UnregisterSignal(old_loc, COMSIG_MOD_MODULE_REMOVED)
|
|
selected_module.set_output(null)
|
|
wearer.set_output(null)
|
|
deployed.set_output(FALSE)
|
|
activated.set_output(FALSE)
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/proc/on_module_select(datum/source, obj/item/mod/module/module)
|
|
SIGNAL_HANDLER
|
|
selected_module.set_output(module.name)
|
|
on_module_selected.set_output(COMPONENT_SIGNAL)
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/proc/on_module_changed()
|
|
SIGNAL_HANDLER
|
|
var/modules_list = list()
|
|
for(var/obj/item/mod/module/module in attached_module.mod.modules)
|
|
if(module.module_type != MODULE_PASSIVE)
|
|
modules_list += module.name
|
|
module_to_select.possible_options = modules_list
|
|
if (module_to_select.possible_options.len)
|
|
module_to_select.set_value(module_to_select.possible_options[1])
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/proc/on_mod_part_toggled()
|
|
SIGNAL_HANDLER
|
|
var/string_list = list()
|
|
var/is_deployed = TRUE
|
|
for(var/obj/item/part as anything in attached_module.mod.get_parts())
|
|
if(part.loc == attached_module.mod)
|
|
is_deployed = FALSE
|
|
else
|
|
var/part_name = "Undefined"
|
|
if(istype(part, /obj/item/clothing/head/mod))
|
|
part_name = "Helmet"
|
|
if(istype(part, /obj/item/clothing/suit/mod))
|
|
part_name = "Chestplate"
|
|
if(istype(part, /obj/item/clothing/gloves/mod))
|
|
part_name = "Gloves"
|
|
if(istype(part, /obj/item/clothing/shoes/mod))
|
|
part_name = "Boots"
|
|
string_list += part_name
|
|
deployed_parts.set_output(string_list)
|
|
deployed.set_output(is_deployed)
|
|
on_deploy.set_output(COMPONENT_SIGNAL)
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/proc/on_mod_toggled()
|
|
SIGNAL_HANDLER
|
|
activated.set_output(attached_module.mod.active)
|
|
on_toggle_finish.set_output(COMPONENT_SIGNAL)
|
|
|
|
/obj/item/circuit_component/mod_adapter_core/proc/equip_check()
|
|
SIGNAL_HANDLER
|
|
if(!attached_module.mod?.wearer)
|
|
return
|
|
wearer.set_output(attached_module.mod.wearer)
|