Built with Claude Opus. (WIP) -- The Oppenheimer Energy Lance is a prototype mega weapon capable of annihilating entire bases in a single shot, hence the name. It operates purely on electricity. It has energy discharge options that you select using the built-in HUD, capable of producing anything from a 30 tile radius crater up to a 2000 tile radius one. At maximum charge it draws 36 GW from the grid for 16 seconds, then releases that energy over 5.7 seconds, creating an unstable ball of energy.
Mods introducing new content into the game.
Version: 0.31.0
Date: 2026-09-14
Changes:
- 36 CAPACITOR BANKS. Each corner cluster is now 3x3, nine to operate
(one full cluster), thirty-six for the top of the dial. Each bank
holds a thirty-sixth of the charge instead of a sixteenth. The pad is
55 tiles across.
- THE FIRING RING IS HAZARD CONCRETE AGAIN. A two-tile band under the
drawn conduit ring, flowing round the gun between the clusters and
straight across the four lanes. The rest of the hardstand is
unchanged.
- The Lance Substations stand further out, at the new corners, and
reach 14 tiles to cover a whole 3x3 cluster.
- 32 runway lamps, adding a pair at the substation row on each lane.
- Oppenheimer turrets must now be 56 tiles apart (was 48), so two pads
never overlap.
- Existing installations: every bank is still in its slot (the old
slots are part of the new layout); the twenty new slots are ghosted.
Each substation is moved out to its new corner with its wires kept,
because the old spot is now a bank slot; one that cannot move is
reported. Lamps move and the pad is re-laid. Schema 14 -> 15.
Version: 0.30.0
Date: 2026-09-14
Changes:
- THE CHARGING SPHERE, RELIT. User, from a screenshot at 139 tiles/5%
charge: "sloppy, not imposing" -- the same complaint 0.29.0 fixed for
the pad, this time for the ball. Four fixes, all in implode.draw_orb
(shared by the growth phase and the collapse):
- Shading banding fixed: shade.layers 6 -> 16 at an equivalent total
alpha (0.15 -> 0.06) and a linear colour ease (shade.ease = 1, was a
bare quadratic u*u) instead of packing the gradient into the last two
layers.
- THE RIM HALO. A single hard stroke around a filled disc reads as this
mod's own danger-preview rings (render.preview, also filled=false) --
an information overlay, not a hot edge. Replaced with ball.halo_steps
fading, widening strokes stepping outward from the true edge.
- THE BALL CASTS LIGHT (ball.light, rendering.draw_light, scaled off the
current radius, capped). Everything before this was confined to the
ball's own silhouette no matter how hot it got.
- Infall streaks (implode.draw_streaks_at, both the growth and collapse
phases) now draw a small hot dot at the leading end -- the one closest
to the ball -- instead of one flat colour top to bottom.
- No schema change: config and rendering only, nothing persisted.
Version: 0.29.0
Date: 2026-09-14
Changes:
- THE PAD IS A HARDSTAND. Straight lines only: a two-tile hazard rim,
a refined-concrete field, a concrete cross along the four beam lanes
that breaks out through the rim, and a two-tile hazard frame around a
square concrete stage under the gun. The tile grid can only draw a
circle as uneven steps, so the tiled firing ring, the stepped moat and
the round stage are gone; the drawn conduit ring is the one circle.
- The hazard stripes mitre at the corners (left and right variants).
- The pad is one tile wider on each side (47 across), so the masts no
longer crowd the rim.
- RUNWAY LIGHTS. The lamps stand in pairs either side of each beam
lane, one pair per bank row and mast row, so every lamp lines up with
the hardware beside it. 24 lamps, up from 20. The four that sat on the
moat next to the stage are gone.
- Only the bank and mast slots keep a marked socket, hidden once built.
- The strike flash is square, to match the stage.
- Existing lamps are moved onto the new slots and the four new ones
ghosted; existing pads are re-laid. Schema 12 -> 13.
- A lamp slot that would stand under a capacitor bank's art is now a
load error naming the slot.
- THE BUFFERED AND FUEL-CELL BANK TIERS ARE REMOVED. Only the standard
Capacitor Bank remains -- their items, recipes, technology unlocks
and locale entries are gone. Existing banks of either tier did not
survive the update (the engine drops entities of a deleted prototype
before any migration runs); their slots are re-ghosted for the
standard bank on load.
Version: 0.28.2
Date: 2026-09-14
Bugfixes:
- A TOTAL POWER CUT MID-CHARGE STILL FIRED THE GUN. Losing all incoming
power partway through the 16-second charge correctly froze the chamber
gauge -- no energy was arriving -- but nothing aborted the sequence:
the brownout/DARK detector that exists for exactly this case
explicitly skips the FIRE state, and beam.fire has no power floor of
its own. The tape played out in full and the gun discharged anyway, at
whatever charge it actually held, including zero. Zero joules banked
at the strike now reports a misfire instead of lighting a lance at
power 0.
Version: 0.28.1
Date: 2026-09-14
Changes:
- Updated description further
Version: 0.28.0
Date: 2026-09-14
Features:
- CAPACITOR ARCS. Once a charge passes 10% of the order, red lightning pings
from bank to bank, faster and thicker as the charge climbs. Mostly within
a cluster; some jump to the neighbouring cluster, never across the gun.
- THE BROWNOUT BEAT. On the strike every lamp, bank glow and the conduit
ring drop almost to black for 14 ticks, then slam back.
- THE IGNITION SHOCK. On the strike a ring of dust races across the pad
from the stage to the rim.
- BARREL VENTING. After a shot, steam pours off the muzzle, from the point
the lance left, thinning out over about 5.5 seconds.
- THE BALL IS A SPHERE. The growing sphere and the collapse are shaded
with a stack of offset discs lit from the upper left, and the ground
shadow is pushed away from the light to match. The shading is drawn in
the world only, not on the map.
Bugfixes:
- THE LAMPS CLIPPED THE CAPACITOR BANKS, ALL TWENTY OF THEM. The offsets
cleared the bank's 3-tile footprint, not its art, which is 4.06 tiles wide
and 5.9 tall; and the per-bank lamps stood 2.5 tiles out along a diagonal,
only 1.77 tiles per axis. The lamps now stand in an L-bracket on each
cluster's gun-facing edges, cleared against the bank art itself.
- THE CONTACT EXPLOSIONS PLAYED UNDER THE BALL. They spawned at the aim
point, which the ball's opaque fill covers within a few ticks. They now
land where the drawn lance meets the ball's near face.
Changes:
- Existing lamps are moved onto the new slots on load, not deleted; ghosts
are re-placed. Schema 11 -> 12.
- Fixed the formatting of the 0.27.1 to 0.27.3 entries (tabs).
Version: 0.27.3
Date: 2026-09-14
Changes:
- Updated description reflecting energy reading calculations
Version: 0.27.2
Date: 2026-09-14
Changes:
- Updated thumbnail
Version: 0.27.1
Date: 2026-09-14
Changes:
- Updated description
Version: 0.27.0
Date: 2026-09-14
Features:
- THE PAD IS ITS OWN CROSSHAIR. The floor steps light to dark toward the
gun: a light refined-concrete stage under it, a hazard frame, a dark
stone-path moat, a concrete field with four light lanes on the axes, a
two-tile hazard firing ring at radius 17 running through the bank
clusters, then a dark curb and the hazard rim. Every slot keeps a light
pad. Slot geometry is unchanged. Only mineable base tiles are used.
- The conduit ring is now drawn on the concrete firing ring.
- GROUNDBREAKING IS A SEQUENCE. Placing the gun draws an outline of the
pad, ghosts the masts, then each cluster's banks clockwise, then pours
the floor outward from the centre over about 3.5 seconds. A save taken
mid-pour finishes it.
- COMMISSIONING. When the last bank and mast link, the masts light one
after another, then the conduit ring draws itself around the loop, each
spur appearing as the arc reaches it.
- FIRING. A dim aim line runs from the gun to the rim and swings with the
barrel. During the charge, 24 bulbs run round the firing ring and spin
up with it. Just before the strike they race to where the aim line
crosses the ring and stream down it into the barrel. On the strike the
stage flashes white and keeps a scorch mark, up to six.
Changes:
- Existing pads are re-laid in the new plan on load, and an existing
complete installation commissions once. Schema 10 -> 11, render STYLE
9 -> 10.
Version: 0.26.4
Date: 2026-09-14
Bugfixes:
- THE STANDBY HUM HAD A ~0.5s GAP EVERY LOOP. It was `ambient_sounds`, an
atmosphere-effect system built for occasional environmental noise --
`average_pause_seconds` tunes the average gap between REPLAYS of a
one-shot clip, it does not make one loop gaplessly, so even at 0 it
audibly re-triggered with a dead patch every cycle.
- Switched to `working_sound`, which the engine loops natively. Merged
it with #77's own working_sound (the charge whine) into one
`main_sounds` array, since a prototype has exactly one working_sound
key -- the same pattern vanilla's own accumulator uses to layer two
sounds on one entity.
Info:
- The old ambient_sounds choice reasoned that working_sound "is driven
by the entity being working", so it would never start on a turret
that never works. `EntityPrototype.working_sound`'s own doc text says
otherwise ("will also work on entities that don't actually do work",
confirmed via apiq), and #77 was already live proof of it, fifty
lines below the hum's old ambient_sounds block the whole time.
- NOT run in game. If the hum stays silent specifically in STANDBY
(unlike #77's charging state), main_sounds needs some activity
signal after all -- fallback is a scripted loop timed off this file's
own measured duration (sound/README.md).
Version: 0.26.3
Date: 2026-09-14
Bugfixes:
- THE DOUBLE BARREL. Reported in game as a second turret sprite pasted on at
a weird angle. Two bugs stacked. The native folded_animation was still
drawn, frozen at one facing, under the 0.26.0 script head -- a
transparent sprite cannot hide a different facing of itself. And the
script head was a single frame: AnimationPrototype has no
direction_count, so the 64-facing sheet loaded as its north frame only,
and writing the render object's orientation spun that bitmap.
- The native rotating layers are now a transparent 1x1 frame and
energy_glow_animation is removed. The head is a 64-frame strip whose
facing is chosen by animation_offset; its shadow and lens glow are
script-drawn alongside it on the same frame (C.turret.head).
- Render STYLE 8 -> 9, so every save rebuilds its head, seeded from the
entity's real orientation rather than north.
Version: 0.26.2
Date: 2026-09-14
Changes:
- THE BEAM MUZZLE, SETTLED LIVE. muzzle_forward_mult/muzzle_lift_mult had
sat at neutral placeholders since the 0.24.0 chassis swap -- a linear
scale of vanilla laser-turret's own source_offset, never checked
against this turret's real ~3x scale-up and added tower. Read off
/oppenheimer-muzzle's marker against the actual barrel tip: 0.7
forward, 1.1 lift.
Info:
- Traced vanilla's laser-turret prototype directly while investigating:
it carries TWO separate, undocumented source_offset fields (one on
attack_parameters paired with source_direction_count = 64, one nested
in the beam's own action_delivery). Neither has doc text in the
shipped spec, so which one actually governs the on-screen origin was
only ever going to be settled by looking, not by reading.
Version: 0.26.1
Date: 2026-09-14
Bugfixes:
- THE BARREL WAS NEVER ACTUALLY TURNING -- A DEAD WRITE, NOT A RENDER
GAP. write_orientation wrote relative_turret_orientation first and only
fell through to orientation if that pcall threw. It never throws on
this chassis: confirmed via apiq against the shipped spec, writing it
"does nothing if the vehicle doesn't have a turret" -- accepted
silently, not an error, so the fallback line that actually moves the
barrel was never reached. orientation is now written directly. The
0.26.0 script-drawn head was wired correctly all along; there was
simply nothing changing for it to follow.
- THE STALL DETECTOR COULD NEVER HAVE CAUGHT IT EITHER. turret.slew's
"did the last command take" check compared this tick's reading
against the PREVIOUS WRITE TARGET rather than the previous READING --
a frozen barrel produces the same comparison every tick under that
test, so the 20-second give-up could never fire. Now compares
consecutive readings, which is what "stuck" means.
Info:
- Found by tracing why the fire-control panel's "N degrees to target"
held at the same number across three separate CONFIRM attempts, then
confirming the mechanism against the on-disk API spec rather than
assuming the write behaves like the read.
Version: 0.26.0
Date: 2026-09-14
Changes:
- THE ROTATING BARREL IS NOW SCRIPT-DRAWN, NOT AN ENTITY-GRAPHICS FIELD.
Gate 09 (0.24.0's rotation-fix attempt, folded_animation_is_stateless =
true) came back negative in the field: the engine did not re-render the
64-direction sheet against turret.slew's scripted orientation writes
while genuinely folded. A standalone animation prototype
(N.anim.turret_head, the identical sheet) is now drawn with
rendering.draw_animation and its own .orientation written every tick
from turret.slew, fully covering the frozen native layer beneath it.
The shadow layer is left native and static -- rendering.draw_animation
has no draw_as_shadow parameter, and this was not worth guessing at for
a shadow when the barrel itself is the thing actually reported broken.
Info:
- render.lua's render-bag STYLE bumped 7 -> 8 for the new head object, so
an installation built before this version rebuilds its render bag
rather than sitting there without one.
Version: 0.25.0
Date: 2026-09-13
Changes:
- THE INSTALLATION'S STATUS SIGNAL NOW LIVES ON THE REAL GROUND LAMPS. Used
to be a separate rendering.draw_light floating near each bank/mast --
reported as reading like disconnected FX rather than the hardware itself.
render.lights() now paints colour straight onto every real N.ground_lamp
entity's own .color instead (found by position each repaint; still not
tracked in schema/storage). The floating per-bank/mast lights are gone
with it.
- POSITION SET / READY (aim, barrel aligned and terrain confirmed) is now
solid AMBER, its own hue -- it used to borrow the discharge red at a
gentler flash. The charge ramp below it is unchanged: dark red climbing
to bright red with a growing flicker as the banks fill, exactly as it
was.
- THE LANCE LIT (the 5.7 s beam sustain) now holds steady at peak
brightness instead of flashing roughly 3.3 times a second -- reported as
"looks dumb" over what should read as the charge ramp's own peak, held.
- The barrel's electric-arc crackle FX (scripts/barrelfx.lua, the three
node pairs that sparked red during the charge cue) is removed outright,
not just disabled. The unrelated standby muzzle glow (also barrel-
mounted) is unchanged.
Bugfixes:
- GROUND LAMPS WERE NEVER ACTUALLY BROKEN, ONLY DARKNESS-GATED. Reported as
"none of the lights work" in daylight -- vanilla's own darkness_for_all_
lamps_on doing exactly what it always does on a lamp with no always_on
set. always_on = true now, so the fixture's day/night state stops mattering.
- THE PER-BANK LAMPS CLIPPED THEIR OWN BATTERIES. Root cause: all four lamps
in a 2x2 cluster shared the cluster's one outward direction, so the two
inner-corner banks pushed their lamps into their own cluster-mates
instead of open ground. Each of the sixteen bank lamps now gets its own
inward direction, computed from its own offset toward the turret --
guaranteed not to collide with a sibling bank. Also reverted the lamp
sprite from the turret's own 3x scale to vanilla's native size, and
raised light_when_colored's intensity off vanilla small-lamp's own dim
default (0), which is what read as "so dim the running lights overpower
them" once a lamp is in coloured mode essentially all the time.
Info:
- render.lua's render-bag STYLE bumped 6 -> 7 so an installation from
before this version has its old floating status-light objects torn down
and rebuilt without them, rather than left behind, dark and unmaintained.
- C.lights.bank/mast, C.barrelfx.emitters, and C.sound.arc_cue_start/_end
are deleted, not left as dead knobs -- nothing reads them any more.
- changelog.txt history before 0.20.0 (0.1.0-0.19.1, the pre-beam
artillery-shell build and the early lance versions) is removed from this
file -- it was no longer being read, only carried.
Version: 0.24.0
Date: 2026-09-13
Bugfixes:
- THE 0.23.0 CHASSIS SWAP WAS ONLY HALF DONE. Reported in game: the
installation still read as an artillery turret. graphics_set.base_
visualisation -- the big, static plinth under the rotating housing --
was never touched in 0.23.0; it was still artillery-turret-base.png
(plus its shadow) verbatim, tinted to match. Only the small rotating
housing on top had become laser-turret's. Now laser-turret-base.png /
-base-shadow.png / -reflection.png, dimensions and native shift copied
from base's own graphics_set/water_reflection. corpse and
dying_explosion move to laser-turret's own remnants/explosion for the
same reason -- a "fully replaced" chassis should not still leave an
artillery wreck behind when it dies.
- THE ROTATION BUG, DIAGNOSED AND GIVEN A TARGETED FIX. Reported in game:
the barrel does not turn and fires in a fixed direction regardless of
the designated target -- exactly the risk 0.23.0's own header flagged
as unverified. Root cause, confirmed by reading vanilla's own
laser-turret prototype rather than guessing: vanilla does NOT put its
64-direction shooting sheet in folded_animation. folded_animation
there is a single static frame (laser_turret_extension{frame_count=1});
the rotating sheet is prepared_animation, which only renders once the
turret's native AI has a real acquired target -- a state this mod can
never reach without reintroducing the autonomous-firing risk the whole
range-lock design exists to prevent. Fix attempt:
folded_animation_is_stateless = true, a genuine TurretPrototype field
(confirmed via apiq; the shipped spec carries no prose for it beyond
name/type/default) whose name is a precise match for the symptom.
UNVERIFIED -- Gate 09. If this does not resolve it, the fallback is a
script-drawn rendering.draw_animation object with an explicit
orientation this mod sets itself every tick, bypassing the
prototype's animation-state machine entirely; not built pre-emptively.
- THE BARREL GLOW AND CHARGE ARCS WERE ANCHORED ABOUT 2.6x TOO FAR FROM
THE HOUSING. Reported in game as "light FX do not work" and arcs that
"don't always show". Both scripts/render.lua's muzzle_glow_point and
scripts/barrelfx.lua's nodes() anchor to beam.tip_distance(), which
was still built from artillery's own projectile_creation_distance
(1.6 tiles, a vanilla 3x3 ARTILLERY hull) with two multipliers stacked
on top, tuned via /oppenheimer-muzzle for THAT geometry -- landing the
origin 10.18 tiles out. C.gun.projectile_creation_distance is now
laser-turret's own beam-source offset (vanilla's
attack_parameters.ammo_type.action.action_delivery.source_offset,
{0, -1.31439}, confirmed from base source) and the two multipliers
that were compensating for the old wrong base are reset to neutral
(1.0, 0) rather than re-guessed a third time -- re-tune live via
/oppenheimer-muzzle before trusting either again.
Changes:
- C.barrelfx.emitters.color: pale blue -> red, matching the capacitor
banks' own charge-arc colour (C.lights.colour.charging) -- asked for
explicitly, so the barrel arcs read as the same system as the bank
arcs instead of a second, differently-coloured one.
Features:
- A REAL LAMP AT EVERY CAPACITOR BANK, not only the four cluster-corner
ground lamps. Asked for explicitly, alongside (not instead of) the
existing per-bank charge-glow render object. Reuses N.ground_lamp at
sixteen more auto-ghosted slots (C.bank_lamp_slot_defs,
C.lamp.per_bank_enabled). First-guess placement, like every other
offset in this mod: every bank in a 2x2 cluster shares its cluster's
one outward direction, so the two inner-corner banks push toward
their own cluster-mates rather than into open ground, and some of the
sixteen ghosts may fail to place -- harmless when it happens, worth a
look in game.
Info:
- NOT run in game. Highest-risk item, in order: whether
folded_animation_is_stateless actually makes the barrel track
orientation while folded (Gate 09); whether the reset muzzle geometry
lands anywhere near correct before /oppenheimer-muzzle retuning;
whether all sixteen per-bank lamp ghosts place cleanly.
Version: 0.23.1
Date: 2026-09-13
Bugfixes:
- MASSIVE UPS STALL FIRING A 100% CHARGE SHOT. Reported in game: a
sandbox-map, no-enemies test still froze hard on a max-yield shot.
scripts/front.lua's acquire() -- the one mechanism the wave, the
collapse and the fire wave all share -- called
surface.force_generate_chunk_requests() once per MISSING CHUNK inside
its per-row search loop. That call blocks and drains the entire pending
generation queue regardless of what triggered it, so calling it once per
chunk was never "bounded by one acquisition run" the way the comment
claimed -- it was one full blocking terrain-generation flush per missing
chunk in that run. The Sedov front is fastest in its first few ticks,
exactly where a 100%-yield acquisition run is widest, so over
unexplored sandbox terrain that meant dozens of synchronous generation
flushes landing on a single tick. acquire() now walks its own geometry
twice -- once to queue every missing chunk in the run and flush ONCE,
once to actually search -- rather than interleaving the two. Two cheap
arithmetic passes over each_ring_run, not two engine calls; the search
pass is now also guaranteed every chunk it touches was already flushed,
which the old interleaved version was not strictly guaranteed either
(a chunk requested by an EARLIER row in the same run had no guarantee
its own flush had landed before that row's own search ran).
- NOT run in game. The freeze was reported before this fix; the fix itself
has not yet been confirmed to resolve it.
Version: 0.23.0
Date: 2026-09-13
Features:
- THE CHASSIS CHANGED FROM artillery-turret TO electric-turret. A laser
turret's whole prototype family is built for a beam leaving a housing;
an artillery turret's is built around a shell's own ballistics, and this
mod's beam was always that chassis aimed at nothing and fired by hand
anyway. The rotating art now comes from laser-turret's own 64-direction
shooting sheet (not its 4-way folded/raising one -- see
prototypes/entity.lua's header for why that distinction matters), tinted
dark gunmetal to match the installation's own plinth. The turning
mechanism, the safety model, and everything scripts/beam.lua does are
unaffected: LuaEntity.orientation is documented as "the orientation of
the weapon" for non-artillery turrets, which is exactly the fallback
scripts/turret.lua already had in place, and the native attack is kept
permanently unreachable (attack_parameters.range near zero) the same
way the old flare-based gate was replaced with an inert projectile --
lock at the effect, not at the authority.
Bugfixes:
- PRE-EXISTING, FOUND WHILE REWRITING THIS BLOCK: prototypes/entity.lua set
alert_icon_scale TWICE in one table literal (0 for #103, chart_scale for
#62), so the second silently clobbered the first. alert_icon_scale
controls entity alert badges, not chart icon size, so #62 was very
likely never doing what its own comment claimed either way. Both are
moot now regardless -- #103's reason (hide the "no ammo" alert) does not
apply without an ammo inventory. Left unset.
Known losses, accepted knowingly:
- THE RESONANCE-CELL CHAMBER'S WORLD-VISIBLE ALT-MODE AMMO BADGE IS GONE.
electric-turret has no ammo inventory at all, so scripts/turret.lua's
sync_cells now writes rec.cells as a plain number instead of real N.shell
items in a real inventory. The fire-control panel's own readout
(scripts/gui.lua) is unaffected -- it reads rec.cells directly now,
still the one place that number is written.
Known regressions, not yet fixed:
- logistics.circuit_disabled reads LuaControlBehavior.disabled, which
belonged to LuaArtilleryTurretControlBehavior. get_control_behavior now
returns a LuaTurretControlBehavior instead -- a different class, with no
`disabled` field at all -- so this silently always reads false instead
of erroring. LOW severity: nothing safety-critical depends on it, the
installation just stops noticing when a player has circuit-disabled it.
The 2.0 turret family's real enable/disable-by-circuit surface has not
been identified yet.
- NO MIGRATION STEP for existing saves' turrets. Same class of breakage as
0.11.0's accumulator-to-EEI bank change (see that entry's
banks-rebuilt message) -- an artillery-turret-typed entity in an old
save will not survive becoming electric-turret-typed, and nothing yet
detects that and reports it the way 0.11.0 did. Costs nothing today
(testing has been in the map editor) but is a real gap before this ships
to a save anyone is attached to.
Info:
- source_offset = {0, -3.423489/4} on vanilla's own laser-turret
attack_parameters is the first non-guessed reference point this mod has
had for where a beam should leave the housing -- noted in
prototypes/entity.lua, NOT yet folded into C.beam.muzzle_forward_mult/
_lift_mult. Those numbers were tuned for the old artillery barrel and
almost certainly need re-tuning via /oppenheimer-muzzle against the new
art before they mean anything again.
- UNVERIFIED, HIGHEST-RISK ITEM IN THIS VERSION: whether the engine
actually re-renders a scripted LuaEntity.orientation write against
folded_animation's frames while the turret is genuinely folded (its
permanent state here, since the native attack can never find a target).
Vanilla itself never explores that combination in normal play. If it
does not work, the barrel will not visibly turn during AIM even though
turret.slew is writing orientation every tick -- Gate 09, first thing to
check in game.
- NOT run in game.
Version: 0.22.0
Date: 2026-09-13
Features:
- THE STATUS LIGHTS GOT A SECOND SUB-STATE. AIM is now yellow, flashing, while
the barrel is still rotating onto a designated point; once it is aligned AND
the ground under the shot has actually been confirmed generated, it switches
to flashing red -- "ready to fire", distinguished from the FIRE state's own
flashing red by pace and amplitude alone (gentler, capped at 1.0), not hue,
since both are honestly "this gun is dangerous". STANDBY is solid blue now
instead of breathing (C.lights.standby_solid, one flag to revert).
- THE CAPACITOR BANKS' CHARGE GLOW FLICKERS. A small amount of plain
math.random noise on top of the existing fill-proportional alpha, scaled by
fill so an empty bank stays dark -- explicitly not a second precise state
signal, just texture that reads as heavy energy draw. C.lights.bank_charge
.flicker_amount.
- THE BARREL HAS ITS OWN FX. A soft standby glow at the muzzle, on its own
slow rhythm independent of the status lights (C.barrelfx.glow); and three
pairs of emitter nodes flanking the barrel that crackle with forked arcs
during the electrifying cue BeamFire.ogg's own charge sound carries around
10.5-12 s in (C.sound.arc_cue_start/_end, C.barrelfx.emitters,
scripts/barrelfx.lua). Node positions are a first guess, same as the
muzzle origin was -- /oppenheimer-muzzle now draws them alongside the
muzzle-tuning circles so both get settled in one session.
- GROUND LAMPS. Four real vanilla small-lamp entities (cloned under this
mod's own name so they can be auto-ghosted and told apart from a player's
own lamps), one at the inside corner of each capacitor cluster -- the
mirror of the masts, which stand at the outside corner. Purely decorative;
vanilla's own lamp behaviour needs nothing from control.lua, so unlike the
pylons and masts they carry no schema or adoption tracking at all.
Bugfixes:
- THE BOOM LANDED ABOUT A SECOND LATE EVEN STANDING ON TOP OF THE SHOT.
Reported in game. Not thunder()'s distance delay (boom_delay_min floors at
8 ticks, negligible) -- C.blast.implosion.beat_ticks, the deliberate pause
between the collapse finishing and the release that every stage of the
detonation is offset by, was 40 ticks (0.67 s) of felt silence between
"the core has visibly finished collapsing" and "everything actually goes
off". Cut to 15 -- C.blast.implosion.stamp_life_min, the floor below which
the last collapsing shell's fade would outlive the flash it is supposed to
finish before (stamp_life() clamps DOWN to beat_ticks before it clamps UP
to stamp_life_min, so anything lower reopens that overlap in the other
direction). Going tighter than 15 means shortening the shell fade itself,
not this number alone.
Version: 0.21.1
Date: 2026-09-13
Bugfixes:
- 0.21.0 ONLY SWAPPED HALF THE BOOM. The broadcast layer (scripts/detonate.lua's thunder(),
audible from the map) got ImplosionBoom.ogg; a SECOND, independent copy of the old stock
sound -- N.ex_boom in prototypes/vfx/explosions.lua, the near-field world-positional layer --
still embedded __base__/large-explosion-1.ogg, at a flat volume 1.5, on its own fixed 100-tick
delay unrelated to the broadcast's distance-based timing. Reported as a leftover explosion
sound trailing the new one by about half a second for anyone standing near their own shot.
N.ex_boom now carries the same ImplosionBoom.ogg, at C.sound.boom_volume_floor rather than a
volume picked for a different file, and C.blast.stages.boom moved from 100 to 10 ticks so the
near-field copy lands with the broadcast's own near-field floor instead of 1.67 s after it.
- This also explains why the broadcast's energy-scaling looked like it wasn't doing anything up
close: the near-field layer's flat, unscaled volume was the dominant thing a nearby listener
heard, regardless of what the broadcast layer's yield-based volume was doing underneath it.
Info:
- N.ex_cap (the mushroom cap's embedded sound) still references stock large-explosion-1/2.ogg
and was left alone -- confirmed dead code under C.blast.style = "implosion" (the current,
only-used style); it never fires. Revisit only if the style is ever switched to "atomic".
- Neither embedded layer scales with yield the way the broadcast does -- an ExplosionPrototype's
`sound` is baked at data-stage load, no runtime hook. Exact per-yield scaling on the near-field
copy would mean building one N.ex_boom variant per C.charge.yield_targets step, the way the
flash and scorch decal already are. Not done; the near-field layer is now pinned to the
broadcast's own volume floor instead, which is close rather than exact.
Version: 0.21.0
Date: 2026-09-13
Bugfixes:
- A BIG SHOT COULD STILL LEAVE NESTS UNTOUCHED PAST THE PREGEN DISC. 0.20.1/0.20.2 force-generate
the near-epicentre ground before the fronts move, capped at 512 tiles to avoid a strike-tick
hitch, and trust the wave's own chart_ahead backstop to keep the rest of a big shot's ground
built as the front travels. Nothing ever verified that backstop actually kept up: front.lua's
acquire() called find_entities_filtered on a chunk the instant its lead reached it, and an
ungenerated chunk returns {} indistinguishable from a genuinely empty one -- so a chunk the
async queue had not finished yet was acquired anyway, bin nothing, and the front never looks
at it again. acquire() now checks is_chunk_generated per chunk and force-generates just that
one chunk if it is missing -- the same trade impact.settle_terrain already makes at the
strike, spread thin across the sweep instead of risked in one place. Shared by the wave, the
implosion shock and the fire wave, since all three go through this one function.
- THE DETONATION'S BOOM WAS A STOCK EFFECT SIZED FOR A FEW TILES, PLAYED OVER A BLAST UP TO 2000.
__base__/sound/fight/large-explosion-1.ogg finished before the Sedov wave had covered more
than a few percent of a big shot's radius, so most of the visible detonation played out in
silence. Replaced with sound/ImplosionBoom.ogg (10.500 s = 630 ticks). Volume now scales with
the shot's yield (C.sound.boom_volume_floor / boom_volume_exponent) -- duration cannot, since
play_sound has no stop, mute or seek anywhere in the runtime API, so the clip always plays to
the end regardless of what the shot paid for.
- THE DESIGNATOR'S BLAST-RADIUS PREVIEW NEVER APPEARED ON THE CHART. render.preview has drawn
four rings at the real damage-band radii since 0.14.0, but through a plain rendering.draw_
circle -- invisible on the map, which is the exact mistake 0.16.0 already fixed once for the
sphere. A player designating a long-range shot is usually standing at the gun, not at the
target, so a multi-hundred-tile preview ring was frequently drawn somewhere nobody was
looking. Now routed through mapdraw.circle, so it appears on the chart the same way the
sphere, the wave and the collapse already do. mapdraw.circle itself gained a return value
(world, chart render objects) and forwards `forces`/`players` to the chart copy, neither of
which any prior caller needed.
- Generation now starts at the first remote press (designate), not only at CONFIRM. Async and
free -- request_to_generate_chunks on ground already requested or generated is a no-op -- and
the barrel's own slew can hold AIM for up to ~21 s before CONFIRM is even legal, with no
timeout after that either. All of it previously generated nothing.
- Corrected stale timing in the turret's in-game description and the fire-control CONFIRM
tooltip: both still said "21 seconds, strikes at 17, burns for 4", left over from before the
audio's exact duration was measured. It is 21.7 s total, strike at 16 s, 5.7 s of sustain
(config.lua's discharge_at / sequence_ticks, not rounded).
Features:
- THE PREVIEW NOW WARNS WHEN IT DOESN'T KNOW. The outer band samples is_chunk_generated at
C.blast.rings.preview.coverage_samples points around its own circumference and switches to a
distinct colour (`unconfirmed`) when fewer than coverage_warn_threshold are generated yet --
a READOUT, not a lock, same rule as the existing danger colour and the dynamic standoff in
turret.designate. Re-samples roughly every 3 seconds while a player sits in AIM, so it
catches up as generation (now starting at designate) finishes in the background.
Locale:
- The capacitor bank description still said "top of the yield selector" -- the selector was
replaced by the charge-rate dial in 0.13.0. Reworded.
- The damage-multiplier startup setting's description claimed it scales detonation damage. It
is fully inert: C.shell.damage_multiplier is written from the setting and never read anywhere
else in the mod, a fossil from when the gun threw a shell. Reworded to say so, in the same
spirit as the shell-speed technology's existing "does nothing" note.
Version: 0.20.2
Date: 2026-09-10
Bugfixes:
- CONFIRM DROPPED THE GAME TO 5 FPS FOR THE WHOLE FIRING SEQUENCE. 0.20.1 generated the entire
blast disc up front, and the request radius scales with the blast: a full-dial shot asked the
map generator for a 64-chunk radius -- 16641 chunks -- on a single CONFIRM. The async queue
then churned through terrain, resource and enemy-base generation for the entire 21 second
sequence, and the strike's force_generate_chunk_requests() flushed the remainder in one
blocking tick on top of it. Selection was fine because designation only charts the fireball
ring; the disc-wide request was new at CONFIRM.
- The pregen request is now capped at C.blast.rings.pregen.max_chunks (16 = 512 tiles). Only the
near-epicentre ground has to exist before the fronts move -- the fireball, the collapse shock
(which is center-weighted and barely touches the rim), and the arcs off the small early ball.
The wave already generates its own ground chunk by chunk as it travels, with ~28 seconds to
do it, so everything past the cap is built by the front that reaches it. force_at_strike is
kept but is now bounded by the same cap.
Info:
- C.blast.rings.pregen gains max_chunks. Raise it if a big shot on unexplored ground leaves rim
nests standing -- though the wave sweep should be collecting those.
Version: 0.20.1
Date: 2026-09-10
Bugfixes:
- THE BLAST LEFT WHOLE NESTS UNTOUCHED INSIDE THE CRATER, worse the bigger the shot. 0.20.0
revealed the map as the wave travelled and took terrain GENERATION with it -- but
find_entities_filtered returns nothing for a chunk the generator has not built yet, so the
wave payout, the collapse shock and the arcs off the growing ball all swept over ungenerated
ground and the spawners and worms standing on it took zero damage. A small shot mostly lands
on explored ground and only clipped its fringe; a megaton reached far enough into unbuilt map
to spare most of what it covered.
- The whole blast disc is now generated during the firing sequence: requested at CONFIRM, where
the 17 seconds of charge before the beam lights is far more time than the generator needs,
and force-completed at the strike so the last chunks cannot slip through. Map reveal
(chart_ahead) stays lazy -- a map that fills in late is invisible; a nest that takes no
damage is not.
Info:
- New config block C.blast.rings.pregen: enabled, margin_chunks, force_at_strike.
Version: 0.20.0
Date: 2026-09-10
Major Features:
- THE DIAL IS 1%..100% AND 100% IS 2000 TILES. The 8850 tile ceiling was a map-generation job
with a trigger: every radius-squared bill in the mod was priced against it. Energy steps are
unchanged (5% rungs, 1% slider); 100% is still 36 GJ/s, a 576 GJ trigger and 1.00 Mt.
- THE WAVE IS SLOW, AND IT IS SEDOV. The front follows R ~ t^(2/5), the Sedov-Taylor point
blast, at an average of 1.2 tiles a tick: out of the fireball fast, then a crawl, 2000 tiles
in about 28 seconds. The ring is stamped whenever the front has moved a fraction of a puff's
width instead of every tick, and each puff lives long enough to overlap the layer behind it,
so a slow front is one continuous band of fire rather than sixty rings stacked on each other.
- THE RINGS ARE OVERPRESSURE CONTOURS. Damage beyond the fireball follows Brode's (1955) fit for
peak overpressure against scaled distance, with the blast edge at 0.1 bar, where that fit
stops being valid. The fireball (>= 20 psi, inner 21.4%) is obliterated outright; the heavy,
severe and blast rings follow the curve from 100% of the payload down to 7.3% at the rim.
- ABSOLUTE DAMAGE. One payload in hit points (60000 at the fireball's edge), not a percentage of
the victim's health, so the weapon scales with biter health: soft targets die to the rim,
armoured ones only where the pressure is high enough. A new infinite technology, Oppenheimer
Lance Payload, adds 20% a level to every stage.
- EVERY STAGE HURTS. The growing ball's inner tenth is a fire wave that burns each thing once as
it passes. Arcs off the rim hunt the band just outside it, strike what they find for an
electric chip, and jump to the next target. The collapse is a converging shock: one physical
hit as the shell crosses each thing, rising as r^-0.907 toward the centre.
- THE BEAM VAPORIZES. Anything under the drawn beam, inside its drawn width, dies outright.
Changes:
- The map is revealed by the wave. Designation charts only the fireball ring; the rest is charted
a few seconds ahead of the front as it travels, ungenerated chunks are requested explicitly,
and the crater is re-charted behind the paint.
- Tile paint happens only on the wave, and follows the front every tick instead of lagging it.
The growth phase no longer paints its footprint.
- The lance's map line now stops at the ball's near face, as the world beam does.
Optimizations:
- THE GROWTH PHASE WAS PAYING THREE AREA-PRICED BILLS AT ONCE, reported as 10 FPS on a 25%
shot. It re-charted the whole blast box frame by frame (LuaForce.chart refreshes what it is
given) on top of the same box charted at designation; it painted 9000 tiles every 4 ticks
that the wave then repainted from radius zero; and the beam searched the whole bounding box
of its line every 10 ticks, a square ~125000 tiles across for a diagonal 500 tile shot. The
first two are gone and the third is a row of small boxes along the drawn beam.
- scripts/front.lua: every moving front -- the fire wave, the collapse and the shock wave -- now
finds its victims chunk by chunk just ahead of itself. The disc is searched once in total,
spread across the sweep, instead of by full-disc queries.
- The tile paint reuses its per-tile tables instead of allocating two per tile per tick.
Bugfixes:
- THE WAVE STARTED UP TO ~16% OF A COLLAPSE AFTER THE FLASH on any shot between two built yield
steps. 0.18.1 moved the wave's start onto the shot's raw power, reasoning that the collapse ran
on it; scripts/implode.lua in fact runs the collapse on the variant's clock, and the release
stages in prototypes/vfx/waves.lua are baked on it too. The wave is back on the variant's
clock, which all three now share.
Info:
- Migration: detonations and lances in flight in a 0.19.x save are ended, and any installation
set above 100% is clamped to it.