Apply player damage once per projectile

This commit is contained in:
Admin 2026-09-18 01:15:56 +00:00
parent 1a99e1c362
commit 564c6a82b5

View File

@ -3,7 +3,7 @@ import './style.css';
import airshipSheetUrl from './assets/airships.svg?url'; import airshipSheetUrl from './assets/airships.svg?url';
import explosionSheetUrl from './assets/explosions.svg?url'; import explosionSheetUrl from './assets/explosions.svg?url';
import { airshipLog, registerDebugSnapshot } from './diagnostics.js'; import { airshipLog, registerDebugSnapshot } from './diagnostics.js';
import { normalizePlayerDamage, reducePlayerVolleyHits } from './game-logic.js'; import { normalizePlayerDamage, reducePlayerProjectileHits } from './game-logic.js';
const WORLD_SIZE = 2400; const WORLD_SIZE = 2400;
const PLAYER_MAX_SPEED = 180; const PLAYER_MAX_SPEED = 180;
@ -18,7 +18,6 @@ const SHOT_LIFETIME = 900;
const PLAYER_MAX_HULL = 100; const PLAYER_MAX_HULL = 100;
const PIRATE_MAX_HULL = 120; const PIRATE_MAX_HULL = 120;
const PIRATE_SHOT_DAMAGE = 6; const PIRATE_SHOT_DAMAGE = 6;
const PLAYER_HIT_COOLDOWN_MS = 300;
const MAX_PIRATES = 6; const MAX_PIRATES = 6;
const AUTO_RESET_MS = 2200; const AUTO_RESET_MS = 2200;
@ -44,10 +43,7 @@ class GameScene extends Phaser.Scene {
this.playerHull = PLAYER_MAX_HULL; this.playerHull = PLAYER_MAX_HULL;
this.gameState = 'playing'; this.gameState = 'playing';
this.lastPlayerShot = 0; this.lastPlayerShot = 0;
this.lastPlayerHitAt = -Infinity;
this.pendingPlayerHits = []; this.pendingPlayerHits = [];
this.nextPirateVolleyId = 1;
this.damagedPlayerVolleys = new Set();
this.lastDiagnosticsAt = -Infinity; this.lastDiagnosticsAt = -Infinity;
this.wave = 1; this.wave = 1;
this.defeated = 0; this.defeated = 0;
@ -461,7 +457,6 @@ class GameScene extends Phaser.Scene {
fireBroadside(ship, side, group, texture, damage, velocityScale) { fireBroadside(ship, side, group, texture, damage, velocityScale) {
if (!ship?.body) return; if (!ship?.body) return;
const actor = group === this.pirateShots ? 'pirate' : 'player'; const actor = group === this.pirateShots ? 'pirate' : 'player';
const volleyId = actor === 'pirate' ? this.nextPirateVolleyId++ : null;
const base = headingRad(ship) + side * Math.PI / 2; const base = headingRad(ship) + side * Math.PI / 2;
airshipLog('combat:broadside-fired', { airshipLog('combat:broadside-fired', {
@ -471,7 +466,6 @@ class GameScene extends Phaser.Scene {
x: Math.round(ship.x), x: Math.round(ship.x),
y: Math.round(ship.y), y: Math.round(ship.y),
angle: Math.round(ship.angle), angle: Math.round(ship.angle),
volleyId,
}, 'debug'); }, 'debug');
const offsets = [-7, 0, 7]; const offsets = [-7, 0, 7];
@ -484,7 +478,6 @@ class GameScene extends Phaser.Scene {
shot.body.setAllowGravity(false); shot.body.setAllowGravity(false);
shot.setData('bornAt', this.time.now); shot.setData('bornAt', this.time.now);
shot.setData('damage', damage); shot.setData('damage', damage);
if (volleyId !== null) shot.setData('volleyId', volleyId);
shot.setVelocity( shot.setVelocity(
Math.cos(angle) * SHOT_SPEED * velocityScale + ship.body.velocity.x * 0.25, Math.cos(angle) * SHOT_SPEED * velocityScale + ship.body.velocity.x * 0.25,
Math.sin(angle) * SHOT_SPEED * velocityScale + ship.body.velocity.y * 0.25, Math.sin(angle) * SHOT_SPEED * velocityScale + ship.body.velocity.y * 0.25,
@ -541,14 +534,12 @@ class GameScene extends Phaser.Scene {
this.pendingPlayerHits.push({ this.pendingPlayerHits.push({
shot, shot,
damage, damage,
volleyId: shot.getData('volleyId'),
x: shot.x, x: shot.x,
y: shot.y, y: shot.y,
}); });
airshipLog('combat:player-hit-queued', { airshipLog('combat:player-hit-queued', {
damage, damage,
volleyId: shot.getData('volleyId'),
pendingHits: this.pendingPlayerHits.length, pendingHits: this.pendingPlayerHits.length,
shotAgeMs: this.time.now - (shot.getData('bornAt') || this.time.now), shotAgeMs: this.time.now - (shot.getData('bornAt') || this.time.now),
hull: this.playerHull, hull: this.playerHull,
@ -571,28 +562,25 @@ class GameScene extends Phaser.Scene {
gameState: this.gameState, gameState: this.gameState,
}; };
const result = reducePlayerVolleyHits({ const result = reducePlayerProjectileHits({
hull: this.playerHull, hull: this.playerHull,
hits, hits,
seenVolleyIds: this.damagedPlayerVolleys,
maxHull: PLAYER_MAX_HULL, maxHull: PLAYER_MAX_HULL,
fallbackDamage: PIRATE_SHOT_DAMAGE, fallbackDamage: PIRATE_SHOT_DAMAGE,
}); });
this.damagedPlayerVolleys = result.seenVolleyIds;
this.playerHull = result.hull; this.playerHull = result.hull;
const { acceptedHits, ignoredHits, totalDamage, gameOver } = result; const { totalDamage, appliedHits, gameOver } = result;
if (acceptedHits.length > 0) { if (appliedHits > 0) {
const impact = acceptedHits[0];
try { try {
for (const impact of hits) {
this.spawnExplosion(impact.x, impact.y, 0.32); this.spawnExplosion(impact.x, impact.y, 0.32);
}
this.flashShip(this.player, 0xffcccc); this.flashShip(this.player, 0xffcccc);
airshipLog('combat:player-hit-fx', { airshipLog('combat:player-hit-fx', {
x: Math.round(impact.x), impacts: hits.length,
y: Math.round(impact.y),
scale: 0.32, scale: 0.32,
volleyId: impact.volleyId ?? null,
}, 'debug'); }, 'debug');
} catch (error) { } catch (error) {
airshipLog('combat:player-hit-fx-error', { airshipLog('combat:player-hit-fx-error', {
@ -603,10 +591,8 @@ class GameScene extends Phaser.Scene {
airshipLog('combat:player-hit-processed', { airshipLog('combat:player-hit-processed', {
queuedHits: hits.length, queuedHits: hits.length,
appliedHits: acceptedHits.length, appliedHits,
ignoredHits: ignoredHits.length, ignoredHits: 0,
acceptedVolleyIds: acceptedHits.map((hit) => hit.volleyId ?? null),
ignoredVolleyIds: ignoredHits.map((hit) => hit.volleyId ?? null),
damage: totalDamage, damage: totalDamage,
hullBefore: beforeHull, hullBefore: beforeHull,
hullAfter: this.playerHull, hullAfter: this.playerHull,