hockey-manager/src/engine/game-state.js
Pierre Wessman 0eb0574fbd init
2025-09-16 10:30:13 +02:00

208 lines
5.7 KiB
JavaScript

class GameState {
constructor() {
this.reset();
this.eventListeners = {};
}
reset() {
this.period = 1;
this.timeRemaining = 20 * 60; // 20 minutes in seconds
this.homeScore = 0;
this.awayScore = 0;
this.gameSpeed = 1;
this.isPaused = false;
this.gameOver = false;
this.stats = {
home: {
shots: 0,
saves: 0,
hits: 0,
penalties: [],
faceoffWins: 0
},
away: {
shots: 0,
saves: 0,
hits: 0,
penalties: [],
faceoffWins: 0
}
};
this.gameEvents = [];
this.lastEventTime = 0;
this.rink = {
width: 1000,
height: 600,
centerX: 500,
centerY: 300,
goalWidth: 120,
goalHeight: 40,
corners: {
radius: 80
},
faceoffDots: [
{ x: 200, y: 150 }, // Home left
{ x: 200, y: 450 }, // Home right
{ x: 500, y: 300 }, // Center
{ x: 800, y: 150 }, // Away left
{ x: 800, y: 450 } // Away right
]
};
this.powerPlay = {
home: null,
away: null
};
}
formatTime(seconds) {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = Math.floor(seconds % 60);
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}
getPeriodName() {
switch (this.period) {
case 1: return '1st';
case 2: return '2nd';
case 3: return '3rd';
default: return 'OT';
}
}
updateTime(deltaTime) {
if (this.isPaused || this.gameOver) return;
this.timeRemaining -= deltaTime * this.gameSpeed;
if (this.timeRemaining <= 0) {
this.timeRemaining = 0;
this.endPeriod();
}
this.updatePenalties(deltaTime);
}
endPeriod() {
this.period++;
if (this.period > 3 && this.homeScore !== this.awayScore) {
this.gameOver = true;
this.emit('game-end', { winner: this.homeScore > this.awayScore ? 'home' : 'away' });
} else if (this.period <= 3) {
this.timeRemaining = 20 * 60;
this.emit('period-end', { period: this.period - 1 });
} else {
this.timeRemaining = 5 * 60; // Overtime
this.emit('overtime-start');
}
}
addGoal(team) {
if (team === 'home') {
this.homeScore++;
} else {
this.awayScore++;
}
this.addEvent(`GOAL - ${team.toUpperCase()}!`);
this.emit('goal', { team, homeScore: this.homeScore, awayScore: this.awayScore });
}
addShot(team) {
this.stats[team].shots++;
this.emit('shot', { team, shots: this.stats[team].shots });
}
addSave(team) {
this.stats[team].saves++;
this.emit('save', { team, saves: this.stats[team].saves });
}
addPenalty(team, player, type, duration = 120) {
const penalty = {
player,
type,
duration,
timeRemaining: duration
};
this.stats[team].penalties.push(penalty);
this.addEvent(`PENALTY - ${team.toUpperCase()} ${player}: ${type}`);
const oppositeTeam = team === 'home' ? 'away' : 'home';
this.powerPlay[oppositeTeam] = Date.now() + (duration * 1000);
this.emit('penalty', { team, player, type, duration });
}
updatePenalties(deltaTime) {
['home', 'away'].forEach(team => {
this.stats[team].penalties = this.stats[team].penalties.filter(penalty => {
penalty.timeRemaining -= deltaTime * this.gameSpeed;
if (penalty.timeRemaining <= 0) {
this.emit('penalty-expired', { team, penalty });
return false;
}
return true;
});
});
['home', 'away'].forEach(team => {
if (this.powerPlay[team] && Date.now() > this.powerPlay[team]) {
this.powerPlay[team] = null;
}
});
}
addEvent(description) {
const event = {
time: this.formatTime(20 * 60 - this.timeRemaining),
period: this.period,
description,
timestamp: Date.now()
};
this.gameEvents.unshift(event);
if (this.gameEvents.length > 50) {
this.gameEvents.pop();
}
}
togglePause() {
this.isPaused = !this.isPaused;
this.emit('pause-toggle', { isPaused: this.isPaused });
}
setSpeed(speed) {
this.gameSpeed = Math.max(0.1, Math.min(5, speed));
this.emit('speed-change', { speed: this.gameSpeed });
}
on(event, callback) {
if (!this.eventListeners[event]) {
this.eventListeners[event] = [];
}
this.eventListeners[event].push(callback);
}
emit(event, data) {
if (this.eventListeners[event]) {
this.eventListeners[event].forEach(callback => callback(data));
}
}
getGameState() {
return {
period: this.period,
timeRemaining: this.timeRemaining,
homeScore: this.homeScore,
awayScore: this.awayScore,
stats: { ...this.stats },
isPaused: this.isPaused,
gameSpeed: this.gameSpeed,
gameOver: this.gameOver,
powerPlay: { ...this.powerPlay }
};
}
}