From 5fbfd2447ad61f330c50809fd1349c4242015f86 Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Tue, 9 Apr 2024 02:01:17 +0100 Subject: [PATCH] [NO GBP]Fixes ethereal charging and recharge station charge speed. (#82483) ## About The Pull Request Fixes many instances of things not charging ethereals properly. Scales all things that are meant for charging/taking from the ethereal stomach by STANDARD_CELL_CHARGE, so we never run into this issue again. Ethereal stomachs now store a cell inside them, and uses that for the charge instead of tracking a variable. Fixes recharging stations not being able to charge ethereal stomachs. The ethereal signal proc attempted to feed a callback datum to adjust_charge(), which caused a runtime. Changes that by invoking the charge_cell callback instead. Also fixes recharge station charging speed. They weren't converted correctly. Also formats their charging speed in their description, and displays power rather than referencing cycles. ## Why It's Good For The Game So ethereals charge properly. Closes #82470 ## Changelog :cl: fix: Fixes many instances of energy sources for ethereals supplying a thousand times less energy than intended. fix: Fixes recharging stations not being able to charge ethereals. fix: Fixes recharge stations charging too fast. qol: Recharge stations display their recharging speed in formatted power, rather than unformatted energy per cycle. /:cl: --------- Co-authored-by: san7890 --- code/__DEFINES/apc_defines.dm | 2 +- code/__DEFINES/lights.dm | 2 +- code/__DEFINES/mobs.dm | 14 +++---- code/game/machinery/rechargestation.dm | 6 +-- code/modules/mod/mod_core.dm | 2 +- code/modules/power/apc/apc_attack.dm | 12 +++--- code/modules/power/cell.dm | 37 +++++++++++++++++-- .../reagents/drinks/alcohol_reagents.dm | 6 +-- .../reagents/drinks/drink_reagents.dm | 2 +- .../chemistry/reagents/food_reagents.dm | 2 +- code/modules/religion/religion_sects.dm | 8 ++-- .../internal/stomach/stomach_ethereal.dm | 31 ++++++++++------ 12 files changed, 81 insertions(+), 43 deletions(-) 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