208 lines
5.7 KiB
JavaScript
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 }
|
|
};
|
|
}
|
|
} |