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)