diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm
index 9b0883173a9e..c2b807b8aa8b 100644
--- a/code/__DEFINES/wires.dm
+++ b/code/__DEFINES/wires.dm
@@ -100,6 +100,7 @@
#define WIRE_FIRE_DETECT "Automatic Detection"
#define WIRE_FIRE_TRIGGER "Alarm Trigger"
#define WIRE_FIRE_RESET "Alarm Reset"
+#define WIRE_DISCHARGE "Discharge" // OCULIS EDIT ADDITION
// Wire states for the AI
#define AI_WIRE_NORMAL 0
diff --git a/code/_onclick/hud/parallax/random_layer.dm b/code/_onclick/hud/parallax/random_layer.dm
index dad43cd8d1b5..bb72bfb69c73 100644
--- a/code/_onclick/hud/parallax/random_layer.dm
+++ b/code/_onclick/hud/parallax/random_layer.dm
@@ -24,11 +24,13 @@
/// Gassy background with a few random colors
/atom/movable/screen/parallax_layer/random/space_gas
+ /* // OCULIS EDIT REMOVAL START
//IRIS EDIT START
icon = 'modular_iris/master_files/icons/effects/electrobox.dmi'
icon_state = "lightning"
speed = 0.5
//IRIS EDIT END
+ */ // OCULIS EDIT REMOVAL END
/// The colors we can be
var/possible_colors = list(COLOR_STRONG_VIOLET, COLOR_VIOLET, COLOR_LIGHT_PINK, COLOR_MOSTLY_PURE_PINK, COLOR_AMETHYST, COLOR_OCULIS_LOGO, COLOR_PURPLE) //OCULIS EDIT
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 660e345ec49a..1a7609a3b242 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -243,6 +243,7 @@ SUBSYSTEM_DEF(ticker)
//Configure mode and assign player to antagonists
var/can_continue = FALSE
can_continue = SSdynamic.select_roundstart_antagonists() //Choose antagonists
+ SSeidolon_storm.initialize_storm_intensity() // OCULIS EDIT ADDITION - EIDOLON_STORM
CHECK_TICK
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PRE_JOBS_ASSIGNED, src)
can_continue = can_continue && SSjob.divide_occupations() //Distribute jobs
diff --git a/modular_oculis/modules/storm/code/anchor/anchor_computer.dm b/modular_oculis/modules/storm/code/anchor/anchor_computer.dm
new file mode 100644
index 000000000000..62d0e32a25f2
--- /dev/null
+++ b/modular_oculis/modules/storm/code/anchor/anchor_computer.dm
@@ -0,0 +1,69 @@
+/obj/item/circuitboard/computer/redspace_anchor_control
+ name = "Redspace Anchor Control"
+ greyscale_colors = CIRCUIT_COLOR_COMMAND
+ build_path = /obj/machinery/computer/redspace_anchor_computer
+
+/obj/machinery/computer/redspace_anchor_computer
+ name = "redspace anchor control computer"
+ desc = "Used to control the redspace anchor."
+ icon_screen = "comm"
+ circuit = /obj/item/circuitboard/computer/redspace_anchor_control
+ var/obj/machinery/redspace_anchor/connected_anchor = null
+
+/obj/machinery/computer/redspace_anchor_computer/Initialize(mapload, obj/item/circuitboard/C)
+ . = ..()
+ for(var/obj/machinery/redspace_anchor/anchor as anything in SSmachines.get_machines_by_type(/obj/machinery/redspace_anchor))
+ if(anchor.z == z)
+ connected_anchor = anchor
+ update_appearance()
+
+/obj/machinery/computer/redspace_anchor_computer/update_overlays()
+ if(connected_anchor?.breaker)
+ icon_screen = "comm"
+ else
+ icon_screen = "syndishuttle"
+ . = ..()
+
+/obj/machinery/computer/redspace_anchor_computer/ui_status(mob/user, datum/ui_state/state)
+ if(HAS_SILICON_ACCESS(user) && connected_anchor.ai_disabled)
+ to_chat(user, span_info("AI control has been disabled."))
+ else if(!connected_anchor.shorted)
+ return ..()
+ return UI_CLOSE
+
+/obj/machinery/computer/redspace_anchor_computer/ui_interact(mob/user, datum/tgui/ui)
+ . = ..()
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "RedspaceAnchor", name)
+ ui.open()
+
+/obj/machinery/computer/redspace_anchor_computer/ui_data(mob/user)
+ var/list/data = list()
+ data["breaker"] = connected_anchor.breaker
+ data["charge_count"] = connected_anchor.charge_count
+ data["charging_state"] = connected_anchor.charging_state
+ data["on"] = connected_anchor.on
+ data["operational"] = (connected_anchor.machine_stat & BROKEN) ? FALSE : TRUE
+ data["violetspace_energy"] = connected_anchor.violetspace_energy
+ return data
+
+/obj/machinery/computer/redspace_anchor_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ switch(action)
+ if("gentoggle")
+ connected_anchor.breaker = !connected_anchor.breaker
+ investigate_log("was toggled [connected_anchor.breaker ? "ON" : "OFF"] by [key_name(usr)].", INVESTIGATE_ENGINE)
+ if(connected_anchor.violetspace_energy)
+ connected_anchor.trigger_unsafe_discharge()
+ investigate_log("was overloaded by remaining violetspace energy.", INVESTIGATE_ENGINE)
+ connected_anchor.set_power()
+ . = TRUE
+ if("discharge_violetspace")
+ if(connected_anchor.violetspace_energy && connected_anchor.can_discharge)
+ investigate_log("has discharged violetspace energy by [key_name(usr)].", INVESTIGATE_ENGINE)
+ connected_anchor.trigger_safe_discharge()
+ . = TRUE
diff --git a/modular_oculis/modules/storm/code/anchor/redspace_anchor.dm b/modular_oculis/modules/storm/code/anchor/redspace_anchor.dm
new file mode 100644
index 000000000000..10094bafefd4
--- /dev/null
+++ b/modular_oculis/modules/storm/code/anchor/redspace_anchor.dm
@@ -0,0 +1,278 @@
+#define POWER_IDLE 0
+#define POWER_UP 1
+#define POWER_DOWN 2
+
+/obj/machinery/redspace_anchor
+ name = "redspace anchor"
+ icon = 'modular_oculis/modules/storm/icons/redspace_anchor.dmi'
+ icon_state = "anchor_off"
+ interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+
+ /*
+ * Yes, I know this doesn't use BASE_MACHINE_IDLE_CONSUMPTION at all,
+ * and this is purelly done so that the code is readable without pulling out a calculator
+ * to make sure these values are right.
+ */
+ use_power = IDLE_POWER_USE
+ idle_power_usage = (6 MEGA WATTS) // Lotta fucking power to keep the storm at bay.
+
+ // 3x3 offset by one row
+ pixel_x = -32
+ pixel_y = -32
+ bound_height = 96
+ bound_width = 96
+ bound_x = -32
+ bound_y = -32
+ density = TRUE
+ move_resist = INFINITY
+
+ /// Whether the redspace anchor is currently active.
+ var/on = TRUE
+ /// If the main breaker is on/off, to enable/disable the anchor.
+ var/breaker = TRUE
+ /// If the power cable is cut or not.
+ var/shorted = FALSE
+ /// If a silicon can interact with it.
+ var/ai_disabled = FALSE
+ /// If the anchor will produce an alarm when changing states.
+ var/alarm_disabled = FALSE
+ /// If the anchor can safely discharge its redspace energy.
+ var/can_discharge = TRUE
+ /// If the generator is idle, charging, or down.
+ var/charging_state = POWER_IDLE
+ /// How much charge the redspace anchor has, goes down when breaker is shut, and shuts down at 0.
+ var/charge_count = 100
+
+ /// The overlay currently used.
+ var/current_overlay = null
+
+ /// Audio for when the redspace anchor is on
+ var/datum/looping_sound/redspace_anchor/soundloop
+
+ /// How much excess violetspace energy the redspace anchor has, which can cause it to fail once it reaches 100.
+ var/violetspace_energy = 0
+
+/obj/machinery/redspace_anchor/Initialize(mapload)
+ . = ..()
+ SSeidolon_storm.register_anchor(src)
+ set_wires(new /datum/wires/redspace_anchor(src))
+ soundloop = new(src, start_immediately = FALSE)
+ if(on)
+ add_overlay("activated")
+
+/obj/machinery/redspace_anchor/examine(mob/user)
+ if(HAS_TRAIT(user, TRAIT_MINDSHIELD))
+ desc = "The most important machine on the station. You feel more... Stable, near it."
+ return ..()
+ desc = "The most important machine on the station. \n[span_danger("Looking directly at it gives you a headache.")]"
+ return ..()
+
+/obj/machinery/redspace_anchor/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE)
+ return FALSE
+
+/obj/machinery/redspace_anchor/ex_act(severity, target)
+ if(severity >= EXPLODE_DEVASTATE) // Very sturdy.
+ set_broken()
+ return TRUE
+ return FALSE
+
+/obj/machinery/redspace_anchor/blob_act(obj/structure/blob/B)
+ if(prob(20))
+ set_broken()
+
+/obj/machinery/redspace_anchor/zap_act(power, zap_flags)
+ . = ..()
+ if(zap_flags & ZAP_MACHINE_EXPLOSIVE)
+ qdel(src) //like the singulo, tesla deletes it. stops it from exploding over and over
+
+// You aren't allowed to move.
+/obj/machinery/redspace_anchor/Move()
+ . = ..()
+ qdel(src)
+
+/obj/machinery/redspace_anchor/proc/set_broken()
+ atom_break()
+ update_appearance()
+
+/obj/machinery/redspace_anchor/proc/set_fix()
+ set_machine_stat(machine_stat & ~BROKEN)
+ update_appearance()
+
+/obj/machinery/redspace_anchor/update_icon_state()
+ . = ..()
+ if(on)
+ icon_state = "anchor_on"
+ else
+ icon_state = "anchor_off"
+
+/obj/machinery/redspace_anchor/screwdriver_act(mob/living/user, obj/item/tool)
+ if(machine_stat & BROKEN)
+ return
+ tool.play_tool_sound(src)
+ toggle_panel_open()
+ to_chat(user, span_notice("The wires have been [panel_open ? "exposed" : "unexposed"]."))
+ update_appearance()
+ return TRUE
+
+// Wire interactions
+/obj/machinery/redspace_anchor/proc/reset(wire)
+ switch(wire)
+ if(WIRE_POWER)
+ if(!wires.is_cut(WIRE_POWER))
+ shorted = FALSE
+ set_power()
+ if(WIRE_AI)
+ if(!wires.is_cut(WIRE_AI))
+ ai_disabled = FALSE
+ if(WIRE_ALARM)
+ if(!wires.is_cut(WIRE_ALARM))
+ alarm_disabled = FALSE
+ if(WIRE_DISCHARGE)
+ update_appearance()
+
+/obj/machinery/redspace_anchor/power_change()
+ . = ..()
+ if(SSticker.current_state == GAME_STATE_PLAYING)
+ investigate_log("has [machine_stat & NOPOWER ? "lost" : "regained"] power.", INVESTIGATE_ENGINE)
+ set_power()
+
+// Set the charging state based on power/breaker.
+/obj/machinery/redspace_anchor/proc/set_power()
+ var/new_state = FALSE
+ if(machine_stat & (NOPOWER|BROKEN) || !breaker || shorted)
+ new_state = FALSE
+ else if(breaker)
+ new_state = TRUE
+
+ charging_state = new_state ? POWER_UP : POWER_DOWN // Startup sequence animation.
+ if(SSticker.current_state == GAME_STATE_PLAYING)
+ investigate_log("is now [charging_state == POWER_UP ? "charging" : "discharging"].", INVESTIGATE_ENGINE)
+ update_appearance()
+
+/obj/machinery/redspace_anchor/proc/enable()
+ charging_state = POWER_IDLE
+ on = TRUE
+
+ //soundloop.start()
+ update_appearance()
+
+ if(SSticker.current_state == GAME_STATE_PLAYING)
+ investigate_log("was brought online.", INVESTIGATE_ENGINE)
+ message_admins("The redspace anchor was brought online [ADMIN_VERBOSEJMP(src)]")
+ shake_everyone()
+
+/obj/machinery/redspace_anchor/proc/disable()
+ charging_state = POWER_IDLE
+ on = FALSE
+
+ //soundloop.stop()
+ update_appearance()
+
+ if(SSticker.current_state == GAME_STATE_PLAYING)
+ investigate_log("was brought offline.", INVESTIGATE_ENGINE)
+ message_admins("The redspace anchor was brought offline. [ADMIN_VERBOSEJMP(src)]")
+ shake_everyone()
+
+// Charge/Discharge and turn on/off when you reach 0/100 percent.
+/obj/machinery/redspace_anchor/process()
+ if(machine_stat & BROKEN)
+ cut_overlays()
+ return
+
+ var/overlay_state = null
+ switch(charge_count)
+ if(0 to 20)
+ overlay_state = null
+ if(21 to 40)
+ overlay_state = "startup"
+ if(41 to 60)
+ overlay_state = "idle"
+ if(61 to 80)
+ overlay_state = "activating"
+ if(81 to 100)
+ overlay_state = "activated"
+
+ if(overlay_state != current_overlay)
+ cut_overlays()
+ if(overlay_state)
+ add_overlay(overlay_state)
+ current_overlay = overlay_state
+
+ if(charging_state == POWER_IDLE)
+ return
+ if((charging_state == POWER_UP) && (charge_count >= 100))
+ enable()
+ else if((charging_state == POWER_DOWN) && (charge_count <= 0))
+ disable()
+ else
+ if(charging_state == POWER_UP)
+ charge_count += 2
+ else if(charging_state == POWER_DOWN)
+ charge_count -= 2
+
+ for(var/mob/mobs as anything in GLOB.mob_list)
+ var/turf/mob_turf = get_turf(mobs)
+ if(!istype(mob_turf))
+ continue
+ if(!is_valid_z_level(src, mob_turf))
+ continue
+ if(mobs.client)
+ if((charge_count % 4 == 0 && prob(75)) && !alarm_disabled) // Let them know it is charging/discharging.
+ if(charging_state == POWER_UP)
+ mobs.playsound_local(mob_turf, 'sound/effects/magic/cosmic_expansion.ogg', 100, TRUE)
+ else
+ mobs.playsound_local(mob_turf, 'sound/effects/magic/swap.ogg', 100, TRUE)
+ if((charge_count <= 50) && (charging_state == POWER_DOWN) && prob(5))
+ to_chat(mobs, span_bolddanger("You feel a foreign presence encroaching around you."))
+
+/// Shake everyone on the z level to let them know that the anchor was enagaged/disengaged.
+/obj/machinery/redspace_anchor/proc/shake_everyone()
+ var/turf/T = get_turf(src)
+ var/sound/alert_sound = sound('sound/effects/alert.ogg')
+ for(var/mob/mobs as anything in GLOB.mob_list)
+ var/turf/mob_turf = get_turf(mobs)
+ if(!istype(mob_turf))
+ continue
+ if(!is_valid_z_level(T, mob_turf))
+ continue
+ if(mobs.client)
+ shake_camera(mobs, 15, 1)
+ mobs.playsound_local(T, null, 100, 1, 0.5, sound_to_use = alert_sound)
+ if(!SSmapping.level_has_any_trait(z, ZTRAIT_STATION))
+ return
+ if(on)
+ priority_announce("Redspace Anchor activated. Storm dissipation in progress.", "Redspace Anchor")
+ else
+ priority_announce("Warning: Redspace Anchor has been disabled. Storm encroaching on station perimeter.", "Redspace Anchor")
+
+/obj/machinery/redspace_anchor/proc/tick(intensity)
+ if((charging_state != POWER_IDLE) || !on)
+ return
+ violetspace_energy += (rand(1,5) * intensity)
+ if(violetspace_energy >= 100)
+ trigger_unsafe_discharge()
+
+/obj/machinery/redspace_anchor/proc/trigger_unsafe_discharge()
+ violetspace_energy = 0
+ breaker = FALSE
+ set_power()
+ priority_announce(
+ text = "Redspace Anchor failure! Unsafe shutdown in progress!",
+ title = "Redspace Anchor",
+ sound = SSstation.announcer.get_rand_alert_sound(),
+ has_important_message = TRUE,
+ )
+
+/obj/machinery/redspace_anchor/proc/trigger_safe_discharge()
+ violetspace_energy = 0
+ priority_announce(
+ text = "Redspace Anchor safe discharge in progress.",
+ title = "Redspace Anchor",
+ sound = SSstation.announcer.get_rand_alert_sound(),
+ has_important_message = TRUE,
+ )
+
+#undef POWER_IDLE
+#undef POWER_UP
+#undef POWER_DOWN
diff --git a/modular_oculis/modules/storm/code/anchor/redspace_anchor_soundloop.dm b/modular_oculis/modules/storm/code/anchor/redspace_anchor_soundloop.dm
new file mode 100644
index 000000000000..d75c4e5767d9
--- /dev/null
+++ b/modular_oculis/modules/storm/code/anchor/redspace_anchor_soundloop.dm
@@ -0,0 +1,6 @@
+/datum/looping_sound/redspace_anchor
+ mid_sounds = list('sound/machines/hypertorus/loops/hypertorus_nominal.ogg')
+ mid_length = 6 SECONDS
+ volume = 55
+ extra_range = 15
+ vary = TRUE
diff --git a/modular_oculis/modules/storm/code/anchor/wires.dm b/modular_oculis/modules/storm/code/anchor/wires.dm
new file mode 100644
index 000000000000..eea37514f107
--- /dev/null
+++ b/modular_oculis/modules/storm/code/anchor/wires.dm
@@ -0,0 +1,65 @@
+/datum/wires/redspace_anchor
+ holder_type = /obj/machinery/redspace_anchor
+ proper_name = "Redspace Anchor"
+
+/datum/wires/redspace_anchor/New(atom/holder)
+ wires = list(
+ WIRE_POWER,
+ WIRE_AI,
+ WIRE_ALARM,
+ WIRE_DISCHARGE,
+ )
+ add_duds(13) // It's a complicated machine. It's gonna have lots of wires.
+ ..()
+
+/datum/wires/redspace_anchor/interactable(mob/user)
+ if(!..())
+ return FALSE
+ return TRUE
+
+/datum/wires/redspace_anchor/get_status()
+ var/obj/machinery/redspace_anchor/A = holder
+ var/list/status = list()
+ status += "The short indicator is [A.shorted ? "lit" : "off"]."
+ status += "The AI connection light is [!A.ai_disabled ? "on" : "off"]."
+ status += "The alarm light is [!A.alarm_disabled ? "on" : "off"]."
+ return status
+
+/datum/wires/redspace_anchor/on_pulse(wire)
+ var/obj/machinery/redspace_anchor/anchor = holder
+ switch(wire)
+ if(WIRE_POWER) // Short out for a long time.
+ if(!anchor.shorted)
+ anchor.shorted = TRUE
+ anchor.update_appearance()
+ addtimer(CALLBACK(anchor, TYPE_PROC_REF(/obj/machinery/redspace_anchor, reset), wire), 2 MINUTES)
+ if(WIRE_AI) // Disable AI control for a while.
+ if(!anchor.ai_disabled)
+ anchor.ai_disabled = TRUE
+ addtimer(CALLBACK(anchor, TYPE_PROC_REF(/obj/machinery/redspace_anchor, reset), wire), 10 SECONDS)
+ if(WIRE_ALARM)
+ if(!anchor.alarm_disabled)
+ anchor.alarm_disabled = TRUE
+ addtimer(CALLBACK(anchor, TYPE_PROC_REF(/obj/machinery/redspace_anchor, reset), wire), 10 SECONDS)
+ anchor.update_appearance()
+ if(WIRE_DISCHARGE)
+ if(anchor.can_discharge && anchor.violetspace_energy)
+ anchor.trigger_safe_discharge()
+
+/datum/wires/redspace_anchor/on_cut(wire, mend, source)
+ var/obj/machinery/redspace_anchor/anchor = holder
+ switch(wire)
+ if(WIRE_POWER)
+ anchor.shorted = !mend
+ anchor.update_appearance()
+ if(WIRE_AI)
+ anchor.ai_disabled = mend // Enable/disable AI control.
+ if(WIRE_ALARM)
+ anchor.alarm_disabled = mend
+ if(WIRE_DISCHARGE)
+ anchor.can_discharge = mend
+
+/datum/wires/redspace_anchor/can_reveal_wires(mob/user)
+ if(HAS_TRAIT(user, TRAIT_KNOW_ENGI_WIRES))
+ return TRUE
+ return ..()
diff --git a/modular_oculis/modules/storm/code/storm/storm_layer.dm b/modular_oculis/modules/storm/code/storm/storm_layer.dm
new file mode 100644
index 000000000000..c6bbe0c5f0cc
--- /dev/null
+++ b/modular_oculis/modules/storm/code/storm/storm_layer.dm
@@ -0,0 +1,6 @@
+/atom/movable/screen/parallax_layer/random/space_gas/storm
+ parallax_color = list(1,0,0,0, 0,0,0,0, 0,0,2,0, 0,0,0,1, 0,0,0,0) //very vibrant purple
+
+/atom/movable/screen/parallax_layer/random/space_gas/storm/apply_global_effects()
+ . = ..()
+ set_base_starlight("#911855")
diff --git a/modular_oculis/modules/storm/code/storm/storm_rulesets.dm b/modular_oculis/modules/storm/code/storm/storm_rulesets.dm
new file mode 100644
index 000000000000..3f48ca526790
--- /dev/null
+++ b/modular_oculis/modules/storm/code/storm/storm_rulesets.dm
@@ -0,0 +1,46 @@
+#define STORM_INTENSITY_NONE 0
+#define STORM_INTENSITY_CALM 1
+#define STORM_INTENSITY_DRIZZLE 2
+#define STORM_INTENSITY_STORM 3
+#define STORM_INTENSITY_MONSOON 4
+#define STORM_INTENSITY_ADMIN 5
+
+/datum/storm_ruleset
+ /// Which storm intensity this ruleset belongs to. See defines for values.
+ var/intensity = STORM_INTENSITY_NONE
+ /// Minimum population required for this ruleset to be selected at roundstart.
+ var/min_pop = 0
+ /// How much time it takes between each storm cooldown.
+ var/storm_cooldown = 10 MINUTES
+
+/datum/storm_ruleset/calm
+ intensity = STORM_INTENSITY_CALM
+ min_pop = 0
+ storm_cooldown = 10 MINUTES
+
+/datum/storm_ruleset/drizzle
+ intensity = STORM_INTENSITY_DRIZZLE
+ min_pop = 10
+ storm_cooldown = 10 MINUTES
+
+/datum/storm_ruleset/storm
+ intensity = STORM_INTENSITY_STORM
+ min_pop = 15
+ storm_cooldown = 5 MINUTES
+
+/datum/storm_ruleset/monsoon
+ intensity = STORM_INTENSITY_MONSOON
+ min_pop = 25
+ storm_cooldown = 5 MINUTES
+
+/datum/storm_ruleset/admin
+ intensity = STORM_INTENSITY_ADMIN
+ min_pop = 999
+ storm_cooldown = 10 MINUTES
+
+#undef STORM_INTENSITY_NONE
+#undef STORM_INTENSITY_CALM
+#undef STORM_INTENSITY_DRIZZLE
+#undef STORM_INTENSITY_STORM
+#undef STORM_INTENSITY_MONSOON
+#undef STORM_INTENSITY_ADMIN
diff --git a/modular_oculis/modules/storm/code/storm/storm_subsystem.dm b/modular_oculis/modules/storm/code/storm/storm_subsystem.dm
new file mode 100644
index 000000000000..2fd59a2f45cd
--- /dev/null
+++ b/modular_oculis/modules/storm/code/storm/storm_subsystem.dm
@@ -0,0 +1,54 @@
+PROCESSING_SUBSYSTEM_DEF(eidolon_storm)
+ name = "Eidolon Storm"
+ stat_tag = "ES"
+ ss_flags = SS_NO_INIT | SS_KEEP_TIMING
+ runlevels = RUNLEVEL_GAME
+ wait = 1 MINUTES
+
+ COOLDOWN_DECLARE(eidolon_storm_cooldown)
+ /// Currently selected storem intensity. See defines for values.
+ var/datum/storm_ruleset/chosen_storm_ruleset = /datum/storm_ruleset
+ /// The station's redspace anchor. We shouldn't care for any other anchors in the game.
+ var/obj/machinery/redspace_anchor/station_anchor = null
+
+/datum/controller/subsystem/processing/eidolon_storm/proc/register_anchor(obj/machinery/redspace_anchor/anchor)
+ if(!SSmapping.level_has_any_trait(anchor.z, ZTRAIT_STATION)) // So that we can have decorative anchors on other z levels, like on castor.
+ return
+ if(station_anchor) // Incase some admin fucks up and spawns in a second anchor on the station z level.
+ return
+ station_anchor = anchor
+
+/datum/controller/subsystem/processing/eidolon_storm/proc/initialize_storm_intensity()
+ var/list/player_candidates = list()
+ for(var/mob/dead/new_player/player as anything in GLOB.new_player_list - SSjob.unassigned)
+ if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
+ player_candidates += player
+ var/roundstart_population = length(player_candidates)
+
+ var/list/possible_rulesets = list()
+ for(var/storm_ruleset as anything in subtypesof(/datum/storm_ruleset))
+ var/datum/storm_ruleset/intensity_datum = new storm_ruleset()
+ if(roundstart_population < intensity_datum.min_pop)
+ qdel(intensity_datum)
+ continue
+ possible_rulesets += intensity_datum
+ chosen_storm_ruleset = pick(possible_rulesets)
+
+ log_dynamic("Selected intensity: [chosen_storm_ruleset.intensity]")
+ log_dynamic("- Roundstart population: [roundstart_population]")
+ SSblackbox.record_feedback(
+ "associative",
+ "storm_intensity",
+ 1,
+ list(
+ "server_name" = CONFIG_GET(string/serversqlname),
+ "intensity" = chosen_storm_ruleset.intensity,
+ "player_count" = roundstart_population,
+ ),
+ )
+
+/datum/controller/subsystem/processing/eidolon_storm/fire(resumed = FALSE)
+ if(!COOLDOWN_FINISHED(src, eidolon_storm_cooldown))
+ return
+ COOLDOWN_START(src, eidolon_storm_cooldown, (chosen_storm_ruleset.storm_cooldown))
+ station_anchor?.tick(chosen_storm_ruleset.intensity)
diff --git a/modular_oculis/modules/storm/icons/redspace_anchor.dmi b/modular_oculis/modules/storm/icons/redspace_anchor.dmi
new file mode 100644
index 000000000000..cdb2ab65852d
Binary files /dev/null and b/modular_oculis/modules/storm/icons/redspace_anchor.dmi differ
diff --git a/modular_oculis/modules/storm/readme.md b/modular_oculis/modules/storm/readme.md
new file mode 100644
index 000000000000..240aade61c71
--- /dev/null
+++ b/modular_oculis/modules/storm/readme.md
@@ -0,0 +1,29 @@
+https://github.com/Monkestation/OculisStation/pull/46
+
+## \
+
+Module ID: EIDOLON_STORM
+
+### Description:
+
+This module is responsible for Eidolon's storm, anchor, as well as how both work mechanically.
+
+### TG Proc/File Changes:
+
+- `code/__DEFINES/wires.dm`
+
+### Modular Overrides:
+
+- N/A
+
+### Defines:
+
+- N/A
+
+### Included files that are not contained in this module:
+
+- `tgui/packages/tgui/interfaces/RedspaceAnchor.tsx`
+
+### Credits:
+
+XeonMations
diff --git a/tgstation.dme b/tgstation.dme
index 2a2dc4021c4d..faf511753978 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -10332,6 +10332,13 @@
#include "modular_oculis\modules\species\ethereal\code\stomach_ethereal.dm"
#include "modular_oculis\modules\stickers\code\boxes.dm"
#include "modular_oculis\modules\stickers\code\stickers.dm"
+#include "modular_oculis\modules\storm\code\anchor\anchor_computer.dm"
+#include "modular_oculis\modules\storm\code\anchor\redspace_anchor.dm"
+#include "modular_oculis\modules\storm\code\anchor\redspace_anchor_soundloop.dm"
+#include "modular_oculis\modules\storm\code\anchor\wires.dm"
+#include "modular_oculis\modules\storm\code\storm\storm_layer.dm"
+#include "modular_oculis\modules\storm\code\storm\storm_rulesets.dm"
+#include "modular_oculis\modules\storm\code\storm\storm_subsystem.dm"
#include "modular_oculis\modules\tg_lizards\code\tails.dm"
#include "modular_oculis\modules\turfs\oculis_turfs.dm"
#include "modular_oculis\modules\unique_lizards\code\client_colour.dm"
diff --git a/tgui/packages/tgui/interfaces/RedspaceAnchor.tsx b/tgui/packages/tgui/interfaces/RedspaceAnchor.tsx
new file mode 100644
index 000000000000..fea6375b90c5
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/RedspaceAnchor.tsx
@@ -0,0 +1,86 @@
+// THIS IS A OCULIS UI FILE
+import {
+ Box,
+ Button,
+ LabeledList,
+ NoticeBox,
+ ProgressBar,
+ Section,
+} from 'tgui-core/components';
+
+import { useBackend } from '../backend';
+import { Window } from '../layouts';
+
+export const RedspaceAnchor = (props) => {
+const { data } = useBackend();
+const { operational } = data;
+return (
+
+
+ {!operational && No data available}
+ {!!operational && }
+
+
+ );
+};
+
+const RedspaceAnchorContent = (props) => {
+const { act, data } = useBackend();
+const { breaker, charge_count, charging_state, on, operational, violetspace_energy } = data;
+return (
+
+
+
+
+
+
+
+
+ {charging_state === 0 &&
+ ((on && Fully Charged) || (
+ Not Charging
+ ))}
+ {charging_state === 1 && Charging}
+ {charging_state === 2 && Discharging}
+
+
+
+
+
+ act('discharge_violetspace')}
+ >
+ Discharge
+
+
+
+
+ );
+};