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 )