diff --git a/js/scenes/GameScene.js b/js/scenes/GameScene.js index 0d5bdfb..9565b46 100644 --- a/js/scenes/GameScene.js +++ b/js/scenes/GameScene.js @@ -1156,7 +1156,7 @@ export class GameScene extends Phaser.Scene { // A combat level landed (the system fires its own burst + voice + // the armor bump on the manager's 'levelup' event — the skill // layer will subscribe to that same event later): the feed's line. - onLevelUp: (level) => this.combatHud?.kill(`LEVEL ${level} — XP`), + onLevelUp: (level) => this.combatHud?.kill(`LEVEL ${level} — XP` + (level > 5 ? ' · +1 SKILL POINT' : '')), onPlayerDamage: (n, a) => { if (!this.combatHud || !a) return; if (a.shieldHit > 0) this.combatHud.flash('shield'); @@ -1694,6 +1694,17 @@ export class GameScene extends Phaser.Scene { // system so its perks (dual cannon / targeting computer) are live from the // first frame, exactly as they are after a fresh lock-in. if (this.combat) this.combat.classState = this.classState; + // LEVEL-UP SKILL-POINT GRANT — the "level-up bonus" seam the ledger + // promised (ClassState.awardSkillPoints): every combat level landed past + // 5 banks one point (level 6 pays, 7 pays, …). The manager fires one + // 'levelup' event per level crossed, so a three-level jump banks three; + // points land in the bank whether or not a class is on file yet (the + // spend side is what stays gated on one). + if (this.combat) { + this.combat.xp.on('levelup', (ev) => { + if (ev.to > 5) this.classState.awardSkillPoints(1); + }); + } // ---- THE SKILL LAYER (data/skills.json, js/skills/SkillState.js) ---- // The run's skill LEDGER — the points spent in the class's tree and which @@ -9592,13 +9603,17 @@ export class GameScene extends Phaser.Scene { } /** - * The READY-RESEARCH cue's scene-side switch (per frame, update): one + * The deck's attract cues' scene-side switch (per frame, update): one * cue on screen at a time — - * - console CLOSED: the deck's RESEARCH slot wears the periodic + * - RESEARCH READY: the deck's RESEARCH slot wears the periodic * yellow shimmer (face sweep → edge run, js/ui/ShimmerCue.js); - * - console OPEN: the console wears it instead (its tabs' edge - * shimmers + the jump-gate tech's ACK pulse — _paintCues), and - * the deck's slot rests. + * - SKILL POINTS BANKED: the deck's SHIP slot wears the same + * shimmer (the bank sits in the ship console's class plate) — + * research wins the slot when both are ready (the active beat); + * - console OPEN: the console wears its own half instead (the + * research tabs' edge shimmers — _paintCues), and the deck's + * slot rests (same for the ship slot while its console — class + * or skill — is up). * setShimmer is idempotent, so the per-frame call is a no-op when * the beat is unchanged. The cue also rests while a project runs * (researchAnyAvailable) and under the deck's standby (the ActionBar @@ -9608,8 +9623,13 @@ export class GameScene extends Phaser.Scene { _applyResearchCue() { const bar = this.actionBar; if (!bar || typeof bar.setShimmer !== 'function') return; - const on = this.researchAnyAvailable() && this.researchWindow?.isOpen !== true; - bar.setShimmer(on ? 'research' : null); + if (this.researchAnyAvailable() && this.researchWindow?.isOpen !== true) { + bar.setShimmer('research'); + return; // research owns the cue (the active beat) + } + const points = Number(this.classState?.skillPoints) || 0; + const shipOpen = this.shipWindow?.isOpen === true || this.classWindow?.isOpen === true || this.skillWindow?.isOpen === true; + bar.setShimmer(points > 0 && !shipOpen ? 'ship' : null); } /** Entering a system begins its NAV chart: the SYSTEM category's