75 lines
2.6 KiB
JavaScript
75 lines
2.6 KiB
JavaScript
/**
|
|
* The "decode" scramble — the shared type-out effect of the console.
|
|
*
|
|
* The main menu uses it on the Galaxy Seed field (it "decodes" in as the
|
|
* panel assembles); the game uses it on the system dossier HUD — the
|
|
* system name and every data line below it type themselves in as the
|
|
* ship arrives. One effect, two scenes.
|
|
*
|
|
* Over `dur` ms the target string reveals left-to-right while the
|
|
* unrevealed slots hold random glyphs from the decode alphabet — the
|
|
* console pulling a signal out of static.
|
|
*
|
|
* Pure (no Phaser): build one per line with a start time, poll
|
|
* `display(time)` from the scene's `update()`, and drop it once
|
|
* `finished(time)`. The time base is the engine loop time the scene's
|
|
* `update(time, delta)` receives (=== `this.time.now` after that frame).
|
|
*
|
|
* const dec = new ScrambleDecode('Kepler-9', t0, DECODE_DURATION);
|
|
* // each frame: if (dec.started(time)) text.setText(dec.display(time));
|
|
* // done when: dec.finished(time)
|
|
*/
|
|
|
|
/** The alphabet unrevealed slots draw from (no vowels, no 0/1 — signal, not language). */
|
|
export const DECODE_CHARS = 'abcdefghjkmnpqrstuvwxyz23456789#%+*<>?';
|
|
|
|
/** The menu's seed-field window (ms) — the canonical decode timing. */
|
|
export const DECODE_DURATION = 620;
|
|
|
|
export class ScrambleDecode {
|
|
/**
|
|
* @param {string} value the final text
|
|
* @param {number} t0 absolute start time (scene time, in ms)
|
|
* @param {number} [dur] reveal window in ms
|
|
*/
|
|
constructor(value, t0, dur = DECODE_DURATION) {
|
|
this.value = String(value ?? '');
|
|
this.t0 = t0;
|
|
this.dur = dur > 0 ? dur : 1;
|
|
}
|
|
|
|
started(time) {
|
|
return time >= this.t0;
|
|
}
|
|
|
|
finished(time) {
|
|
return (time - this.t0) / this.dur >= 1;
|
|
}
|
|
|
|
/**
|
|
* The display string at `time`: the revealed prefix of the target with
|
|
* the rest scrambled. '' before the start, the exact target once
|
|
* finished (the reveal lands at ~87% of the window, then holds).
|
|
*/
|
|
display(time) {
|
|
if (!this.started(time)) return '';
|
|
if (this.finished(time)) return this.value;
|
|
const u = (time - this.t0) / this.dur;
|
|
const reveal = Math.floor(Math.max(0, Math.min(1, u * 1.15)) * this.value.length);
|
|
let out = '';
|
|
for (let i = 0; i < this.value.length; i++) {
|
|
out += i < reveal ? this.value[i] : DECODE_CHARS[(Math.random() * DECODE_CHARS.length) | 0];
|
|
}
|
|
return out;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Per-line window for multi-line decodes (the system dossier): ~70 ms per
|
|
* character — the menu's feel — floored so short lines don't flicker and
|
|
* capped so long ones don't drag.
|
|
*/
|
|
export function decodeDur(length = 0) {
|
|
return Math.max(420, Math.min(880, 320 + length * 46));
|
|
}
|