Files
2026-07-15 01:28:56 -04:00

160 lines
5.4 KiB
Go

package parameter
import (
"time"
)
// Core game grid and timing
const (
// GameRenderUpdate is the frontend frame interval (~60fps). Beat
// quantization is owned by the engine; this only paces UI wakeups
GameRenderUpdate = 16 * time.Millisecond
// GameDeltaZBase is the level-1 inter-chord interval. GameDeltaZStep
// shortens it per level down to the GameDeltaZMin floor
GameDeltaZBase = 500 * time.Millisecond
GameDeltaZStep = 20 * time.Millisecond
GameDeltaZMin = 300 * time.Millisecond
// PlayerRowResetChords chords at whatever tempo is running, so a pattern's
// landing chord is invariant across levels and across a Boost.
// 3 * GameDeltaZBase == the previous 1500ms; level 1 is unchanged.
// Lane (X) shifts are persistent and never auto-reset
PlayerRowResetChords = 3
// ItemFadeDuration is the burn-out span of a consumed positive item.
// Kept under GameDeltaZMin/BoostSpeedFactor so the effect always completes inside one
// chord and reads as consumption, not as the strip scrolling
ItemFadeDuration = 140 * time.Millisecond
// ItemFlashFraction is the leading white-flash portion of the burn-out
ItemFlashFraction = 0.25
// TransitionDuration is the level-clear interlude length
TransitionDuration = 2000 * time.Millisecond
// Song length ceiling
GamePlayIndexZMax = 256
// Chord dimensions
GamePlayIndexYMax = 3
GamePlayIndexXMax = 3
// Player spawn position (grid center)
GamePlayIndexYStart = GamePlayIndexYMax / 2
GamePlayIndexXStart = GamePlayIndexXMax / 2
)
// Song generation
const (
// SongBaseLength + (level-1)*SongLengthPerLevel chords per level,
// capped at GamePlayIndexZMax
SongBaseLength = 72
SongLengthPerLevel = 12
// Guaranteed empty chords at song edges (grace-in, clean finish)
GenIntroRest = 6
GenOutroRest = 4
// Rest gap between pattern chains: GenRestBase shrinks by one per level
// down to GenRestMin
GenRestBase = 7
GenRestMin = 2
// Patterns chained back-to-back per burst
GenChainBase = 1
GenChainMax = 5
// Chance of a single empty chord between chained patterns
GenBreatherProbability = 0.5
)
// Lookahead observation window. Window width covers every wall band; band
// geometry and trap threshold are parameterized here
const (
// PositionLookaheadWindow is how many upcoming chords (starting at the
// current one, distance 0) are scanned per grid position.
// Hard ceiling: game.TileLookaheadMaxWindow (wall bitmask width)
PositionLookaheadWindow = 10
// Wall proximity bands. Band 0 is the arrived wall (distance 0); bands
// 1..WallBandCount-1 each span WallBandSize chords. Band index selects
// border fill density and color
WallBandSize = 3
WallBandCount = 4
// TrapGapMax is the largest reopen gap still flagged as a trap: a lane
// that clears for <= this many chords before another wall shuts it
TrapGapMax = 2
// ConsumeRingSize bounds the consumed-note ring the frontends read
// for burn-out. A magnet sweep can consume up to
// GamePlayIndexYMax*GamePlayIndexXMax*PositionLookaheadWindow notes; on
// overflow the oldest burn-out is dropped (visual-only degradation)
ConsumeRingSize = 64
// MorphWindow is the chord-distance over which a non-wall Value's color
// interpolates from distant to arrived
MorphWindow = 4
)
// Player effects granted by items. Both survive a level change and are cleared on restart
const (
// BoostDuration is the wall-clock lifetime of a Boost. A second pickup
// refreshes the deadline, it does not extend it
BoostDuration = 10 * time.Second
// BoostSpeedFactor divides the inter-chord interval while a Boost runs.
// Integer divisor: the boosted interval stays exact. A slow effect would
// multiply in the same place
BoostSpeedFactor = 2
// BoostWarnRemaining is the Boost tail over which the HUD countdown blinks.
// Expiry inside a wall band kills on the next beat; the player
// needs the lead time to leave the lane
BoostWarnRemaining = 2 * time.Second
// ShieldCharges is the charge count a Shield pickup arms. Each charge
// absorbs one negative contact; charges never expire and do not stack
ShieldCharges = 1
)
// The burn-out must finish inside the tightest beat — the level floor divided by the Boost factor.
// Also proves the boosted interval is > 0, which bounds the Update beat loop
const _ = uint(GameDeltaZMin/BoostSpeedFactor - ItemFadeDuration)
// Compile-time: the window must reach the far edge of the last band
const _ = uint(PositionLookaheadWindow - (WallBandSize*(WallBandCount-1) + 1))
// Tile geometry derives from the strip. PositionLookaheadWindow is
// the only knob; width follows so the strip is 1:1 with the interior
const (
RenderMarginX = 1
RenderMarginY = 1
// RenderHeaderRows is the chrome above the grid (LEVEL / ENERGY).
// No footer, no title
RenderHeaderRows = 1
// One interior column per lookahead chord, plus the two border columns
RenderNoteWidth = PositionLookaheadWindow + 2
RenderNoteHeight = 5
RenderGapX = 2
RenderGapY = 1
// Fixed interior row offsets, relative to the tile top border
RenderRowTimer = 1
RenderRowDist = 2
RenderRowStrip = 3
// Distance row: "gDD gDD" — glyph + chord-distance, positive group then negative group
RenderDistDigits = 2
RenderDistCols = 2*(1+RenderDistDigits) + 1
// RenderBlinkPeriod is the half-cycle of the nearest-item blink. The
// distance-row group of the tile(s) holding the grid-wide nearest
// positive/negative occurrence alternates between two colors at this rate
RenderBlinkPeriod = 120 * time.Millisecond
)