diff --git a/code/__DEFINES/anomalies.dm b/code/__DEFINES/anomalies.dm new file mode 100644 index 000000000000..59bcbf05c638 --- /dev/null +++ b/code/__DEFINES/anomalies.dm @@ -0,0 +1,22 @@ +///Defines for anomaly types +#define ANOMALY_FLUX "flux_anomaly" +#define ANOMALY_FLUX_EXPLOSIVE "flux_explosive_anomaly" +#define ANOMALY_GRAVITATIONAL "gravitational_anomaly" +#define ANOMALY_HALLUCINATION "hallucination_anomaly" +#define ANOMALY_PYRO "pyro_anomaly" +#define ANOMALY_BLUESPACE "bluespace_anomaly" +#define ANOMALY_VORTEX "vortex_anomaly" +#define ANOMALY_RADIATION "radiation_anomaly" +#define ANOMALY_RADIATION_X "radiation_goat_anomaly" + +///Defines for area allowances +#define ANOMALY_AREA_BLACKLIST list(/area/ai_monitored/turret_protected/ai,/area/ai_monitored/turret_protected/ai_upload,/area/engine,/area/solar,/area/holodeck,/area/shuttle) +#define ANOMALY_AREA_SUBTYPE_WHITELIST list(/area/engine/break_room) + +///Defines for the different types of explosion a flux anomaly can have +#define ANOMALY_FLUX_NO_EXPLOSION 0 +#define ANOMALY_FLUX_EXPLOSION 1 + +///Defines if rad anomaly can spawn rad goat can have +#define ANOMALY_RADIATION_NO_GOAT 0 +#define ANOMALY_RADIATION_YES_GOAT 1 diff --git a/code/__DEFINES/power.dm b/code/__DEFINES/power.dm index 58edfeb91baa..bf481517156a 100644 --- a/code/__DEFINES/power.dm +++ b/code/__DEFINES/power.dm @@ -2,6 +2,7 @@ #define SOLAR_TRACK_TIMED 1 #define SOLAR_TRACK_AUTO 2 +#define TESLA_HYPERCHARGED_POWER TESLA_DEFAULT_POWER*2 #define TESLA_DEFAULT_POWER 1738260 #define TESLA_MINI_POWER 869130 //Multiplier of all power consumed. diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 6530b7475f18..88683c70aaa9 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -609,7 +609,7 @@ Class Procs: /obj/machinery/proc/can_be_overridden() . = 1 -/obj/machinery/tesla_act(power, tesla_flags, shocked_objects) +/obj/machinery/tesla_act(power, tesla_flags, shocked_objects, zap_gib = FALSE) ..() if((tesla_flags & TESLA_MACHINE_EXPLOSIVE) && !(resistance_flags & INDESTRUCTIBLE)) if(prob(60)) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 003fa74a0a19..3ca575ba7cb1 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -2,6 +2,8 @@ /// Chance of taking a step per second #define ANOMALY_MOVECHANCE 45 +///////////////////// + /obj/effect/anomaly name = "anomaly" desc = "A mysterious anomaly, seen commonly only in the region of space that the station orbits..." @@ -10,6 +12,7 @@ anchored = TRUE light_range = 3 var/obj/item/assembly/signaler/anomaly/aSignal + var/core_type var/area/impact_area var/lifespan = 990 @@ -18,16 +21,32 @@ var/countdown_colour var/obj/effect/countdown/anomaly/countdown + /// Do we keep on living forever? + var/immortal = FALSE + /obj/effect/anomaly/Initialize(mapload, new_lifespan) . = ..() GLOB.poi_list |= src START_PROCESSING(SSobj, src) impact_area = get_area(src) - aSignal = new(src) - aSignal.name = "[name] core" + switch(core_type) + if(ANOMALY_RADIATION) + aSignal = new /obj/item/assembly/signaler/anomaly/radiation(src) + if(ANOMALY_HALLUCINATION) + aSignal = new /obj/item/assembly/signaler/anomaly/hallucination(src) + if(ANOMALY_FLUX) + aSignal = new /obj/item/assembly/signaler/anomaly/flux(src) + if(ANOMALY_GRAVITATIONAL) + aSignal = new /obj/item/assembly/signaler/anomaly/grav(src) + if(ANOMALY_PYRO) + aSignal = new /obj/item/assembly/signaler/anomaly/pyro(src) + if(ANOMALY_BLUESPACE) + aSignal = new /obj/item/assembly/signaler/anomaly/bluespace(src) + if(ANOMALY_VORTEX) + aSignal = new /obj/item/assembly/signaler/anomaly/vortex(src) + aSignal.code = rand(1,100) - aSignal.anomaly_type = type var/frequency = rand(MIN_FREE_FREQ, MAX_FREE_FREQ) if(ISMULTIPLE(frequency, 2))//signaller frequencies are always uneven! @@ -37,6 +56,8 @@ if(new_lifespan) lifespan = new_lifespan death_time = world.time + lifespan + if(immortal) + return // no countdown for forever anomalies countdown = new(src) if(countdown_colour) countdown.color = countdown_colour @@ -44,7 +65,7 @@ /obj/effect/anomaly/process(delta_time) anomalyEffect(delta_time) - if(death_time < world.time) + if(death_time < world.time && !immortal) if(loc) detonate() qdel(src) @@ -84,6 +105,7 @@ /obj/effect/anomaly/grav name = "gravitational anomaly" icon_state = "shield2" + core_type = ANOMALY_GRAVITATIONAL density = FALSE var/boing = 0 @@ -140,10 +162,14 @@ /obj/effect/anomaly/flux name = "flux wave anomaly" icon_state = "electricity2" + core_type = ANOMALY_FLUX density = FALSE // so it doesn't awkwardly block movement when it doesn't stun you var/canshock = 0 var/shockdamage = 30 - var/explosive = TRUE + var/explosive = ANOMALY_FLUX_NO_EXPLOSION + +/obj/effect/anomaly/flux/explosion + explosive = ANOMALY_FLUX_EXPLOSION /obj/effect/anomaly/flux/anomalyEffect(delta_time) ..() @@ -184,13 +210,11 @@ span_italics("You hear a heavy electrical crack.")) /obj/effect/anomaly/flux/detonate() - if(explosive) - message_admins("An anomaly has detonated.") //yogs - log_game("An anomaly has detonated.") //yogs - explosion(src, 1, 4, 16, 18) //Low devastation, but hits a lot of stuff. - else - new /obj/effect/particle_effect/sparks(loc) - + switch(explosive) + if(ANOMALY_FLUX_EXPLOSION) + explosion(src, devastation_range = 1, heavy_impact_range = 4, light_impact_range = 16, flash_range = 18) //Low devastation, but hits a lot of stuff. + if(ANOMALY_FLUX_NO_EXPLOSION) + new /obj/effect/particle_effect/sparks(loc) ///////////////////// @@ -198,6 +222,7 @@ name = "bluespace anomaly" icon = 'icons/obj/projectiles.dmi' icon_state = "bluespace" + core_type = ANOMALY_BLUESPACE density = TRUE /obj/effect/anomaly/bluespace/anomalyEffect() @@ -269,6 +294,7 @@ name = "pyroclastic anomaly" icon_state = "pyro" color = "#ffa952" + core_type = ANOMALY_PYRO var/ticks = 0 /// How many seconds between each gas release var/releasedelay = 10 @@ -308,6 +334,7 @@ /obj/effect/anomaly/bhole name = "vortex anomaly" icon_state = "bhole3" + core_type = ANOMALY_VORTEX desc = "That's a nice station you have there. It'd be a shame if something happened to it." /obj/effect/anomaly/bhole/anomalyEffect() @@ -371,51 +398,89 @@ ///////////////////////// /obj/effect/anomaly/radiation name = "radiation anomaly" - icon = 'icons/obj/projectiles.dmi' icon_state = "radiation_anomaly" + core_type = ANOMALY_RADIATION density = TRUE - var/spawn_goat = FALSE //For goat spawning + var/spawn_goat = ANOMALY_RADIATION_NO_GOAT //For goat spawning -/obj/effect/anomaly/radiation/admin //bussing - spawn_goat = TRUE +/obj/effect/anomaly/radiation/goat //bussing + spawn_goat = ANOMALY_RADIATION_YES_GOAT /obj/effect/anomaly/radiation/anomalyEffect() ..() - for(var/i = 1 to 15) + for(var/i = 1 to 5) fire_nuclear_particle() - radiation_pulse(src, 500, 5) + radiation_pulse(src, 10000, 5) /obj/effect/anomaly/radiation/proc/makegoat() - var/turf/open/T = get_turf(src) - var/mob/living/simple_animal/hostile/retaliate/goat/radioactive/S = new(T) - - var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a radioactive goat?", ROLE_SENTIENCE, null, null, 100, S, POLL_IGNORE_PYROSLIME) - if(LAZYLEN(candidates)) - var/mob/dead/observer/chosen = pick(candidates) - S.key = chosen.key - var/datum/action/cooldown/spell/conjure/radiation_anomaly/spell - spell.Grant(S) - log_game("[key_name(S.key)] was made into a radioactive goat by radiation anomaly at [AREACOORD(T)].") + for(var/i=1 to 15) + fire_nuclear_particle() + radiation_pulse(src, 20000, 7) + if(spawn_goat == ANOMALY_RADIATION_YES_GOAT) + var/turf/open/T = get_turf(src) + var/mob/living/simple_animal/hostile/retaliate/goat/radioactive/S = new(T) + + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a radioactive goat?", ROLE_SENTIENCE, null, null, 100, S, POLL_IGNORE_PYROSLIME) + if(LAZYLEN(candidates)) + var/mob/dead/observer/chosen = pick(candidates) + S.key = chosen.key + var/datum/action/cooldown/spell/conjure/radiation_anomaly/spell + spell.Grant(S) + log_game("[key_name(S.key)] was made into a radioactive goat by radiation anomaly at [AREACOORD(T)].") /obj/effect/anomaly/radiation/detonate() - INVOKE_ASYNC(src, PROC_REF(rad_Spin)) + INVOKE_ASYNC(src, PROC_REF(makegoat)) -/obj/effect/anomaly/radiation/proc/rad_Spin(increment = 1) - if(increment > 100) - if(spawn_goat)//only spawn the goat once, when the anomaly explodes - INVOKE_ASYNC(src, PROC_REF(makegoat)) - qdel(src) - radiation_pulse(src, 5000, 7) - var/turf/T = get_turf(src) - var/angle = increment * 10 - T.fire_nuclear_particle(angle) - addtimer(CALLBACK(src, PROC_REF(rad_Spin), increment + 1), 0.7) - +///////////////////// -/obj/effect/anomaly/radiation/process(delta_time) - anomalyEffect(delta_time) - if(death_time < world.time) - if(loc) - detonate() +/obj/effect/anomaly/hallucination + name = "hallucination anomaly" + icon_state = "hallucination_anomaly" + core_type = ANOMALY_HALLUCINATION + /// Time passed since the last effect, increased by delta_time of the SSobj + var/ticks = 0 + /// How many seconds between each small hallucination pulses + var/release_delay = 5 + +/obj/effect/anomaly/hallucination/anomalyEffect(delta_time) + . = ..() + ticks += delta_time + if(ticks < release_delay) + return + ticks -= release_delay + var/turf/open/our_turf = get_turf(src) + if(istype(our_turf)) + hallucination_pulse(our_turf, 5) + +/obj/effect/anomaly/hallucination/detonate() + var/turf/open/our_turf = get_turf(src) + if(istype(our_turf)) + hallucination_pulse(our_turf, 10) + +/proc/hallucination_pulse(turf/location, range, strength = 50) + for(var/mob/living/carbon/human/near in view(location, range)) + // If they are immune to hallucinations + if (HAS_TRAIT(near, TRAIT_MESONS) || (near.mind && HAS_TRAIT(near.mind, TRAIT_MESONS))) + continue + + // Blind people don't get hallucinations + if (is_blind(near)) + continue + + // Everyone else + var/dist = sqrt(1 / max(1, get_dist(near, location))) + near.adjust_hallucinations(max(150, strength * dist)) + near.adjust_jitter(10 SECONDS) + near.adjust_confusion(10 SECONDS) + near.adjust_dizzy(10 SECONDS) + near.adjust_drowsiness(10 SECONDS) + var/static/list/messages = list( + "You feel your conscious mind fall apart!", + "Reality warps around you!", + "Something's wispering around you!", + "You are going insane!", + "What was that?!" + ) + to_chat(near, span_warning("[pick(messages)]")) #undef ANOMALY_MOVECHANCE diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 48d7010af310..52e7e793e80a 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -240,13 +240,13 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e SSfire_burning.processing -= src ///Called when the obj is hit by a tesla bolt. -/obj/proc/tesla_act(power, tesla_flags, shocked_targets) +/obj/proc/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) obj_flags |= BEING_SHOCKED addtimer(CALLBACK(src, PROC_REF(reset_shocked)), 10) if(power < TESLA_MINI_POWER) //tesla bolts bounce twice, tesla miniball bolts bounce only once return var/power_bounced = power / 2 - tesla_zap(src, 3, power_bounced, tesla_flags, shocked_targets) + tesla_zap(src, 3, power_bounced, tesla_flags, shocked_targets, zap_gib) //The surgeon general warns that being buckled to certain objects receiving powerful shocks is greatly hazardous to your health ///Only tesla coils and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later. diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm index f6cd06afe898..7178befd2ad3 100644 --- a/code/modules/antagonists/blob/structures/_blob.dm +++ b/code/modules/antagonists/blob/structures/_blob.dm @@ -209,7 +209,7 @@ if(prob(100 - severity * 30)) new /obj/effect/temp_visual/emp(get_turf(src)) -/obj/structure/blob/tesla_act(power) +/obj/structure/blob/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) ..() if(overmind) if(overmind.blobstrain.tesla_reaction(src, power)) diff --git a/code/modules/antagonists/clockcult/clock_mobs.dm b/code/modules/antagonists/clockcult/clock_mobs.dm index c2bd915cc3aa..f51d9430640f 100644 --- a/code/modules/antagonists/clockcult/clock_mobs.dm +++ b/code/modules/antagonists/clockcult/clock_mobs.dm @@ -37,7 +37,7 @@ /mob/living/simple_animal/hostile/clockwork/ratvar_act() fully_heal(TRUE) -/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) return 0 //ouch, my metal-unlikely-to-be-damaged-by-electricity-body /mob/living/simple_animal/hostile/clockwork/examine(mob/user) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 6d18e95b65df..d4c6bdef3518 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -428,7 +428,7 @@ return qdel(src) -/obj/machinery/nuclearbomb/tesla_act(power, tesla_flags) +/obj/machinery/nuclearbomb/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) ..() if(tesla_flags & TESLA_MACHINE_EXPLOSIVE) qdel(src)//like the singulo, tesla deletes it. stops it from exploding over and over diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 999bc9ac0c40..b13868abde02 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -185,7 +185,7 @@ /obj/item/assembly/signaler/anomaly name = "anomaly core" desc = "The neutralized core of an anomaly. It'd probably be valuable for research." - icon_state = "anomaly core" + icon_state = "anomaly_core" item_state = "electronic" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' @@ -217,10 +217,42 @@ /obj/item/assembly/signaler/anomaly/attack_self() return +//Anomaly cores +/obj/item/assembly/signaler/anomaly/pyro + name = "\improper pyroclastic anomaly core" + desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research." + anomaly_type = /obj/effect/anomaly/pyro + +/obj/item/assembly/signaler/anomaly/grav + name = "\improper gravitational anomaly core" + desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research." + anomaly_type = /obj/effect/anomaly/grav + +/obj/item/assembly/signaler/anomaly/flux + name = "\improper flux anomaly core" + desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research." + anomaly_type = /obj/effect/anomaly/flux + +/obj/item/assembly/signaler/anomaly/bluespace + name = "\improper bluespace anomaly core" + desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research." + anomaly_type = /obj/effect/anomaly/bluespace + +/obj/item/assembly/signaler/anomaly/vortex + name = "\improper vortex anomaly core" + desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research." + anomaly_type = /obj/effect/anomaly/bhole + +/obj/item/assembly/signaler/anomaly/hallucination + name = "\improper hallucination anomaly core" + desc = "The neutralized core of a hallucination anomaly. It seems to be moving, but it's probably your imagination. It'd probably be valuable for research." + icon_state = "hallucination_core" + anomaly_type = /obj/effect/anomaly/hallucination + /obj/item/assembly/signaler/anomaly/radiation name = "\improper radiation anomaly core" desc = "The neutralized core of a radiation anomaly. It keeps pulsing an ominous green. It'd probably be valuable for research." - icon_state = "anomaly core" + icon_state = "radiation_core" anomaly_type = /obj/effect/anomaly/radiation /obj/item/assembly/signaler/cyborg diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 67038a58a391..ac89e60fddb8 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -11,7 +11,9 @@ /obj/effect/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse, /obj/effect/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla, /obj/effect/anomaly/pyro = /obj/item/clothing/suit/armor/reactive/fire, - /obj/effect/anomaly/bluespace = /obj/item/clothing/suit/armor/reactive/teleport + /obj/effect/anomaly/bluespace = /obj/item/clothing/suit/armor/reactive/teleport, + /obj/effect/anomaly/radiation = /obj/item/clothing/suit/armor/reactive/radiation, + /obj/effect/anomaly/hallucination = /obj/item/clothing/suit/armor/reactive/hallucinating, ) if(istype(I, /obj/item/assembly/signaler/anomaly)) @@ -28,9 +30,6 @@ /obj/item/clothing/suit/armor/reactive name = "reactive armor" desc = "Doesn't seem to do much for some reason." - var/active = 0 - var/reactivearmor_cooldown_duration = 0 //cooldown specific to reactive armor - var/reactivearmor_cooldown = 0 icon_state = "reactiveoff" item_state = "reactiveoff" blood_overlay_type = "armor" @@ -38,6 +37,18 @@ actions_types = list(/datum/action/item_action/toggle) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF hit_reaction_chance = 50 + ///Whether the armor will try to react to hits (is it on) + var/active = 0 + ///This will be true for 30 seconds after an EMP, it makes the reaction effect dangerous to the user. + var/bad_effect = FALSE + ///Message sent when the armor is emp'd. It is not the message for when the emp effect goes off. + var/emp_message = span_warning("The reactive armor has been emp'd! Damn, now it's REALLY gonna not do much!") + ///Message sent when the armor is still on cooldown, but activates. + var/cooldown_message = span_danger("The reactive armor fails to do much, as it is recharging! From what? Only the reactive armor knows.") + ///Duration of the cooldown specific to reactive armor for when it can activate again. + var/reactivearmor_cooldown_duration = 5 SECONDS + ///The cooldown itself of the reactive armor for when it can activate again. + COOLDOWN_DECLARE(reactivearmor_cooldown) /obj/item/clothing/suit/armor/reactive/attack_self(mob/user) active = !(active) @@ -50,94 +61,161 @@ icon_state = "reactiveoff" item_state = "reactiveoff" add_fingerprint(user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.update_inv_wear_suit() + for(var/datum/action/A in actions) + A.build_all_button_icons() return +/obj/item/clothing/suit/armor/reactive/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, damage, attack_type) + . = ..() + + if(!active || !prob(hit_reaction_chance)) + return FALSE + if(reactivearmor_cooldown_duration && !COOLDOWN_FINISHED(src, reactivearmor_cooldown)) + cooldown_activation(owner) + return FALSE + if(reactivearmor_cooldown_duration) + COOLDOWN_START(src, reactivearmor_cooldown, reactivearmor_cooldown_duration) + + if(bad_effect) + return emp_activation(owner, hitby, attack_text, damage, attack_type) + else + return reactive_activation(owner, hitby, attack_text, damage, attack_type) + +/** + * A proc for doing cooldown effects (like the sparks on the tesla armor, or the semi-stealth on stealth armor) + * Called from the suit activating whilst on cooldown. + * You should be calling ..() + */ +/obj/item/clothing/suit/armor/reactive/proc/cooldown_activation(mob/living/carbon/human/owner) + owner.visible_message(cooldown_message) + +/** + * A proc for doing reactive armor effects. + * Called from the suit activating while off cooldown, with no emp. + * Returning TRUE will block the attack that triggered this + */ +/obj/item/clothing/suit/armor/reactive/proc/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("The reactive armor doesn't do much! No surprises here.")) + return TRUE + +/** + * A proc for doing owner unfriendly reactive armor effects. + * Called from the suit activating while off cooldown, while the armor is still suffering from the effect of an EMP. + * Returning TRUE will block the attack that triggered this + */ +/obj/item/clothing/suit/armor/reactive/proc/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("The reactive armor doesn't do much, despite being emp'd! Besides giving off a special message, of course.")) + return TRUE + /obj/item/clothing/suit/armor/reactive/emp_act(severity) . = ..() - if(. & EMP_PROTECT_SELF) + if(. & EMP_PROTECT_SELF || bad_effect || !active) //didn't get hit or already emp'd, or off return - active = 0 - icon_state = "reactiveoff" - item_state = "reactiveoff" - reactivearmor_cooldown = world.time + 200 + if(ismob(loc)) + to_chat(loc, emp_message) + bad_effect = TRUE + addtimer(VARSET_CALLBACK(src, bad_effect, FALSE), 30 SECONDS) //When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!) /obj/item/clothing/suit/armor/reactive/teleport name = "reactive teleport armor" desc = "Someone separated our Research Director from his own head!" + emp_message = span_warning("The reactive armor's teleportation calculations begin spewing errors!") + cooldown_message = span_danger("The reactive teleport system is still recharging! It fails to activate!") + reactivearmor_cooldown_duration = 10 SECONDS var/tele_range = 6 var/rad_amount= 15 - reactivearmor_cooldown_duration = 100 - -/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!active) - return 0 - if(!damage) - return 0 - if(prob(hit_reaction_chance)) - var/mob/living/carbon/human/H = owner - if(world.time < reactivearmor_cooldown) - owner.visible_message(span_danger("The reactive teleport system is still recharging! It fails to teleport [H]!")) - return - owner.visible_message(span_danger("The reactive teleport system flings [H] clear of [attack_text], shutting itself off in the process!")) - do_teleport(H, get_turf(H), tele_range, asoundin = 'sound/magic/blink.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) - H.rad_act(rad_amount) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return 1 - return 0 + +/obj/item/clothing/suit/armor/reactive/teleport/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("The reactive teleport system flings [owner] clear of [attack_text], shutting itself off in the process!")) + playsound(get_turf(owner),'sound/magic/blink.ogg', 100, 1) + do_teleport(teleatom = owner, destination = get_turf(owner), no_effects = TRUE, precision = tele_range, channel = TELEPORT_CHANNEL_BLUESPACE) + owner.rad_act(rad_amount) + return TRUE + +/obj/item/clothing/suit/armor/reactive/teleport/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("The reactive teleport system flings itself clear of [attack_text], leaving someone behind in the process!")) + owner.dropItemToGround(src, TRUE, TRUE) + playsound(get_turf(owner), 'sound/machines/buzz-sigh.ogg', 50, 1) + playsound(get_turf(owner), 'sound/magic/blink.ogg', 100, 1) + do_teleport(teleatom = src, destination = get_turf(owner), no_effects = TRUE, precision = tele_range, channel = TELEPORT_CHANNEL_BLUESPACE) + owner.rad_act(rad_amount) + return FALSE //you didn't actually evade the attack now did you //Fire /obj/item/clothing/suit/armor/reactive/fire name = "reactive incendiary armor" desc = "An experimental suit of armor with a reactive sensor array rigged to a flame emitter. For the stylish pyromaniac." + cooldown_message = span_danger("The reactive incendiary armor activates, but fails to send out flames as it is still recharging its flame jets!") + emp_message = span_warning("The reactive incendiary armor's targeting system begins rebooting...") + +/obj/item/clothing/suit/armor/reactive/fire/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], sending out jets of flame!")) + playsound(get_turf(owner),'sound/magic/fireball.ogg', 100, 1) + for(var/mob/living/carbon/C in ohearers(6, owner)) + C.fire_stacks += 8 + C.ignite_mob() + owner.fire_stacks = -20 + return TRUE -/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!active) - return 0 - if(!damage) - return 0 - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message(span_danger("The reactive incendiary armor on [owner] activates, but fails to send out flames as it is still recharging its flame jets!")) - return - owner.visible_message(span_danger("[src] blocks [attack_text], sending out jets of flame!")) - playsound(get_turf(owner),'sound/magic/fireball.ogg', 100, 1) - for(var/mob/living/carbon/C in range(6, owner)) - if(C != owner) - C.adjust_fire_stacks(8) - C.ignite_mob() - owner.fire_stacks = -1 - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return 1 - return 0 +/obj/item/clothing/suit/armor/reactive/fire/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] just makes [attack_text] worse by spewing fire on [owner]!")) + playsound(get_turf(owner),'sound/magic/fireball.ogg', 100, 1) + owner.fire_stacks += 12 + owner.ignite_mob() + return FALSE //Stealth /obj/item/clothing/suit/armor/reactive/stealth name = "reactive stealth armor" desc = "An experimental suit of armor that renders the wearer invisible on detection of imminent harm, and creates a decoy that runs away from the owner. You can't fight what you can't see." - reactivearmor_cooldown_duration = 80 - -/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!active) - return 0 - if(!damage) - return 0 - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message(span_danger("The reactive stealth system on [owner] activates, but is still recharging its holographic emitters!")) - return - var/mob/living/simple_animal/hostile/illusion/escape/E = new(owner.loc) - E.Copy_Parent(owner, 50) - E.GiveTarget(owner) //so it starts running right away - E.Goto(owner, E.move_to_delay, E.minimum_distance) - owner.alpha = 0 - owner.visible_message(span_danger("[owner] is hit by [attack_text] in the chest!")) //We pretend to be hit, since blocking it would stop the message otherwise - spawn(40) - owner.alpha = initial(owner.alpha) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return 1 + cooldown_message = span_danger("The reactive stealth system activates, but is not charged enough to fully cloak!") + emp_message = span_warning("The reactive stealth armor's threat assessment system crashes...") + ///when triggering while on cooldown will only flicker the alpha slightly. this is how much it removes. + var/cooldown_alpha_removal = 50 + ///cooldown alpha flicker- how long it takes to return to the original alpha + var/cooldown_animation_time = 3 SECONDS + ///how long they will be fully stealthed + var/stealth_time = 4 SECONDS + ///how long it will animate back the alpha to the original + var/animation_time = 2 SECONDS + var/in_stealth = FALSE + +/obj/item/clothing/suit/armor/reactive/stealth/cooldown_activation(mob/living/carbon/human/owner) + if(in_stealth) + return //we don't want the cooldown message either) + owner.alpha = max(0, owner.alpha - cooldown_alpha_removal) + animate(owner, alpha = initial(owner.alpha), time = cooldown_animation_time) + ..() + +/obj/item/clothing/suit/armor/reactive/stealth/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + var/mob/living/simple_animal/hostile/illusion/escape/decoy = new(owner.loc) + decoy.Copy_Parent(owner, 50) + decoy.GiveTarget(owner) //so it starts running right away + decoy.Goto(owner, decoy.move_to_delay, decoy.minimum_distance) + in_stealth = TRUE + owner.visible_message(span_danger("[owner] is hit by [attack_text] in the chest!")) //We pretend to be hit, since blocking it would stop the message otherwise + owner.alpha = 0 + addtimer(CALLBACK(src, PROC_REF(end_stealth), owner), stealth_time) + return TRUE + +/obj/item/clothing/suit/armor/reactive/stealth/proc/end_stealth(mob/living/carbon/human/owner) + in_stealth = FALSE + animate(owner, alpha = initial(owner.alpha), time = animation_time) + +/obj/item/clothing/suit/armor/reactive/stealth/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + if(!isliving(hitby)) + return FALSE //it just doesn't activate + var/mob/living/attacker = hitby + owner.visible_message(span_danger("[src] activates, cloaking the wrong person!")) + attacker.alpha = 0 + addtimer(VARSET_CALLBACK(attacker, alpha, initial(attacker.alpha)), 4 SECONDS) + return FALSE //Tesla @@ -149,6 +227,8 @@ var/tesla_power = 25000 var/tesla_range = 20 var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE + cooldown_message = span_danger("The tesla capacitors on the reactive tesla armor are still recharging! The armor merely emits some sparks.") + emp_message = span_warning("The tesla capacitors beep ominously for a moment.") /obj/item/clothing/suit/armor/reactive/tesla/dropped(mob/user) ..() @@ -160,24 +240,24 @@ if(slot_flags & slot) //Was equipped to a valid slot for this item? user.flags_1 |= TESLA_IGNORE_1 -/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!active) - return FALSE - if(!damage) - return FALSE - if(owner.stat == DEAD) - return FALSE - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread - sparks.set_up(1, 1, src) - sparks.start() - owner.visible_message(span_danger("The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.")) - return - owner.visible_message(span_danger("[src] blocks [attack_text], sending out arcs of lightning!")) - tesla_zap(owner, tesla_range, tesla_power, tesla_flags) - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return TRUE +/obj/item/clothing/suit/armor/reactive/tesla/cooldown_activation(mob/living/carbon/human/owner) + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() + ..() + +/obj/item/clothing/suit/armor/reactive/tesla/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], sending out arcs of lightning!")) + tesla_zap(owner, tesla_range, tesla_power, tesla_flags) + return TRUE + +/obj/item/clothing/suit/armor/reactive/tesla/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], but pulls a massive charge of energy into [owner] from the surrounding environment!")) + if(istype(owner)) + owner.flags_1 &= ~TESLA_IGNORE_1 + electrocute_mob(owner, get_area(src), src, 1) + owner.flags_1 |= TESLA_IGNORE_1 + return FALSE //Repulse @@ -186,67 +266,117 @@ desc = "An experimental suit of armor that violently throws back attackers." reactivearmor_cooldown_duration = 5 SECONDS var/repulse_force = MOVE_FORCE_EXTREMELY_STRONG + cooldown_message = span_danger("The repulse generator is still recharging! It fails to generate a strong enough wave!") + emp_message = span_warning("The repulse generator is reset to default settings...") + +/obj/item/clothing/suit/armor/reactive/repulse/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + playsound(get_turf(owner),'sound/magic/repulse.ogg', 100, 1) + owner.visible_message(span_danger("[src] blocks [attack_text], converting the attack into a wave of force!")) + var/turf/T = get_turf(owner) + var/list/thrown_items = list() + for(var/atom/movable/A in orange(7, T)) + if(A.anchored || thrown_items[A]) + continue + var/throwtarget = get_edge_target_turf(T, get_dir(T, get_step_away(A, T))) + A.safe_throw_at(throwtarget, 10, 1, force = repulse_force) + thrown_items[A] = A -/obj/item/clothing/suit/armor/reactive/repulse/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!active) - return 0 - if(!damage) - return 0 - if(prob(hit_reaction_chance)) - if(world.time < reactivearmor_cooldown) - owner.visible_message(span_danger("The repulse generator is still recharging!")) - return 0 - playsound(get_turf(owner),'sound/magic/repulse.ogg', 100, 1) - owner.visible_message(span_danger("[src] blocks [attack_text], converting the attack into a wave of force!")) - var/turf/T = get_turf(owner) - var/list/thrown_items = list() - for(var/atom/movable/A in range(T, 7)) - if(A == owner || A.anchored || thrown_items[A]) - continue - var/throwtarget = get_edge_target_turf(T, get_dir(T, get_step_away(A, T))) - A.safe_throw_at(throwtarget, 10, 1, force = repulse_force) - thrown_items[A] = A - - reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration - return 1 + return TRUE + +/obj/item/clothing/suit/armor/reactive/repulse/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + playsound(get_turf(owner),'sound/magic/repulse.ogg', 100, 1) + owner.visible_message(span_danger("[src] does not block [attack_text], and instead generates an attracting force!")) + var/turf/T = get_turf(owner) + var/list/thrown_items = list() + for(var/atom/movable/A as mob|obj in orange(7, T)) + if(A.anchored || thrown_items[A]) + continue + A.safe_throw_at(owner, 10, 1, force = repulse_force) + thrown_items[A] = A + + return FALSE + +//Table /obj/item/clothing/suit/armor/reactive/table name = "reactive table armor" desc = "If you can't beat the memes, embrace them." var/tele_range = 10 + cooldown_message = span_danger("The reactive table armor's fabricators are still on cooldown!") + emp_message = span_danger("The reactive table armor's fabricators click and whirr ominously for a moment...") -/obj/item/clothing/suit/armor/reactive/table/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) - if(!active) - return 0 - if(!damage) - return 0 - if(prob(hit_reaction_chance)) - var/mob/living/carbon/human/H = owner - if(world.time < reactivearmor_cooldown) - owner.visible_message(span_danger("The reactive table armor's fabricators are still on cooldown!")) - return - owner.visible_message(span_danger("The reactive teleport system flings [H] clear of [attack_text] and slams [H.p_them()] into a fabricated table!")) - owner.visible_message("[H] GOES ON THE TABLE!!!") - owner.Paralyze(40) - var/list/turfs = new/list() - for(var/turf/T in orange(tele_range, H)) - if(T.density) - continue - if(T.x>world.maxx-tele_range || T.xworld.maxy-tele_range || T.y[owner] GOES ON THE TABLE!!!") + owner.Paralyze(40) + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table) + do_teleport(teleatom = owner, destination = get_turf(owner), no_effects = TRUE, precision = tele_range, channel = TELEPORT_CHANNEL_BLUESPACE) + new /obj/structure/table(get_turf(owner)) + return TRUE + +/obj/item/clothing/suit/armor/reactive/table/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("The reactive teleport system flings [owner] clear of [attack_text] and slams [owner.p_them()] into a fabricated glass table!")) + owner.visible_message("[owner] GOES ON THE TABLE!!!") + SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "table", /datum/mood_event/table) + do_teleport(teleatom = owner, destination = get_turf(owner), no_effects = TRUE, precision = tele_range, channel = TELEPORT_CHANNEL_BLUESPACE) + var/obj/structure/table/glass/table = new(get_turf(owner)) + table.table_shatter(owner) + return TRUE + +//Hallucinating + +/obj/item/clothing/suit/armor/reactive/hallucinating + name = "reactive hallucinating armor" + desc = "An experimental suit of armor with sensitive detectors hooked up to the mind of the wearer, sending mind pulses that causes hallucinations around you." + cooldown_message = span_warning("The connection is currently out of sync... Recalibrating.") + emp_message = span_warning("You feel the backsurge of a mind pulse.") + var/effect_range = 3 + clothing_traits = list(TRAIT_MESONS) + +/obj/item/clothing/suit/armor/reactive/hallucinating/cooldown_activation(mob/living/carbon/human/owner) + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() + ..() + +/obj/item/clothing/suit/armor/reactive/hallucinating/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], sending out mental pulses!")) + var/turf/location = get_turf(owner) + if(location) + hallucination_pulse(location, effect_range, strength = 25) + return TRUE + +/obj/item/clothing/suit/armor/reactive/hallucinating/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], but pulls a massive charge of mental energy into [owner] from the surrounding environment!")) + owner.adjust_hallucinations(150) + return TRUE + +//Radiation + +/obj/item/clothing/suit/armor/reactive/radiation + name = "reactive radiation armor" + desc = "An experimental suit of armor thats give the owner radiation proof and on activation releases a wave of radiation around the owner." + cooldown_message = span_warning("The connection is currently out of sync... Recalibrating.") + emp_message = span_warning("You feel the radiation wave within you.") + var/effect_range = 3 + clothing_traits = list(TRAIT_RADIMMUNE) + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 100, FIRE = 100, ACID = 100) + flags_1 = RAD_PROTECT_CONTENTS_1 + +/obj/item/clothing/suit/armor/reactive/radiation/cooldown_activation(mob/living/carbon/human/owner) + var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() + ..() + +/obj/item/clothing/suit/armor/reactive/radiation/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], sending out radiation pulses and nuclear particles!")) + radiation_pulse(src, 1000, effect_range) + for(var/i = 1 to 15) + fire_nuclear_particle() + return TRUE + +/obj/item/clothing/suit/armor/reactive/radiation/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) + owner.visible_message(span_danger("[src] blocks [attack_text], but pulls a massive charge of radiation wave into [owner] from the surrounding environment!")) + owner.adjustToxLoss(10) + return TRUE diff --git a/code/modules/events/anomaly.dm b/code/modules/events/anomaly.dm index 558ddbb6a220..abb1aaca83a6 100644 --- a/code/modules/events/anomaly.dm +++ b/code/modules/events/anomaly.dm @@ -16,17 +16,10 @@ var/static/list/allowed_areas if(!allowed_areas) //Places that shouldn't explode - var/list/safe_area_types = typecacheof(list( - /area/ai_monitored/turret_protected/ai, - /area/ai_monitored/turret_protected/ai_upload, - /area/engine, - /area/solar, - /area/holodeck, - /area/shuttle) - ) + var/list/safe_area_types = typecacheof(ANOMALY_AREA_BLACKLIST) //Subtypes from the above that actually should explode. - var/list/unsafe_area_subtypes = typecacheof(list(/area/engine/break_room)) + var/list/unsafe_area_subtypes = typecacheof(ANOMALY_AREA_SUBTYPE_WHITELIST) allowed_areas = make_associative(GLOB.the_station_areas) - safe_area_types + unsafe_area_subtypes @@ -45,6 +38,10 @@ /datum/round_event/anomaly/start() var/turf/T = pick(get_area_turfs(impact_area)) + var/max_rolls=0 //In case all the turfs in the area are walls, will break out of rolling for a new turf forever and will just spawn the anomaly inside a wall + while(is_anchored_dense_turf(T) && max_rolls<15) //Will roll for a new turf if the selected turf is a wall until it's not a wall + T = safepick(get_area_turfs(impact_area)) + max_rolls++ var/newAnomaly if(T) newAnomaly = new anomaly_path(T) diff --git a/code/modules/events/anomaly_flux.dm b/code/modules/events/anomaly_flux.dm index 4737ad9bb416..4ecd8a57e6d6 100644 --- a/code/modules/events/anomaly_flux.dm +++ b/code/modules/events/anomaly_flux.dm @@ -9,7 +9,7 @@ /datum/round_event/anomaly/anomaly_flux startWhen = 10 announceWhen = 3 - anomaly_path = /obj/effect/anomaly/flux + anomaly_path = /obj/effect/anomaly/flux/explosion /datum/round_event/anomaly/anomaly_flux/announce(fake) priority_announce("Localized hyper-energetic flux wave detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_hallucination.dm b/code/modules/events/anomaly_hallucination.dm new file mode 100644 index 000000000000..0f3628c7e0b8 --- /dev/null +++ b/code/modules/events/anomaly_hallucination.dm @@ -0,0 +1,15 @@ +/datum/round_event_control/anomaly/anomaly_hallucination + name = "Anomaly: Hallucination" + typepath = /datum/round_event/anomaly/anomaly_hallucination + + min_players = 10 + max_occurrences = 5 + weight = 20 + +/datum/round_event/anomaly/anomaly_hallucination + startWhen = 10 + announceWhen = 3 + anomaly_path = /obj/effect/anomaly/hallucination + +/datum/round_event/anomaly/anomaly_hallucination/announce(fake) + priority_announce("Hallucinatory event hitting the station. Expected location: [impact_area.name].", "Anomaly Alert") diff --git a/code/modules/events/anomaly_radiation.dm b/code/modules/events/anomaly_radiation.dm index aa105573cf5e..e5d631b17b98 100644 --- a/code/modules/events/anomaly_radiation.dm +++ b/code/modules/events/anomaly_radiation.dm @@ -12,6 +12,6 @@ /datum/round_event/anomaly/anomaly_radiation/announce(fake) if(prob(90)) - priority_announce("Radioactive anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") + priority_announce("Large radiation pulse detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert") else - print_command_report("Radioactive anomaly detected on long range scanners. Expected location: [impact_area.name].", "Radioactive anomaly") + print_command_report("Large radiation pulse detected on long range scanners. Expected location: [impact_area.name].", "Radioactive anomaly") diff --git a/code/modules/events/portal_storm.dm b/code/modules/events/portal_storm.dm index 86c2095e4c48..b59f85d41392 100644 --- a/code/modules/events/portal_storm.dm +++ b/code/modules/events/portal_storm.dm @@ -131,17 +131,51 @@ /datum/round_event/portal_storm/resonance_cascade boss_types = list( - /mob/living/simple_animal/hostile/asteroid/goliath/beast = 12, - /mob/living/simple_animal/hostile/asteroid/marrowweaver = 12 + /mob/living/simple_animal/hostile/megafauna/bubblegum = 1, + /mob/living/simple_animal/hostile/megafauna/dragon = 1, + /mob/living/simple_animal/hostile/megafauna/stalwart = 1, + /mob/living/simple_animal/hostile/megafauna/colossus = 1, + /mob/living/simple_animal/hostile/megafauna/hierophant = 1, + /mob/living/simple_animal/hostile/megafauna/legion = 1, + /mob/living/simple_animal/hostile/retaliate/goat/king = 1, + /mob/living/simple_animal/hostile/megafauna/swarmer_swarm_beacon = 4, + /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner = 6, + /mob/living/simple_animal/hostile/megafauna/demonic_frost_miner = 6, + /mob/living/simple_animal/hostile/asteroid/elite/broodmother = 5, + /mob/living/simple_animal/hostile/asteroid/elite/herald = 5, + /mob/living/simple_animal/hostile/asteroid/elite/legionnaire = 5, + /mob/living/simple_animal/hostile/asteroid/elite/pandora = 5, + /mob/living/simple_animal/hostile/space_dragon = 5 ) hostile_types = list( - /mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril = 24, - /mob/living/simple_animal/hostile/asteroid/basilisk/watcher = 24, + /mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril = 25, + /mob/living/simple_animal/hostile/asteroid/basilisk/watcher = 25, + /mob/living/simple_animal/hostile/asteroid/goliath/beast = 25, + /mob/living/simple_animal/hostile/asteroid/marrowweaver = 25 + ) + var/list/anomaly_types = list( + ANOMALY_FLUX_EXPLOSIVE = 150, + ANOMALY_RADIATION = 130, + ANOMALY_RADIATION_X = 5, + ANOMALY_VORTEX = 130, + ANOMALY_PYRO = 140, + ANOMALY_HALLUCINATION = 140, + ANOMALY_GRAVITATIONAL = 160, ) endWhen = INFINITY // keep going until it's done /datum/round_event/portal_storm/resonance_cascade/start() . = ..() + var/list/nether_areas = GLOB.generic_event_spawns + for(var/i in 1 to 50) + var/area/target_event_spawn = pick_n_take(nether_areas) + if(!target_event_spawn) + return + + var/obj/structure/spawner/nether/doom = new(target_event_spawn.loc) + doom.max_integrity = 250 + doom.spawn_time = 20 SECONDS + for(var/obj/machinery/power/apc/A in GLOB.apcs_list) if(!is_station_level(A.z)) continue @@ -156,12 +190,32 @@ else A.visible_message(span_userdanger("[A] overloads and makes a huge arc!")) tesla_zap(A, 5, 10000) // woe - SSshuttle.emergency.request(null) // can't call the shuttle if all the APCs blew up, so give the crew some help + message_centcom("Alert, a large scale of abnormal activity has been detected on [station_name()]. Investigate and send the special forces to the station immediately.", "Central Command Higher Dimensional Affairs") + priority_announce("Unknown anomalous portals detected on a large scale of the station. There is no additional data.", "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES) + addtimer(CALLBACK(src, PROC_REF(call_shuttle)), 4 SECONDS) //Wait till the annoucement finishes till the the next one so the sounds dont overlap each other + +/datum/round_event/portal_storm/resonance_cascade/proc/call_shuttle() + SSshuttle.emergency.request(null, reason = "Shuttle has been automatically called due to the event, standing by.") // can't call the shuttle if all the APCs blew up, so give the crew some help /datum/round_event/portal_storm/resonance_cascade/announce(fake) if(fake) // no point in trying to fake it, has much more impact if it's only the real thing return - priority_announce(readable_corrupted_text("Massive energy surge detected on [station_name()]. Immediate evacuation is recommended."), sound='sound/misc/airraid.ogg') + priority_announce("Attention all personnel, this is an emergency announcement on [station_name()]. \ + An evacuation is immediately underway due to abnormal hostile activity detected on the premises. \ + A distress signal has been sent to Central Command to alert them of the situation. In addition to that, \ + we have observed a substantial number of meteors approaching the station on a large scale. \ + Please remain calm and follow the evacuation procedures provided. \ + Proceed to the designated evacuation points swiftly and orderly, To ensure your safety, \ + please avoid areas with abnormal activity and refrain from going outside the station to minimize the risk of collisions with meteors. \ + Security personnel are present to assist and ensure your safety. \ + Cooperate with their instructions and refrain from engaging with any hostiles. \ + Central Command is actively responding and coordinating a comprehensive emergency response. \ + Your safety is our utmost priority during this evacuation. \ + Stay vigilant, report any suspicious activity, and await further instructions at the designated evacuation points. \ + Assistance is on the way.", + title = "Central Command Higher Dimensional Affairs", + sound = 'sound/misc/airraid.ogg', + ) /datum/round_event/portal_storm/resonance_cascade/tick() var/turf/T = get_safe_random_station_turf() @@ -180,4 +234,10 @@ if(!boss_types[type]) boss_types -= type + var/anomaly = pick(anomaly_types) + anomaly_types[anomaly] = anomaly_types[anomaly] - 1 + supermatter_anomaly_gen(T, anomaly, rand(5, 10), has_weak_lifespan = TRUE) + if(!anomaly_types[anomaly]) + anomaly_types -= anomaly + time_to_end() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 5e7771f117e5..bf69491e297b 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -380,7 +380,7 @@ var/obj/item/organ/O = X O.emp_act(severity) -/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) if(tesla_shock && (flags_1 & TESLA_IGNORE_1)) return FALSE if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE)) @@ -418,7 +418,14 @@ revive() INVOKE_ASYNC(src, PROC_REF(emote), "gasp") adjust_jitter(10 SECONDS) - adjustOrganLoss(ORGAN_SLOT_BRAIN, 100, 199) //yogs end + adjustOrganLoss(ORGAN_SLOT_BRAIN, 100, 199) + if(gib && siemens_coeff > 0) + visible_message( + span_danger("[src] body is emitting a loud noise!"), \ + span_userdanger("You feel like you are about to explode!"), \ + span_italics("You hear a loud noise!"), \ + ) + addtimer(CALLBACK(src, PROC_REF(supermatter_tesla_gib)), 4 SECONDS) //yogs end if(override) return override else diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 31ff51729fd7..ed7a8ed12094 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -48,7 +48,7 @@ if(org_zone == BODY_ZONE_CHEST) O.Remove(src) O.forceMove(Tsec) - O.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) + O.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) else for(var/X in internal_organs) var/obj/item/organ/I = X @@ -60,18 +60,29 @@ continue I.Remove(src) I.forceMove(Tsec) - I.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) + I.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) if(!no_brain && !no_organs)//drop other heads/brains carried if your own would be dropped for(var/X in src.get_all_contents()) if(istype(X, /obj/item/organ/brain) || istype(X, /obj/item/bodypart/head)) var/obj/item/H = X if(H) H.forceMove(Tsec) - H.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) + H.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) /mob/living/carbon/spread_bodyparts() for(var/X in bodyparts) var/obj/item/bodypart/BP = X BP.drop_limb() - BP.throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),rand(1,3),5) + BP.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) + +/mob/living/carbon/proc/supermatter_tesla_gib() //leave chest behind and vital organs + for(var/obj/item/carbon_contents in src) + dropItemToGround(carbon_contents) + if(prob(50)) + carbon_contents.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5) + adjustFireLoss(1000) + ADD_TRAIT(src, TRAIT_DISFIGURED, TRAIT_GENERIC) + spill_organs() + spread_bodyparts() + spawn_gibs() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index ce5c35340e5f..21eff3f12126 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -275,7 +275,7 @@ return 1 /mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M) - if(check_shields(M, 0, "the M.name")) + if(check_shields(M, 0, "the [M.name]")) visible_message(span_danger("[M] attempted to touch [src]!")) return 0 @@ -500,7 +500,7 @@ //Added a safety check in case you want to shock a human mob directly through electrocute_act. -/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) if(tesla_shock) var/total_coeff = 1 if(gloves) @@ -537,7 +537,7 @@ siemens_coeff *= physiology.siemens_coeff dna.species.spec_electrocute_act(src, shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun) - . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun) + . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun, gib) if(.) electrocution_animation(40) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index ee9f775a52af..71280ac679c4 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -360,7 +360,7 @@ take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1)) return 1 -/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage) if(tesla_shock && (flags_1 & TESLA_IGNORE_1)) return FALSE diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 22bb114f4910..d873e563013f 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -725,8 +725,8 @@ add_overlay(head_overlay) update_fire() -/mob/living/silicon/robot/proc/self_destruct() - if(emagged || module.syndicate_module) +/mob/living/silicon/robot/proc/self_destruct(explode_override = FALSE) + if(emagged || module.syndicate_module || explode_override) if(mmi) qdel(mmi) explosion(src.loc,1,2,4,flame_range = 2) diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index fc08a0dba7b2..80e710a1518e 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -200,3 +200,12 @@ updatehealth() if(prob(75) && Proj.damage > 0) spark_system.start() + +/mob/living/silicon/robot/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) + if(gib) + visible_message( + span_danger("[src] begins to heat up!"), \ + span_userdanger("You begin to heat up!"), \ + ) + addtimer(CALLBACK(src, PROC_REF(self_destruct), TRUE), 4 SECONDS) + return ..() diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 52737a74543b..3942d298949d 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -97,11 +97,11 @@ return return ..() -/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) if(buckled_mobs) for(var/mob/living/M in buckled_mobs) unbuckle_mob(M) - M.electrocute_act(shock_damage/100, source, siemens_coeff, safety, tesla_shock, illusion, stun) //Hard metal shell conducts! + M.electrocute_act(shock_damage/100, source, siemens_coeff, safety, tesla_shock, illusion, stun, gib) //Hard metal shell conducts! return 0 //So borgs they don't die trying to fix wiring /mob/living/silicon/emp_act(severity) diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index 7378886bf841..148022aec96e 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -179,3 +179,8 @@ else visual_effect_icon = ATTACK_EFFECT_SMASH ..() + +/mob/living/simple_animal/electrocute_act(shock_damage, obj/source, siemens_coeff, safety, tesla_shock, illusion, stun, gib) + if(gib) + gib() + return ..() diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 22d332c7946d..5334e54e44d1 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -112,7 +112,7 @@ /mob/living/simple_animal/hostile/construct/narsie_act() return -/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) return 0 /mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 45c2791364f6..fd63fa71afb3 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -288,5 +288,5 @@ // Why would bees pay attention to drones? return 1 -/mob/living/simple_animal/drone/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE) +/mob/living/simple_animal/drone/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE) return 0 //So they don't die trying to fix wiring diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index 5b39274ba275..e736be830e23 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -70,14 +70,6 @@ Difficulty: Hard small_sprite_type = /datum/action/small_sprite/megafauna/bubblegum music_component = /datum/component/music_player/battle music_path = /datum/music/sourced/battle/bubblegum - -/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize(mapload) - . = ..() - if(true_spawn) - for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_living_list) - if(B != src) - return INITIALIZE_HINT_QDEL //There can be only one - /datum/action/innate/megafauna_attack/triple_charge name = "Triple Charge" button_icon = 'icons/mob/actions/actions_items.dmi' diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index ef18ec4231a3..0c7ab0eaa9c2 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -38,7 +38,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne if(prob(20)) set_broken() -/obj/machinery/gravity_generator/tesla_act(power, tesla_flags) +/obj/machinery/gravity_generator/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) ..() if(tesla_flags & TESLA_MACHINE_EXPLOSIVE) qdel(src)//like the singulo, tesla deletes it. stops it from exploding over and over diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index f067bf88904e..61580719f0be 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -786,7 +786,7 @@ on = TRUE && !forced_off update() -/obj/machinery/light/tesla_act(power, tesla_flags) +/obj/machinery/light/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) if(tesla_flags & TESLA_MACHINE_EXPLOSIVE) explosion(src,0,0,0,flame_range = 5, adminlog = 0) qdel(src) diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm index 580bcb142e8a..c0d58a290d9f 100644 --- a/code/modules/power/rtg.dm +++ b/code/modules/power/rtg.dm @@ -96,6 +96,6 @@ /obj/machinery/power/rtg/abductor/fire_act(exposed_temperature, exposed_volume) overload() -/obj/machinery/power/rtg/abductor/tesla_act() +/obj/machinery/power/rtg/abductor/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) ..() //extend the zap overload() diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 262e24993d01..3689d4eb9d73 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -303,6 +303,9 @@ current_size = STAGE_SIX icon = 'icons/effects/352x352.dmi' icon_state = "singularity_s11" + desc = "[initial(desc)] It glows fiercely with inner fire." + name = "supermatter-charged [initial(name)]" + set_light(10) pixel_x = -160 pixel_y = -160 grav_pull = 15 @@ -371,10 +374,7 @@ var/gain = A.singularity_act(current_size, src) src.energy += gain if(istype(A, /obj/machinery/power/supermatter_crystal) && !consumedSupermatter) - desc = "[initial(desc)] It glows fiercely with inner fire." - name = "supermatter-charged [initial(name)]" consumedSupermatter = 1 - set_light(10) return diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index ed6de19c7df6..3e658011ab0e 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -63,8 +63,6 @@ #define DAMAGE_HARDCAP 0.002 #define DAMAGE_INCREASE_MULTIPLIER 0.25 -#define MIASMA_DELAM_PERCENTAGE 50 ///The percentage of miasma before it is classed as a miasma delamination, causing a blob to spawn. - #define THERMAL_RELEASE_MODIFIER 5 //Higher == less heat released during reaction, not to be confused with the above values #define PLASMA_RELEASE_MODIFIER 750 //Higher == less plasma released by reaction #define OXYGEN_RELEASE_MODIFIER 325 //Higher == less oxygen released at high temperature/power @@ -82,11 +80,6 @@ #define HALLUCINATION_RANGE(P) (min(7, round(P ** 0.25))) -#define GRAVITATIONAL_ANOMALY "gravitational_anomaly" -#define FLUX_ANOMALY "flux_anomaly" -#define PYRO_ANOMALY "pyro_anomaly" -#define RADIATION_ANOMALY "radiation_anomaly" - //If integrity percent remaining is less than these values, the monitor sets off the relevant alarm. #define SUPERMATTER_DELAM_PERCENT 5 #define SUPERMATTER_EMERGENCY_PERCENT 25 @@ -165,6 +158,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/resonance_cascading = FALSE // IT'S NOT SHUTTING DOWN!!!!!!! var/noblium_suppressed = FALSE // or is it? + // Blob related shit + var/supermatter_blob = FALSE // Well say sike rn + // Radio related variables var/obj/item/radio/radio var/radio_key = /obj/item/encryptionkey/headset_eng @@ -223,7 +219,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/damage_mod = 1 var/heal_mod = 1 - /obj/machinery/power/supermatter_crystal/Initialize(mapload) . = ..() uid = gl_uid++ @@ -254,9 +249,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/examine(mob/user) . = ..() - if (istype(user, /mob/living/carbon)) - if ((!HAS_TRAIT(user, TRAIT_MESONS)) && (get_dist(user, src) < HALLUCINATION_RANGE(power))) - . += span_danger("You get headaches just from looking at it.") + var/immune = HAS_TRAIT(user, TRAIT_MESONS) || HAS_TRAIT(user.mind, TRAIT_MESONS) + if (isliving(user) && !immune && (get_dist(user, src) < HALLUCINATION_RANGE(power))) + . += span_danger("You get headaches just from looking at it.") /obj/machinery/power/supermatter_crystal/proc/get_status() var/turf/T = get_turf(src) @@ -319,7 +314,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/speaking if(corruptor_attached) - speaking = "SUPERMATTER CRITICAL FAILURE ENGAGING FAILSAFE" //technically the failsafe is fail-danger, but whatever. + speaking = "SUPERMATTER CRITICAL FAILURE ENGAGING FAILSAFE." //technically the failsafe is fail-danger, but whatever. else speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated." radio.talk_into(src, speaking, common_channel, language = get_selected_language()) @@ -348,8 +343,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(i == 10 SECONDS) playsound(src, 'yogstation/sound/voice/sm/fcitadel_10sectosingularity.ogg', 100, FALSE, 100, pressure_affected=FALSE) if(antinoblium_attached && !resonance_cascading) // yogs- resonance cascade! + priority_announce("RESONANCE CASCADE IMMINENT.", "Anomaly Alert", 'sound/misc/notice1.ogg') resonance_cascading = TRUE sound_to_playing_players('sound/magic/lightning_chargeup.ogg', 50, FALSE) // yogs end + if(supermatter_blob) + priority_announce("LEVEL 5 BIOHAZARD OUTBREAK IMMINENT.", "Anomaly Alert", 'sound/misc/notice1.ogg') else if(corruptor_attached) speaking = "[round(i*0.1*rand(),1)]..." @@ -361,85 +359,24 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) radio.talk_into(src, speaking, common_channel) sleep(1 SECONDS) - explode() + delamination_event() -/obj/machinery/power/supermatter_crystal/proc/explode() +/obj/machinery/power/supermatter_crystal/proc/delamination_event() if (is_main_engine) SSpersistence.rounds_since_engine_exploded = ROUNDCOUNT_ENGINE_JUST_EXPLODED for (var/obj/structure/sign/delamination_counter/sign as anything in GLOB.map_delamination_counters) sign.update_count(ROUNDCOUNT_ENGINE_JUST_EXPLODED) - for(var/mob in GLOB.alive_mob_list) - var/mob/living/M = mob - var/turf/T2 = get_turf_global(M) - if(istype(M) && T2 && T2.z == z) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.adjust_hallucinations(max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(M, src) + 1)) ) ) ) - var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(M, src) + 1) ) - M.rad_act(rads) + new /datum/supermatter_delamination(power, combined_gas, get_turf(src), explosion_power, gasmix_power_ratio, antinoblium_attached, resonance_cascading, last_rads, supermatter_blob) - var/turf/T = get_turf(src) - for(var/_M in GLOB.player_list) - var/mob/M = _M - var/turf/T2 = get_turf(M) - if(T2.z == z) - SEND_SOUND(M, 'sound/magic/charge.ogg') - to_chat(M, span_boldannounce("You feel reality distort for a moment...")) - SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam) - - if (T) - var/datum/gas_mixture/air = T.return_air() - if (air) - if (((air.get_moles(/datum/gas/miasma) / air.total_moles()) * 100) > MIASMA_DELAM_PERCENTAGE && air.total_moles() > 5000) - var/list/candidates = pollGhostCandidates("Do you wish to be considered for the special role of Supermatter Blob?", ROLE_BLOB, null, ROLE_BLOB) - if(candidates.len) - var/mob/dead/observer/new_blob = pick(candidates) - var/mob/camera/blob/BC = new_blob.become_overmind(350, 1.5, 1) - BC.forceMove(T) - BC.place_blob_core(BLOB_FORCE_PLACEMENT) - - message_admins("[src] has created a blob. [ADMIN_JMP(src)].") - investigate_log("has created a blob.", INVESTIGATE_SUPERMATTER) - qdel(src) - return - - if(resonance_cascading) - sound_to_playing_players('sound/magic/lightningbolt.ogg', volume = 50) - var/datum/round_event_control/resonance_cascade/xen = new - xen.runEvent() - message_admins("[src] has caused a resonance cascade.") - investigate_log("has caused a resonance cascade.", INVESTIGATE_SUPERMATTER) - - if(combined_gas > MOLE_PENALTY_THRESHOLD && !resonance_cascading) - message_admins("[src] has collapsed into a singularity. [ADMIN_JMP(src)].") - investigate_log("has collapsed into a singularity.", INVESTIGATE_SUPERMATTER) - if(T) - var/obj/singularity/S = new(T) - if(antinoblium_attached) - S.energy = 2400 - else - S.energy = 800 - S.consume(src) - else - if(power < 0) // in case of negative energy, make it positive - power = -power - var/explosion_mod = clamp((1.001**power) / ((1.001**power) + SUPERMATTER_EXPLOSION_LAMBDA), 0.1, 1) - //trying to cheat by spacing the crystal? YOU FOOL THERE ARE NO LOOPHOLES TO ESCAPE YOUR UPCOMING DEATH - if(istype(T, /turf/open/space) || combined_gas < MOLE_SPACE_THRESHOLD) - message_admins("[src] has exploded in empty space.") - investigate_log("has exploded in empty space.", INVESTIGATE_SUPERMATTER) - explosion_mod = max(explosion_mod, 0.5) - else - message_admins("[src] has exploded") - investigate_log("has exploded.", INVESTIGATE_SUPERMATTER) - INVOKE_ASYNC(GLOBAL_PROC, /proc/empulse, T, explosion_power * explosion_mod, (explosion_power * explosion_mod * 2) + (explosion_power/4), TRUE, FALSE, FALSE, TRUE) - explosion(T, explosion_power * explosion_mod * 0.5, explosion_power * explosion_mod + 2, explosion_power * explosion_mod + 4, explosion_power * explosion_mod + 6, 1, 1) - radiation_pulse(T, (last_rads + 2400) * explosion_power) - if(power > POWER_PENALTY_THRESHOLD && !resonance_cascading) - investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER) - var/obj/singularity/energy_ball/E = new(T) - E.energy = power - qdel(src) + qdel(src) + +/obj/machinery/power/supermatter_crystal/proc/pulsewave() + var/atom/movable/gravity_lens/shockwave = new(get_turf(src)) + shockwave.transform = matrix().Scale(0.5) + shockwave.pixel_x = -240 + shockwave.pixel_y = -240 + animate(shockwave, alpha = 0, transform = matrix().Scale(20), time = 10 SECONDS, easing = QUAD_EASING) + QDEL_IN(shockwave, 10.5 SECONDS) /obj/machinery/power/supermatter_crystal/proc/surge(amount) surging = amount @@ -536,6 +473,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/nobliumcomp = max(removed.get_moles(/datum/gas/hypernoblium)/combined_gas, 0) var/antinobliumcomp = max(removed.get_moles(/datum/gas/antinoblium)/combined_gas, 0) var/nitriumcomp = max(removed.get_moles(/datum/gas/nitrium)/combined_gas, 0) + var/miasmacomp = max(removed.get_moles(/datum/gas/miasma)/combined_gas, 0) if (healcomp >= 0.1) heal_mod = (healcomp * HEALIUM_HEAL_MOD) + 1 //Increases healing and healing cap @@ -551,6 +489,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) var/bzmol = max(removed.get_moles(/datum/gas/bz), 0) var/nitriummol = max(removed.get_moles(/datum/gas/nitrium), 0) var/antinobmol = max(removed.get_moles(/datum/gas/antinoblium), 0) + var/miasmol = max(removed.get_moles(/datum/gas/miasma), 0) // Power of the gas. Scale of 0 to 1 gasmix_power_ratio = clamp(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp + nitriumcomp + antinobliumcomp - pluoxiumcomp - n2comp, 0, 1) @@ -568,7 +507,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling + clamp(co2comp - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1) else powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling - 0.05,0, 1) - powerloss_inhibitor = clamp(1-(powerloss_dynamic_scaling * clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1) + + if(support_integrity >= 10 && !supermatter_blob) + powerloss_inhibitor = clamp(1-(powerloss_dynamic_scaling * clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1) if(matter_power) var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40) @@ -613,16 +554,23 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) message_admins("[src] has reached criticial antinoblium concentration and started a resonance cascade.") antinoblium_attached = TRUE // oh god oh fuck + if (miasmacomp >= 0.5 && miasmol > 500 && !supermatter_blob) //requires around 4500 mol of miasma for the blob + supermatter_blob = TRUE // you are fucked + // adding enough hypernoblium can save it, but only if it hasn't gotten too bad and it wasn't corrupted using the traitor kit if(nobliumcomp >= 0.5 && antinoblium_attached && !corruptor_attached && support_integrity > 10 && damage <= damage_archived) support_integrity += 2 if(support_integrity >= 100) support_integrity = 100 antinoblium_attached = FALSE + radio.use_command = FALSE noblium_suppressed = TRUE else noblium_suppressed = FALSE + if((supermatter_blob || antinoblium_attached) && !radio.use_command) + radio.use_command = TRUE + var/device_energy = power * REACTION_POWER_MODIFIER //To figure out how much temperature to add each tick, consider that at one atmosphere's worth @@ -638,7 +586,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) //Calculate how much gas to release, antinoblium seeded SM produces much more gas - if(antinoblium_attached) + if(antinoblium_attached || supermatter_blob) removed.adjust_moles(/datum/gas/plasma, max(((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER) * (1+(100-support_integrity)/25), 0)) removed.adjust_moles(/datum/gas/oxygen, max((((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER) * (1+(100-support_integrity)/25), 0)) else if(haloncomp >= 0.15) @@ -676,16 +624,18 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10) supermatter_zap(src, 5, clamp(power*2, 4000, 20000)) - if(prob(15) && (power > POWER_PENALTY_THRESHOLD || combined_gas > MOLE_PENALTY_THRESHOLD || antinoblium_attached)) + if(prob(15) && (power > POWER_PENALTY_THRESHOLD || combined_gas > MOLE_PENALTY_THRESHOLD || antinoblium_attached || supermatter_blob)) supermatter_pull(src, power/750) - if(prob(5)) - supermatter_anomaly_gen(src, FLUX_ANOMALY, rand(5, 10)) - if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(5) || prob(1)) - supermatter_anomaly_gen(src, GRAVITATIONAL_ANOMALY, rand(5, 10)) - if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2) || prob(0.3) && power > POWER_PENALTY_THRESHOLD) - supermatter_anomaly_gen(src, PYRO_ANOMALY, rand(5, 10)) - if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(3) || prob(0.5)) - supermatter_anomaly_gen(src, RADIATION_ANOMALY, rand(5, 10)) + if(prob(5) || (antinoblium_attached || supermatter_blob) && prob(10)) + supermatter_anomaly_gen(src, ANOMALY_FLUX, rand(5, 10)) + if(prob(5) || (antinoblium_attached || supermatter_blob) && prob(10)) + supermatter_anomaly_gen(src, ANOMALY_HALLUCINATION, rand(5, 10)) + if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(5) || prob(1) || (antinoblium_attached || supermatter_blob) && prob(10)) + supermatter_anomaly_gen(src, ANOMALY_GRAVITATIONAL, rand(5, 10)) + if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2) || prob(0.3) && power > POWER_PENALTY_THRESHOLD || (antinoblium_attached || supermatter_blob) && prob(10)) + supermatter_anomaly_gen(src, ANOMALY_PYRO, rand(5, 10)) + if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(5) || prob(0.5) || (antinoblium_attached || supermatter_blob) && prob(10)) + supermatter_anomaly_gen(src, ANOMALY_RADIATION, rand(5, 10)) if(damage > warning_point) // while the core is still damaged and it's still worth noting its status if(damage_archived < warning_point) //If damage_archive is under the warning point, this is the very first cycle that we've reached said point. @@ -697,7 +647,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(corruptor_attached) radio.talk_into(src, "[warning_alert] Integrity: [get_fake_integrity()]%!", common_channel) else - radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel) + radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%.", common_channel) SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM) log_game("The supermatter crystal: [emergency_alert] Integrity: [get_integrity()]%") // yogs start - Logs SM chatter investigate_log("The supermatter crystal: [emergency_alert] Integrity: [get_integrity()]%", INVESTIGATE_SUPERMATTER) // yogs end @@ -710,7 +660,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(corruptor_attached) radio.talk_into(src, "[warning_alert] Integrity: [get_fake_integrity()]%!", engineering_channel) else - radio.talk_into(src, "[warning_alert] Integrity: [get_integrity()]%", engineering_channel) + radio.talk_into(src, "[warning_alert] Integrity: [get_integrity()]%.", engineering_channel) SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM) log_game("The supermatter crystal: [warning_alert] Integrity: [get_integrity()]%") // yogs start - Logs SM chatter investigate_log("The supermatter crystal: [warning_alert] Integrity: [get_integrity()]%", INVESTIGATE_SUPERMATTER) // yogs end @@ -737,6 +687,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) radio.talk_into(src, "Warning: Critical coolant mass reached.", engineering_channel) log_game("The supermatter crystal: Warning: Critical coolant mass reached.") // yogs start - Logs SM chatter investigate_log("The supermatter crystal: Warning: Critical coolant mass reached.", INVESTIGATE_SUPERMATTER) // yogs end + + if(supermatter_blob) + radio.talk_into(src, "DANGER: BIOHAZARD DETECTED, VACATE THE CHAMBER IMMEDIATELY.", engineering_channel) + log_game("The supermatter crystal: DANGER: BIOHAZARD DETECTED, VACATE THE CHAMBER IMMEDIATELY.") // yogs start - Logs SM chatter + investigate_log("The supermatter crystal: DANGER: BIOHAZARD DETECTED, VACATE THE CHAMBER IMMEDIATELY.", INVESTIGATE_SUPERMATTER) // yogs end + if(damage >= emergency_point) + radio.talk_into(src, "DANGER: SUPERMATTER BIOHAZARD LEVELS HAVE EXCEEDED SAFETY THRESHOLDS.", common_channel) + log_game("DANGER: SUPERMATTER BIOHAZARD LEVELS HAVE EXCEEDED SAFETY THRESHOLDS.") // yogs start - Logs SM chatter + investigate_log("DANGER: SUPERMATTER BIOHAZARD LEVELS HAVE EXCEEDED SAFETY THRESHOLDS.", INVESTIGATE_SUPERMATTER) // yogs end if(antinoblium_attached) if(support_integrity <= 10) @@ -751,6 +710,23 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(damage > explosion_point) countdown() + //blob SM HAMMM + if(supermatter_blob) + powerloss_inhibitor = 0.01 + power += 10000 + if(prob(30)) + radiation_pulse(src, 5000, 4) + pulsewave() + T.hotspot_expose(max(500+FIRE_MINIMUM_TEMPERATURE_TO_EXIST,T.return_air().return_temperature()), 100) + playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10) + supermatter_zap(src, 5, power) + for(var/i = 1 to 20) + fire_nuclear_particle() + if(istype(T, /turf/open/space) || T.return_air().total_moles() < MOLE_SPACE_THRESHOLD) + damage += DAMAGE_HARDCAP * explosion_point + if(prob(2)) + empulse(src, 10, 5) + //emagged SM go BRRRRRRR here if(antinoblium_attached && !noblium_suppressed) if(prob(10+round(damage/(explosion_point/20),1)*3) & support_integrity>0)//radio chatter to make people panic @@ -762,23 +738,25 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(80) radio.talk_into(src, "COMPLETE FAILURE OF CHARGE SEQUESTRATION IMMINENT, ACTIVATING EMERGENCY CHARGE DISPERSION SYSTEM!", engineering_channel) if(70) - radio.talk_into(src, "CHARGE DISPERSION SYSTEM ACTIVE. CORRUPTION OF PARANOBLIUM INTERFACE SYSTEM DETECTED, MATTER EMISSION LEVELS RISING", engineering_channel) + radio.talk_into(src, "CHARGE DISPERSION SYSTEM ACTIVE. CORRUPTION OF PARANOBLIUM INTERFACE SYSTEM DETECTED, MATTER EMISSION LEVELS RISING.", engineering_channel) if(60) - radio.talk_into(src, "PARANOBLIUM INTERFACE OPERATING AT [round(75+ rand()*10,0.01)]% CAPACITY, MATTER EMISSION FACTOR RISING", engineering_channel) + radio.talk_into(src, "PARANOBLIUM INTERFACE OPERATING AT [round(75+ rand()*10,0.01)]% CAPACITY, MATTER EMISSION FACTOR RISING.", engineering_channel) if(50) - radio.talk_into(src, "COMPLETE FAILURE OF GAMMA RADIATION SUPPRESSION SYSTEM DETECTED, ACTIVATING GAMMA EMISSION BUNDLING AND DISPERSION SYSTEM", engineering_channel) + radio.talk_into(src, "COMPLETE FAILURE OF GAMMA RADIATION SUPPRESSION SYSTEM DETECTED, ACTIVATING GAMMA EMISSION BUNDLING AND DISPERSION SYSTEM.", engineering_channel) if(40) - radio.talk_into(src, "DISPERSION SYSTEM ACTIVATION FAILED, BUNDLER NOW FIRING WITHOUT GUIDANCE", engineering_channel) + radio.talk_into(src, "DISPERSION SYSTEM ACTIVATION FAILED, BUNDLER NOW FIRING WITHOUT GUIDANCE.", engineering_channel) + priority_announce("SUPERMATTER INSTABILITY IS AT 60%, PULSEWAVE IMMINENT.", "Anomaly Alert", 'sound/misc/notice1.ogg') if(30) - radio.talk_into(src, "WARNING ENERGY SPIKE IN CRYSTAL WELL DETECTED, ESTIMATED ENERGY OUTPUT EXCEEDS PEAK CHARGE DISPERSION CAPACITY", engineering_channel) + radio.talk_into(src, "WARNING ENERGY SPIKE IN CRYSTAL WELL DETECTED, ESTIMATED ENERGY OUTPUT EXCEEDS PEAK CHARGE DISPERSION CAPACITY.", engineering_channel) if(20) - radio.talk_into(src, "CRYSTAL WELL DESTABILIZED, ELECTROMAGNETIC PULSES INBOUND, PARANOBLIUM INTERFACE OPERATING AT [round(15+ rand()*10,0.01)]% CAPACITY", common_channel) + radio.talk_into(src, "CRYSTAL WELL DESTABILIZED, ELECTROMAGNETIC PULSES INBOUND, PARANOBLIUM INTERFACE OPERATING AT [round(15+ rand()*10,0.01)]% CAPACITY.", common_channel) if(10) - radio.talk_into(src, "ELECTROMAGNETIC FIELD CONTAINMENT FAILED, PARANOBLIUM INTERFACE NONFUNCTIONAL, RESONANCE CASCADE IMMINENT", common_channel) + radio.talk_into(src, "ELECTROMAGNETIC FIELD CONTAINMENT FAILED, PARANOBLIUM INTERFACE NONFUNCTIONAL, RESONANCE CASCADE IMMINENT.", common_channel) + priority_announce("SUPERMATTER INSTABILITY IS AT 90%, SUPERMATTER SURGE DETECTED, VACATE THE AREA IMMEDIATELY.", "Anomaly Alert", 'sound/misc/notice1.ogg') if(6) - radio.talk_into(src, "ELECTROMAGNETIC PULSES IMMINENT, CONTAINMENT AND COOLING FAILURE IMMINENT", common_channel) - if(1) //after those emps, anyone who can hear this must be lucky. - radio.talk_into(src, "COMPLETE DESTABILIZATION OF ALL MAJOR SUPPORT SYSTEMS, MATTER EMISSION FACTOR AT 600%, COMPLETE EVACUATION IS ADVISED", common_channel) + radio.talk_into(src, "ELECTROMAGNETIC PULSES IMMINENT, CONTAINMENT AND COOLING FAILURE IMMINENT.", common_channel) + if(1) + priority_announce("COMPLETE DESTABILIZATION OF ALL MAJOR SUPPORT SYSTEMS, MATTER EMISSION FACTOR AT 600%, COMPLETE EVACUATION IS ADVISED.", "Anomaly Alert", 'sound/misc/notice1.ogg') support_integrity -= 1 radiation_pulse(src, (100-support_integrity)*2, 4) if(support_integrity<3) @@ -794,10 +772,13 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) if(prob(10)) T.hotspot_expose(max(((100-support_integrity)*2)+FIRE_MINIMUM_TEMPERATURE_TO_EXIST,T.return_air().return_temperature()), 100) if(prob(10+round(support_integrity/10,1))) + pulsewave() var/ballcount = round(10-(support_integrity/10), 1) // Cause more radballs to be spawned for(var/i = 1 to ballcount) fire_nuclear_particle() if(support_integrity<10) + powerloss_inhibitor = 0.01 //ensure big explosion + surging = 10000 if(istype(T, /turf/open/space) || T.return_air().total_moles() < MOLE_SPACE_THRESHOLD) damage += DAMAGE_HARDCAP * explosion_point //Can't cheat by spacing the crystal to buy time, it will just delaminate faster if(prob(2)) @@ -1025,7 +1006,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) message_admins("Antinoblium shard has been attached to the SM and is now going BRRRRRR.") to_chat(user, "You attach the antinoblium shard to the [src], moving your hand away before a sudden gravitational wave pulls the [W] into the crystal as it flashes to ash!") playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1) - radio.use_command = TRUE radiation_pulse(src, 150, 4) empulse(src, 3,6) qdel(W) @@ -1163,19 +1143,28 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) step_towards(P,center) step_towards(P,center) -/obj/machinery/power/supermatter_crystal/proc/supermatter_anomaly_gen(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5) - var/turf/L = pick(orange(anomalyrange, anomalycenter)) - if(L) - switch(type) - if(FLUX_ANOMALY) - var/obj/effect/anomaly/flux/A = new(L, 300) - A.explosive = FALSE - if(GRAVITATIONAL_ANOMALY) - new /obj/effect/anomaly/grav(L, 250) - if(PYRO_ANOMALY) - new /obj/effect/anomaly/pyro(L, 400) - if(RADIATION_ANOMALY) - new /obj/effect/anomaly/radiation(L, 400) +/proc/supermatter_anomaly_gen(turf/anomalycenter, type = ANOMALY_FLUX, anomalyrange = 5, has_weak_lifespan = TRUE) + var/turf/local_turf = pick(RANGE_TURFS(anomalyrange, anomalycenter) - anomalycenter) + if(!local_turf) + return + + switch(type) + if(ANOMALY_FLUX) + new /obj/effect/anomaly/flux(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_FLUX_EXPLOSIVE) + new /obj/effect/anomaly/flux/explosion(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_GRAVITATIONAL) + new /obj/effect/anomaly/grav(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_HALLUCINATION) + new /obj/effect/anomaly/hallucination(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_PYRO) + new /obj/effect/anomaly/pyro(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_VORTEX) + new /obj/effect/anomaly/bhole(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_RADIATION) + new /obj/effect/anomaly/radiation(local_turf, has_weak_lifespan ? rand(250, 300) : null) + if(ANOMALY_RADIATION_X) + new /obj/effect/anomaly/radiation/goat(local_turf, has_weak_lifespan ? rand(250, 300) : null) /obj/machinery/proc/supermatter_zap(atom/zapstart, range = 3, power) . = zapstart.dir @@ -1293,8 +1282,3 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) return ..() #undef HALLUCINATION_RANGE -#undef GRAVITATIONAL_ANOMALY -#undef SUPERMATTER_EXPLOSION_LAMBDA -#undef FLUX_ANOMALY -#undef PYRO_ANOMALY -#undef RADIATION_ANOMALY diff --git a/code/modules/power/supermatter/supermatter_delamination.dm b/code/modules/power/supermatter/supermatter_delamination.dm new file mode 100644 index 000000000000..5893ca5d2282 --- /dev/null +++ b/code/modules/power/supermatter/supermatter_delamination.dm @@ -0,0 +1,143 @@ +/datum/supermatter_delamination + ///Power amount of the SM at the moment of death + var/supermatter_power = 0 + ///Amount of total gases interacting with the SM + var/supermatter_gas_amount = 0 + ///Reference to the supermatter turf + var/turf/supermatter_turf + ///Baseline strenght of the explosion caused by the SM + var/supermatter_explosion_power = 0 + ///Amount the gasmix will affect the explosion size + var/supermatter_gasmix_power_ratio = 0 + ///Antinoblium inside sm + var/supermatter_antinoblium = FALSE + ///Trigger resonance cascading + var/supermatter_cascading = FALSE + ///Radiation amount + var/supermatter_radiation = 0 + ///Blob shit + var/supermatter_blob = FALSE + +/datum/supermatter_delamination/New(supermatter_power, supermatter_gas_amount, turf/supermatter_turf, supermatter_explosion_power, supermatter_gasmix_power_ratio, supermatter_antinoblium, supermatter_cascading, supermatter_radiation, supermatter_blob) + . = ..() + + src.supermatter_power = supermatter_power + src.supermatter_gas_amount = supermatter_gas_amount + src.supermatter_turf = supermatter_turf + src.supermatter_explosion_power = supermatter_explosion_power + src.supermatter_gasmix_power_ratio = supermatter_gasmix_power_ratio + src.supermatter_antinoblium = supermatter_antinoblium + src.supermatter_cascading = supermatter_cascading + src.supermatter_radiation = supermatter_radiation + src.supermatter_blob = supermatter_blob + + setup_mob_interaction() + setup_delamination_type() + +/datum/supermatter_delamination/proc/setup_mob_interaction() + for(var/mob/living/victim as anything in GLOB.alive_mob_list) + if(!istype(victim) || victim.z != supermatter_turf.z) + continue + + if(ishuman(victim)) + //Hilariously enough, running into a closet should make you get hit the hardest. + var/mob/living/carbon/human/human = victim + human.adjust_hallucinations(max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(victim, src) + 1)) ) ) ) + + var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(victim, src) + 1) ) + victim.rad_act(rads) + + for(var/mob/victim as anything in GLOB.player_list) + var/turf/mob_turf = get_turf(victim) + if(supermatter_turf.z != mob_turf.z) + continue + + SEND_SOUND(victim, 'sound/magic/charge.ogg') + + if (victim.z != supermatter_turf.z) + to_chat(victim, span_boldannounce("You hold onto \the [victim.loc] as hard as you can, as reality distorts around you. You feel safe.")) + continue + + to_chat(victim, span_boldannounce("You feel reality distort for a moment...")) + SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam) + +/datum/supermatter_delamination/proc/setup_delamination_type() + if(supermatter_blob) + call_blob() + return + if(supermatter_cascading && !supermatter_blob) + call_cascading() + call_cascadetesla() + call_explosion() + return + if(supermatter_gas_amount > MOLE_PENALTY_THRESHOLD && !supermatter_cascading && !supermatter_blob) + call_singulo() + return + if(supermatter_power > POWER_PENALTY_THRESHOLD && !supermatter_cascading && !supermatter_blob) + call_tesla() + call_explosion() + return + +/datum/supermatter_delamination/proc/shockwave() //borrowed ynot's code + var/atom/movable/gravity_lens/shockwave = new(supermatter_turf) + shockwave.transform = matrix().Scale(0.5) + shockwave.pixel_x = -240 + shockwave.pixel_y = -240 + animate(shockwave, alpha = 0, transform = matrix().Scale(20), time = 10 SECONDS, easing = QUAD_EASING) + QDEL_IN(shockwave, 10.5 SECONDS) + +/datum/supermatter_delamination/proc/call_cascading() + sound_to_playing_players('sound/magic/lightningbolt.ogg', volume = 50) + shockwave() //a pulse when sm is blown up + var/datum/round_event_control/resonance_cascade/cascade_roundevent = locate(/datum/round_event_control/resonance_cascade) in SSevents.control + cascade_roundevent.runEvent() + message_admins("The Supermatter Crystal has caused a resonance cascade.") + +/datum/supermatter_delamination/proc/call_singulo() + if(!supermatter_turf) + return + var/obj/singularity/created_singularity = new(supermatter_turf) + created_singularity.energy = 2400 + created_singularity.consumedSupermatter = 1 + message_admins("The Supermatter Crystal has created a singularity [ADMIN_JMP(created_singularity)].") + +/datum/supermatter_delamination/proc/call_explosion() + if(supermatter_power < 0) // in case of negative energy, make it positive + supermatter_power = -supermatter_power + var/explosion_mod = clamp((1.001**supermatter_power) / ((1.001**supermatter_power) + SUPERMATTER_EXPLOSION_LAMBDA), 0.1, 1) + //trying to cheat by spacing the crystal? YOU FOOL THERE ARE NO LOOPHOLES TO ESCAPE YOUR UPCOMING DEATH + if(istype(supermatter_turf, /turf/open/space) || supermatter_gas_amount < MOLE_SPACE_THRESHOLD) + message_admins("[src] has exploded in empty space.") + explosion_mod = max(explosion_mod, 0.5) + else + message_admins("[src] has exploded") + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(empulse), supermatter_turf, supermatter_explosion_power * explosion_mod, (supermatter_explosion_power * explosion_mod * 2) + (supermatter_explosion_power/4), TRUE, FALSE, FALSE, TRUE) + explosion(supermatter_turf, supermatter_explosion_power * explosion_mod * 0.5, supermatter_explosion_power * explosion_mod + 2, supermatter_explosion_power * explosion_mod + 4, supermatter_explosion_power * explosion_mod + 6, 1, 1) + radiation_pulse(supermatter_turf, (supermatter_radiation + 2400) * supermatter_explosion_power) + +/datum/supermatter_delamination/proc/call_tesla() + if(supermatter_turf) + var/obj/singularity/energy_ball/supermatter_tesla = new(supermatter_turf) + supermatter_tesla.energy = supermatter_power + message_admins("The Supermatter Crystal has created an energy ball [ADMIN_JMP(supermatter_tesla)].") + +/datum/supermatter_delamination/proc/call_cascadetesla() + if(supermatter_turf) + var/obj/singularity/energy_ball/supermatter/supermatter_tesla = new(supermatter_turf) + supermatter_tesla.energy += supermatter_power * 100 // god + message_admins("The Supermatter Crystal has created an energy ball [ADMIN_JMP(supermatter_tesla)].") + +/datum/supermatter_delamination/proc/call_blob() + var/list/candidates = pollGhostCandidates("Do you wish to be considered for the special role of Blazing Oil Blob?", ROLE_BLOB, null, ROLE_BLOB) + if(candidates.len) + var/mob/dead/observer/new_blob = pick(candidates) + var/mob/camera/blob/BC = new_blob.become_overmind(350, 1.5, 1) + var/explosion_mod = clamp((1.001**supermatter_power) / ((1.001**supermatter_power) + SUPERMATTER_EXPLOSION_LAMBDA), 0.1, 1) + BC.set_strain(/datum/blobstrain/reagent/blazing_oil) //to protect against the fire around the blob when sm shitting itself + BC.forceMove(supermatter_turf) + BC.place_blob_core(BLOB_FORCE_PLACEMENT) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(empulse), supermatter_turf, supermatter_explosion_power * explosion_mod, (supermatter_explosion_power * explosion_mod * 2) + (supermatter_explosion_power/4), TRUE, FALSE, FALSE, TRUE) + message_admins("Supermatter has created a blob. [ADMIN_JMP(BC)].") + else + supermatter_blob = FALSE + setup_delamination_type() //No blob? :( do other delams then diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index e4396c6a1a83..f4a6a731d77e 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -78,7 +78,7 @@ return ..() -/obj/machinery/power/tesla_coil/tesla_act(power, tesla_flags, shocked_targets) +/obj/machinery/power/tesla_coil/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) if(anchored && !panel_open) obj_flags |= BEING_SHOCKED add_avail((power * (1 - percentage_power_loss))*input_power_multiplier) @@ -114,7 +114,7 @@ research_points_per_zap = 6 // level 1 coil: 44/m, level coil 2: 60/m, level coil 3: 90/m, level coil 4: 180/m money_per_zap = 6 -/obj/machinery/power/tesla_coil/research/tesla_act(power, tesla_flags, shocked_things) +/obj/machinery/power/tesla_coil/research/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) if(anchored && !panel_open) obj_flags |= BEING_SHOCKED add_avail((power * (1 - percentage_power_loss))*input_power_multiplier) @@ -178,7 +178,7 @@ return ..() -/obj/machinery/power/grounding_rod/tesla_act(power) +/obj/machinery/power/grounding_rod/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) if(anchored && !panel_open) flick("grounding_rodhit", src) tesla_buckle_check(power) diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 932dd6e24bf4..5065b33f64b3 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -10,24 +10,36 @@ grav_pull = 0 contained = 0 density = TRUE - energy = 0 + energy = 50 dissipate = 1 dissipate_delay = 5 dissipate_strength = 1 - var/list/orbiting_balls = list() var/miniball = FALSE var/produced_power var/energy_to_raise = 32 var/energy_to_lower = -20 var/max_balls = 10 var/zap_range = 7 + ///Boolean that, if TRUE, will not lose energy and tesla zap will dust you + var/hypercharged = FALSE -/obj/singularity/energy_ball/Initialize(mapload, starting_energy = 50, is_miniball = FALSE) + ///List of all energy balls that's orbiting this one. + var/list/obj/singularity/energy_ball/orbiting_balls = list() + +/obj/singularity/energy_ball/Initialize(mapload, starting_energy = energy, is_miniball = FALSE) miniball = is_miniball . = ..() if(!is_miniball) set_light(10, 7, "#EEEEFF") +/obj/singularity/energy_ball/supermatter + name = "supermatter energy ball" + color = "#ffe800" + energy = 10000 + max_balls = 20 + zap_range = 20 + hypercharged = TRUE + /obj/singularity/energy_ball/ex_act(severity, target) return @@ -36,45 +48,47 @@ var/obj/singularity/energy_ball/EB = orbiting.parent EB.orbiting_balls -= src - for(var/ball in orbiting_balls) - var/obj/singularity/energy_ball/EB = ball - qdel(EB) - - . = ..() + QDEL_LIST(orbiting_balls) + return ..() /obj/singularity/energy_ball/admin_investigate_setup() if(miniball) return //don't annnounce miniballs - ..() + return ..() /obj/singularity/energy_ball/process() - if(!orbiting) - handle_energy() - - move_the_basket_ball(4 + orbiting_balls.len * 1.5) + if(orbiting) + energy = 0 // ensure we dont have miniballs of miniballs + return - playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30) + handle_energy() + move_the_basket_ball(4 + orbiting_balls.len * 1.5) + playsound(loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30) - pixel_x = 0 - pixel_y = 0 + pixel_x = 0 + pixel_y = 0 + if(hypercharged) + tesla_zap(src, zap_range, TESLA_HYPERCHARGED_POWER, TESLA_DEFAULT_FLAGS | TESLA_ALLOW_DUPLICATES, zap_gib = TRUE) + else tesla_zap(src, zap_range, TESLA_DEFAULT_POWER) - pixel_x = -32 - pixel_y = -32 + pixel_x = -32 + pixel_y = -32 - var/list/RG = range(1, src) - for(var/obj/singularity/energy_ball/E in RG) - if(!E.miniball && E != src) - collide(E) + var/list/around_us = range(1, src) + for(var/obj/singularity/energy_ball/E in around_us) + if(!E.miniball && E != src) + collide(E) - for (var/ball in orbiting_balls) - if(prob(80)) //tesla nerf/reducing lag, each miniball now has only 20% to trigger the zap - continue + for (var/obj/singularity/energy_ball/ball as anything in orbiting_balls) + if(prob(80)) //tesla nerf/reducing lag, each miniball now has only 20% to trigger the zap + continue + if(ball.hypercharged) + tesla_zap(ball, zap_range, TESLA_DEFAULT_POWER, TESLA_DEFAULT_FLAGS | TESLA_ALLOW_DUPLICATES, zap_gib = TRUE) + else tesla_zap(ball, rand(2, zap_range), TESLA_MINI_POWER) - else - energy = 0 // ensure we dont have miniballs of miniballs /obj/singularity/energy_ball/examine(mob/user) . = ..() @@ -113,7 +127,7 @@ energy_to_lower = energy_to_raise - 20 energy_to_raise = energy_to_raise * 1.25 - playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30) + playsound(loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30) addtimer(CALLBACK(src, PROC_REF(new_mini_ball)), 100) else if(energy < energy_to_lower && orbiting_balls.len) @@ -124,6 +138,8 @@ qdel(Orchiectomy_target) else if(orbiting_balls.len) + if(hypercharged) + dissipate = 0 dissipate() //sing code has a much better system. /obj/singularity/energy_ball/proc/new_mini_ball() @@ -134,7 +150,11 @@ if(orbiting_balls.len >= max_balls) return - var/obj/singularity/energy_ball/EB = new(loc, 0, TRUE) + var/obj/singularity/energy_ball/EB + if(hypercharged) + EB = new /obj/singularity/energy_ball/supermatter(loc, 0, TRUE) + else + EB = new /obj/singularity/energy_ball(loc, 0, TRUE) EB.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7) var/icon/I = icon(icon,icon_state,dir) @@ -144,7 +164,6 @@ EB.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36)) - /obj/singularity/energy_ball/Bump(atom/A) dust_mobs(A) @@ -171,14 +190,17 @@ /obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target) if (istype(target)) target.orbiting_balls += src + color = target.color GLOB.poi_list -= src target.dissipate_strength = target.orbiting_balls.len - . = ..() + return ..() + /obj/singularity/energy_ball/stop_orbit() if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball)) var/obj/singularity/energy_ball/orbitingball = orbiting.parent orbitingball.orbiting_balls -= src + color = initial(color) orbitingball.dissipate_strength = orbitingball.orbiting_balls.len . = ..() if (!QDELETED(src)) @@ -198,7 +220,7 @@ var/mob/living/carbon/C = A C.dust() -/proc/tesla_zap(atom/source, zap_range = 3, power, tesla_flags = TESLA_DEFAULT_FLAGS, list/shocked_targets) +/proc/tesla_zap(atom/source, zap_range = 3, power, tesla_flags = TESLA_DEFAULT_FLAGS, list/shocked_targets, zap_gib = FALSE) . = source.dir if(power < 1000) return @@ -211,29 +233,35 @@ var/obj/machinery/closest_machine var/obj/structure/closest_structure var/obj/structure/blob/closest_blob - var/static/things_to_shock = typecacheof(list(/obj/machinery, /mob/living, /obj/structure)) - var/static/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, - /obj/machinery/power/emitter, - /obj/machinery/field/generator, - /mob/living/simple_animal, - /obj/machinery/particle_accelerator/control_box, - /obj/structure/particle_accelerator/fuel_chamber, - /obj/structure/particle_accelerator/particle_emitter/center, - /obj/structure/particle_accelerator/particle_emitter/left, - /obj/structure/particle_accelerator/particle_emitter/right, - /obj/structure/particle_accelerator/power_box, - /obj/structure/particle_accelerator/end_cap, - /obj/machinery/field/containment, - /obj/structure/disposalpipe, - /obj/structure/disposaloutlet, - /obj/machinery/disposal/deliveryChute, - /obj/machinery/camera, - /obj/structure/sign, - /obj/machinery/gateway, - /obj/structure/lattice, - /obj/structure/grille, - /obj/machinery/the_singularitygen/tesla, - /obj/structure/frame/machine)) + var/static/things_to_shock = typecacheof(list( + /obj/machinery, + /mob/living, + /obj/structure, + )) + var/static/blacklisted_tesla_types = typecacheof(list( + /obj/machinery/atmospherics/pipe, + /obj/machinery/power/emitter, + /obj/machinery/field/generator, + /mob/living/simple_animal/hostile, + /mob/living/simple_animal/slime, + /obj/machinery/particle_accelerator/control_box, + /obj/structure/particle_accelerator/fuel_chamber, + /obj/structure/particle_accelerator/particle_emitter/center, + /obj/structure/particle_accelerator/particle_emitter/left, + /obj/structure/particle_accelerator/particle_emitter/right, + /obj/structure/particle_accelerator/power_box, + /obj/structure/particle_accelerator/end_cap, + /obj/machinery/field/containment, + /obj/structure/disposalpipe, + /obj/structure/disposaloutlet, + /obj/machinery/disposal/deliveryChute, + /obj/machinery/camera, + /obj/structure/sign, + /obj/machinery/gateway, + /obj/structure/lattice, + /obj/machinery/the_singularitygen/tesla, + /obj/structure/frame/machine, + )) // +3 to range specifically to include grounding rods that are zap_range+3 away for(var/A in typecache_filter_multi_list_exclusion(oview(source, zap_range+3), things_to_shock, blacklisted_tesla_types)) @@ -266,14 +294,11 @@ else if(isliving(A)) var/mob/living/L = A - if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD && !(L.flags_1 & TESLA_IGNORE_1)) + if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD && !(L.status_flags & GODMODE) && !(L.mob_biotypes & MOB_SPIRIT) && !(L.flags_1 & TESLA_IGNORE_1)) closest_mob = L closest_atom = A closest_dist = dist - else if(closest_mob) - continue - else if(ismachinery(A)) var/obj/machinery/M = A if(dist <= zap_range && (dist < closest_dist || !closest_machine) && !(M.obj_flags & BEING_SHOCKED)) @@ -281,9 +306,6 @@ closest_atom = A closest_dist = dist - else if(closest_mob) - continue - else if(istype(A, /obj/structure/blob)) var/obj/structure/blob/B = A if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(B.obj_flags & BEING_SHOCKED)) @@ -291,9 +313,6 @@ closest_atom = A closest_dist = dist - else if(closest_blob) - continue - else if(isstructure(A)) var/obj/structure/S = A if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !(S.obj_flags & BEING_SHOCKED)) @@ -304,7 +323,10 @@ //Alright, we've done our loop, now lets see if was anything interesting in range if(closest_atom) //common stuff - source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5, maxdistance = INFINITY) + if(zap_gib) + source.Beam(closest_atom, icon_state = "solar_beam", time = 5, maxdistance = INFINITY) + else + source.Beam(closest_atom, icon_state = "lightning[rand(1,12)]", time = 5, maxdistance = INFINITY) if(!(tesla_flags & TESLA_ALLOW_DUPLICATES)) LAZYSET(shocked_targets, closest_atom, TRUE) var/zapdir = get_dir(source, closest_atom) @@ -320,20 +342,20 @@ else if(closest_mob) var/shock_damage = (tesla_flags & TESLA_MOB_DAMAGE)? (min(round(power/600), 90) + rand(-5, 5)) : 0 - closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1, stun = (tesla_flags & TESLA_MOB_STUN)) + closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1, stun = (tesla_flags & TESLA_MOB_STUN), gib = zap_gib) if(issilicon(closest_mob)) var/mob/living/silicon/S = closest_mob if((tesla_flags & TESLA_MOB_STUN) && (tesla_flags & TESLA_MOB_DAMAGE)) S.emp_act(EMP_LIGHT) - tesla_zap(S, 7, power / 1.5, tesla_flags, shocked_targets) // metallic folks bounce it further + tesla_zap(S, 7, power / 1.5, tesla_flags, shocked_targets, zap_gib) // metallic folks bounce it further else - tesla_zap(closest_mob, 5, power / 1.5, tesla_flags, shocked_targets) + tesla_zap(closest_mob, 5, power / 1.5, tesla_flags, shocked_targets, zap_gib) else if(closest_machine) - closest_machine.tesla_act(power, tesla_flags, shocked_targets) + closest_machine.tesla_act(power*1.9, tesla_flags, shocked_targets, zap_gib) else if(closest_blob) - closest_blob.tesla_act(power, tesla_flags, shocked_targets) + closest_blob.tesla_act(power, tesla_flags, shocked_targets, zap_gib) else if(closest_structure) - closest_structure.tesla_act(power, tesla_flags, shocked_targets) + closest_structure.tesla_act(power, tesla_flags, shocked_targets, zap_gib) diff --git a/code/modules/power/tesla/generator.dm b/code/modules/power/tesla/generator.dm index 53d7010806be..e38490f491f3 100644 --- a/code/modules/power/tesla/generator.dm +++ b/code/modules/power/tesla/generator.dm @@ -5,6 +5,6 @@ icon_state = "TheSingGen" creation_type = /obj/singularity/energy_ball -/obj/machinery/the_singularitygen/tesla/tesla_act(power, tesla_flags) +/obj/machinery/the_singularitygen/tesla/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) if(tesla_flags & TESLA_MACHINE_EXPLOSIVE) energy += power diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 060216b2c47c..357ebd1f6a58 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -77,7 +77,7 @@ /obj/structure/reagent_dispensers/fueltank/fire_act(exposed_temperature, exposed_volume) boom() -/obj/structure/reagent_dispensers/fueltank/tesla_act() +/obj/structure/reagent_dispensers/fueltank/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) ..() //extend the zap boom() diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index eabed4943521..ea1054a6a9d9 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -251,7 +251,7 @@ else SSshuttle.emergencyLastCallLoc = null - priority_announce("The emergency shuttle has been called. [GLOB.security_level >= SEC_LEVEL_RED ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.[reason][SSshuttle.emergencyLastCallLoc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ]", null, ANNOUNCER_SHUTTLECALLED, "Priority") + priority_announce("The emergency shuttle has been called. [GLOB.security_level >= SEC_LEVEL_RED ? "Red Alert state confirmed: Dispatching priority shuttle. " : "" ]It will arrive in [timeLeft(600)] minutes.\nNature of emergency:\n\n[reason][SSshuttle.emergencyLastCallLoc ? "\n\nCall signal traced. Results can be viewed on any communications console." : "" ]", null, ANNOUNCER_SHUTTLECALLED, "Priority") /obj/docking_port/mobile/emergency/cancel(area/signalOrigin) if(mode != SHUTTLE_CALL) diff --git a/code/modules/spells/spell_types/conjure/rad_goat.dm b/code/modules/spells/spell_types/conjure/rad_goat.dm index c85c4510191e..7103209ab04b 100644 --- a/code/modules/spells/spell_types/conjure/rad_goat.dm +++ b/code/modules/spells/spell_types/conjure/rad_goat.dm @@ -1,7 +1,7 @@ /datum/action/cooldown/spell/conjure/radiation_anomaly name = "Spawn Radiation Anomaly" desc = "Spawn a radiation anomaly!" - button_icon = 'icons/obj/projectiles.dmi' + button_icon = 'icons/effects/effects.dmi' button_icon_state = "radiation_anomaly" sound = 'sound/weapons/resonator_fire.ogg' diff --git a/code/modules/swarmers/swarmer.dm b/code/modules/swarmers/swarmer.dm index 1fe92c9b868b..fdfad769000b 100644 --- a/code/modules/swarmers/swarmer.dm +++ b/code/modules/swarmers/swarmer.dm @@ -258,7 +258,7 @@ playsound(src, 'sound/effects/sparks4.ogg', 50, TRUE) do_teleport(target, safe_turf , 0, channel = TELEPORT_CHANNEL_BLUESPACE) -/mob/living/simple_animal/hostile/swarmer/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE) +/mob/living/simple_animal/hostile/swarmer/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE, gib = FALSE) if(!tesla_shock) return FALSE return ..() diff --git a/code/modules/vehicles/bicycle.dm b/code/modules/vehicles/bicycle.dm index cc42c122ac97..cfbf585ec6a7 100644 --- a/code/modules/vehicles/bicycle.dm +++ b/code/modules/vehicles/bicycle.dm @@ -10,7 +10,7 @@ D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4))) D.vehicle_move_delay = 0 -/obj/vehicle/ridden/bicycle/tesla_act() // :::^^^))) +/obj/vehicle/ridden/bicycle/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) // :::^^^))) name = "fried bicycle" desc = "Well spent." color = rgb(63, 23, 4) diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 9f197ef7b8bf..eca845f3fd81 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/obj/assemblies/new_assemblies.dmi b/icons/obj/assemblies/new_assemblies.dmi index 1c00e9511046..7b0c9a434449 100644 Binary files a/icons/obj/assemblies/new_assemblies.dmi and b/icons/obj/assemblies/new_assemblies.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 2850636df4f2..9a42039a46df 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/sound/misc/airraid.ogg b/sound/misc/airraid.ogg index 820eaccf91d7..cc9913becdde 100644 Binary files a/sound/misc/airraid.ogg and b/sound/misc/airraid.ogg differ diff --git a/yogstation.dme b/yogstation.dme index 5cf92d66c9a6..8eb77c73e0f8 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -27,6 +27,7 @@ #include "code\__DEFINES\actions.dm" #include "code\__DEFINES\admin.dm" #include "code\__DEFINES\ai.dm" +#include "code\__DEFINES\anomalies.dm" #include "code\__DEFINES\antagonists.dm" #include "code\__DEFINES\art.dm" #include "code\__DEFINES\assembly.dm" @@ -2245,6 +2246,7 @@ #include "code\modules\events\anomaly_bluespace.dm" #include "code\modules\events\anomaly_flux.dm" #include "code\modules\events\anomaly_grav.dm" +#include "code\modules\events\anomaly_hallucination.dm" #include "code\modules\events\anomaly_pyro.dm" #include "code\modules\events\anomaly_radiation.dm" #include "code\modules\events\anomaly_vortex.dm" @@ -3171,6 +3173,7 @@ #include "code\modules\power\singularity\particle_accelerator\particle_control.dm" #include "code\modules\power\singularity\particle_accelerator\particle_emitter.dm" #include "code\modules\power\supermatter\supermatter.dm" +#include "code\modules\power\supermatter\supermatter_delamination.dm" #include "code\modules\power\tesla\coil.dm" #include "code\modules\power\tesla\energy_ball.dm" #include "code\modules\power\tesla\generator.dm" diff --git a/yogstation/code/game/gamemodes/gangs/dominator.dm b/yogstation/code/game/gamemodes/gangs/dominator.dm index 7f1c896a0522..d4b82ec6c01c 100644 --- a/yogstation/code/game/gamemodes/gangs/dominator.dm +++ b/yogstation/code/game/gamemodes/gangs/dominator.dm @@ -51,7 +51,7 @@ /obj/machinery/dominator/hulk_damage() return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED -/obj/machinery/dominator/tesla_act() +/obj/machinery/dominator/tesla_act(power, tesla_flags, shocked_targets, zap_gib = FALSE) qdel(src) /obj/machinery/dominator/update_overlays() diff --git a/yogstation/code/modules/assembly/signaler.dm b/yogstation/code/modules/assembly/signaler.dm index 08dc33171402..b2e322f8c71b 100644 --- a/yogstation/code/modules/assembly/signaler.dm +++ b/yogstation/code/modules/assembly/signaler.dm @@ -1,5 +1,4 @@ /obj/item/assembly/signaler - icon = 'yogstation/icons/obj/assemblies/new_assemblies.dmi' var/static/list/label_colors = list("red", "green", "blue", "cyan", "magenta", "yellow", "white") var/label_color = "green" diff --git a/yogstation/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm b/yogstation/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm index d0b41df6733d..9f12c8ccc5a8 100644 --- a/yogstation/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm +++ b/yogstation/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm @@ -151,7 +151,7 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0) return -/mob/living/simple_animal/hostile/floor_cluwne/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)//prevents runtimes with machine fuckery +/mob/living/simple_animal/hostile/floor_cluwne/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE, gib = FALSE)//prevents runtimes with machine fuckery return FALSE /mob/living/simple_animal/hostile/floor_cluwne/proc/Found_You() diff --git a/yogstation/icons/obj/assemblies/new_assemblies.dmi b/yogstation/icons/obj/assemblies/new_assemblies.dmi deleted file mode 100644 index 37ad19bbc885..000000000000 Binary files a/yogstation/icons/obj/assemblies/new_assemblies.dmi and /dev/null differ