mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
Rewrites plasma rigging code to be much more flexible and dynamic, and cover more cases (#94861)
## About The Pull Request Instead of being snowflake interactions on objects themselves, rigging things with plasma or welding fuel is now handled on reagents' side via ``on_spark_act``, allowing each reagent to decide how they want to handle exposure to electric currents or violent heating. - Obviously plasma and welding fuel cause explosions, but former gains additional power from electric current being passed through it (same math as powercells), while latter doesn't explode unless in an enclosed space, or a high enough current/temperature has been reached, and merely creates a hotspot instead. - Napalm and phlogiston create hotspots, or (try to) damage the holder if they're enclosed - Sorium, liquid dark matter, TATP, nitroglycerin and flash/smoke/sonic powders trigger their usual detonation effects, albeit slightly weaker. - Teslium creates a ZAP, with additional power for a BIG ZAP if it has been triggered by electric current. - RDX becomes spicier with temperature and current, similarly to how it becomes more dangerous when mixed with LE or teslium. - Gunpowder produces a delayed explosion effect (unless its hot or the current is high enough, in which case its instant) and causes sparks as the message claims it does (normal gunpowder explosions also do that) Plasma and gunpowder rigged items can now be controlled using stabilizing agent - in its presence, plasma will not explode unless the used charge is higher than 0.2% of a standard cell's per unit of agent, while gunpowder will instead spend 0.1 + (charge / 10% of a standard cell's charge) units of agent to delay its detonation. Smoke (powder) now produces a visible message and slightly damages lungs of whoever it reacted inside of, if the container was a mob. The numbers on plasma/welding fuel rigs should be ***roughly*** the same. Also lighters can now be rigged in a fashion similar to welding tools. Also it turns out we broke light rigging at some point, so now it works again. ## Why It's Good For The Game This makes the system much more flexible and allows players to make more creative IEDs, expanding upon the sandbox aspect of the game. Also I have an upcoming project bringing IEDs (kind of, in a new form) back, which is why I wrote this in the first place (but decided to atomize the PRs). As for smoke damage, it feels weird to not have any tells when someone suddenly starts hacking up volumetric amounts of smoke, it makes sense that they'd struggle a bit after coughing a few dozen cubic meters of thick vape clouds. ## Changelog 🆑 add: Multiple new reagents such as napalm, sorium, TATP, smoke/sonic/flash powders and other explosives can now be used to rig cells or tools. add: Plasma and gunpowder rigged items can now have controlled current requirement/delay by adding some stabilizing agent alongside the main reagent. balance: Creating chemical smoke inside of a mob now makes them violently cough it up, damaging their lungs a bit. fix: Chemically-rigged lightbulbs now once again explode. refactor: Refactored how power cells, welding tools, lightbulbs, cigarettes (and now, lighters) handle being rigged with chemicals. /🆑
This commit is contained in:
@@ -788,6 +788,34 @@
|
||||
set_temperature(round(chem_temp))
|
||||
handle_reactions()
|
||||
|
||||
/*
|
||||
* Call in case of electrical current exposure, rapid heating or blunt force, things that would set off explosives and alike
|
||||
* Arguments:
|
||||
* * power_charge - If we were triggered from electric current, how much power was dumped into us?
|
||||
* * enclosed - Is the reaction happening in an enclosed container or not? Doesn't use reagent holder's flags as it might be called on reagents "exiting" the container
|
||||
* * banned_reagents - List of reagent types which we may want to have custom handling for and should avoid checking in here
|
||||
*/
|
||||
/datum/reagents/proc/spark_act(power_charge, enclosed, list/banned_reagents)
|
||||
if (!islist(banned_reagents))
|
||||
banned_reagents = list(banned_reagents)
|
||||
var/result = NONE
|
||||
var/update = FALSE
|
||||
for (var/datum/reagent/reagent as anything in reagent_list)
|
||||
if (is_type_in_list(reagent, banned_reagents))
|
||||
continue
|
||||
var/reagent_result = reagent.on_spark_act(power_charge, enclosed)
|
||||
if (!reagent_result)
|
||||
continue
|
||||
result |= (reagent_result & SPARK_ACT_RETURNS)
|
||||
if (!(reagent_result & SPARK_ACT_KEEP_REAGENT))
|
||||
reagent.volume = 0
|
||||
update = TRUE
|
||||
|
||||
if (result & SPARK_ACT_CLEAR_ALL)
|
||||
clear_reagents()
|
||||
else if (update)
|
||||
update_total()
|
||||
return result
|
||||
|
||||
//===============================Logging==========================================
|
||||
/// Outputs a log-friendly list of reagents based on the internal reagent_list.
|
||||
|
||||
@@ -236,6 +236,17 @@
|
||||
/datum/reagent/proc/on_mob_dead(mob/living/carbon/affected_mob, seconds_per_tick)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
/*
|
||||
* Called when a reagent is exposed to electric current, rapidly heated or smashed, something that would cause explosives to get easily set off
|
||||
* Returning a SPARK_ACT_ flag will signal that an action has occurred as a result, for parent behavior and logging purposes
|
||||
* Probably shouldn't be called from within a mob's bloodstream, unless you're ready for some very explosive results
|
||||
* Arguments:
|
||||
* * power_charge - If we were triggered from electric current, how much power was dumped into us?
|
||||
* * enclosed - Is the reaction happening in an enclosed container or not? Doesn't use reagent holder's flags as it might be called on reagents "exiting" the container
|
||||
*/
|
||||
/datum/reagent/proc/on_spark_act(power_charge = 0, enclosed = TRUE)
|
||||
return NONE
|
||||
|
||||
/**
|
||||
* Called after add_reagents creates a new reagent.
|
||||
*
|
||||
|
||||
@@ -1298,7 +1298,6 @@
|
||||
|
||||
/datum/reagent/fuel/expose_turf(turf/exposed_turf, reac_volume)
|
||||
. = ..()
|
||||
|
||||
if(!istype(exposed_turf) || isspaceturf(exposed_turf))
|
||||
return
|
||||
|
||||
@@ -1309,6 +1308,16 @@
|
||||
if(pool)
|
||||
pool.burn_amount = max(min(round(reac_volume / 5), 10), 1)
|
||||
|
||||
/datum/reagent/fuel/on_spark_act(power_charge, enclosed)
|
||||
// Doesn't go boom in open air unless we pass a REALLY high current or if we're hot enough
|
||||
if (!enclosed && power_charge < STANDARD_BATTERY_VALUE && holder.chem_temp < 474)
|
||||
var/turf/our_turf = get_turf(holder.my_atom)
|
||||
our_turf?.hotspot_expose(holder.chem_temp * 10, volume)
|
||||
return NONE
|
||||
|
||||
reagent_explode(holder, volume, strengthdiv = 10, clear_holder_reagents = FALSE)
|
||||
return SPARK_ACT_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
/datum/reagent/space_cleaner
|
||||
name = "Space Cleaner"
|
||||
description = "A compound used to clean things. Now with 50% more sodium hypochlorite! Can be used to clean wounds, but it's not really meant for that."
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
if(affected_mob.adjust_organ_loss(ORGAN_SLOT_HEART, -0.5 * metabolization_ratio * seconds_per_tick * normalise_creation_purity(), required_organ_flag = affected_organ_flags))
|
||||
return UPDATE_MOB_HEALTH
|
||||
|
||||
/datum/reagent/nitroglycerin/on_spark_act(power_charge, enclosed)
|
||||
reagent_explode(holder, volume, strengthdiv = 2, clear_holder_reagents = FALSE)
|
||||
return SPARK_ACT_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
/datum/reagent/stabilizing_agent
|
||||
name = "Stabilizing Agent"
|
||||
description = "Keeps unstable chemicals stable. This does not work on everything."
|
||||
@@ -85,6 +89,11 @@
|
||||
taste_description = "air and bitterness"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/sorium/on_spark_act(power_charge, enclosed)
|
||||
var/range = clamp(sqrt(volume), 1, 6)
|
||||
goonchem_vortex(get_turf(holder.my_atom), 1, range)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
/datum/reagent/liquid_dark_matter
|
||||
name = "Liquid Dark Matter"
|
||||
description = "Sucks everything into the detonation point."
|
||||
@@ -92,6 +101,11 @@
|
||||
taste_description = "compressed bitterness"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/liquid_dark_matter/on_spark_act(power_charge, enclosed)
|
||||
var/range = clamp(sqrt(volume / 2), 1, 6)
|
||||
goonchem_vortex(get_turf(holder.my_atom), 0, range)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
/datum/reagent/gunpowder
|
||||
name = "Gunpowder"
|
||||
description = "Explodes. Violently."
|
||||
@@ -116,10 +130,29 @@
|
||||
return
|
||||
var/location = get_turf(holder.my_atom)
|
||||
var/datum/effect_system/reagents_explosion/e = new()
|
||||
e.set_up(1 + round(volume/6, 1), location, 0, 0, message = 0)
|
||||
e.set_up(1 + round(volume / 6, 1), location, message = FALSE)
|
||||
e.start(holder.my_atom)
|
||||
holder.clear_reagents()
|
||||
|
||||
/datum/reagent/gunpowder/on_spark_act(power_charge, enclosed)
|
||||
// Gunpowder doesn't blow in presence of stabilizing agent but instead consumes it every time it'd get triggered
|
||||
var/agent_volume = holder.get_reagent_amount(/datum/reagent/stabilizing_agent)
|
||||
if (agent_volume)
|
||||
var/sapped_amt = 0.1 + round(power_charge / (0.1 * STANDARD_CELL_CHARGE), 0.01)
|
||||
holder.remove_reagent(/datum/reagent/stabilizing_agent, sapped_amt)
|
||||
if (agent_volume > sapped_amt)
|
||||
return
|
||||
|
||||
if (power_charge >= STANDARD_CELL_CHARGE || holder.chem_temp >= 474)
|
||||
reagent_explode(holder, volume, modifier = 5, strengthdiv = 10, clear_holder_reagents = FALSE)
|
||||
return SPARK_ACT_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
holder.my_atom.visible_message(span_boldnotice("Sparks start flying around the gunpowder!"))
|
||||
if (!enclosed)
|
||||
do_sparks(2, TRUE, get_turf(holder.my_atom))
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reagent_explode), holder, volume, 5, 10), rand(5 SECONDS, 10 SECONDS))
|
||||
return SPARK_ACT_NON_DESTRUCTIVE // just wait a bit...
|
||||
|
||||
/datum/reagent/rdx
|
||||
name = "RDX"
|
||||
description = "Military grade explosive"
|
||||
@@ -127,6 +160,17 @@
|
||||
taste_description = "salt"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/rdx/on_spark_act(power_charge, enclosed)
|
||||
if (power_charge)
|
||||
// Okay but what if we made a REALLY big boom?
|
||||
var/power_coeff = log(2, power_charge / STANDARD_CELL_CHARGE)
|
||||
reagent_explode(holder, volume, modifier = min(2 * power_coeff, 8), strengthdiv = 7 / min(power_coeff, 4), clear_holder_reagents = FALSE)
|
||||
else if (holder.chem_temp >= 474)
|
||||
reagent_explode(holder, volume, modifier = 2, strengthdiv = 7, clear_holder_reagents = FALSE)
|
||||
else
|
||||
reagent_explode(holder, volume, strengthdiv = 8, clear_holder_reagents = FALSE)
|
||||
return SPARK_ACT_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
/datum/reagent/tatp
|
||||
name = "TaTP"
|
||||
description = "Suicide grade explosive"
|
||||
@@ -134,6 +178,10 @@
|
||||
taste_description = "death"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/tatp/on_spark_act(power_charge, enclosed)
|
||||
reagent_explode(holder, volume, strengthdiv = 1.5 + rand() * 1.5, clear_holder_reagents = FALSE)
|
||||
return SPARK_ACT_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
/datum/reagent/flash_powder
|
||||
name = "Flash Powder"
|
||||
description = "Makes a very bright flash."
|
||||
@@ -141,6 +189,26 @@
|
||||
taste_description = "salt"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/flash_powder/on_spark_act(power_charge, enclosed)
|
||||
// Even weaker version of the normal flash effect
|
||||
var/turf/location = get_turf(holder.my_atom)
|
||||
if (!enclosed)
|
||||
do_sparks(2, TRUE, location)
|
||||
var/range = round(volume / 15, 1)
|
||||
holder.my_atom.flash_lighting_fx(range = (range + 2))
|
||||
for(var/mob/living/victim in get_hearers_in_view(range, location))
|
||||
if(!victim.flash_act(affect_silicon = TRUE))
|
||||
continue
|
||||
var/distance = get_dist(location, victim)
|
||||
if(distance <= 4 || issilicon(victim))
|
||||
victim.Paralyze(max(2 SECONDS / max(1, distance), 0.5 SECONDS))
|
||||
victim.Knockdown(max(20 SECONDS / max(1, distance), 6 SECONDS))
|
||||
else
|
||||
victim.adjust_dizzy_up_to(max(20 SECONDS / max(1, distance), 0.5 SECONDS), 20 SECONDS)
|
||||
victim.dropItemToGround(victim.get_active_held_item())
|
||||
victim.dropItemToGround(victim.get_inactive_held_item())
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
/datum/reagent/smoke_powder
|
||||
name = "Smoke Powder"
|
||||
description = "Makes a large cloud of smoke that can carry reagents."
|
||||
@@ -148,6 +216,23 @@
|
||||
taste_description = "smoke"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/smoke_powder/on_spark_act(power_charge, enclosed)
|
||||
// Can't really make a cloud of smoke if we're inside of an enclosed container
|
||||
// ...unless we're a mob, in which case this is pretty cursed
|
||||
if (enclosed && !ismob(holder.my_atom))
|
||||
return
|
||||
var/location = get_turf(holder.my_atom)
|
||||
var/datum/effect_system/fluid_spread/smoke/chem/smoke_system = new()
|
||||
playsound(location, 'sound/effects/smoke.ogg', 50, TRUE, -3)
|
||||
if (iscarbon(holder.my_atom))
|
||||
var/mob/living/carbon/victim = holder.my_atom
|
||||
if (victim.stat != DEAD)
|
||||
victim.visible_message(span_warning("[victim] starts violently coughing up smoke!"))
|
||||
victim.adjust_organ_loss(ORGAN_SLOT_LUNGS, volume / 15)
|
||||
smoke_system.set_up(amount = volume / 1.5, holder = holder.my_atom, location = location, carry = holder, silent = FALSE)
|
||||
smoke_system.start(log = TRUE)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
/datum/reagent/sonic_powder
|
||||
name = "Sonic Powder"
|
||||
description = "Makes a deafening noise."
|
||||
@@ -155,6 +240,14 @@
|
||||
taste_description = "loud noises"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
|
||||
/datum/reagent/sonic_powder/on_spark_act(power_charge, enclosed)
|
||||
// Even weaker version of the normal flash effect
|
||||
var/turf/location = get_turf(holder.my_atom)
|
||||
var/range = round(volume / 15, 1)
|
||||
for(var/mob/living/victim in get_hearers_in_view(range, location))
|
||||
victim.soundbang_act(1, 10 SECONDS, rand(0, 0.5 SECONDS))
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
/datum/reagent/phlogiston
|
||||
name = "Phlogiston"
|
||||
description = "Catches you on fire and makes you ignite."
|
||||
@@ -166,7 +259,7 @@
|
||||
/datum/reagent/phlogiston/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0)
|
||||
. = ..()
|
||||
exposed_mob.adjust_fire_stacks(1)
|
||||
var/burndmg = max(0.3*exposed_mob.fire_stacks * (1 - touch_protection), 0.3)
|
||||
var/burndmg = max(0.3 * exposed_mob.fire_stacks * (1 - touch_protection), 0.3)
|
||||
if(burndmg)
|
||||
exposed_mob.adjust_fire_loss(burndmg, 0)
|
||||
exposed_mob.ignite_mob()
|
||||
@@ -177,6 +270,18 @@
|
||||
if(metabolizer.adjust_fire_loss(0.15 * max(metabolizer.fire_stacks, 0.15) * metabolization_ratio * seconds_per_tick, updating_health = FALSE))
|
||||
return UPDATE_MOB_HEALTH
|
||||
|
||||
/datum/reagent/phlogiston/on_spark_act(power_charge, enclosed)
|
||||
if (enclosed && !ismob(holder.my_atom))
|
||||
if (!holder.my_atom.uses_integrity)
|
||||
return
|
||||
// Spicy!
|
||||
holder.my_atom.take_damage(volume / 3, BURN, FIRE, FALSE)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE | SPARK_ACT_KEEP_REAGENT
|
||||
|
||||
var/turf/our_turf = get_turf(holder.my_atom)
|
||||
our_turf?.hotspot_expose(holder.chem_temp * 50, volume)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
/datum/reagent/napalm
|
||||
name = "Napalm"
|
||||
description = "Very flammable."
|
||||
@@ -201,7 +306,19 @@
|
||||
/datum/reagent/napalm/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume)
|
||||
. = ..()
|
||||
if(istype(exposed_mob) && (methods & (TOUCH|VAPOR|PATCH)))
|
||||
exposed_mob.adjust_fire_stacks(min(reac_volume/4, 20))
|
||||
exposed_mob.adjust_fire_stacks(min(reac_volume / 4, 20))
|
||||
|
||||
/datum/reagent/napalm/on_spark_act(power_charge, enclosed)
|
||||
if (enclosed && !ismob(holder.my_atom))
|
||||
if (!holder.my_atom.uses_integrity)
|
||||
return
|
||||
// Spicy!
|
||||
holder.my_atom.take_damage(volume / 5, BURN, FIRE, FALSE)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE | SPARK_ACT_KEEP_REAGENT
|
||||
|
||||
var/turf/our_turf = get_turf(holder.my_atom)
|
||||
our_turf?.hotspot_expose(round(holder.chem_temp * 30 * (1 + sqrt(power_charge / STANDARD_CELL_CHARGE)), 1), volume)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
#define CRYO_SPEED_PREFACTOR 0.4
|
||||
#define CRYO_SPEED_CONSTANT 0.1
|
||||
@@ -328,6 +445,11 @@
|
||||
var/mob/living/carbon/human/affected_human = affected_mob
|
||||
affected_human.physiology.siemens_coeff *= 0.5
|
||||
|
||||
/datum/reagent/teslium/on_spark_act(power_charge, enclosed)
|
||||
tesla_zap(source = holder.my_atom, zap_range = round(volume / 5, 1), power = volume * 20 + power_charge, cutoff = 1 KILO JOULES, zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_LOW_POWER_GEN)
|
||||
playsound(holder.my_atom, 'sound/machines/defib/defib_zap.ogg', 50, TRUE)
|
||||
return SPARK_ACT_NON_DESTRUCTIVE
|
||||
|
||||
/datum/reagent/teslium/energized_jelly
|
||||
name = "Energized Jelly"
|
||||
description = "Electrically-charged jelly. Boosts jellypeople's nervous system, but only shocks other lifeforms."
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
|
||||
#define LIQUID_PLASMA_BP (50+T0C)
|
||||
#define LIQUID_PLASMA_IG (325+T0C)
|
||||
#define LIQUID_PLASMA_CHARGE_COEFF 2.7
|
||||
|
||||
/datum/reagent/toxin/plasma
|
||||
name = "Plasma"
|
||||
@@ -141,15 +142,30 @@
|
||||
exposed_turf.atmos_spawn_air("[GAS_PLASMA]=[reac_volume];[TURF_TEMPERATURE(temp)]")
|
||||
return ..()
|
||||
|
||||
#undef LIQUID_PLASMA_BP
|
||||
#undef LIQUID_PLASMA_IG
|
||||
|
||||
/datum/reagent/toxin/plasma/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume)//Splashing people with plasma is stronger than fuel!
|
||||
// Splashing people with plasma is stronger than fuel!
|
||||
/datum/reagent/toxin/plasma/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume)
|
||||
. = ..()
|
||||
if(methods & (TOUCH|VAPOR))
|
||||
exposed_mob.adjust_fire_stacks(reac_volume / 5)
|
||||
return
|
||||
|
||||
/datum/reagent/toxin/plasma/on_spark_act(power_charge, enclosed)
|
||||
// If we have any stabilizing agent in the mix, we need 0.2% of a standard cell value per mol of agent to be spent at once to blow
|
||||
// This should allow for some more creative traps to be made with plasma
|
||||
var/agent_volume = holder.get_reagent_amount(/datum/reagent/stabilizing_agent)
|
||||
if (agent_volume && power_charge < agent_volume * 0.002 * STANDARD_CELL_CHARGE)
|
||||
return NONE
|
||||
|
||||
// Plasma explosions become stronger with higher current, and don't care about if they're enclosed or not
|
||||
var/power_modifier = max(0, round(power_charge / STANDARD_CELL_CHARGE * LIQUID_PLASMA_CHARGE_COEFF, 1) - 1)
|
||||
reagent_explode(holder, volume, modifier = power_modifier, strengthdiv = 5, clear_holder_reagents = FALSE)
|
||||
return SPARK_ACT_DESTRUCTIVE | SPARK_ACT_CLEAR_ALL
|
||||
|
||||
#undef LIQUID_PLASMA_BP
|
||||
#undef LIQUID_PLASMA_IG
|
||||
#undef LIQUID_PLASMA_CHARGE_COEFF
|
||||
|
||||
/datum/reagent/toxin/hot_ice
|
||||
name = "Hot Ice Slush"
|
||||
description = "Frozen plasma, worth its weight in gold, to the right people."
|
||||
|
||||
@@ -278,52 +278,68 @@
|
||||
*
|
||||
* arguments:
|
||||
* * holder - the reagents datum that it is being used on
|
||||
* * created_volume - the volume of reacting elements
|
||||
* * volume - the volume of reacting elements
|
||||
* * modifier - a flat additive numeric to the size of the explosion - set this if you want a minimum range
|
||||
* * strengthdiv - the divisional factor of the explosion, a larger number means a smaller range - This is the part that modifies an explosion's range with volume (i.e. it divides it by this number)
|
||||
* * clear_mob_reagents - should our mob be purged of their reagents?
|
||||
* * clear_holder_reagents - should the reagent holder be fully purged? Heavily recommended to be TRUE, unless you have code handling that elsewhere down the line for whatever reason
|
||||
* * flame_factor - multiplier to flame range of the explosion
|
||||
* * flash_factor - multiplier to flash range of the explosion
|
||||
*/
|
||||
/datum/chemical_reaction/proc/default_explode(datum/reagents/holder, created_volume, modifier = 0, strengthdiv = 10, clear_mob_reagents)
|
||||
var/power = modifier + round(created_volume/strengthdiv, 1)
|
||||
if(power > 0)
|
||||
var/turf/T = get_turf(holder.my_atom)
|
||||
/proc/reagent_explode(datum/reagents/holder, volume, modifier = 0, strengthdiv = 10, clear_mob_reagents = FALSE, clear_holder_reagents = TRUE, flash_factor = null, flame_factor = null)
|
||||
if (QDELETED(holder))
|
||||
return
|
||||
|
||||
var/power = modifier + round(volume / strengthdiv, 1)
|
||||
if (power > 0)
|
||||
var/turf/our_turf = get_turf(holder.my_atom)
|
||||
var/inside_msg
|
||||
if(ismob(holder.my_atom))
|
||||
var/mob/M = holder.my_atom
|
||||
inside_msg = " inside [ADMIN_LOOKUPFLW(M)]"
|
||||
if (ismob(holder.my_atom))
|
||||
var/mob/owner = holder.my_atom
|
||||
inside_msg = " inside [ADMIN_LOOKUPFLW(owner)]"
|
||||
var/lastkey = holder.my_atom.fingerprintslast //This can runtime (null.fingerprintslast) - due to plumbing?
|
||||
var/touch_msg = "N/A"
|
||||
if(lastkey)
|
||||
if (lastkey)
|
||||
var/mob/toucher = get_mob_by_key(lastkey)
|
||||
touch_msg = "[ADMIN_LOOKUPFLW(toucher)]"
|
||||
if(!istype(holder.my_atom, /obj/machinery/plumbing)) //excludes standard plumbing equipment from spamming admins with this shit
|
||||
message_admins("Reagent explosion reaction occurred at [ADMIN_VERBOSEJMP(T)][inside_msg]. Last Fingerprint: [touch_msg].")
|
||||
log_game("Reagent explosion reaction occurred at [AREACOORD(T)]. Last Fingerprint: [lastkey ? lastkey : "N/A"]." )
|
||||
var/datum/effect_system/reagents_explosion/e = new()
|
||||
e.set_up(power , T, 0, 0)
|
||||
e.start(holder.my_atom)
|
||||
if (ismob(holder.my_atom))
|
||||
if(!clear_mob_reagents)
|
||||
return
|
||||
// Only clear reagents if they use a special explosive reaction to do it; it shouldn't apply
|
||||
// to any explosion inside a person
|
||||
holder.clear_reagents()
|
||||
if(iscarbon(holder.my_atom))
|
||||
var/mob/living/carbon/victim = holder.my_atom
|
||||
var/vomit_flags = MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE
|
||||
// The vomiting here is for effect, not meant to help with purging
|
||||
victim.vomit(vomit_flags, distance = 5)
|
||||
// Not quite the same if the reaction is in their stomach; they'll throw up
|
||||
// from any explosion, but it'll only make them puke up everything in their
|
||||
// stomach
|
||||
else if (istype(holder.my_atom, /obj/item/organ/stomach))
|
||||
if (!istype(holder.my_atom, /obj/machinery/plumbing)) //excludes standard plumbing equipment from spamming admins with this shit
|
||||
message_admins("Reagent explosion reaction occurred at [ADMIN_VERBOSEJMP(our_turf)][inside_msg]. Last Fingerprint: [touch_msg].")
|
||||
log_game("Reagent explosion reaction occurred at [AREACOORD(our_turf)]. Last Fingerprint: [lastkey ? lastkey : "N/A"]." )
|
||||
var/datum/effect_system/reagents_explosion/explosion_system = new()
|
||||
explosion_system.set_up(power, our_turf, flash_fact = flash_factor, flame_fact = flame_factor)
|
||||
explosion_system.start(holder.my_atom)
|
||||
|
||||
if (istype(holder.my_atom, /obj/item/organ/stomach))
|
||||
var/obj/item/organ/stomach/indigestion = holder.my_atom
|
||||
if(power < 1)
|
||||
return
|
||||
indigestion.owner?.vomit(MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE, lost_nutrition = 150, distance = 5, purge_ratio = 1)
|
||||
if (clear_mob_reagents)
|
||||
indigestion.owner?.vomit(MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE, lost_nutrition = 150, distance = 5, purge_ratio = 1)
|
||||
if (clear_holder_reagents)
|
||||
holder.clear_reagents()
|
||||
return
|
||||
|
||||
if (!ismob(holder.my_atom))
|
||||
holder.clear_reagents()
|
||||
return
|
||||
else
|
||||
|
||||
// Not quite the same if the reaction is in their stomach; they'll throw up
|
||||
// from any explosion, but it'll only make them puke up everything in their
|
||||
// stomach
|
||||
if (!clear_mob_reagents)
|
||||
return
|
||||
|
||||
// Only clear reagents if they use a special explosive reaction to do it; it shouldn't apply
|
||||
// to any explosion inside a person
|
||||
if (clear_holder_reagents)
|
||||
holder.clear_reagents()
|
||||
|
||||
if (iscarbon(holder.my_atom))
|
||||
var/mob/living/carbon/victim = holder.my_atom
|
||||
var/vomit_flags = MOB_VOMIT_MESSAGE | MOB_VOMIT_FORCE
|
||||
// The vomiting here is for effect, not meant to help with purging
|
||||
victim.vomit(vomit_flags, distance = 5)
|
||||
|
||||
/*
|
||||
*Creates a flash effect only - less expensive than explode()
|
||||
*
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
message_admins("Reagent explosion reaction occurred at [ADMIN_VERBOSEJMP(T)][inside_msg]. Last Fingerprint: [touch_msg].")
|
||||
log_game("Reagent explosion reaction occurred at [AREACOORD(T)]. Last Fingerprint: [lastkey ? lastkey : "N/A"]." )
|
||||
var/datum/effect_system/reagents_explosion/e = new()
|
||||
e.set_up(power, T, 0, 0)
|
||||
e.set_up(power, T)
|
||||
e.start(holder.my_atom)
|
||||
holder.clear_reagents()
|
||||
|
||||
|
||||
@@ -222,10 +222,10 @@
|
||||
purity_min = 0.32
|
||||
|
||||
/datum/chemical_reaction/medicine/ephedrine/overheated(datum/reagents/holder, datum/equilibrium/equilibrium, vol_added)
|
||||
default_explode(holder, equilibrium.reacted_vol, 0, 25)
|
||||
reagent_explode(holder, equilibrium.reacted_vol, 0, 25)
|
||||
|
||||
/datum/chemical_reaction/medicine/ephedrine/overly_impure(datum/reagents/holder, datum/equilibrium/equilibrium, vol_added)
|
||||
default_explode(holder, equilibrium.reacted_vol, 0, 20)
|
||||
reagent_explode(holder, equilibrium.reacted_vol, 0, 20)
|
||||
|
||||
/datum/chemical_reaction/medicine/diphenhydramine
|
||||
results = list(/datum/reagent/medicine/diphenhydramine = 4)
|
||||
|
||||
@@ -17,30 +17,39 @@
|
||||
var/clear_mob_reagents = FALSE
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume, clear_mob_reagents)
|
||||
if (!ismob(holder.my_atom))
|
||||
reagent_explode(holder, created_volume, modifier, strengthdiv, clear_mob_reagents)
|
||||
return
|
||||
|
||||
// If an explosive reaction clears mob reagents, it should always be a minimum power
|
||||
if(ismob(holder.my_atom) && clear_mob_reagents)
|
||||
if(clear_mob_reagents)
|
||||
if(round((created_volume / strengthdiv) + modifier, 1) < 1)
|
||||
modifier += 1 - ((created_volume / strengthdiv) + modifier)
|
||||
reagent_explode(holder, created_volume, modifier, strengthdiv, clear_mob_reagents)
|
||||
return
|
||||
|
||||
// If this particular explosion doesn't automatically clear mob reagents as an inherent quality,
|
||||
// then we can still clear mob reagents with some mad science malpractice that shouldn't work but
|
||||
// does because omnizine is magic and also it's the future or whatever
|
||||
if(ismob(holder.my_atom) && !clear_mob_reagents)
|
||||
// The explosion needs to be a minimum power to clear reagents: see above
|
||||
var/purge_power = round((created_volume / strengthdiv) + modifier, 1)
|
||||
if(purge_power >= 1)
|
||||
var/has_purging_chemical = FALSE
|
||||
// They need one of the purge reagents in them
|
||||
for(var/purging_chem in PURGING_REAGENTS)
|
||||
if(holder.has_reagent(purging_chem))
|
||||
// We have a purging chemical
|
||||
has_purging_chemical = TRUE
|
||||
break
|
||||
// Then we need omnizine! MAGIC!
|
||||
var/has_omnizine = holder.has_reagent(/datum/reagent/medicine/omnizine)
|
||||
if(has_purging_chemical && has_omnizine)
|
||||
// With all this medical "science" combined, we can clear mob reagents
|
||||
clear_mob_reagents = TRUE
|
||||
default_explode(holder, created_volume, modifier, strengthdiv, clear_mob_reagents)
|
||||
// The explosion needs to be a minimum power to clear reagents: see above
|
||||
var/purge_power = round((created_volume / strengthdiv) + modifier, 1)
|
||||
if(purge_power < 1)
|
||||
reagent_explode(holder, created_volume, modifier, strengthdiv, clear_mob_reagents)
|
||||
return
|
||||
|
||||
var/has_purging_chemical = FALSE
|
||||
// They need one of the purge reagents in them
|
||||
for(var/purging_chem in PURGING_REAGENTS)
|
||||
if(holder.has_reagent(purging_chem))
|
||||
// We have a purging chemical
|
||||
has_purging_chemical = TRUE
|
||||
break
|
||||
// Then we need omnizine! MAGIC!
|
||||
var/has_omnizine = holder.has_reagent(/datum/reagent/medicine/omnizine)
|
||||
if(has_purging_chemical && has_omnizine)
|
||||
// With all this medical "science" combined, we can clear mob reagents
|
||||
clear_mob_reagents = TRUE
|
||||
reagent_explode(holder, created_volume, modifier, strengthdiv, clear_mob_reagents)
|
||||
|
||||
#undef PURGING_REAGENTS
|
||||
/datum/chemical_reaction/reagent_explosion/nitroglycerin
|
||||
@@ -62,7 +71,7 @@
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/rdx
|
||||
results = list(/datum/reagent/rdx= 2)
|
||||
required_reagents = list(/datum/reagent/phenol = 2, /datum/reagent/toxin/acid/nitracid = 1, /datum/reagent/acetone_oxide = 1 )
|
||||
required_reagents = list(/datum/reagent/phenol = 2, /datum/reagent/toxin/acid/nitracid = 1, /datum/reagent/acetone_oxide = 1)
|
||||
required_catalysts = list(/datum/reagent/gold) //royal explosive
|
||||
required_temp = 404
|
||||
strengthdiv = 8
|
||||
@@ -199,7 +208,8 @@
|
||||
mix_message = span_boldnotice("Sparks start flying around the gunpowder!")
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/gunpowder_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
|
||||
addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), rand(5 SECONDS, 10 SECONDS))
|
||||
do_sparks(2, TRUE, get_turf(holder.my_atom))
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reagent_explode), holder, created_volume, modifier, strengthdiv), rand(5 SECONDS, 10 SECONDS))
|
||||
|
||||
/datum/chemical_reaction/thermite
|
||||
results = list(/datum/reagent/thermite = 3)
|
||||
@@ -391,6 +401,12 @@
|
||||
S.start(log = TRUE)
|
||||
if(holder?.my_atom)
|
||||
holder.clear_reagents()
|
||||
if (!iscarbon(holder?.my_atom))
|
||||
return
|
||||
var/mob/living/carbon/victim = holder.my_atom
|
||||
if (victim.stat != DEAD)
|
||||
victim.visible_message(span_warning("[victim] starts violently coughing up smoke!"))
|
||||
victim.adjust_organ_loss(ORGAN_SLOT_LUNGS, created_volume / 5)
|
||||
|
||||
/datum/chemical_reaction/smoke_powder_smoke
|
||||
required_reagents = list(/datum/reagent/smoke_powder = 1)
|
||||
@@ -409,6 +425,14 @@
|
||||
S.start(log = TRUE)
|
||||
if(holder?.my_atom)
|
||||
holder.clear_reagents()
|
||||
if(holder?.my_atom)
|
||||
holder.clear_reagents()
|
||||
if (!iscarbon(holder?.my_atom))
|
||||
return
|
||||
var/mob/living/carbon/victim = holder.my_atom
|
||||
if (victim.stat != DEAD)
|
||||
victim.visible_message(span_warning("[victim] starts violently coughing up smoke!"))
|
||||
victim.adjust_organ_loss(ORGAN_SLOT_LUNGS, created_volume / 10)
|
||||
|
||||
/datum/chemical_reaction/sonic_powder
|
||||
results = list(/datum/reagent/sonic_powder = 3)
|
||||
@@ -603,7 +627,7 @@
|
||||
added_delay += 1.5 SECONDS
|
||||
if(created_volume >= 10) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast.
|
||||
addtimer(CALLBACK(src, PROC_REF(zappy_zappy), holder, T3), added_delay)
|
||||
addtimer(CALLBACK(src, PROC_REF(default_explode), holder, created_volume, modifier, strengthdiv), added_delay)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reagent_explode), holder, created_volume, modifier, strengthdiv), added_delay)
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/teslium_lightning/proc/zappy_zappy(datum/reagents/holder, power)
|
||||
var/atom/holder_atom = holder.my_atom
|
||||
|
||||
Reference in New Issue
Block a user