Add four-way cannon and stimulant bonuses with XP multiplier and healing ticks
This commit is contained in:
parent
145341d992
commit
26d2dad489
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 9.5 KiB |
Binary file not shown.
|
|
@ -30,8 +30,10 @@ export class Player {
|
|||
this._baseFireInterval = 250; // ms between shots
|
||||
this._isMoving = false;
|
||||
this._isShooting = false;
|
||||
this.weaponMode = 'default'; // 'default' | 'shotgun' | 'rocket'
|
||||
this.weaponMode = 'default'; // 'default' | 'shotgun' | 'rocket' | 'fourway' | 'stimulant'
|
||||
this.weaponTimeLeft = 0; // ms remaining for timed weapon
|
||||
this.weaponDuration = 0; // initial duration of current weapon (for HUD ratio)
|
||||
this._stimulantTickTimer = 0;
|
||||
|
||||
this._createAnims();
|
||||
this._buildSprite(x, y);
|
||||
|
|
@ -82,6 +84,13 @@ export class Player {
|
|||
this._updateRockets();
|
||||
if (this.weaponTimeLeft > 0) {
|
||||
this.weaponTimeLeft -= delta;
|
||||
if (this.weaponMode === 'stimulant') {
|
||||
this._stimulantTickTimer -= delta;
|
||||
if (this._stimulantTickTimer <= 0) {
|
||||
this._stimulantTickTimer = 3000;
|
||||
this.hp = Math.min(this.hp + this.stats.maxHp * 0.1, this.stats.maxHp);
|
||||
}
|
||||
}
|
||||
if (this.weaponTimeLeft <= 0) {
|
||||
this.weaponTimeLeft = 0;
|
||||
this.weaponMode = 'default';
|
||||
|
|
@ -118,6 +127,7 @@ export class Player {
|
|||
this._fireCooldown = this._baseFireInterval / this.stats.fireRate;
|
||||
if (this.weaponMode === 'shotgun') this._spawnShotgunBurst();
|
||||
else if (this.weaponMode === 'rocket') this._spawnRocket();
|
||||
else if (this.weaponMode === 'fourway') this._spawnFourWayBurst();
|
||||
else this._spawnBullet();
|
||||
}
|
||||
}
|
||||
|
|
@ -172,6 +182,20 @@ export class Player {
|
|||
});
|
||||
}
|
||||
|
||||
_spawnFourWayBurst() {
|
||||
this.scene.sound.play('sfx-shoot', { volume: 0.4 });
|
||||
[0, Math.PI / 2, Math.PI, Math.PI * 1.5].forEach(offset => {
|
||||
const angle = this.facing + offset;
|
||||
const bx = this.x + Math.cos(angle) * GUN_TIP_DIST;
|
||||
const by = this.y + Math.sin(angle) * GUN_TIP_DIST;
|
||||
const bullet = this.scene.add.circle(bx, by, BULLET_SIZE, 0xffff00);
|
||||
this.scene.physics.add.existing(bullet);
|
||||
bullet.body.setVelocity(Math.cos(angle) * BULLET_SPEED, Math.sin(angle) * BULLET_SPEED);
|
||||
bullet.damage = this.stats.damage;
|
||||
this.bullets.add(bullet);
|
||||
});
|
||||
}
|
||||
|
||||
_spawnRocket() {
|
||||
this.scene.sound.play('sfx-shoot', { volume: 0.5 });
|
||||
const bx = this.x + Math.cos(this.facing) * GUN_TIP_DIST;
|
||||
|
|
@ -193,15 +217,30 @@ export class Player {
|
|||
});
|
||||
}
|
||||
|
||||
get xpMultiplier() {
|
||||
return this.weaponMode === 'stimulant' ? 2 : 1;
|
||||
}
|
||||
|
||||
applyBonus(type) {
|
||||
if (type === 'medpack') {
|
||||
this.hp = Math.min(this.hp + this.stats.maxHp * 0.5, this.stats.maxHp);
|
||||
} else if (type === 'shotgun') {
|
||||
this.weaponMode = 'shotgun';
|
||||
this.weaponTimeLeft = 20000;
|
||||
this.weaponDuration = 20000;
|
||||
} else if (type === 'rocket') {
|
||||
this.weaponMode = 'rocket';
|
||||
this.weaponTimeLeft = 20000;
|
||||
this.weaponDuration = 20000;
|
||||
} else if (type === 'fourway') {
|
||||
this.weaponMode = 'fourway';
|
||||
this.weaponTimeLeft = 20000;
|
||||
this.weaponDuration = 20000;
|
||||
} else if (type === 'stimulant') {
|
||||
this.weaponMode = 'stimulant';
|
||||
this.weaponTimeLeft = 15000;
|
||||
this.weaponDuration = 15000;
|
||||
this._stimulantTickTimer = 3000;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export class GameScene extends Phaser.Scene {
|
|||
this._enemyProjectiles = [];
|
||||
|
||||
// Event wiring
|
||||
this.events.on('enemy-killed', ({ xp }) => this.xpSystem.addXP(xp));
|
||||
this.events.on('enemy-killed', ({ xp }) => this.xpSystem.addXP(xp * this.player.xpMultiplier));
|
||||
this.events.on('enemy-projectile-spawned', proj => this._enemyProjectiles.push(proj));
|
||||
this.events.on('level-up', level => this._showLevelUp(level));
|
||||
this.events.on('game-over', () => this._onGameOver());
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
const BONUS_LIFETIME_MS = 15000;
|
||||
const BLINK_START_MS = 10000; // blink when < 5s left (at 10s elapsed of 15s)
|
||||
const COOLDOWN_PICKUP = 20000;
|
||||
const COOLDOWN_PICKUP = 10000;
|
||||
const COOLDOWN_EXPIRE = 10000;
|
||||
const FIRST_SPAWN_MS = 20000;
|
||||
const PICKUP_RADIUS = 32;
|
||||
const BONUS_TYPES = ['medpack', 'shotgun', 'rocket'];
|
||||
const BONUS_TYPES = ['medpack', 'shotgun', 'rocket', 'fourway', 'stimulant'];
|
||||
|
||||
const FRAME_INDEX = { medpack: 0, shotgun: 1, rocket: 2 };
|
||||
const GLOW_COLOR = { medpack: 0x44ff44, shotgun: 0xff9900, rocket: 0xff3300 };
|
||||
const FRAME_INDEX = { medpack: 0, shotgun: 1, rocket: 2, fourway: 3, stimulant: 4 };
|
||||
const GLOW_COLOR = { medpack: 0x44ff44, shotgun: 0xff9900, rocket: 0xff3300, fourway: 0x00ffff, stimulant: 0xaa44ff };
|
||||
|
||||
export class BonusManager {
|
||||
constructor(scene, player) {
|
||||
|
|
@ -19,8 +19,10 @@ export class BonusManager {
|
|||
|
||||
update(delta) {
|
||||
if (!this._active) {
|
||||
this._countdown -= delta;
|
||||
if (this._countdown <= 0) this._spawn();
|
||||
if (this._player.weaponMode === 'default') {
|
||||
this._countdown -= delta;
|
||||
if (this._countdown <= 0) this._spawn();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +59,7 @@ export class BonusManager {
|
|||
}
|
||||
|
||||
_spawn() {
|
||||
const type = BONUS_TYPES[Phaser.Math.Between(0, 2)];
|
||||
const type = BONUS_TYPES[Phaser.Math.Between(0, BONUS_TYPES.length - 1)];
|
||||
const cell = this._findSpawnCell();
|
||||
if (!cell) {
|
||||
// No valid cell found — retry in 2 seconds
|
||||
|
|
|
|||
|
|
@ -82,11 +82,12 @@ export class HUD {
|
|||
this._weaponBarFill.setVisible(hasWeapon);
|
||||
this._weaponLabel.setVisible(hasWeapon);
|
||||
if (hasWeapon) {
|
||||
const ratio = Math.max(0, this.player.weaponTimeLeft / 20000);
|
||||
const ratio = Math.max(0, this.player.weaponTimeLeft / this.player.weaponDuration);
|
||||
this._weaponBarFill.width = 200 * ratio;
|
||||
const color = this.player.weaponMode === 'rocket' ? 0xff3300 : 0xff9900;
|
||||
this._weaponBarFill.setFillStyle(color);
|
||||
this._weaponLabel.setText(this.player.weaponMode === 'rocket' ? 'ROCKET LAUNCHER' : 'SHOTGUN');
|
||||
const colorMap = { shotgun: 0xff9900, rocket: 0xff3300, fourway: 0x00ffff, stimulant: 0xaa44ff };
|
||||
const labelMap = { shotgun: 'SHOTGUN', rocket: 'ROCKET LAUNCHER', fourway: 'FOUR-WAY CANNON', stimulant: 'STIMULANT' };
|
||||
this._weaponBarFill.setFillStyle(colorMap[this.player.weaponMode] ?? 0xffffff);
|
||||
this._weaponLabel.setText(labelMap[this.player.weaponMode] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue