diff --git a/src/config/game.config.js b/src/config/game.config.js index 6b05d7b..50bb0d5 100644 --- a/src/config/game.config.js +++ b/src/config/game.config.js @@ -24,6 +24,15 @@ export const POWERUP_RATES = { spring: 0.04, propeller: 0.025, rocket: 0.012, + magnet: 0.02, + shield: 0.025, +}; + +export const COIN = { + spawnChance: 0.42, // per platform, chance to drop a cluster of coins + value: 1, // $GWEI per coin + magnetRadius: 150, // px within which the magnet pulls coins + magnetSpeed: 560, // px/s pull speed }; export const ENEMY_RATES = { @@ -65,4 +74,5 @@ export const PHYSICS = { export const POWERUP_DURATION = { propeller: 3500, rocket: 3000, + magnet: 6000, }; diff --git a/src/entities/Coin.js b/src/entities/Coin.js new file mode 100644 index 0000000..022001a --- /dev/null +++ b/src/entities/Coin.js @@ -0,0 +1,62 @@ +import { Physics } from 'phaser'; +import { COIN } from '../config/game.config.js'; + +export class Coin extends Physics.Arcade.Sprite { + constructor(scene, x, y) { + super(scene, x, y, 'coin'); + scene.add.existing(this); + scene.physics.add.existing(this); + + this.setScale(0.7); + this.body.allowGravity = false; + this.body.setCircle(this.width / 2); + this.collected = false; + + // subtle idle pulse + this.pulse = scene.tweens.add({ + targets: this, + scaleX: 0.78, + scaleY: 0.78, + duration: 600, + yoyo: true, + repeat: -1, + ease: 'Sine.easeInOut', + }); + } + + preUpdate(time, delta) { + super.preUpdate(time, delta); + if (this.collected) return; + const p = this.scene.player; + if (p && p.active && p.magnetActive) { + const dist = Phaser.Math.Distance.Between(this.x, this.y, p.x, p.y); + if (dist < COIN.magnetRadius) { + const ang = Phaser.Math.Angle.Between(this.x, this.y, p.x, p.y); + const step = COIN.magnetSpeed * (delta / 1000); + this.x += Math.cos(ang) * step; + this.y += Math.sin(ang) * step; + } + } + } + + collect() { + if (this.collected) return false; + this.collected = true; + if (this.pulse) { this.pulse.stop(); this.pulse = null; } + if (this.body) this.body.enable = false; + this.scene.tweens.add({ + targets: this, + scale: 1.4, + alpha: 0, + duration: 160, + ease: 'Quad.easeOut', + onComplete: () => this.destroy(), + }); + return true; + } + + destroy(fromScene) { + if (this.pulse) { this.pulse.stop(); this.pulse = null; } + super.destroy(fromScene); + } +} diff --git a/src/entities/Magnet.js b/src/entities/Magnet.js new file mode 100644 index 0000000..f417efe --- /dev/null +++ b/src/entities/Magnet.js @@ -0,0 +1,33 @@ +import { Physics } from 'phaser'; + +export class Magnet extends Physics.Arcade.Sprite { + constructor(scene, x, y) { + super(scene, x, y, 'magnet'); + scene.add.existing(this); + scene.physics.add.existing(this, true); + + this.setScale(0.8); + this.body.setSize(this.width * 0.8, this.height * 0.8); + this.body.setOffset(this.width * 0.1, this.height * 0.1); + this.consumed = false; + + this.floatTween = scene.tweens.add({ + targets: this, y: y - 6, duration: 700, yoyo: true, repeat: -1, ease: 'Sine.easeInOut', + }); + } + + onPlayerTouch(player) { + if (this.consumed) return false; + this.consumed = true; + this.body.enable = false; + this.setVisible(false); + player.startMagnet(); + this.destroy(); + return true; + } + + destroy(fromScene) { + if (this.floatTween) { this.floatTween.stop(); this.floatTween = null; } + super.destroy(fromScene); + } +} diff --git a/src/entities/Player.js b/src/entities/Player.js index 82fdbcc..1e7cd33 100644 --- a/src/entities/Player.js +++ b/src/entities/Player.js @@ -21,11 +21,28 @@ export class Player extends Physics.Arcade.Sprite { this.state = 'normal'; this.propellerTimer = 0; this.rocketTimer = 0; + + // Magnet and shield are independent of the movement state machine. + this.magnetTimer = 0; + this.magnetActive = false; + this.shielded = false; + this.shieldAura = null; } update(cursors, wasd, touchLeft, touchRight, time, delta) { if (this.state === 'dead') return; + // Magnet ticks in every state. + if (this.magnetTimer > 0) { + this.magnetTimer -= delta; + this.magnetActive = this.magnetTimer > 0; + } + + // Keep the shield aura glued to the player. + if (this.shieldAura) { + this.shieldAura.setPosition(this.x, this.y); + } + let velocityX = 0; if (cursors.left.isDown || wasd.left.isDown || touchLeft) velocityX = -PLAYER_SPEED; if (cursors.right.isDown || wasd.right.isDown || touchRight) velocityX = PLAYER_SPEED; @@ -94,6 +111,46 @@ export class Player extends Physics.Arcade.Sprite { this.setScale(0.45); } + startMagnet() { + this.magnetTimer = POWERUP_DURATION.magnet; + this.magnetActive = true; + } + + startShield() { + this.shielded = true; + if (this.shieldAura) this.shieldAura.destroy(); + this.shieldAura = this.scene.add.image(this.x, this.y, 'px_ring') + .setTint(0x22d3ee) + .setScale(1.5) + .setAlpha(0.7) + .setDepth(this.depth - 1); + this.scene.tweens.add({ + targets: this.shieldAura, + scale: 1.7, + alpha: 0.35, + duration: 700, + yoyo: true, + repeat: -1, + ease: 'Sine.easeInOut', + }); + } + + consumeShield() { + this.shielded = false; + if (this.shieldAura) { + const aura = this.shieldAura; + this.shieldAura = null; + this.scene.tweens.add({ + targets: aura, + scale: 2.6, + alpha: 0, + duration: 250, + ease: 'Quad.easeOut', + onComplete: () => aura.destroy(), + }); + } + } + startPropeller() { if (this.state === 'dead') return; this._stopSquash(); @@ -132,6 +189,10 @@ export class Player extends Physics.Arcade.Sprite { die() { if (this.state === 'dead') return; this._stopSquash(); + this.magnetActive = false; + this.magnetTimer = 0; + if (this.shieldAura) { this.shieldAura.destroy(); this.shieldAura = null; } + this.shielded = false; this.state = 'dead'; this.setTexture('player_dead'); this.setScale(0.4); diff --git a/src/entities/Shield.js b/src/entities/Shield.js new file mode 100644 index 0000000..0965228 --- /dev/null +++ b/src/entities/Shield.js @@ -0,0 +1,33 @@ +import { Physics } from 'phaser'; + +export class Shield extends Physics.Arcade.Sprite { + constructor(scene, x, y) { + super(scene, x, y, 'shield'); + scene.add.existing(this); + scene.physics.add.existing(this, true); + + this.setScale(0.8); + this.body.setSize(this.width * 0.8, this.height * 0.8); + this.body.setOffset(this.width * 0.1, this.height * 0.1); + this.consumed = false; + + this.floatTween = scene.tweens.add({ + targets: this, y: y - 6, duration: 700, yoyo: true, repeat: -1, ease: 'Sine.easeInOut', + }); + } + + onPlayerTouch(player) { + if (this.consumed) return false; + this.consumed = true; + this.body.enable = false; + this.setVisible(false); + player.startShield(); + this.destroy(); + return true; + } + + destroy(fromScene) { + if (this.floatTween) { this.floatTween.stop(); this.floatTween = null; } + super.destroy(fromScene); + } +} diff --git a/src/managers/PlatformManager.js b/src/managers/PlatformManager.js index 60e819b..ff2a3d0 100644 --- a/src/managers/PlatformManager.js +++ b/src/managers/PlatformManager.js @@ -2,11 +2,14 @@ import { Platform } from '../entities/Platform.js'; import { Spring } from '../entities/Spring.js'; import { PropellerHat } from '../entities/PropellerHat.js'; import { Rocket } from '../entities/Rocket.js'; +import { Magnet } from '../entities/Magnet.js'; +import { Shield } from '../entities/Shield.js'; +import { Coin } from '../entities/Coin.js'; import { Enemy } from '../entities/Enemy.js'; import { rng } from '../utils/random.js'; import { GAME_WIDTH, PLATFORM_GAP_MIN, PLATFORM_GAP_MAX, - SPAWN_RATES, POWERUP_RATES, ENEMY_RATES, DIFFICULTY, UNLOCK, + SPAWN_RATES, POWERUP_RATES, ENEMY_RATES, DIFFICULTY, UNLOCK, COIN, } from '../config/game.config.js'; export class PlatformManager { @@ -15,6 +18,7 @@ export class PlatformManager { this.platforms = scene.add.group({ classType: Platform }); this.enemies = scene.add.group({ classType: Enemy }); this.powerups = scene.add.group(); + this.coins = scene.add.group({ classType: Coin }); this.lastY = scene.scale.height - 80; this.highestY = this.lastY; } @@ -29,6 +33,7 @@ export class PlatformManager { this.cleanupGroup(this.platforms, killLine); this.cleanupGroup(this.enemies, killLine); this.cleanupGroup(this.powerups, killLine); + this.cleanupGroup(this.coins, killLine); } cleanupGroup(group, killLine) { @@ -71,15 +76,20 @@ export class PlatformManager { if (type !== 'breaking' && type !== 'reorg') { this.maybeSpawnPowerUp(x, this.highestY - 25); } + this.maybeSpawnCoins(x, this.highestY); this.maybeSpawnEnemy(x, this.highestY, difficultyLevel); } maybeSpawnPowerUp(platformX, y) { + const r = POWERUP_RATES; const rand = rng.frac(); let type = null; - if (rand < POWERUP_RATES.spring) type = 'spring'; - else if (rand < POWERUP_RATES.spring + POWERUP_RATES.propeller) type = 'propeller'; - else if (rand < POWERUP_RATES.spring + POWERUP_RATES.propeller + POWERUP_RATES.rocket) type = 'rocket'; + let acc = 0; + if (rand < (acc += r.spring)) type = 'spring'; + else if (rand < (acc += r.propeller)) type = 'propeller'; + else if (rand < (acc += r.rocket)) type = 'rocket'; + else if (rand < (acc += r.magnet)) type = 'magnet'; + else if (rand < (acc += r.shield)) type = 'shield'; if (!type) return; @@ -90,6 +100,32 @@ export class PlatformManager { this.powerups.add(new PropellerHat(this.scene, x, y - 35)); } else if (type === 'rocket') { this.powerups.add(new Rocket(this.scene, x, y - 45)); + } else if (type === 'magnet') { + this.powerups.add(new Magnet(this.scene, x, y - 35)); + } else if (type === 'shield') { + this.powerups.add(new Shield(this.scene, x, y - 35)); + } + } + + // Drop a small cluster of $GWEI coins (line or arc) above a platform. + maybeSpawnCoins(platformX, platformY) { + if (rng.frac() >= COIN.spawnChance) return; + + const count = rng.between(3, 5); + const spacing = 26; + const arc = rng.frac() < 0.5; // half arcs, half vertical lines + const baseX = Phaser.Math.Clamp(platformX + rng.between(-30, 30), 40, GAME_WIDTH - 40); + const topY = platformY - rng.between(40, 70); + + for (let i = 0; i < count; i++) { + let cx = baseX; + let cy = topY - i * spacing; + if (arc) { + cx = baseX + Math.sin((i / (count - 1)) * Math.PI) * 36 * (rng.frac() < 0.5 ? 1 : -1); + cy = topY - i * (spacing - 4); + } + cx = Phaser.Math.Clamp(cx, 20, GAME_WIDTH - 20); + this.coins.add(new Coin(this.scene, cx, cy)); } } @@ -143,4 +179,8 @@ export class PlatformManager { getPowerups() { return this.powerups; } + + getCoins() { + return this.coins; + } } diff --git a/src/managers/ScoreManager.js b/src/managers/ScoreManager.js index 7f5abc9..99fe981 100644 --- a/src/managers/ScoreManager.js +++ b/src/managers/ScoreManager.js @@ -1,4 +1,4 @@ -import { SCORE } from '../config/game.config.js'; +import { SCORE, POWERUP_DURATION } from '../config/game.config.js'; import { storage, KEYS } from '../utils/storage.js'; export class ScoreManager { @@ -10,6 +10,7 @@ export class ScoreManager { this.comboMultiplier = 1; this.genesisActive = false; this.genesisJumps = 0; + this.gwei = 0; this.hudBg = scene.add.rectangle(10, 10, 200, 90, 0x000000, 0.5) .setOrigin(0) @@ -40,6 +41,12 @@ export class ScoreManager { color: '#aaa', }).setOrigin(1, 0).setScrollFactor(0).setDepth(200).setShadow(1, 1, '#000000', 2, false, true); + this.hudGwei = scene.add.text(scene.scale.width - 16, 34, '◈ 0', { + fontFamily: '"Press Start 2P", monospace', + fontSize: '12px', + color: '#ffd700', + }).setOrigin(1, 0).setScrollFactor(0).setDepth(200).setShadow(1, 1, '#000000', 2, false, true); + // Powerup duration bar (hidden until active) this.powerupBarBg = scene.add.rectangle(scene.scale.width / 2, scene.scale.height - 24, 200, 12, 0x000000, 0.6) .setStrokeStyle(2, 0xa855f7) @@ -92,6 +99,12 @@ export class ScoreManager { total = 3000; color = 0xff4444; label = 'ROCKET'; + } else if (player.magnetActive) { + active = 'magnet'; + remaining = Math.max(0, player.magnetTimer); + total = POWERUP_DURATION.magnet; + color = 0xffd700; + label = 'MAGNET'; } if (active) { @@ -166,6 +179,12 @@ export class ScoreManager { if (this.scene.achievements) this.scene.achievements.onScore(this.score); } + addGwei(amount) { + this.gwei += amount; + this.hudGwei.setText(`◈ ${this.gwei}`); + this.scene.tweens.add({ targets: this.hudGwei, scale: 1.3, duration: 90, yoyo: true }); + } + onFall() { if (this.combo > 0) { this.combo = 0; @@ -214,6 +233,7 @@ export class ScoreManager { this.hudBlocks.destroy(); this.hudCombo.destroy(); this.hudBest.destroy(); + this.hudGwei.destroy(); this.powerupBarBg.destroy(); this.powerupBarFill.destroy(); this.powerupBarLabel.destroy(); diff --git a/src/managers/SoundManager.js b/src/managers/SoundManager.js index 1349a86..dd96c52 100644 --- a/src/managers/SoundManager.js +++ b/src/managers/SoundManager.js @@ -142,6 +142,11 @@ class SoundManager { this._beep(660, 0.05, 'square', 0.12); } + coin() { + this._beep(988, 0.05, 'square', 0.12); + setTimeout(() => this._beep(1319, 0.08, 'square', 0.12), 45); + } + newBest() { [523, 659, 783, 1046, 1318].forEach((f, i) => setTimeout(() => this._beep(f, 0.18, 'triangle', 0.25), i * 80)); } diff --git a/src/managers/StatsManager.js b/src/managers/StatsManager.js index 8806a7d..f9bb642 100644 --- a/src/managers/StatsManager.js +++ b/src/managers/StatsManager.js @@ -5,6 +5,7 @@ const DEFAULTS = { totalJumps: 0, totalStomps: 0, totalBlocks: 0, + totalCoins: 0, bestCombo: 0, }; @@ -14,7 +15,7 @@ const DEFAULTS = { */ export class StatsManager { constructor() { - this.run = { jumps: 0, stomps: 0, bestCombo: 0 }; + this.run = { jumps: 0, stomps: 0, coins: 0, bestCombo: 0 }; } static load() { @@ -34,6 +35,10 @@ export class StatsManager { this.run.stomps += 1; } + onCoin() { + this.run.coins += 1; + } + onCombo(multiplier) { if (multiplier > this.run.bestCombo) this.run.bestCombo = multiplier; } @@ -44,6 +49,7 @@ export class StatsManager { t.gamesPlayed += 1; t.totalJumps += this.run.jumps; t.totalStomps += this.run.stomps; + t.totalCoins += this.run.coins; t.totalBlocks += blockHeight || 0; t.bestCombo = Math.max(t.bestCombo, this.run.bestCombo); storage.setJSON(KEYS.stats, t); diff --git a/src/scenes/BootScene.js b/src/scenes/BootScene.js index d6df228..43221d5 100644 --- a/src/scenes/BootScene.js +++ b/src/scenes/BootScene.js @@ -148,5 +148,52 @@ export class BootScene extends Scene { } springGfx.strokePath(); springGfx.generateTexture('spring', 20, 32); + + // $GWEI coin — gold disc with highlight + purple diamond (matches Naddie) + const coin = this.make.graphics({ x: 0, y: 0, add: false }); + coin.fillStyle(0xb8860b, 1); coin.fillCircle(16, 16, 15); + coin.fillStyle(0xffd700, 1); coin.fillCircle(16, 16, 13); + coin.fillStyle(0xfff3b0, 1); coin.fillCircle(16, 16, 9); + coin.fillStyle(0xffd700, 1); coin.fillCircle(16, 16, 7); + coin.fillStyle(0x7c3aed, 1); + coin.beginPath(); + coin.moveTo(16, 9); coin.lineTo(21, 16); coin.lineTo(16, 23); coin.lineTo(11, 16); + coin.closePath(); coin.fillPath(); + coin.fillStyle(0xffffff, 0.5); coin.fillCircle(12, 11, 2); + coin.generateTexture('coin', 32, 32); + + // Magnet — classic red/grey horseshoe + const mag = this.make.graphics({ x: 0, y: 0, add: false }); + mag.lineStyle(9, 0xe11d48, 1); + mag.beginPath(); + mag.arc(20, 18, 13, Math.PI, 0, false); // top arc opening downward + mag.strokePath(); + mag.lineStyle(9, 0xe11d48, 1); + mag.beginPath(); mag.moveTo(7, 18); mag.lineTo(7, 32); mag.strokePath(); + mag.beginPath(); mag.moveTo(33, 18); mag.lineTo(33, 32); mag.strokePath(); + mag.fillStyle(0xd1d5db, 1); + mag.fillRect(3, 31, 8, 6); + mag.fillRect(29, 31, 8, 6); + mag.generateTexture('magnet', 40, 40); + + // Shield — cyan heater shield with glassy fill + const sh = this.make.graphics({ x: 0, y: 0, add: false }); + const drawShield = (inset, fill, alpha) => { + sh.fillStyle(fill, alpha); + sh.beginPath(); + sh.moveTo(20, 2 + inset); + sh.lineTo(36 - inset, 9 + inset / 2); + sh.lineTo(36 - inset, 22); + sh.lineTo(20, 40 - inset); + sh.lineTo(4 + inset, 22); + sh.lineTo(4 + inset, 9 + inset / 2); + sh.closePath(); + sh.fillPath(); + }; + drawShield(0, 0x0e7490, 1); + drawShield(3, 0x22d3ee, 1); + drawShield(8, 0xa5f3fc, 0.9); + sh.fillStyle(0xffffff, 0.5); sh.fillRect(12, 10, 4, 12); + sh.generateTexture('shield', 40, 42); } } diff --git a/src/scenes/GameOverScene.js b/src/scenes/GameOverScene.js index 786e657..7b44df3 100644 --- a/src/scenes/GameOverScene.js +++ b/src/scenes/GameOverScene.js @@ -2,6 +2,7 @@ import { Scene } from 'phaser'; import { sound } from '../managers/SoundManager.js'; import { createButton } from '../utils/ui.js'; import { todaySeed } from '../utils/random.js'; +import { storage, KEYS } from '../utils/storage.js'; export class GameOverScene extends Scene { constructor() { @@ -14,6 +15,7 @@ export class GameOverScene extends Scene { this.isNewBest = data.isNewBest || false; this.mode = data.mode || 'normal'; this.dailyBest = data.dailyBest; + this.gwei = data.gwei || 0; } retry() { @@ -55,14 +57,21 @@ export class GameOverScene extends Scene { color: '#d8b4fe', }).setOrigin(0.5); - this.add.text(width / 2, height * 0.61, `Gas Score: ${this.finalScore}`, { + this.add.text(width / 2, height * 0.60, `Gas Score: ${this.finalScore}`, { fontFamily: '"Press Start 2P", monospace', fontSize: '16px', color: '#a855f7', }).setOrigin(0.5); + const wallet = storage.getInt(KEYS.gwei, 0); + this.add.text(width / 2, height * 0.655, `◈ +${this.gwei} $GWEI (wallet: ${wallet})`, { + fontFamily: '"Press Start 2P", monospace', + fontSize: '11px', + color: '#ffd700', + }).setOrigin(0.5); + if (this.mode === 'daily') { - this.add.text(width / 2, height * 0.665, `DAILY · Today's Best: ${this.dailyBest ?? this.finalScore}`, { + this.add.text(width / 2, height * 0.695, `DAILY · Today's Best: ${this.dailyBest ?? this.finalScore}`, { fontFamily: '"Press Start 2P", monospace', fontSize: '10px', color: '#ffd700', diff --git a/src/scenes/GameScene.js b/src/scenes/GameScene.js index 46cb942..de5f305 100644 --- a/src/scenes/GameScene.js +++ b/src/scenes/GameScene.js @@ -10,7 +10,7 @@ import { StatsManager } from '../managers/StatsManager.js'; import { sound } from '../managers/SoundManager.js'; import { storage, KEYS } from '../utils/storage.js'; import { rng } from '../utils/random.js'; -import { GAME_WIDTH, GAME_HEIGHT, SCORE, PHYSICS } from '../config/game.config.js'; +import { GAME_WIDTH, GAME_HEIGHT, SCORE, PHYSICS, COIN } from '../config/game.config.js'; export class GameScene extends Scene { constructor() { @@ -70,6 +70,7 @@ export class GameScene extends Scene { this.physics.add.collider(this.player, this.platformManager.getPlatforms(), this.handlePlatformCollision, this.platformCollisionFilter, this); this.physics.add.overlap(this.player, this.platformManager.getPowerups(), this.handlePowerup, null, this); this.physics.add.overlap(this.player, this.platformManager.getEnemies(), this.handleEnemy, null, this); + this.physics.add.overlap(this.player, this.platformManager.getCoins(), this.handleCoin, null, this); this.cameras.main.setBounds(0, -999999, GAME_WIDTH, 999999 + GAME_HEIGHT); // Doodle-jump camera: free movement below the trigger line, camera only @@ -250,9 +251,27 @@ export class GameScene extends Scene { this.createJumpParticles(player.x, player.y + player.displayHeight / 2 + 3); return; } + // Gas Limit shield absorbs one hit instead of dying. + if (player.shielded) { + player.consumeShield(); + this.createExplosion(enemy.x, enemy.y); + enemy.destroy(); + sound.stomp(); + this.flashScreen(); + return; + } this.gameOver(enemy.x, enemy.y); } + handleCoin(player, coin) { + if (this.isGameOver) return; + if (coin && typeof coin.collect === 'function' && coin.collect()) { + this.scoreManager.addGwei(COIN.value); + if (this.stats) this.stats.onCoin(); + sound.coin(); + } + } + gameOver(ex, ey) { if (this.isGameOver) return; this.isGameOver = true; @@ -268,6 +287,12 @@ export class GameScene extends Scene { } const score = this.scoreManager.score; const blockHeight = this.scoreManager.blockHeight; + const gwei = this.scoreManager.gwei; + + // Bank the run's $GWEI into the persistent wallet. + if (gwei > 0) { + storage.setItem(KEYS.gwei, storage.getInt(KEYS.gwei, 0) + gwei); + } if (this.stats) this.stats.flush(blockHeight); @@ -285,7 +310,7 @@ export class GameScene extends Scene { this.time.delayedCall(1500, () => { this.scoreManager.destroy(); this.scene.start('GameOverScene', { - score, blockHeight, isNewBest, mode: this.mode, dailyBest, + score, blockHeight, isNewBest, mode: this.mode, dailyBest, gwei, }); }); } diff --git a/src/scenes/MenuScene.js b/src/scenes/MenuScene.js index a9a7911..290bff9 100644 --- a/src/scenes/MenuScene.js +++ b/src/scenes/MenuScene.js @@ -234,12 +234,14 @@ export class MenuScene extends Scene { ['Games played', s.gamesPlayed], ['Total jumps', s.totalJumps], ['Enemies stomped', s.totalStomps], + ['Coins collected', s.totalCoins || 0], ['Blocks climbed', s.totalBlocks], ['Best combo', `x${(s.bestCombo || 1).toFixed(1)}`], ['Best score', storage.getInt(KEYS.best, 0)], + ['$GWEI wallet', storage.getInt(KEYS.gwei, 0)], ]; rows.forEach((row, i) => { - const y = height / 2 - 100 + i * 42; + const y = height / 2 - 130 + i * 38; m.add(this.add.text(width / 2 - 170, y, row[0], { fontFamily: '"Press Start 2P", monospace', fontSize: '10px', color: '#d8b4fe', }).setOrigin(0, 0.5)); @@ -300,6 +302,7 @@ export class MenuScene extends Scene { StatsManager.reset(); storage.removeItem(KEYS.best); storage.removeItem(KEYS.achievements); + storage.removeItem(KEYS.gwei); resetBtn.label.setText('DONE'); sound.click(); }, { width: 240, height: 42, fontSize: '12px', bgColor: 0x581c87, hoverColor: 0x7e22ce }); diff --git a/src/utils/storage.js b/src/utils/storage.js index 86491d9..4b1cf72 100644 --- a/src/utils/storage.js +++ b/src/utils/storage.js @@ -11,6 +11,7 @@ export const KEYS = { tutorialSeen: 'naddie_tutorial_seen', achievements: 'naddie_achievements_v1', particleQuality: 'naddie_particle_quality', + gwei: 'naddie_gwei_total', stats: 'naddie_stats_v1', dailyPrefix: 'naddie_daily_', };