diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index c44ab970b9f..643df226f1d 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -1482,6 +1482,10 @@ /// Called when the integrated circuit is locked. #define COMSIG_CIRCUIT_SET_LOCKED "circuit_set_locked" +/// Called before power is used in an integrated circuit (power_to_use) +#define COMSIG_CIRCUIT_PRE_POWER_USAGE "circuit_pre_power_usage" + #define COMPONENT_OVERRIDE_POWER_USAGE (1<<0) + /// Called right before the integrated circuit data is converted to json. Allows modification to the data right before it is returned. #define COMSIG_CIRCUIT_PRE_SAVE_TO_JSON "circuit_pre_save_to_json" diff --git a/code/datums/components/shell.dm b/code/datums/components/shell.dm index b3ce2396949..ebe99cd4c2e 100644 --- a/code/datums/components/shell.dm +++ b/code/datums/components/shell.dm @@ -14,8 +14,19 @@ /// A list of components that cannot be removed var/list/obj/item/circuit_component/unremovable_circuit_components + /// Whether the shell is locked or not var/locked = FALSE + // The variables below are used only for anchored shells + /// The amount of power used in the last minute + var/power_used_in_minute = 0 + + /// The cooldown time to reset the power_used_in_minute to 0 + COOLDOWN_DECLARE(power_used_cooldown) + + /// The maximum power that the shell can use in a minute before entering overheating and destroying itself. + var/max_power_use_in_minute = 20000 + /datum/component/shell/Initialize(unremovable_circuit_components, capacity, shell_flags, starting_circuit) . = ..() if(!ismovable(parent)) @@ -119,12 +130,16 @@ examine_text += span_notice("The cover panel to the integrated circuit is [locked? "locked" : "unlocked"].") var/obj/item/stock_parts/cell/cell = attached_circuit.cell examine_text += span_notice("The charge meter reads [cell ? round(cell.percent(), 1) : 0]%.") - if((shell_flags & SHELL_FLAG_REQUIRE_ANCHOR) && !source.anchored) - examine_text += span_notice("The integrated circuit is non-functional whilst the shell is unanchored.") if (shell_flags & SHELL_FLAG_USB_PORT) examine_text += span_notice("There is a USB port on the front.") + if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR) + examine_text += span_notice("The shell does not require a battery to function and will draw from the area's APC whenever possible.") + if(!source.anchored) + examine_text += span_danger("The integrated circuit is non-functional whilst the shell is unanchored.") + + /** * Called when the shell is anchored. * @@ -256,6 +271,24 @@ source.balloon_alert(user, "it won't fit!") return COMPONENT_CANCEL_ADD_COMPONENT +/datum/component/shell/proc/override_power_usage(datum/source, power_to_use) + SIGNAL_HANDLER + if(COOLDOWN_FINISHED(src, power_used_cooldown)) + power_used_in_minute = 0 + + var/area/location = get_area(parent) + if(!location.powered(AREA_USAGE_EQUIP)) + return + + if(power_used_in_minute > max_power_use_in_minute) + explosion(parent, light_impact_range = 1, explosion_cause = attached_circuit) + remove_circuit() + return + location.use_power(power_to_use, AREA_USAGE_EQUIP) + power_used_in_minute += power_to_use + COOLDOWN_START(src, power_used_cooldown, 1 MINUTES) + return COMPONENT_OVERRIDE_POWER_USAGE + /** * Attaches a circuit to the parent. Doesn't do any checks to see for any existing circuits so that should be done beforehand. */ @@ -267,6 +300,8 @@ attached_circuit = circuitboard if(!(shell_flags & SHELL_FLAG_CIRCUIT_FIXED) && !circuitboard.admin_only) RegisterSignal(circuitboard, COMSIG_MOVABLE_MOVED, .proc/on_circuit_moved) + if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR) + RegisterSignal(circuitboard, COMSIG_CIRCUIT_PRE_POWER_USAGE, .proc/override_power_usage) RegisterSignal(circuitboard, COMSIG_PARENT_QDELETING, .proc/on_circuit_delete) for(var/obj/item/circuit_component/to_add as anything in unremovable_circuit_components) to_add.forceMove(attached_circuit) @@ -295,6 +330,7 @@ COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING, COMSIG_CIRCUIT_ADD_COMPONENT_MANUALLY, + COMSIG_CIRCUIT_PRE_POWER_USAGE, )) if(attached_circuit.loc == parent || (!QDELETED(attached_circuit) && attached_circuit.loc == null)) var/atom/parent_atom = parent diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm index 7b67b413d8b..41e9ee88abf 100644 --- a/code/modules/wiremod/core/component.dm +++ b/code/modules/wiremod/core/component.dm @@ -262,9 +262,11 @@ message_admins("[display_name] tried to execute on [parent.get_creator_admin()] that has admin_only set to 0") return FALSE - var/obj/item/stock_parts/cell/cell = parent.get_cell() - if(!cell?.use(power_usage_per_input)) - return FALSE + var/flags = SEND_SIGNAL(parent, COMSIG_CIRCUIT_PRE_POWER_USAGE, power_usage_per_input) + if(!(flags & COMPONENT_OVERRIDE_POWER_USAGE)) + var/obj/item/stock_parts/cell/cell = parent.get_cell() + if(!cell?.use(power_usage_per_input)) + return FALSE if((!port || port.trigger == .proc/input_received) && (circuit_flags & CIRCUIT_FLAG_INPUT_SIGNAL) && !COMPONENT_TRIGGERED_BY(trigger_input, port)) return FALSE diff --git a/code/modules/wiremod/shell/airlock.dm b/code/modules/wiremod/shell/airlock.dm index 9b77dde27fe..81437a1ff3b 100644 --- a/code/modules/wiremod/shell/airlock.dm +++ b/code/modules/wiremod/shell/airlock.dm @@ -18,7 +18,7 @@ /datum/component/shell, \ unremovable_circuit_components = list(new /obj/item/circuit_component/airlock, new /obj/item/circuit_component/airlock_access_event), \ capacity = SHELL_CAPACITY_LARGE, \ - shell_flags = SHELL_FLAG_ALLOW_FAILURE_ACTION \ + shell_flags = SHELL_FLAG_ALLOW_FAILURE_ACTION|SHELL_FLAG_REQUIRE_ANCHOR \ ) /obj/machinery/door/airlock/shell/check_access(obj/item/I)