diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index e0649723e01..85a1c2b0215 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -519,29 +519,30 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
access = access_eva
/datum/supply_packs/engineering/inflatable
- name = "Inflatable barriers"
+ name = "Inflatable barriers Crate"
contains = list(/obj/item/weapon/storage/briefcase/inflatable,
/obj/item/weapon/storage/briefcase/inflatable,
/obj/item/weapon/storage/briefcase/inflatable)
cost = 20
containername = "Inflatable Barrier Crate"
-/datum/supply_packs/engineering/supermatter
- name = "Supermatter Crystal Crate"
- contains = list(/obj/machinery/power/supermatter)
- cost = 50 //Yes that's a fucking lot.
- containername = "Supermatter Shard Crate"
- containertype = /obj/structure/closet/crate/secure/large/reinforced
+/datum/supply_packs/engineering/engine/supermatter_shard
+ name = "Supermatter Shard Crate"
+ contains = list(/obj/machinery/power/supermatter_shard)
+ cost = 50 //So cargo thinks twice before killing themselves with it
+ containertype = /obj/structure/closet/crate/secure
+ containername = "supermatter shard crate"
access = access_ce
-/datum/supply_packs/engineering/teg
- name = "Thermo-Electric Generator"
+/datum/supply_packs/engineering/engine/teg
+ name = "Thermo-Electric Generator Crate"
contains = list(
/obj/machinery/power/generator,
/obj/machinery/atmospherics/binary/circulator,
/obj/machinery/atmospherics/binary/circulator
)
cost = 25
+ containertype = /obj/structure/closet/crate/secure
containername = "Thermo-Electric Generator Components"
access = access_ce
@@ -592,7 +593,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/weapon/storage/firstaid/adv)
cost = 10
containername = "advaced first aid kits crate"
-
+
/datum/supply_packs/medical/firstaibrute
name = "Brute Trauma Treatment Kits Crate"
contains = list(/obj/item/weapon/storage/firstaid/brute,
diff --git a/code/game/smoothwall.dm b/code/game/smoothwall.dm
index 75cb92b774b..3c55255eb78 100644
--- a/code/game/smoothwall.dm
+++ b/code/game/smoothwall.dm
@@ -86,12 +86,12 @@
shroom.icon_state = "glowshroomf"
shroom.pixel_x = 0
shroom.pixel_y = 0
- for(var/obj/effect/supermatter_crystal/crystal in get_step(src,direction))
+/* for(var/obj/effect/supermatter_crystal/crystal in get_step(src,direction))
if(!crystal.floor) //crystals drop to the floor
crystal.floor = 1
crystal.icon_state = "supermatter_crystalf"
crystal.pixel_x = 0
- crystal.pixel_y = 0
+ crystal.pixel_y = 0 */
return ..()
// DE-HACK
diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm
index 3acc2e08a90..1528307d566 100644
--- a/code/modules/mob/living/carbon/human/species/apollo.dm
+++ b/code/modules/mob/living/carbon/human/species/apollo.dm
@@ -108,6 +108,6 @@
/datum/species/nucleation/handle_death(var/mob/living/carbon/human/H)
var/turf/T = get_turf(H)
H.visible_message("\red[H]'s body explodes, leaving behind a pile of microscopic crystals!")
- supermatter_delamination(T, 2, 0, 0) // Create a small supermatter burst upon death
- new /obj/item/weapon/shard/supermatter( T )
+ explosion(T, 0, 0, 2, 2) // Create a small explosion burst upon death
+// new /obj/item/weapon/shard/supermatter( T )
del(H)
\ No newline at end of file
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index efc75eae0c6..a1d86e5f6dd 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -244,7 +244,7 @@
/obj/singularity/proc/consume(var/atom/A)
var/gain = A.singularity_act(current_size)
src.energy += gain
- if(istype(A, /obj/machinery/power/supermatter) && !consumedSupermatter)
+ if(istype(A, /obj/machinery/power/supermatter_shard) && !consumedSupermatter)
desc = "[initial(desc)] It glows fiercely with inner fire."
name = "supermatter-charged [initial(name)]"
consumedSupermatter = 1
diff --git a/code/game/objects/effects/sm_crystals.dm b/code/modules/power/supermatter/sm_crystals.dm
similarity index 100%
rename from code/game/objects/effects/sm_crystals.dm
rename to code/modules/power/supermatter/sm_crystals.dm
diff --git a/code/game/objects/items/weapons/sm_shard.dm b/code/modules/power/supermatter/sm_shard.dm
similarity index 100%
rename from code/game/objects/items/weapons/sm_shard.dm
rename to code/modules/power/supermatter/sm_shard.dm
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
new file mode 100644
index 00000000000..482395a852d
--- /dev/null
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -0,0 +1,299 @@
+//Ported from /vg/station13, which was in turn forked from baystation12;
+//Please do not bother them with bugs from this port, however, as it has been modified quite a bit.
+//Modifications include removing the world-ending full supermatter variation, and leaving only the shard.
+
+#define NITROGEN_RETARDATION_FACTOR 2 //Higher == N2 slows reaction more
+#define THERMAL_RELEASE_MODIFIER 5 //Higher == less heat released during reaction
+#define PLASMA_RELEASE_MODIFIER 750 //Higher == less plasma released by reaction
+#define OXYGEN_RELEASE_MODIFIER 325 //Higher == less oxygen released at high temperature/power
+#define REACTION_POWER_MODIFIER 0.55 //Higher == more overall power
+
+
+//These would be what you would get at point blank, decreases with distance
+#define DETONATION_RADS 200
+#define DETONATION_HALLUCINATION 600
+
+
+#define WARNING_DELAY 30 //seconds between warnings.
+
+/obj/machinery/power/supermatter_shard
+ name = "supermatter shard"
+ desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. You get headaches just from looking at it."
+ icon = 'icons/obj/supermatter.dmi'
+ icon_state = "darkmatter_shard"
+ density = 1
+ anchored = 0
+ light_range = 4
+
+
+ var/gasefficency = 0.125
+
+ var/base_icon_state = "darkmatter_shard"
+
+ var/damage = 0
+ var/damage_archived = 0
+ var/safe_alert = "Crystalline hyperstructure returning to safe operating levels."
+ var/warning_point = 50
+ var/warning_alert = "Danger! Crystal hyperstructure instability!"
+ var/emergency_point = 500
+ var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
+ var/explosion_point = 900
+
+ var/emergency_issued = 0
+
+ var/explosion_power = 8
+
+ var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning
+ var/power = 0
+
+ var/oxygen = 0 // Moving this up here for easier debugging.
+
+ //Temporary values so that we can optimize this
+ //How much the bullets damage should be multiplied by when it is added to the internal variables
+ var/config_bullet_energy = 2
+ //How much of the power is left after processing is finished?
+// var/config_power_reduction_per_tick = 0.5
+ //How much hallucination should it produce per unit of power?
+ var/config_hallucination_power = 0.1
+
+ var/obj/item/device/radio/radio
+
+ //for logging
+ var/has_been_powered = 0
+ var/has_reached_emergency = 0
+
+/obj/machinery/power/supermatter_shard/New()
+ . = ..()
+ radio = new(src)
+ radio.listening = 0
+ investigate_log("has been created.", "supermatter")
+
+
+/obj/machinery/power/supermatter_shard/Destroy()
+ investigate_log("has been destroyed.", "supermatter")
+ qdel(radio)
+ . = ..()
+
+/obj/machinery/power/supermatter_shard/proc/explode()
+ investigate_log("has exploded.", "supermatter")
+ explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1)
+ qdel(src)
+ return
+
+/obj/machinery/power/supermatter_shard/process()
+ var/turf/L = loc
+
+ if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity.
+ return PROCESS_KILL
+
+ if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
+ return //Yeah just stop.
+
+ if(istype(L, /turf/space)) // Stop processing this stuff if we've been ejected.
+ return
+
+ if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
+ if((world.timeofday - lastwarning) / 10 >= WARNING_DELAY)
+ var/stability = num2text(round((damage / explosion_point) * 100))
+
+ if(damage > emergency_point)
+ radio.autosay("[emergency_alert] Instability: [stability]%", src)
+ lastwarning = world.timeofday
+ if(!has_reached_emergency)
+ investigate_log("has reached the emergency point for the first time.", "supermatter")
+ message_admins("[src] has reached the emergency point (JMP).")
+ has_reached_emergency = 1
+
+ else if(damage >= damage_archived) // The damage is still going up
+ radio.autosay("[warning_alert] Instability: [stability]%", src)
+ lastwarning = world.timeofday - 150
+
+ else // Phew, we're safe
+ radio.autosay("[safe_alert]", src)
+ lastwarning = world.timeofday
+
+ if(damage > explosion_point)
+ for(var/mob/living/mob in living_mob_list)
+ if(istype(mob, /mob/living/carbon/human))
+ //Hilariously enough, running into a closet should make you get hit the hardest.
+ var/mob/living/carbon/human/H = mob
+ H.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) )
+ var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(mob, src) + 1) )
+ mob.apply_effect(rads, IRRADIATE)
+
+ explode()
+
+ //Ok, get the air from the turf
+ var/datum/gas_mixture/env = L.return_air()
+
+ //Remove gas from surrounding area
+ var/datum/gas_mixture/removed = env.remove(gasefficency * env.total_moles())
+
+ if(!removed || !removed.total_moles())
+ damage += max((power-1600)/10, 0)
+ power = min(power, 1600)
+ return 1
+
+ damage_archived = damage
+ damage = max( damage + ( (removed.temperature - 800) / 150 ) , 0 )
+ //Ok, 100% oxygen atmosphere = best reaction
+ //Maxes out at 100% oxygen pressure
+ oxygen = max(min((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / MOLES_CELLSTANDARD, 1), 0)
+
+ var/temp_factor = 50
+
+ if(oxygen > 0.8)
+ // with a perfect gas mix, make the power less based on heat
+ icon_state = "[base_icon_state]_glow"
+ else
+ // in normal mode, base the produced energy around the heat
+ temp_factor = 30
+ icon_state = base_icon_state
+
+ power = max( (removed.temperature * temp_factor / T0C) * oxygen + power, 0) //Total laser power plus an overload
+
+ //We've generated power, now let's transfer it to the collectors for storing/usage
+ transfer_energy()
+
+ var/device_energy = power * REACTION_POWER_MODIFIER
+
+ //To figure out how much temperature to add each tick, consider that at one atmosphere's worth
+ //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature
+ //that the device energy is around 2140. At that stage, we don't want too much heat to be put out
+ //Since the core is effectively "cold"
+
+ //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
+ //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
+ removed.temperature += (device_energy / THERMAL_RELEASE_MODIFIER)
+
+ removed.temperature = max(0, min(removed.temperature, 2500))
+
+ //Calculate how much gas to release
+ removed.toxins += max(device_energy / PLASMA_RELEASE_MODIFIER, 0)
+
+ removed.oxygen += max((device_energy + removed.temperature - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
+
+ env.merge(removed)
+
+ for(var/mob/living/carbon/human/l in view(src, min(7, round(power ** 0.25)))) // If they can see it without mesons on. Bad on them.
+ if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
+ l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1, get_dist(l, src)) ) ) )
+
+ for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
+ var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) )
+ l.apply_effect(rads, IRRADIATE)
+
+ power -= (power/500)**3
+
+ return 1
+
+/obj/machinery/power/supermatter_shard
+
+/obj/machinery/power/supermatter_shard/bullet_act(var/obj/item/projectile/Proj)
+ var/turf/L = loc
+ if(!istype(L)) // We don't run process() when we are in space
+ return 0 // This stops people from being able to really power up the supermatter
+ // Then bring it inside to explode instantly upon landing on a valid turf.
+
+
+ if(Proj.flag != "bullet")
+ power += Proj.damage * config_bullet_energy
+ if(!has_been_powered)
+ investigate_log("has been powered for the first time.", "supermatter")
+ message_admins("[src] has been powered for the first time (JMP).")
+ has_been_powered = 1
+ else
+ damage += Proj.damage * config_bullet_energy
+ return 0
+
+/obj/machinery/power/supermatter_shard/singularity_act()
+ var/gain = 100
+ investigate_log("Supermatter shard consumed by singularity.","singulo")
+ message_admins("Singularity has consumed a supermatter shard and can now become stage six.")
+ visible_message("[src] is consumed by the singularity!")
+ for(var/mob/M in mob_list)
+ M << 'sound/effects/supermatter.ogg' //everyone goan know bout this
+ M << "A horrible screeching fills your ears, and a wave of dread washes over you..."
+ qdel(src)
+ return(gain)
+
+/obj/machinery/power/supermatter_shard/attack_robot(mob/user as mob)
+ if(Adjacent(user))
+ return attack_hand(user)
+ else
+ user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
+ return
+
+/obj/machinery/power/supermatter_shard/attack_ai(mob/user as mob)
+ user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
+
+/obj/machinery/power/supermatter_shard/attack_hand(mob/living/user as mob)
+ if(!istype(user))
+ return
+ user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\
+ "You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"",\
+ "You hear an unearthly noise as a wave of heat washes over you.")
+
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
+
+ Consume(user)
+
+/obj/machinery/power/supermatter_shard/proc/transfer_energy()
+ for(var/obj/machinery/power/rad_collector/R in rad_collectors)
+ if(get_dist(R, src) <= 15) // Better than using orange() every process
+ R.receive_pulse(power/10)
+ return
+
+/obj/machinery/power/supermatter_shard/attackby(obj/item/W as obj, mob/living/user as mob, params)
+ if(!istype(W) || (W.flags & ABSTRACT) || !istype(user))
+ return
+ if(user.drop_item(W))
+ Consume(W)
+ user.visible_message("As [user] touches \the [src] with \a [W], silence fills the room...",\
+ "You touch \the [src] with \the [W], and everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\
+ "Everything suddenly goes silent.")
+
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
+
+ user.apply_effect(150, IRRADIATE)
+
+
+/obj/machinery/power/supermatter_shard/Bumped(atom/AM as mob|obj)
+ if(istype(AM, /mob/living))
+ AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\
+ "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\
+ "You hear an unearthly noise as a wave of heat washes over you.")
+ else if(isobj(AM) && !istype(AM, /obj/effect))
+ AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\
+ "You hear a loud crack as you are washed with a wave of heat.")
+ else
+ return
+
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
+
+ Consume(AM)
+
+
+/obj/machinery/power/supermatter_shard/proc/Consume(atom/movable/AM)
+ if(istype(AM, /mob/living))
+ var/mob/living/user = AM
+ user.dust()
+ power += 200
+ message_admins("[src] has consumed [key_name_admin(user)]? (FLW) (JMP).")
+ investigate_log("has consumed [key_name(user)].", "supermatter")
+ else if(isobj(AM) && !istype(AM, /obj/effect))
+ investigate_log("has consumed [AM].", "supermatter")
+ qdel(AM)
+
+ power += 200
+
+ //Some poor sod got eaten, go ahead and irradiate people nearby.
+ for(var/mob/living/L in range(10))
+ var/rads = 500 * sqrt( 1 / (get_dist(L, src) + 1) )
+ L.apply_effect(rads, IRRADIATE)
+ investigate_log("has irradiated [L] after consuming [AM].", "supermatter")
+ if(L in view())
+ L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\
+ "The unearthly ringing subsides and you notice you have new radiation burns.", 2)
+ else
+ L.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2)
diff --git a/code/modules/supermatter/wall.dm b/code/modules/power/supermatter/wall.dm
similarity index 100%
rename from code/modules/supermatter/wall.dm
rename to code/modules/power/supermatter/wall.dm
diff --git a/code/modules/research/xenoarchaeology/artifact/artifact.dm b/code/modules/research/xenoarchaeology/artifact/artifact.dm
index 2c3946b0428..8730b04e063 100644
--- a/code/modules/research/xenoarchaeology/artifact/artifact.dm
+++ b/code/modules/research/xenoarchaeology/artifact/artifact.dm
@@ -13,10 +13,9 @@
artifact_id = "[pick("kappa","sigma","antaeres","beta","omicron","iota","epsilon","omega","gamma","delta","tau","alpha")]-[rand(100,999)]"
artifact_find_type = pick(\
- 5;/obj/machinery/power/supermatter,\
5;/obj/structure/constructshell,\
5;/obj/machinery/wish_granter,\
- 25;/obj/machinery/power/supermatter/shard,\
+ 25;/obj/machinery/power/supermatter_shard,\
50;/obj/structure/cult/pylon,\
100;/obj/machinery/auto_cloner,\
100;/obj/machinery/giga_drill,\
diff --git a/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm b/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm
index 3d2ec6c32c1..cbc755e2c22 100644
--- a/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm
+++ b/code/modules/research/xenoarchaeology/machinery/artifact_analyser.dm
@@ -135,10 +135,7 @@
ecosystem involving self cannibalism and a symbiotic relationship with the contained liquid.
\
Structure is composed of a carbo-titanium alloy with interlaced reinforcing energy fields, and the contained liquid \
resembles proto-plasmic residue supportive of single cellular developmental conditions."
- if(/obj/machinery/power/supermatter)
- return "Super dense plasma clump - Appears to have been shaped or hewn, structure is composed of matter 2000% denser than ordinary carbon matter residue.\
- Potential application as unrefined plasma source."
- if(/obj/machinery/power/supermatter)
+ if(/obj/machinery/power/supermatter_shard)
return "Super dense plasma clump - Appears to have been shaped or hewn, structure is composed of matter 2000% denser than ordinary carbon matter residue.\
Potential application as unrefined plasma source."
if(/obj/structure/constructshell)
diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm
deleted file mode 100644
index 92264de763a..00000000000
--- a/code/modules/supermatter/supermatter.dm
+++ /dev/null
@@ -1,473 +0,0 @@
-
-#define NITROGEN_RETARDATION_FACTOR 0.15 //Higher == N2 slows reaction more
-#define THERMAL_RELEASE_MODIFIER 750 //Higher == more heat released during reaction
-#define PLASMA_RELEASE_MODIFIER 1500 //Higher == less plasma released by reaction
-#define OXYGEN_RELEASE_MODIFIER 1500 //Higher == less oxygen released at high temperature/power
-#define REACTION_POWER_MODIFIER 1.1 //Higher == more overall power
-
-/*
- How to tweak the SM
-
- POWER_FACTOR directly controls how much power the SM puts out at a given level of excitation (power var). Making this lower means you have to work the SM harder to get the same amount of power.
- CRITICAL_TEMPERATURE The temperature at which the SM starts taking damage.
-
- CHARGING_FACTOR Controls how much emitter shots excite the SM.
- DAMAGE_RATE_LIMIT Controls the maximum rate at which the SM will take damage due to high temperatures.
-*/
-
-//Controls how much power is produced by each collector in range - this is the main parameter for tweaking SM balance, as it basically controls how the power variable relates to the rest of the game.
-#define POWER_FACTOR 1.0
-#define DECAY_FACTOR 700 //Affects how fast the supermatter power decays
-#define CRITICAL_TEMPERATURE 5000 //K
-#define CHARGING_FACTOR 0.05
-#define DAMAGE_RATE_LIMIT 3 //damage rate cap at power = 300, scales linearly with power
-
-
-//These would be what you would get at point blank, decreases with distance
-#define DETONATION_RADS 200
-#define DETONATION_HALLUCINATION 600
-
-#define TRANSFORM_DISTANCE_MOD 2 // Size/this is maximum distance from SM during burst for transformation to Nucleation
-
-#define WARNING_DELAY 30 //seconds between warnings.
-
-/obj/machinery/power/supermatter
- name = "Supermatter"
- desc = "A strangely translucent and iridescent crystal. \red You get headaches just from looking at it."
- icon = 'icons/obj/engine.dmi'
- icon_state = "darkmatter"
- density = 1
- anchored = 0
- light_range = 4
-
- var/gasefficency = 0.25
-
- var/base_icon_state = "darkmatter"
-
- var/damage = 0
- var/damage_archived = 0
- var/safe_alert = "Crystaline hyperstructure returning to safe operating levels."
- var/safe_warned = 0
- var/warning_point = 100
- var/warning_alert = "Danger! Crystal hyperstructure instability!"
- var/emergency_point = 700
- var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
- var/explosion_point = 1000
-
- light_color = "#8A8A00"
- var/warning_color = "#B8B800"
- var/emergency_color = "#D9D900"
-
- var/grav_pulling = 0
- var/pull_radius = 14
- // Time in ticks between delamination ('exploding') and exploding (as in the actual boom)
- var/pull_time = 100
- var/explosion_power = 8
-
- var/emergency_issued = 0
-
- // Time in 1/10th of seconds since the last sent warning
- var/lastwarning = 0
-
- // This stops spawning redundand explosions. Also incidentally makes supermatter unexplodable if set to 1.
- var/exploded = 0
-
- var/power = 0
- var/oxygen = 0
-
- //Temporary values so that we can optimize this
- //How much the bullets damage should be multiplied by when it is added to the internal variables
- var/config_bullet_energy = 2
- //How much of the power is left after processing is finished?
-// var/config_power_reduction_per_tick = 0.5
- //How much hallucination should it produce per unit of power?
- var/config_hallucination_power = 0.1
-
- var/obj/item/device/radio/radio
-
- var/debug = 0
- var/uneatable = list(/turf/space, /obj/effect/overlay, /atom/movable/lighting_overlay, /mob/dead, /mob/camera, /mob/new_player)
-
-/obj/machinery/power/supermatter/New()
- . = ..()
- radio = new (src)
-
-
-/obj/machinery/power/supermatter/Del()
- del radio
- . = ..()
-
-/obj/machinery/power/supermatter/proc/explode()
- message_admins("Supermatter exploded at ([x],[y],[z] - JMP)",0,1)
- log_game("Supermatter exploded at ([x],[y],[z])")
- anchored = 1
- grav_pulling = 1
- exploded = 1
- spawn(pull_time)
- var/turf/epicenter = get_turf(src)
- explosion(epicenter, explosion_power, explosion_power*2, explosion_power*3, explosion_power*4, 1)
- supermatter_delamination( epicenter, explosion_power*4, 1 )
- del src
- return
-
-//Changes color and light_range of the light to these values if they were not already set
-/obj/machinery/power/supermatter/proc/shift_light(var/lum, var/clr)
- if(light_color != clr)
- light_color = clr
- if(light_range != lum)
- set_light(lum)
-
-/obj/machinery/power/supermatter/proc/announce_warning()
- var/integrity = damage / explosion_point
- integrity = round(100 - integrity * 100)
- integrity = integrity < 0 ? 0 : integrity
- var/alert_msg = " Integrity at [integrity]%"
-
- if(damage > emergency_point)
- alert_msg = emergency_alert + alert_msg
- lastwarning = world.timeofday - WARNING_DELAY * 4
- else if(damage >= damage_archived) // The damage is still going up
- safe_warned = 0
- alert_msg = warning_alert + alert_msg
- lastwarning = world.timeofday
- else if(!safe_warned)
- safe_warned = 1 // We are safe, warn only once
- alert_msg = safe_alert
- lastwarning = world.timeofday
- else
- alert_msg = null
- if(alert_msg)
- radio.autosay(alert_msg, "Supermatter Monitor")
-
-/obj/machinery/power/supermatter/process()
-
- var/turf/L = loc
-
- if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity.
- return PROCESS_KILL
-
- if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
- return //Yeah just stop.
-
- if(damage > explosion_point)
- if(!exploded)
- if(!istype(L, /turf/space))
- announce_warning()
- explode()
- else if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
- shift_light(5, warning_color)
- if(damage > emergency_point)
- shift_light(7, emergency_color)
- if(!istype(L, /turf/space) && (world.timeofday - lastwarning) >= WARNING_DELAY * 10)
- announce_warning()
- else
- shift_light(4,initial(light_color))
- if(grav_pulling)
- supermatter_pull()
-
- //Ok, get the air from the turf
- var/datum/gas_mixture/removed = null
- var/datum/gas_mixture/env = null
-
- //ensure that damage doesn't increase too quickly due to super high temperatures resulting from no coolant, for example. We dont want the SM exploding before anyone can react.
- //We want the cap to scale linearly with power (and explosion_point). Let's aim for a cap of 5 at power = 300 (based on testing, equals roughly 5% per SM alert announcement).
- var/damage_inc_limit = (power/300)*(explosion_point/1000)*DAMAGE_RATE_LIMIT
-
- if(!istype(L, /turf/space))
- env = L.return_air()
- removed = env.remove(gasefficency * env.total_moles()) //Remove gas from surrounding area
-
- if(!env || !removed || !removed.total_moles())
- damage += max((power - 15*POWER_FACTOR)/10, 0)
- else if (grav_pulling) //If supermatter is detonating, remove all air from the zone
- env.remove(env.total_moles())
- else
- damage_archived = damage
-
- damage = max( damage + min( ( (removed.temperature - CRITICAL_TEMPERATURE) / 150 ), damage_inc_limit ) , 0 )
- //Ok, 100% oxygen atmosphere = best reaction
- //Maxes out at 100% oxygen pressure
- oxygen = max(min((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / removed.total_moles(), 1), 0)
-
- //calculate power gain for oxygen reaction
- var/temp_factor
- var/equilibrium_power
- if (oxygen > 0.8)
- //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 400
- equilibrium_power = 400
- icon_state = "[base_icon_state]_glow"
- else
- //If chain reacting at oxygen == 1, we want the power at 800 K to stabilize at a power level of 250
- equilibrium_power = 250
- icon_state = base_icon_state
-
- temp_factor = ( (equilibrium_power/DECAY_FACTOR)**3 )/800
- power = max( (removed.temperature * temp_factor) * oxygen + power, 0)
-
- //We've generated power, now let's transfer it to the collectors for storing/usage
- transfer_energy()
-
- var/device_energy = power * REACTION_POWER_MODIFIER
-
-
- //Calculate how much gas to release
- removed.toxins += max(device_energy / PLASMA_RELEASE_MODIFIER, 0)
-
- removed.oxygen += max((device_energy + removed.temperature - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
-
- env.merge(removed)
-
-
- for(var/mob/living/carbon/human/l in view(src, min(7, round(sqrt(power/6))))) // If they can see it without mesons on. Bad on them.
- if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
- l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)) ) ) )
-
- //adjusted range so that a power of 300 (pretty high) results in 8 tiles, roughly the distance from the core to the engine monitoring room.
- for(var/mob/living/l in range(src, round(sqrt(power / 5))))
- var/rads = (power / 10) * sqrt( 1 / get_dist(l, src) )
- l.apply_effect(rads, IRRADIATE)
-
- power -= (power/DECAY_FACTOR)**3 //energy losses due to radiation
-
- return 1
-
-
-/obj/machinery/power/supermatter/bullet_act(var/obj/item/projectile/Proj)
- var/turf/L = loc
- if(!istype(L)) // We don't run process() when we are in space
- return 0 // This stops people from being able to really power up the supermatter
- // Then bring it inside to explode instantly upon landing on a valid turf.
-
-
- if(istype(Proj, /obj/item/projectile/beam))
- power += Proj.damage * config_bullet_energy * CHARGING_FACTOR / POWER_FACTOR
- else
- damage += Proj.damage * config_bullet_energy
- return 0
-
-/obj/machinery/power/supermatter/singularity_act()
- var/gain = 100
- investigate_log("Supermatter shard consumed by singularity.","singulo")
- message_admins("Singularity has consumed a supermatter shard and can now become stage six.")
- visible_message("[src] is consumed by the singularity!")
- for(var/mob/M in mob_list)
- M << 'sound/effects/supermatter.ogg' //everyone goan know bout this
- M << "A horrible screeching fills your ears, and a wave of dread washes over you..."
- qdel(src)
- return(gain)
-
-/obj/machinery/power/supermatter/attack_robot(mob/user as mob)
- if(Adjacent(user))
- return attack_hand(user)
- else
- user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
- return
-
-/obj/machinery/power/supermatter/attack_ai(mob/user as mob)
- user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
-
-/obj/machinery/power/supermatter/attack_hand(mob/user as mob)
- if(istype(user,/mob/living/carbon/human/nucleation)) // Nucleation's biology doesn't react to this
- return
-
- user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\
- "You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"",\
- "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.")
-
- Consume(user)
-
-/obj/machinery/power/supermatter/proc/transfer_energy()
- for(var/obj/machinery/power/rad_collector/R in rad_collectors)
- var/distance = get_dist(R, src)
- if(distance <= 15)
- //for collectors using standard plasma tanks at 1013 kPa, the actual power generated will be this power*POWER_FACTOR*20*29 = power*POWER_FACTOR*580
- R.receive_pulse(power * POWER_FACTOR * (min(3/distance, 1))**2)
- return
-
-/obj/machinery/power/supermatter/attackby(obj/item/weapon/W as obj, mob/living/carbon/user as mob)
- user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\
- "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\
- "Everything suddenly goes silent.")
-
- user.unEquip(W)
- Consume(W)
-
- user.apply_effect(150, IRRADIATE)
-
-
-/obj/machinery/power/supermatter/Bumped(atom/AM as mob|obj)
- if(istype(AM, /mob/living))
- if(istype(AM,/mob/living/carbon/human/nucleation)) // Nucleation's biology doesn't react to this
- return
- AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\
- "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\
- "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.")
- else if(!grav_pulling) //To prevent spam, detonating supermatter does not indicate non-mobs being destroyed
- AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\
- "You hear a loud crack as you are washed with a wave of heat.")
-
- Consume(AM)
-
-
-/obj/machinery/power/supermatter/proc/Consume(var/mob/living/user)
- if(istype(user,/mob/living/carbon/human/nucleation)) // Nucleation's biology doesn't react to this
- return
-
- if(istype(user))
- user.dust()
- power += 200
- else
- del user
-
- power += 200
-
- //Some poor sod got eaten, go ahead and irradiate people nearby.
- for(var/mob/living/l in range(10))
- if(l in view())
- l.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\
- "The unearthly ringing subsides and you notice you have new radiation burns.", 2)
- else
- l.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2)
- var/rads = 500 * sqrt( 1 / (get_dist(l, src) + 1) )
- l.apply_effect(rads, IRRADIATE)
-
-
-/obj/machinery/power/supermatter/proc/supermatter_pull()
- //following is adapted from singulo code
- if(defer_powernet_rebuild != 2)
- defer_powernet_rebuild = 1
- // Let's just make this one loop.
- for(var/atom/X in orange(pull_radius,src))
- // Movable atoms only
- if(istype(X, /atom/movable))
- if(is_type_in_list(X, uneatable)) continue
- if(((X) && (!istype(X,/mob/living/carbon/human))))
- step_towards(X,src)
- if(istype(X, /obj)) //unanchored objects pulled twice as fast
- var/obj/O = X
- if(!O.anchored)
- step_towards(X,src)
- else
- step_towards(X,src)
- if(istype(X, /obj/structure/window)) //shatter windows
- var/obj/structure/window/W = X
- W.ex_act(2.0)
- else if(istype(X,/mob/living/carbon/human))
- var/mob/living/carbon/human/H = X
- if(istype(H.shoes,/obj/item/clothing/shoes/magboots))
- var/obj/item/clothing/shoes/magboots/M = H.shoes
- if(M.magpulse)
- step_towards(H,src) //step just once with magboots
- continue
- step_towards(H,src) //step twice
- step_towards(H,src)
-
- if(defer_powernet_rebuild != 2)
- defer_powernet_rebuild = 0
- return
-
-
-proc/supermatter_delamination(var/turf/epicenter, var/size, var/transform_mobs = 0, var/adminlog = 1)
- spawn(0)
- var/start = world.timeofday
- epicenter = get_turf(epicenter)
- if(!epicenter) return
-
- if(adminlog)
- message_admins("Supermatter delamination with size ([size]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z] - JMP)")
- log_game("Supermatter delamination with size ([size]) in area [epicenter.loc.name] ")
-
- playsound(epicenter, 'sound/effects/explosionfar.ogg', 100, 1, round(size*2,1) )
- playsound(epicenter, "explosion", 100, 1, round(size,1) )
-
- if(defer_powernet_rebuild != 2)
- defer_powernet_rebuild = 1
-
- var/x = epicenter.x
- var/y = epicenter.y
- var/z = epicenter.z
-
- epicenter.ChangeTurf( /turf/simulated/floor/plating/smatter )
-
- for(var/mob/living/mob in orange( epicenter, size*2 )) // Irradiate area twice the size of the main blast
- if(epicenter.z == mob.loc.z)
- if( ishuman(mob) )
- //Hilariously enough, running into a closet should make you get hit the hardest.
- var/mob/living/carbon/human/H = mob
- H.hallucination += max(50, min(size*10, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, epicenter) + 1)) ) )
- var/rads = size*10 * sqrt( 1 / (get_dist(mob, epicenter) + 1) )
- mob.apply_effect(rads, IRRADIATE)
-
- for(var/i=0, i