diff --git a/code/__DEFINES/apc_defines.dm b/code/__DEFINES/apc_defines.dm
index 3ce6e4a873c..ee6c2bb67d6 100644
--- a/code/__DEFINES/apc_defines.dm
+++ b/code/__DEFINES/apc_defines.dm
@@ -58,7 +58,7 @@
/// How long it takes an ethereal to drain or charge APCs. Also used as a spam limiter.
#define APC_DRAIN_TIME (7.5 SECONDS)
/// How much power ethereals gain/drain from APCs.
-#define APC_POWER_GAIN (200 KILO JOULES)
+#define APC_POWER_GAIN (0.2 * STANDARD_CELL_CHARGE)
// Wires & EMPs:
/// The wire value used to reset the APCs wires after one's EMPed.
diff --git a/code/__DEFINES/lights.dm b/code/__DEFINES/lights.dm
index b1413a70789..8830f919472 100644
--- a/code/__DEFINES/lights.dm
+++ b/code/__DEFINES/lights.dm
@@ -14,7 +14,7 @@
///Amount of time that takes an ethereal to take energy from the lights
#define LIGHT_DRAIN_TIME (2.5 SECONDS)
///Amount of charge the ethereal gain after the drain
-#define LIGHT_POWER_GAIN 35
+#define LIGHT_POWER_GAIN (0.035 * STANDARD_CELL_CHARGE)
///How many reagents the lights can hold
#define LIGHT_REAGENT_CAPACITY 20
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 066a37b6d48..12b0f36b5a6 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -286,12 +286,12 @@
//Charge levels for Ethereals, in joules.
#define ETHEREAL_CHARGE_NONE 0
-#define ETHEREAL_CHARGE_LOWPOWER (400 KILO JOULES)
-#define ETHEREAL_CHARGE_NORMAL (1 MEGA JOULES)
-#define ETHEREAL_CHARGE_ALMOSTFULL (1.5 MEGA JOULES)
-#define ETHEREAL_CHARGE_FULL (2 MEGA JOULES)
-#define ETHEREAL_CHARGE_OVERLOAD (2.5 MEGA JOULES)
-#define ETHEREAL_CHARGE_DANGEROUS (3 MEGA JOULES)
+#define ETHEREAL_CHARGE_LOWPOWER (0.4 * STANDARD_CELL_CHARGE)
+#define ETHEREAL_CHARGE_NORMAL (1 * STANDARD_CELL_CHARGE)
+#define ETHEREAL_CHARGE_ALMOSTFULL (1.5 * STANDARD_CELL_CHARGE)
+#define ETHEREAL_CHARGE_FULL (2 * STANDARD_CELL_CHARGE)
+#define ETHEREAL_CHARGE_OVERLOAD (2.5 * STANDARD_CELL_CHARGE)
+#define ETHEREAL_CHARGE_DANGEROUS (3 * STANDARD_CELL_CHARGE)
#define CRYSTALIZE_COOLDOWN_LENGTH (120 SECONDS)
@@ -435,7 +435,7 @@
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
#define HUNGER_FACTOR 0.05 //factor at which mob nutrition decreases
-#define ETHEREAL_DISCHARGE_RATE (0.8 KILO WATTS) // Rate at which ethereal stomach charge decreases
+#define ETHEREAL_DISCHARGE_RATE (8e-4 * STANDARD_CELL_CHARGE) // Rate at which ethereal stomach charge decreases
/// How much nutrition eating clothes as moth gives and drains
#define CLOTHING_NUTRITION_GAIN 15
#define REAGENTS_METABOLISM 0.2 //How many units of reagent are consumed per second, by default.
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index a886b54f19d..25f73963fd2 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -67,16 +67,16 @@
recharge_speed = 0
repairs = 0
for(var/datum/stock_part/capacitor/capacitor in component_parts)
- recharge_speed += (capacitor.tier * STANDARD_CELL_CHARGE * 0.1)
+ recharge_speed += 5e-3 * capacitor.tier
for(var/datum/stock_part/servo/servo in component_parts)
repairs += servo.tier - 1
for(var/obj/item/stock_parts/cell/cell in component_parts)
- recharge_speed *= (cell.maxcharge / STANDARD_CELL_CHARGE)
+ recharge_speed *= cell.maxcharge
/obj/machinery/recharge_station/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += span_notice("The status display reads: Recharging [recharge_speed]J per cycle.")
+ . += span_notice("The status display reads: Recharging: [display_power(recharge_speed, convert = FALSE)].")
if(materials.silo)
. += span_notice("The ore silo link indicator is lit, and cyborg restocking can be toggled by Right-Clicking [src].")
if(repairs)
diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm
index 3a765e537eb..0d71db68aac 100644
--- a/code/modules/mod/mod_core.dm
+++ b/code/modules/mod/mod_core.dm
@@ -262,7 +262,7 @@
/obj/item/mod/core/ethereal/charge_amount()
var/obj/item/organ/internal/stomach/ethereal/charge_source = charge_source()
- return charge_source?.crystal_charge || ETHEREAL_CHARGE_NONE
+ return charge_source?.cell.charge() || ETHEREAL_CHARGE_NONE
/obj/item/mod/core/ethereal/max_charge_amount()
return ETHEREAL_CHARGE_FULL
diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm
index c9f04adea86..b57f3465f0d 100644
--- a/code/modules/power/apc/apc_attack.dm
+++ b/code/modules/power/apc/apc_attack.dm
@@ -11,7 +11,7 @@
if(!istype(maybe_ethereal_stomach))
togglelock(user)
else
- if(maybe_ethereal_stomach.crystal_charge >= ETHEREAL_CHARGE_NORMAL)
+ if(maybe_ethereal_stomach.cell.charge() >= ETHEREAL_CHARGE_NORMAL)
togglelock(user)
ethereal_interact(user, modifiers)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -29,19 +29,20 @@
return
var/charge_limit = ETHEREAL_CHARGE_DANGEROUS - APC_POWER_GAIN
var/obj/item/organ/internal/stomach/ethereal/stomach = maybe_stomach
+ var/obj/item/stock_parts/cell/stomach_cell = stomach.cell
if(!((stomach?.drain_time < world.time) && LAZYACCESS(modifiers, RIGHT_CLICK)))
return
if(ethereal.combat_mode)
if(cell.charge <= (cell.maxcharge / 2)) // ethereals can't drain APCs under half charge, this is so that they are forced to look to alternative power sources if the station is running low
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "safeties prevent draining!"), alert_timer_duration)
return
- if(stomach.crystal_charge > charge_limit)
+ if(stomach_cell.charge() > charge_limit)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "charge is full!"), alert_timer_duration)
return
stomach.drain_time = world.time + APC_DRAIN_TIME
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "draining power"), alert_timer_duration)
while(do_after(user, APC_DRAIN_TIME, target = src))
- if(cell.charge <= (cell.maxcharge / 2) || (stomach.crystal_charge > charge_limit))
+ if(cell.charge <= (cell.maxcharge / 2) || (stomach_cell.charge() > charge_limit))
return
balloon_alert(ethereal, "received charge")
stomach.adjust_charge(APC_POWER_GAIN)
@@ -51,20 +52,19 @@
if(cell.charge >= cell.maxcharge - APC_POWER_GAIN)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "APC can't receive more power!"), alert_timer_duration)
return
- if(stomach.crystal_charge < APC_POWER_GAIN)
+ if(stomach_cell.charge() < APC_POWER_GAIN)
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "charge is too low!"), alert_timer_duration)
return
stomach.drain_time = world.time + APC_DRAIN_TIME
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, balloon_alert), ethereal, "transfering power"), alert_timer_duration)
if(!do_after(user, APC_DRAIN_TIME, target = src))
return
- if((cell.charge >= (cell.maxcharge - APC_POWER_GAIN)) || (stomach.crystal_charge < APC_POWER_GAIN))
+ if((cell.charge >= (cell.maxcharge - APC_POWER_GAIN)) || (stomach_cell.charge() < APC_POWER_GAIN))
balloon_alert(ethereal, "can't transfer power!")
return
if(istype(stomach))
while(do_after(user, APC_DRAIN_TIME, target = src))
balloon_alert(ethereal, "transferred power")
- stomach.adjust_charge(-APC_POWER_GAIN)
cell.give(-stomach.adjust_charge(-APC_POWER_GAIN))
else
balloon_alert(ethereal, "can't transfer power!")
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 6a2dd073714..fbd98509512 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -1,6 +1,6 @@
#define CELL_DRAIN_TIME 35
-#define CELL_POWER_GAIN 60
-#define CELL_POWER_DRAIN 750
+#define CELL_POWER_GAIN (0.06 * STANDARD_CELL_CHARGE)
+#define CELL_POWER_DRAIN (0.75 * STANDARD_CELL_CHARGE)
/**
* # Power cell
@@ -186,6 +186,19 @@
explode()
return power_used
+/**
+ * Changes the charge of the cell.
+ * Args:
+ * - amount: The energy to give to the cell (can be negative).
+ * Returns: The energy that was given to the cell (can be negative).
+ */
+/obj/item/stock_parts/cell/proc/change(amount)
+ var/energy_used = clamp(amount, -charge, maxcharge - charge)
+ charge += energy_used
+ if(rigged && energy_used)
+ explode()
+ return energy_used
+
/obj/item/stock_parts/cell/examine(mob/user)
. = ..()
if(rigged)
@@ -259,18 +272,19 @@
var/charge_limit = ETHEREAL_CHARGE_DANGEROUS - CELL_POWER_GAIN
var/obj/item/organ/internal/stomach/ethereal/stomach = maybe_stomach
+ var/obj/item/stock_parts/cell/stomach_cell = stomach.cell
if((stomach.drain_time > world.time) || !stomach)
return
if(charge < CELL_POWER_DRAIN)
to_chat(H, span_warning("[src] doesn't have enough power!"))
return
- if(stomach.crystal_charge > charge_limit)
+ if(stomach_cell.charge() > charge_limit)
to_chat(H, span_warning("Your charge is full!"))
return
to_chat(H, span_notice("You begin clumsily channeling power from [src] into your body."))
stomach.drain_time = world.time + CELL_DRAIN_TIME
while(do_after(user, CELL_DRAIN_TIME, target = src))
- if((charge < CELL_POWER_DRAIN) || (stomach.crystal_charge > charge_limit))
+ if((charge < CELL_POWER_DRAIN) || (stomach_cell.charge() > charge_limit))
return
if(istype(stomach))
to_chat(H, span_notice("You receive some charge from [src], wasting some in the process."))
@@ -503,6 +517,21 @@
/obj/item/stock_parts/cell/inducer_supply
maxcharge = STANDARD_CELL_CHARGE * 5
+/obj/item/stock_parts/cell/ethereal
+ name = "ahelp it"
+ desc = "you sohuldn't see this"
+ maxcharge = ETHEREAL_CHARGE_DANGEROUS
+ charge = ETHEREAL_CHARGE_FULL
+ icon_state = null
+ charge_light_type = null
+ connector_type = null
+ custom_materials = null
+ grind_results = null
+
+/obj/item/stock_parts/cell/ethereal/examine(mob/user)
+ . = ..()
+ CRASH("[src.type] got examined by [user]")
+
#undef CELL_DRAIN_TIME
#undef CELL_POWER_GAIN
#undef CELL_POWER_DRAIN
diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
index 0262c48d546..2f2ff330251 100644
--- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
@@ -2632,7 +2632,7 @@
var/mob/living/carbon/exposed_carbon = exposed_mob
var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
- stomach.adjust_charge(reac_volume * 3)
+ stomach.adjust_charge(reac_volume * 0.003 * STANDARD_CELL_CHARGE)
/datum/reagent/consumable/ethanol/telepole
name = "Telepole"
@@ -2652,7 +2652,7 @@
var/mob/living/carbon/exposed_carbon = exposed_mob
var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
- stomach.adjust_charge(reac_volume * 2)
+ stomach.adjust_charge(reac_volume * 0.002 * STANDARD_CELL_CHARGE)
/datum/reagent/consumable/ethanol/pod_tesla
name = "Pod Tesla"
@@ -2679,7 +2679,7 @@
var/mob/living/carbon/exposed_carbon = exposed_mob
var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
- stomach.adjust_charge(reac_volume * 5)
+ stomach.adjust_charge(reac_volume * 0.005 * STANDARD_CELL_CHARGE)
// Welcome to the Blue Room Bar and Grill, home to Mars' finest cocktails
/datum/reagent/consumable/ethanol/rice_beer
diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
index f733bc686f0..f753f2f1c32 100644
--- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
@@ -1258,4 +1258,4 @@
var/mob/living/carbon/exposed_carbon = exposed_mob
var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
- stomach.adjust_charge(reac_volume * 3)
+ stomach.adjust_charge(reac_volume * 0.003 * STANDARD_CELL_CHARGE)
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 40553bf0aa5..9e87cca3f8b 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -946,7 +946,7 @@
var/mob/living/carbon/exposed_carbon = exposed_mob
var/obj/item/organ/internal/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH)
if(istype(stomach))
- stomach.adjust_charge(reac_volume * 30)
+ stomach.adjust_charge(reac_volume * 0.03 * STANDARD_CELL_CHARGE)
/datum/reagent/consumable/liquidelectricity/enriched/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired)
. = ..()
diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm
index ee5865b835a..16cd82c5650 100644
--- a/code/modules/religion/religion_sects.dm
+++ b/code/modules/religion/religion_sects.dm
@@ -154,10 +154,10 @@
/datum/religion_sect/mechanical/sect_bless(mob/living/target, mob/living/chap)
if(iscyborg(target))
var/mob/living/silicon/robot/R = target
- var/charge_amt = 50
+ var/charge_amount = 0.05 * STANDARD_CELL_CHARGE
if(target.mind?.holy_role == HOLY_ROLE_HIGHPRIEST)
- charge_amt *= 2
- R.cell?.charge += charge_amt
+ charge_amount *= 2
+ R.cell?.charge += charge_amount
R.visible_message(span_notice("[chap] charges [R] with the power of [GLOB.deity]!"))
to_chat(R, span_boldnotice("You are charged by the power of [GLOB.deity]!"))
R.add_mood_event("blessing", /datum/mood_event/blessing)
@@ -171,7 +171,7 @@
var/did_we_charge = FALSE
var/obj/item/organ/internal/stomach/ethereal/eth_stomach = blessed.get_organ_slot(ORGAN_SLOT_STOMACH)
if(istype(eth_stomach))
- eth_stomach.adjust_charge(60)
+ eth_stomach.adjust_charge(0.06 * STANDARD_CELL_CHARGE)
did_we_charge = TRUE
//if we're not targeting a robot part we stop early
diff --git a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm
index c31260cca71..2675f46d13d 100644
--- a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm
+++ b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm
@@ -3,11 +3,19 @@
icon_state = "stomach-p" //Welp. At least it's more unique in functionaliy.
desc = "A crystal-like organ that stores the electric charge of ethereals."
organ_traits = list(TRAIT_NOHUNGER) // We have our own hunger mechanic.
- ///basically satiety but electrical
- var/crystal_charge = ETHEREAL_CHARGE_FULL
+ /// Where the energy of the stomach is stored.
+ var/obj/item/stock_parts/cell/cell
///used to keep ethereals from spam draining power sources
var/drain_time = 0
+/obj/item/organ/internal/stomach/ethereal/Initialize(mapload)
+ . = ..()
+ cell = new /obj/item/stock_parts/cell/ethereal(null)
+
+/obj/item/organ/internal/stomach/ethereal/Destroy()
+ QDEL_NULL(cell)
+ return ..()
+
/obj/item/organ/internal/stomach/ethereal/on_life(seconds_per_tick, times_fired)
. = ..()
adjust_charge(-ETHEREAL_DISCHARGE_RATE * seconds_per_tick)
@@ -27,11 +35,12 @@
stomach_owner.clear_alert(ALERT_ETHEREAL_OVERCHARGE)
/obj/item/organ/internal/stomach/ethereal/handle_hunger_slowdown(mob/living/carbon/human/human)
- human.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - crystal_charge / 100)))
+ human.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - cell.charge() / 100)))
-/obj/item/organ/internal/stomach/ethereal/proc/charge(datum/source, amount, repairs)
+/obj/item/organ/internal/stomach/ethereal/proc/charge(datum/source, datum/callback/charge_cell, seconds_per_tick)
SIGNAL_HANDLER
- adjust_charge(amount / 3.5)
+
+ charge_cell.Invoke(cell, seconds_per_tick / 3.5) // Ethereals don't have NT designed charging ports, so they charge slower.
/obj/item/organ/internal/stomach/ethereal/proc/on_electrocute(datum/source, shock_damage, shock_source, siemens_coeff = 1, flags = NONE)
SIGNAL_HANDLER
@@ -46,12 +55,11 @@
* Returns: The amount of energy that actually got changed in joules.
**/
/obj/item/organ/internal/stomach/ethereal/proc/adjust_charge(amount)
- var/amount_changed = clamp(amount, ETHEREAL_CHARGE_NONE - crystal_charge, ETHEREAL_CHARGE_DANGEROUS - crystal_charge)
- crystal_charge = crystal_charge + amount
- return amount_changed
+ var/amount_changed = clamp(amount, ETHEREAL_CHARGE_NONE - cell.charge(), ETHEREAL_CHARGE_DANGEROUS - cell.charge())
+ return cell.change(amount_changed)
/obj/item/organ/internal/stomach/ethereal/proc/handle_charge(mob/living/carbon/carbon, seconds_per_tick, times_fired)
- switch(crystal_charge)
+ switch(cell.charge())
if(-INFINITY to ETHEREAL_CHARGE_NONE)
carbon.add_mood_event("charge", /datum/mood_event/decharged)
carbon.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/emptycell/ethereal)
@@ -99,8 +107,9 @@
playsound(carbon, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5)
carbon.cut_overlay(overcharge)
- tesla_zap(source = carbon, zap_range = 2, power = crystal_charge * 2.5, cutoff = 1 KILO JOULES, zap_flags = ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES)
- adjust_charge(ETHEREAL_CHARGE_FULL - crystal_charge)
+ // Only a small amount of the energy gets discharged as the zap. The rest dissipates as heat. Keeps the damage and energy from the zap the same regardless of what STANDARD_CELL_CHARGE is.
+ var/discharged_energy = -adjust_charge(ETHEREAL_CHARGE_FULL - cell.charge()) * min(7500 / STANDARD_CELL_CHARGE, 1)
+ tesla_zap(source = carbon, zap_range = 2, power = discharged_energy, cutoff = 1 KILO JOULES, zap_flags = ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES)
carbon.visible_message(span_danger("[carbon] violently discharges energy!"), span_warning("You violently discharge energy!"))
if(prob(10)) //chance of developing heart disease to dissuade overcharging oneself