diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index eb1b2ecce51..1260e3daf03 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -254,3 +254,6 @@ /// Returns a random decimal between x and y. #define RANDOM_DECIMAL(x, y) LERP((x), (y), rand()) + +#define SI_COEFFICIENT "coefficient" +#define SI_UNIT "unit" diff --git a/code/__DEFINES/supermatter.dm b/code/__DEFINES/supermatter.dm index bac35207fb5..5eab41fcdf9 100644 --- a/code/__DEFINES/supermatter.dm +++ b/code/__DEFINES/supermatter.dm @@ -28,6 +28,12 @@ #define MATTER_POWER_CONVERSION 10 //Crystal converts 1/this value of stored matter into energy. +/// The internal energy gain coefficient. +#define GAS_HEAT_POWER_SCALING_COEFFICIENT (1/6) + +/// The base zap power transmission of the supermatter crystal in W/MeV. +#define BASE_POWER_TRANSMISSION_RATE 1040 + //These would be what you would get at point blank, decreases with distance #define DETONATION_HALLUCINATION (20 MINUTES) @@ -165,9 +171,9 @@ #define SM_TEMP_LIMIT_LOW_MOLES "Low Moles Heat Resistance" /// How much we are multiplying our zap energy. -#define SM_ZAP_BASE "Base Zap Multiplier" +#define SM_ZAP_BASE "Base Zap Transmission" /// How much we are multiplying our zap energy because of gas factors. -#define SM_ZAP_GAS "Gas Zap Multiplier" +#define SM_ZAP_GAS "Gas Zap Transmission Modifier" /// Delamination types. #define CASCADE_DELAMINATION "cascade" #define SINGULARITY_DELAMINATION "singularity" diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index 6cda3466949..116fb34fad5 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -119,25 +119,48 @@ dx -= 1 return perimeter -///Format a power value in W, kW, MW, or GW. -/proc/display_power(powerused) - if(powerused < 1000) //Less than a kW - return "[powerused] W" - else if(powerused < 1000000) //Less than a MW - return "[round((powerused * 0.001),0.01)] kW" - else if(powerused < 1000000000) //Less than a GW - return "[round((powerused * 0.000001),0.001)] MW" - return "[round((powerused * 0.000000001),0.0001)] GW" +/** + * Formats a number into a list representing the si unit. + * Access the coefficient with [SI_COEFFICIENT], and access the unit with [SI_UNIT]. + * + * Supports SI exponents between 1e-15 to 1e15, but properly handles numbers outside that range as well. + * Arguments: + * * value - The number to convert to text. Can be positive or negative. + * * unit - The base unit of the number, such as "Pa" or "W". + * * maxdecimals - Maximum amount of decimals to display for the final number. Defaults to 1. + * Returns: [SI_COEFFICIENT = si unit coefficient, SI_UNIT = prefixed si unit.] + */ +/proc/siunit_isolated(value, unit, maxdecimals=1) + var/static/list/prefixes = list("f","p","n","μ","m","","k","M","G","T","P") -///Format an energy value in J, kJ, MJ, or GJ. 1W = 1J/s. + // We don't have prefixes beyond this point + // and this also captures value = 0 which you can't compute the logarithm for + // and also byond numbers are floats and doesn't have much precision beyond this point anyway + if(abs(value) <= 1e-18) + . = list(SI_COEFFICIENT = 0, SI_UNIT = " [unit]") + return + + var/exponent = clamp(log(10, abs(value)), -15, 15) // Calculate the exponent and clamp it so we don't go outside the prefix list bounds + var/divider = 10 ** (round(exponent / 3) * 3) // Rounds the exponent to nearest SI unit and power it back to the full form + var/coefficient = round(value / divider, 10 ** -maxdecimals) // Calculate the coefficient and round it to desired decimals + var/prefix_index = round(exponent / 3) + 6 // Calculate the index in the prefixes list for this exponent + + // An edge case which happens if we round 999.9 to 0 decimals for example, which gets rounded to 1000 + // In that case, we manually swap up to the next prefix if there is one available + if(coefficient >= 1000 && prefix_index < 11) + coefficient /= 1e3 + prefix_index++ + + var/prefix = prefixes[prefix_index] + . = list(SI_COEFFICIENT = coefficient, SI_UNIT = " [prefix][unit]") + +///Format a power value in prefixed watts. +/proc/display_power(powerused) + return siunit(powerused, "W", 3) + +///Format an energy value in prefixed joules. /proc/display_joules(units) - if (units < 1000) // Less than a kJ - return "[round(units, 0.1)] J" - else if (units < 1000000) // Less than a MJ - return "[round(units * 0.001, 0.01)] kJ" - else if (units < 1000000000) // Less than a GJ - return "[round(units * 0.000001, 0.001)] MJ" - return "[round(units * 0.000000001, 0.0001)] GJ" + return siunit(units, "J", 3) /proc/joules_to_energy(joules) return joules * (1 SECONDS) / SSmachines.wait diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index f75e6770207..00317d8cf1c 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -1048,27 +1048,8 @@ GLOBAL_LIST_INIT(binary, list("0","1")) * * For pressure conversion, use proc/siunit_pressure() below */ /proc/siunit(value, unit, maxdecimals=1) - var/static/list/prefixes = list("f","p","n","μ","m","","k","M","G","T","P") - - // We don't have prefixes beyond this point - // and this also captures value = 0 which you can't compute the logarithm for - // and also byond numbers are floats and doesn't have much precision beyond this point anyway - if(abs(value) <= 1e-18) - return "0 [unit]" - - var/exponent = clamp(log(10, abs(value)), -15, 15) // Calculate the exponent and clamp it so we don't go outside the prefix list bounds - var/divider = 10 ** (round(exponent / 3) * 3) // Rounds the exponent to nearest SI unit and power it back to the full form - var/coefficient = round(value / divider, 10 ** -maxdecimals) // Calculate the coefficient and round it to desired decimals - var/prefix_index = round(exponent / 3) + 6 // Calculate the index in the prefixes list for this exponent - - // An edge case which happens if we round 999.9 to 0 decimals for example, which gets rounded to 1000 - // In that case, we manually swap up to the next prefix if there is one available - if(coefficient >= 1000 && prefix_index < 11) - coefficient /= 1e3 - prefix_index++ - - var/prefix = prefixes[prefix_index] - return "[coefficient] [prefix][unit]" + var/si_isolated = siunit_isolated(value, unit, maxdecimals) + return "[si_isolated[SI_COEFFICIENT]][si_isolated[SI_UNIT]]" /** The game code never uses Pa, but kPa, since 1 Pa is too small to reasonably handle diff --git a/code/datums/mutations/touch.dm b/code/datums/mutations/touch.dm index 1f1cefe1cbe..3f798ba52b2 100644 --- a/code/datums/mutations/touch.dm +++ b/code/datums/mutations/touch.dm @@ -38,7 +38,7 @@ ///This var decides if the spell should chain, dictated by presence of power chromosome var/chain = FALSE ///Affects damage, should do about 1 per limb - var/zap_power = 7500 + var/zap_power = 3e6 ///Range of tesla shock bounces var/zap_range = 7 ///flags that dictate what the tesla shock can interact with, Can only damage mobs, Cannot damage machines or generate energy diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index b6327480399..349a895238d 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -1122,10 +1122,10 @@ if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE) && !(resistance_flags & INDESTRUCTIBLE)) explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2, adminlog = FALSE, smoke = FALSE) else if(zap_flags & ZAP_OBJ_DAMAGE) - take_damage(power * 0.0005, BURN, ENERGY) + take_damage(power * 6.25e-7, BURN, ENERGY) if(prob(40)) emp_act(EMP_LIGHT) - power -= power * 0.0005 + power -= power * 5e-4 return ..() /obj/machinery/proc/adjust_item_drop_location(atom/movable/dropped_atom) // Adjust item drop location to a 3x3 grid inside the tile, returns slot id from 0 to 8 diff --git a/code/game/objects/effects/anomalies/anomalies_flux.dm b/code/game/objects/effects/anomalies/anomalies_flux.dm index eee4319b352..2bb3ab28a1a 100644 --- a/code/game/objects/effects/anomalies/anomalies_flux.dm +++ b/code/game/objects/effects/anomalies/anomalies_flux.dm @@ -66,7 +66,7 @@ ///range in whuich we zap var/zap_range = 1 ///strength of the zappy - var/zap_power = 2500 + var/zap_power = 1e6 ///the zappy flags var/zap_flags = ZAP_GENERATES_POWER | ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 524c189acc6..a06b7fdaea7 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -145,7 +145,7 @@ if(has_buckled_mobs()) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m - buckled_mob.electrocute_act((clamp(round(strength/400), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) + buckled_mob.electrocute_act((clamp(round(strength * 3.125e-6), 10, 90) + rand(-5, 5)), src, flags = SHOCK_TESLA) ///the obj is deconstructed into pieces, whether through careful disassembly or when destroyed. /obj/proc/deconstruct(disassembled = TRUE) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 71d15fb3f58..ba8623ec4aa 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -63,6 +63,6 @@ /obj/structure/zap_act(power, zap_flags) if(zap_flags & ZAP_OBJ_DAMAGE) - take_damage(power/8000, BURN, "energy") - power -= power/2000 //walls take a lot out of ya + take_damage(power * 1.5625e-7, BURN, "energy") + power -= power * 5e-4 //walls take a lot out of ya . = ..() diff --git a/code/modules/antagonists/abductor/equipment/glands/electric.dm b/code/modules/antagonists/abductor/equipment/glands/electric.dm index acb1505a71c..9c4d47dc337 100644 --- a/code/modules/antagonists/abductor/equipment/glands/electric.dm +++ b/code/modules/antagonists/abductor/equipment/glands/electric.dm @@ -22,5 +22,5 @@ addtimer(CALLBACK(src, PROC_REF(zap)), rand(30, 100)) /obj/item/organ/internal/heart/gland/electric/proc/zap() - tesla_zap(owner, 4, 8000, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) + tesla_zap(owner, 4, 3.2e6, ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN) playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, TRUE) diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm index 3580e3f3bf8..543da00d2f5 100644 --- a/code/modules/antagonists/blob/structures/_blob.dm +++ b/code/modules/antagonists/blob/structures/_blob.dm @@ -227,10 +227,10 @@ /obj/structure/blob/zap_act(power, zap_flags) if(overmind) if(overmind.blobstrain.tesla_reaction(src, power)) - take_damage(power * 0.0025, BURN, ENERGY) + take_damage(power * 3.125e-6, BURN, ENERGY) else - take_damage(power * 0.0025, BURN, ENERGY) - power -= power * 0.0025 //You don't get to do it for free + take_damage(power * 3.125e-6, BURN, ENERGY) + power -= power * 2.5e-3 //You don't get to do it for free return ..() //You don't get to do it for free /obj/structure/blob/extinguish() diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm index 5062ec7731f..c6e1d6183ef 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm @@ -480,8 +480,8 @@ if(critical_threshold_proximity > 650 && prob(20)) zap_number += 1 - var/cutoff = 1500 - cutoff = clamp(3000 - (power_level * (internal_fusion.total_moles() * 0.45)), 450, 3000) + var/cutoff = 1.2e6 + cutoff = clamp(2.4e6 - (power_level * (internal_fusion.total_moles() * 360)), 3.6e5, 2.4e6) var/zaps_aspect = DEFAULT_ZAP_ICON_STATE var/flags = ZAP_SUPERMATTER_FLAGS @@ -495,7 +495,7 @@ playsound(loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10) for(var/i in 1 to zap_number) - supermatter_zap(src, 5, power_level * 300, flags, zap_cutoff = cutoff, power_level = src.power_level * 1000, zap_icon = zaps_aspect) + supermatter_zap(src, 5, power_level * 2.4e5, flags, zap_cutoff = cutoff, power_level = src.power_level * 1000, zap_icon = zaps_aspect) /obj/machinery/atmospherics/components/unary/hypertorus/core/proc/check_gravity_pulse(seconds_per_tick) if(SPT_PROB(100 - critical_threshold_proximity / 15, seconds_per_tick)) diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 9537fa7b6ef..6c33e287f03 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -226,7 +226,7 @@ emp_message = span_warning("The tesla capacitors beep ominously for a moment.") clothing_traits = list(TRAIT_TESLA_SHOCKIMMUNE) /// How strong are the zaps we give off? - var/zap_power = 25000 + var/zap_power = 1e7 /// How far to the zaps we give off go? var/zap_range = 20 /// What flags do we pass to the zaps we give off? diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm index c49bc455165..974c2e66737 100644 --- a/code/modules/power/rtg.dm +++ b/code/modules/power/rtg.dm @@ -71,7 +71,7 @@ visible_message(span_danger("\The [src] lets out a shower of sparks as it starts to lose stability!"),\ span_hear("You hear a loud electrical crack!")) playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) - tesla_zap(src, 5, power_gen * 0.05) + tesla_zap(src, 5, power_gen * 20) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(explosion), src, 2, 3, 4, null, 8), 10 SECONDS) // Not a normal explosion. /obj/machinery/power/rtg/abductor/bullet_act(obj/projectile/Proj) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 654ea805440..8598b3cccf2 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -53,8 +53,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/damage_archived = 0 var/list/damage_factors - /// How much extra power does the main zap generate. - var/zap_multiplier = 1 + /// The zap power transmission over internal energy. W/MeV. + var/zap_transmission_rate = BASE_POWER_TRANSMISSION_RATE var/list/zap_factors /// The temperature at which we start taking damage @@ -95,7 +95,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /// How much power decay is negated. Complete power decay negation at 1. var/gas_powerloss_inhibition = 0 /// Affects the amount of power the main SM zap makes. - var/gas_power_transmission = 0 + var/gas_power_transmission_rate = 0 /// Affects the power gain the SM experiances from heat. var/gas_heat_power_generation = 0 @@ -109,7 +109,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/external_damage_immediate = 0 ///The cutoff for a bolt jumping, grows with heat, lowers with higher mol count, - var/zap_cutoff = 1500 + var/zap_cutoff = 1.2e6 ///How much the bullets damage should be multiplied by when it is added to the internal variables var/bullet_energy = SUPERMATTER_DEFAULT_BULLET_ENERGY ///How much hallucination should we produce per unit of power? @@ -153,6 +153,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) ///Stores the time of when the last zap occurred var/last_power_zap = 0 + var/last_high_energy_zap = 0 ///Do we show this crystal in the CIMS modular program var/include_in_cims = TRUE @@ -275,7 +276,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) // PART 3: POWER PROCESSING internal_energy_factors = calculate_internal_energy() - zap_factors = calculate_zap_multiplier() + zap_factors = calculate_zap_transmission_rate() if(internal_energy && (last_power_zap + (4 - internal_energy * 0.001) SECONDS) < world.time) playsound(src, 'sound/weapons/emitter2.ogg', 70, TRUE) hue_angle_shift = clamp(903 * log(10, (internal_energy + 8000)) - 3590, -50, 240) @@ -286,9 +287,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) supermatter_zap( zapstart = src, range = 3, - zap_str = 1.25 * internal_energy * zap_multiplier * delta_time, + zap_str = internal_energy * zap_transmission_rate * delta_time, zap_flags = ZAP_SUPERMATTER_FLAGS, - zap_cutoff = 300 * delta_time, + zap_cutoff = 2.4e5 * delta_time, power_level = internal_energy, color = zap_color, ) @@ -374,15 +375,20 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) "name" = factor, "amount" = amount * -1 )) + var/list/internal_energy_si_derived_data = siunit_isolated(internal_energy * 1e6, "eV", 3) data["internal_energy"] = internal_energy + data["internal_energy_coefficient"] = internal_energy_si_derived_data[SI_COEFFICIENT] + data["internal_energy_unit"] = internal_energy_si_derived_data[SI_UNIT] data["internal_energy_factors"] = list() for (var/factor in internal_energy_factors) + var/list/internal_energy_factor_si_derived_data = siunit_isolated(internal_energy_factors[factor] * 1e6, "eV", 3) var/amount = round(internal_energy_factors[factor], 0.01) if(!amount) continue data["internal_energy_factors"] += list(list( "name" = factor, - "amount" = amount + "amount" = internal_energy_factor_si_derived_data[SI_COEFFICIENT], + "unit" = internal_energy_factor_si_derived_data[SI_UNIT], )) data["temp_limit"] = temp_limit data["temp_limit_factors"] = list() @@ -392,7 +398,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) continue data["temp_limit_factors"] += list(list( "name" = factor, - "amount" = amount + "amount" = amount, )) data["waste_multiplier"] = waste_multiplier data["waste_multiplier_factors"] = list() @@ -402,18 +408,42 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) continue data["waste_multiplier_factors"] += list(list( "name" = factor, - "amount" = amount + "amount" = amount, )) - data["zap_multiplier"] = zap_multiplier - data["zap_multiplier_factors"] = list() + + data["zap_transmission_factors"] = list() for (var/factor in zap_factors) - var/amount = round(zap_factors[factor], 0.01) - if(!amount) + var/list/zap_factor_si_derived_data = siunit_isolated(zap_factors[factor] * internal_energy, "W", 2) + if(!zap_factor_si_derived_data[SI_COEFFICIENT]) continue - data["zap_multiplier_factors"] += list(list( + data["zap_transmission_factors"] += list(list( "name" = factor, - "amount" = amount + "amount" = zap_factor_si_derived_data[SI_COEFFICIENT], + "unit" = zap_factor_si_derived_data[SI_UNIT], )) + + ///Add high energy bonus to the zap transmission data so we can accurately measure our power generation from zaps. + var/high_energy_bonus = 0 + var/zap_transmission = zap_transmission_rate * internal_energy + var/zap_power_multiplier = 1 + if(internal_energy > POWER_PENALTY_THRESHOLD) //Supermatter zaps multiply power internally under some conditions for some reason, so we'll snowflake this for now. + ///Power multiplier bonus applied to all zaps. Zap power generation doubles when it reaches 7GeV and 9GeV. + zap_power_multiplier *= 2 ** clamp(round((internal_energy - POWER_PENALTY_THRESHOLD) / 2000), 0, 2) + ///The supermatter releases additional zaps after 5GeV, with more at 7GeV and 9GeV. + var/additional_zap_bonus = clamp(internal_energy * 3200, 6.4e6, 3.2e7) * clamp(round(INVERSE_LERP(1000, 3000, internal_energy)), 1, 4) + high_energy_bonus = (zap_transmission + additional_zap_bonus) * zap_power_multiplier - zap_transmission + var/list/zap_factor_si_derived_data = siunit_isolated(high_energy_bonus, "W", 2) + data["zap_transmission_factors"] += list(list( + "name" = "High Energy Bonus", + "amount" = zap_factor_si_derived_data[SI_COEFFICIENT], + "unit" = zap_factor_si_derived_data[SI_UNIT], + )) + + var/list/zap_transmission_si_derived_data = siunit_isolated(zap_transmission + high_energy_bonus, "W", 2) + data["zap_transmission"] = zap_transmission + high_energy_bonus + data["zap_transmission_coefficient"] = zap_transmission_si_derived_data[SI_COEFFICIENT] + data["zap_transmission_unit"] = zap_transmission_si_derived_data[SI_UNIT] + data["absorbed_ratio"] = absorption_ratio var/list/formatted_gas_percentage = list() for (var/datum/gas/gas_path as anything in subtypesof(/datum/gas)) @@ -577,7 +607,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) * * Updates: * [/obj/machinery/power/supermatter_crystal/var/list/gas_percentage] - * [/obj/machinery/power/supermatter_crystal/var/gas_power_transmission] + * [/obj/machinery/power/supermatter_crystal/var/gas_power_transmission_rate] * [/obj/machinery/power/supermatter_crystal/var/gas_heat_modifier] * [/obj/machinery/power/supermatter_crystal/var/gas_heat_resistance] * [/obj/machinery/power/supermatter_crystal/var/gas_heat_power_generation] @@ -590,7 +620,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) return gas_percentage = list() - gas_power_transmission = 0 + gas_power_transmission_rate = 0 gas_heat_modifier = 0 gas_heat_resistance = 0 gas_heat_power_generation = 0 @@ -607,7 +637,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/datum/sm_gas/sm_gas = current_gas_behavior[gas_path] if(!sm_gas) continue - gas_power_transmission += sm_gas.power_transmission * gas_percentage[gas_path] + gas_power_transmission_rate += sm_gas.power_transmission * gas_percentage[gas_path] gas_heat_modifier += sm_gas.heat_modifier * gas_percentage[gas_path] gas_heat_resistance += sm_gas.heat_resistance * gas_percentage[gas_path] gas_heat_power_generation += sm_gas.heat_power_generation * gas_percentage[gas_path] @@ -637,7 +667,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) external_power_trickle -= min(additive_power[SM_POWER_EXTERNAL_TRICKLE], external_power_trickle) additive_power[SM_POWER_EXTERNAL_IMMEDIATE] = external_power_immediate external_power_immediate = 0 - additive_power[SM_POWER_HEAT] = gas_heat_power_generation * absorbed_gasmix.temperature / 6 + additive_power[SM_POWER_HEAT] = gas_heat_power_generation * absorbed_gasmix.temperature * GAS_HEAT_POWER_SCALING_COEFFICIENT additive_power[SM_POWER_HEAT] && log_activation(who = "environmental factors") // I'm sorry for this, but we need to calculate power lost immediately after power gain. @@ -660,6 +690,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(internal_energy && !activation_logged) stack_trace("Supermatter powered for the first time without being logged. Internal energy factors: [json_encode(internal_energy_factors)]") activation_logged = TRUE // so we dont spam the log. + else if(!internal_energy) + last_power_zap = world.time return additive_power /** Log when the supermatter is activated for the first time. @@ -685,24 +717,24 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) activation_logged = TRUE /** - * Perform calculation for the main zap power multiplier. + * Perform calculation for the main zap power transmission rate in W/MeV. * Description of each factors can be found in the defines. * * Updates: - * [/obj/machinery/power/supermatter_crystal/var/zap_multiplier] + * [/obj/machinery/power/supermatter_crystal/var/zap_transmission_rate] * * Returns: The factors that have influenced the calculation. list[FACTOR_DEFINE] = number */ -/obj/machinery/power/supermatter_crystal/proc/calculate_zap_multiplier() - var/list/additive_transmission = list() - additive_transmission[SM_ZAP_BASE] = 1 - additive_transmission[SM_ZAP_GAS] = gas_power_transmission +/obj/machinery/power/supermatter_crystal/proc/calculate_zap_transmission_rate() + var/list/additive_transmission_rate = list() + additive_transmission_rate[SM_ZAP_BASE] = BASE_POWER_TRANSMISSION_RATE + additive_transmission_rate[SM_ZAP_GAS] = BASE_POWER_TRANSMISSION_RATE * gas_power_transmission_rate - zap_multiplier = 0 - for (var/transmission_types in additive_transmission) - zap_multiplier += additive_transmission[transmission_types] - zap_multiplier = max(zap_multiplier, 0) - return additive_transmission + zap_transmission_rate = 0 + for (var/transmission_types in additive_transmission_rate) + zap_transmission_rate += additive_transmission_rate[transmission_types] + zap_transmission_rate = max(zap_transmission_rate, 0) + return additive_transmission_rate /** * Perform calculation for the waste multiplier. @@ -836,7 +868,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) delamination_strategy.on_select(src) return TRUE -/obj/machinery/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 4000, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list(), zap_cutoff = 1500, power_level = 0, zap_icon = DEFAULT_ZAP_ICON_STATE, color = null) +/obj/machinery/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 3.2e6, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list(), zap_cutoff = 1.2e6, power_level = 0, zap_icon = DEFAULT_ZAP_ICON_STATE, color = null) if(QDELETED(zapstart)) return . = zapstart.dir @@ -931,13 +963,13 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) //Going boom should be rareish if(prob(80)) zap_flags &= ~ZAP_MACHINE_EXPLOSIVE - if(target_type == COIL) - var/multi = 2 - switch(power_level)//Between 7k and 9k it's 4, above that it's 8 + if(target_type == COIL || target_type == ROD) + var/multi = 1 + switch(power_level)//Between 7k and 9k it's 2, above that it's 4 if(SEVERE_POWER_PENALTY_THRESHOLD to CRITICAL_POWER_PENALTY_THRESHOLD) - multi = 4 + multi = 2 if(CRITICAL_POWER_PENALTY_THRESHOLD to INFINITY) - multi = 8 + multi = 4 if(zap_flags & ZAP_SUPERMATTER_FLAGS) var/remaining_power = target.zap_act(zap_str * multi, zap_flags) zap_str = remaining_power / multi //Coils should take a lot out of the power of the zap diff --git a/code/modules/power/supermatter/supermatter_extra_effects.dm b/code/modules/power/supermatter/supermatter_extra_effects.dm index 7fe56d9c2d4..efd84c677fa 100644 --- a/code/modules/power/supermatter/supermatter_extra_effects.dm +++ b/code/modules/power/supermatter/supermatter_extra_effects.dm @@ -91,6 +91,7 @@ /obj/machinery/power/supermatter_crystal/proc/handle_high_power() if(internal_energy <= POWER_PENALTY_THRESHOLD && damage <= danger_point) //If the power is above 5000 or if the damage is above 550 + last_high_energy_zap = world.time //Prevent oddly high initial zap due to high energy zaps not getting triggered via too low energy. return var/range = 4 zap_cutoff = 1500 @@ -99,7 +100,7 @@ var/temp = absorbed_gasmix.temperature if(pressure > 0 && temp > 0) //You may be able to freeze the zapstate of the engine with good planning, we'll see - zap_cutoff = clamp(3000 - (internal_energy * total_moles / 10) / temp, 350, 3000)//If the core is cold, it's easier to jump, ditto if there are a lot of mols + zap_cutoff = clamp(1.2e6 - (internal_energy * total_moles * 40) / temp, 1.4e5, 1.2e6)//If the core is cold, it's easier to jump, ditto if there are a lot of mols //We should always be able to zap our way out of the default enclosure //See supermatter_zap() for more details range = clamp(internal_energy / pressure * 10, 2, 7) @@ -128,9 +129,10 @@ if(zap_count >= 1) playsound(loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10) + var/delta_time = min((world.time - last_high_energy_zap) * 0.1, 16) for(var/i in 1 to zap_count) - supermatter_zap(src, range, clamp(internal_energy*2, 4000, 20000), flags, zap_cutoff = src.zap_cutoff, power_level = internal_energy, zap_icon = src.zap_icon) - + supermatter_zap(src, range, clamp(internal_energy * 3200, 6.4e6, 3.2e7) * delta_time, flags, zap_cutoff = src.zap_cutoff * delta_time, power_level = internal_energy, zap_icon = src.zap_icon) + last_high_energy_zap = world.time if(prob(5)) supermatter_anomaly_gen(src, FLUX_ANOMALY, rand(5, 10)) if(prob(5)) diff --git a/code/modules/power/supermatter/supermatter_gas.dm b/code/modules/power/supermatter/supermatter_gas.dm index 141f78a38b8..df8ef8e5b4f 100644 --- a/code/modules/power/supermatter/supermatter_gas.dm +++ b/code/modules/power/supermatter/supermatter_gas.dm @@ -17,33 +17,40 @@ // Positive is true if more of the amount is a good thing. var/list/numeric_data = list() if(sm_gas.power_transmission) + var/list/si_derived_data = siunit_isolated(sm_gas.power_transmission * BASE_POWER_TRANSMISSION_RATE, "W/MeV", 2) numeric_data += list(list( - "name" = "Power Transmission", - "amount" = sm_gas.power_transmission, + "name" = "Power Transmission Bonus", + "amount" = si_derived_data["coefficient"], + "unit" = si_derived_data["unit"], "positive" = TRUE, )) if(sm_gas.heat_modifier) numeric_data += list(list( "name" = "Waste Multiplier", - "amount" = sm_gas.heat_modifier, + "amount" = 100 * sm_gas.heat_modifier, + "unit" = "%", "positive" = FALSE, )) if(sm_gas.heat_resistance) numeric_data += list(list( "name" = "Heat Resistance", - "amount" = sm_gas.heat_resistance, + "amount" = 100 * sm_gas.heat_resistance, + "unit" = "%", "positive" = TRUE, )) if(sm_gas.heat_power_generation) + var/list/si_derived_data = siunit_isolated(sm_gas.heat_power_generation * GAS_HEAT_POWER_SCALING_COEFFICIENT * 1e7 / SSair.wait, "eV/K/s", 2) numeric_data += list(list( "name" = "Heat Power Gain", - "amount" = sm_gas.heat_power_generation, + "amount" = si_derived_data["coefficient"], + "unit" = si_derived_data["unit"], "positive" = TRUE, )) if(sm_gas.powerloss_inhibition) numeric_data += list(list( "name" = "Power Decay Negation", - "amount" = sm_gas.powerloss_inhibition, + "amount" = 100 * sm_gas.powerloss_inhibition, + "unit" = "%", "positive" = TRUE, )) singular_gas_data["numeric_data"] = numeric_data @@ -59,8 +66,7 @@ GLOBAL_LIST_INIT(sm_gas_behavior, init_sm_gas()) /datum/sm_gas /// Path of the [/datum/gas] involved with this interaction. var/gas_path - - /// Influences zap power without interfering with the crystal's own energy. + /// Influences zap power without interfering with the crystal's own energy. Gets scaled by [BASE_POWER_TRANSMISSION_RATE]. var/power_transmission = 0 /// How much more waste heat and gas the SM generates. var/heat_modifier = 0 @@ -216,7 +222,7 @@ GLOBAL_LIST_INIT(sm_gas_behavior, init_sm_gas()) sm.supermatter_zap( sm, range = 6, - zap_str = clamp(sm.internal_energy * 2, 4000, 20000), + zap_str = clamp(sm.internal_energy * 1600, 3.2e6, 1.6e7), zap_flags = ZAP_MOB_STUN, zap_cutoff = sm.zap_cutoff, power_level = sm.internal_energy, diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index 098ff7ceaee..3cf040b76ef 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -1,7 +1,5 @@ // zap needs to be over this amount to get power -#define TESLA_COIL_THRESHOLD 80 -// each zap power unit produces 400 joules -#define ZAP_TO_ENERGY(p) (joules_to_energy((p) * 400)) +#define TESLA_COIL_THRESHOLD 32000 /obj/machinery/power/energy_accumulator/tesla_coil name = "tesla coil" @@ -107,7 +105,7 @@ power /= 10 zap_buckle_check(power) var/power_removed = powernet ? power * input_power_multiplier : power - stored_energy += max(ZAP_TO_ENERGY(power_removed - TESLA_COIL_THRESHOLD), 0) + stored_energy += max(joules_to_energy(power_removed - TESLA_COIL_THRESHOLD), 0) return max(power - power_removed, 0) //You get back the amount we didn't use /obj/machinery/power/energy_accumulator/tesla_coil/proc/zap() @@ -170,10 +168,9 @@ if(anchored && !panel_open) flick("grounding_rodhit", src) zap_buckle_check(power) - stored_energy += ZAP_TO_ENERGY(power) + stored_energy += joules_to_energy(power) return 0 else . = ..() #undef TESLA_COIL_THRESHOLD -#undef ZAP_TO_ENERGY diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index b21938e2608..7ee8c0085c9 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -1,5 +1,5 @@ -#define TESLA_DEFAULT_POWER 1738260 -#define TESLA_MINI_POWER 869130 +#define TESLA_DEFAULT_POWER 6.95304e8 +#define TESLA_MINI_POWER 3.47652e8 //Zap constants, speeds up targeting #define BIKE (COIL + 1) #define COIL (ROD + 1) @@ -205,7 +205,7 @@ if(!(zap_flags & ZAP_ALLOW_DUPLICATES)) LAZYSET(shocked_targets, source, TRUE) //I don't want no null refs in my list yeah? . = source.dir - if(power < 1000) + if(power < 4e5) return /* @@ -334,7 +334,7 @@ var/mob/living/closest_mob = closest_atom ADD_TRAIT(closest_mob, TRAIT_BEING_SHOCKED, WAS_SHOCKED) addtimer(TRAIT_CALLBACK_REMOVE(closest_mob, TRAIT_BEING_SHOCKED, WAS_SHOCKED), 1 SECONDS) - var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power/600), 90) + rand(-5, 5)) : 0 + var/shock_damage = (zap_flags & ZAP_MOB_DAMAGE) ? (min(round(power/2.4e5), 90) + rand(-5, 5)) : 0 closest_mob.electrocute_act(shock_damage, source, 1, SHOCK_TESLA | ((zap_flags & ZAP_MOB_STUN) ? NONE : SHOCK_NOSTUN)) if(issilicon(closest_mob)) var/mob/living/silicon/S = closest_mob diff --git a/code/modules/projectiles/projectile/energy/tesla.dm b/code/modules/projectiles/projectile/energy/tesla.dm index 9afb816088f..687bd1b8e73 100644 --- a/code/modules/projectiles/projectile/energy/tesla.dm +++ b/code/modules/projectiles/projectile/energy/tesla.dm @@ -5,7 +5,7 @@ damage = 10 //A worse lasergun var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN var/zap_range = 3 - var/power = 10000 + var/power = 4e6 /obj/projectile/energy/tesla/on_hit(atom/target) . = ..() @@ -22,7 +22,7 @@ /obj/projectile/energy/tesla/cannon name = "tesla orb" - power = 20000 + power = 8e6 damage = 15 //Mech man big /obj/projectile/energy/tesla_cannon diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index afe59235478..c8da91b9dde 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -481,7 +481,7 @@ speed = 0.3 /// The power of the zap itself when it electrocutes someone - var/zap_power = 20000 + var/zap_power = 8e6 /// The range of the zap itself when it electrocutes someone var/zap_range = 15 /// The flags of the zap itself when it electrocutes someone @@ -503,7 +503,7 @@ return ..() /obj/projectile/magic/aoe/lightning/no_zap - zap_power = 10000 + zap_power = 4e6 zap_range = 4 zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 707a1dca350..9083de70902 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -542,9 +542,9 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS /datum/chemical_reaction/reagent_explosion/teslium_lightning/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - var/T1 = created_volume * 20 //100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison. - var/T2 = created_volume * 50 - var/T3 = created_volume * 120 + var/T1 = created_volume * 8e3 //100 units : Zap 3 times, with powers 8e5/2e6/4.8e6. Tesla revolvers have a power of 10000 for comparison. + var/T2 = created_volume * 2e4 + var/T3 = created_volume * 4.8e4 var/added_delay = 0.5 SECONDS if(created_volume >= 75) addtimer(CALLBACK(src, PROC_REF(zappy_zappy), holder, T1), added_delay) diff --git a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm index 4d43b6a3a0a..4cc8ee404c1 100644 --- a/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm +++ b/code/modules/surgery/organs/internal/stomach/stomach_ethereal.dm @@ -92,7 +92,7 @@ playsound(carbon, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) carbon.cut_overlay(overcharge) - tesla_zap(carbon, 2, crystal_charge*2.5, ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) + tesla_zap(carbon, 2, crystal_charge * 1e3, ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) adjust_charge(ETHEREAL_CHARGE_FULL - crystal_charge) carbon.visible_message(span_danger("[carbon] violently discharges energy!"), span_warning("You violently discharge energy!")) diff --git a/tgui/packages/tgui/interfaces/Supermatter.tsx b/tgui/packages/tgui/interfaces/Supermatter.tsx index 5dd1bf8c399..57820fd038c 100644 --- a/tgui/packages/tgui/interfaces/Supermatter.tsx +++ b/tgui/packages/tgui/interfaces/Supermatter.tsx @@ -16,6 +16,7 @@ type SMGasMetadata = { numeric_data: { name: string; amount: number; + unit: string; positive: BooleanLike; }[]; }; @@ -28,9 +29,13 @@ type SupermatterProps = { integrity: number; integrity_factors: { name: string; amount: number }[]; internal_energy: number; - internal_energy_factors: { name: string; amount: number }[]; - zap_multiplier: number; - zap_multiplier_factors: { name: string; amount: number }[]; + internal_energy_coefficient: number; + internal_energy_unit: string; + internal_energy_factors: { name: string; amount: number; unit: string }[]; + zap_transmission: number; + zap_transmission_coefficient: number; + zap_transmission_unit: string; + zap_transmission_factors: { name: string; amount: number; unit: string }[]; temp_limit: number; temp_limit_factors: { name: string; amount: number }[]; waste_multiplier: number; @@ -92,9 +97,13 @@ export const SupermatterContent = (props: SupermatterProps, context) => { integrity, integrity_factors, internal_energy, + internal_energy_coefficient, + internal_energy_unit, internal_energy_factors, - zap_multiplier, - zap_multiplier_factors, + zap_transmission, + zap_transmission_coefficient, + zap_transmission_unit, + zap_transmission_factors, temp_limit, temp_limit_factors, waste_multiplier, @@ -166,19 +175,20 @@ export const SupermatterContent = (props: SupermatterProps, context) => { average: [5000, 7000], bad: [7000, Infinity], }}> - {toFixed(internal_energy) + ' MeV/cm3'} + {toFixed(internal_energy_coefficient, 3) + + internal_energy_unit} } detail={ !!internal_energy_factors.length && ( - {internal_energy_factors.map(({ name, amount }) => ( + {internal_energy_factors.map(({ name, amount, unit }) => ( 0 ? 'green' : 'red'}> - {toFixed(amount, 2) + ' MeV/cm3'} + {toFixed(amount, 3) + unit} ))} @@ -187,28 +197,30 @@ export const SupermatterContent = (props: SupermatterProps, context) => { } /> - {toFixed(zap_multiplier, 2) + ' x'} + {toFixed(zap_transmission_coefficient, 2) + + zap_transmission_unit} } detail={ - !!zap_multiplier_factors.length && ( + !!zap_transmission_factors.length && ( - {zap_multiplier_factors.map(({ name, amount }) => ( + {zap_transmission_factors.map(({ name, amount, unit }) => ( 0 ? 'green' : 'red'}> - {toFixed(amount, 2) + ' x'} + {toFixed(amount, 2) + unit} ))} @@ -356,8 +368,8 @@ export const SupermatterContent = (props: SupermatterProps, context) => { : 'red' }> {effect.amount > 0 - ? '+' + effect.amount * 100 + '%' - : effect.amount * 100 + '%'} + ? '+' + effect.amount + effect.unit + : effect.amount + effect.unit} ) )}