mirror of
https://github.com/GoodStartLabs/AI_Diplomacy.git
synced 2026-04-19 12:58:09 +00:00
WIP: Working on fixing moving from game to game
This commit is contained in:
parent
fd00131af2
commit
6f9c050741
8 changed files with 49 additions and 358 deletions
|
|
@ -1,293 +0,0 @@
|
|||
import { gameState } from '../gameState';
|
||||
|
||||
interface EndScreenModalOptions {
|
||||
totalGamesPlayed: number;
|
||||
onRestart?: () => void;
|
||||
}
|
||||
|
||||
let endScreenModalOverlay: HTMLElement | null = null;
|
||||
|
||||
/**
|
||||
* Shows an end screen modal when all games have been completed
|
||||
* @param options Configuration for the end screen modal
|
||||
*/
|
||||
export function showEndScreenModal(options: EndScreenModalOptions): void {
|
||||
const { totalGamesPlayed, onRestart } = options;
|
||||
|
||||
// Close any existing modal
|
||||
closeEndScreenModal();
|
||||
|
||||
// Create overlay
|
||||
endScreenModalOverlay = createEndScreenOverlay();
|
||||
|
||||
// Create modal container
|
||||
const modalContainer = createEndScreenContainer(totalGamesPlayed);
|
||||
|
||||
// Add close button if not in playing mode
|
||||
if (!gameState.isPlaying) {
|
||||
const closeButton = createCloseButton();
|
||||
modalContainer.appendChild(closeButton);
|
||||
}
|
||||
|
||||
// Add to overlay
|
||||
endScreenModalOverlay.appendChild(modalContainer);
|
||||
document.body.appendChild(endScreenModalOverlay);
|
||||
|
||||
// Set up event listeners
|
||||
setupEventListeners(onRestart);
|
||||
|
||||
// Auto-restart after 5 seconds
|
||||
setTimeout(() => {
|
||||
closeEndScreenModal();
|
||||
onRestart?.();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the end screen modal
|
||||
*/
|
||||
export function closeEndScreenModal(): void {
|
||||
if (endScreenModalOverlay) {
|
||||
endScreenModalOverlay.classList.add('fade-out');
|
||||
setTimeout(() => {
|
||||
if (endScreenModalOverlay?.parentNode) {
|
||||
endScreenModalOverlay.parentNode.removeChild(endScreenModalOverlay);
|
||||
}
|
||||
endScreenModalOverlay = null;
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the main overlay element
|
||||
*/
|
||||
function createEndScreenOverlay(): HTMLElement {
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'end-screen-modal-overlay';
|
||||
overlay.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 2000;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
`;
|
||||
|
||||
// Add fade-out class styles
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.end-screen-modal-overlay.fade-out {
|
||||
opacity: 0 !important;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Trigger fade in
|
||||
setTimeout(() => overlay.style.opacity = '1', 10);
|
||||
|
||||
return overlay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the main end screen container
|
||||
*/
|
||||
function createEndScreenContainer(totalGamesPlayed: number): HTMLElement {
|
||||
const container = document.createElement('div');
|
||||
container.className = 'end-screen-modal-container';
|
||||
container.style.cssText = `
|
||||
background: radial-gradient(ellipse at center, #2a1f1f 0%, #1a1015 100%);
|
||||
border: 5px solid #8b7355;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 40px rgba(255, 215, 0, 0.6);
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
position: relative;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
font-family: "Book Antiqua", Palatino, serif;
|
||||
color: #f0e6d2;
|
||||
animation: endScreenGlow 3s ease-in-out infinite alternate;
|
||||
`;
|
||||
|
||||
// Add glow animation
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@keyframes endScreenGlow {
|
||||
0% { box-shadow: 0 0 40px rgba(255, 215, 0, 0.6); }
|
||||
100% { box-shadow: 0 0 60px rgba(255, 215, 0, 0.8); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
// Crown/completion icon
|
||||
const crownElement = document.createElement('div');
|
||||
crownElement.textContent = '👑';
|
||||
crownElement.style.cssText = `
|
||||
font-size: 64px;
|
||||
margin-bottom: 20px;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
`;
|
||||
|
||||
// Add float animation
|
||||
const floatStyle = document.createElement('style');
|
||||
floatStyle.textContent = `
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(floatStyle);
|
||||
|
||||
// Title
|
||||
const titleElement = document.createElement('h1');
|
||||
titleElement.textContent = 'SERIES COMPLETE!';
|
||||
titleElement.style.cssText = `
|
||||
margin: 0 0 20px 0;
|
||||
color: #ffd700;
|
||||
font-size: 42px;
|
||||
font-weight: bold;
|
||||
text-shadow: 3px 3px 6px rgba(0,0,0,0.7);
|
||||
letter-spacing: 2px;
|
||||
`;
|
||||
|
||||
// Completion message
|
||||
const messageElement = document.createElement('h2');
|
||||
messageElement.textContent = `All ${totalGamesPlayed} games completed!`;
|
||||
messageElement.style.cssText = `
|
||||
margin: 0 0 30px 0;
|
||||
color: #f0e6d2;
|
||||
font-size: 24px;
|
||||
font-weight: normal;
|
||||
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
|
||||
`;
|
||||
|
||||
// Restart countdown
|
||||
const countdownElement = document.createElement('div');
|
||||
countdownElement.style.cssText = `
|
||||
background: linear-gradient(90deg, #4a4a4a 0%, #2a2a2a 100%);
|
||||
color: #ffd700;
|
||||
padding: 15px 25px;
|
||||
border-radius: 25px;
|
||||
display: inline-block;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
border: 2px solid #8b7355;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.4);
|
||||
`;
|
||||
|
||||
// Animate countdown
|
||||
let countdown = 5;
|
||||
countdownElement.textContent = `Restarting series in ${countdown} seconds...`;
|
||||
|
||||
const countdownInterval = setInterval(() => {
|
||||
countdown--;
|
||||
if (countdown > 0) {
|
||||
countdownElement.textContent = `Restarting series in ${countdown} seconds...`;
|
||||
} else {
|
||||
countdownElement.textContent = 'Restarting now...';
|
||||
clearInterval(countdownInterval);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Thank you message
|
||||
const thankYouElement = document.createElement('div');
|
||||
thankYouElement.textContent = 'Thank you for watching the AI Diplomacy series!';
|
||||
thankYouElement.style.cssText = `
|
||||
color: #c4b998;
|
||||
font-size: 16px;
|
||||
font-style: italic;
|
||||
margin-top: 20px;
|
||||
`;
|
||||
|
||||
// Assemble container
|
||||
container.appendChild(crownElement);
|
||||
container.appendChild(titleElement);
|
||||
container.appendChild(messageElement);
|
||||
container.appendChild(countdownElement);
|
||||
container.appendChild(thankYouElement);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a close button
|
||||
*/
|
||||
function createCloseButton(): HTMLElement {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = '×';
|
||||
button.className = 'end-screen-close-button';
|
||||
button.style.cssText = `
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 20px;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 40px;
|
||||
color: #8b7355;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
transition: all 0.2s ease;
|
||||
`;
|
||||
|
||||
button.addEventListener('mouseenter', () => {
|
||||
button.style.color = '#ffd700';
|
||||
button.style.transform = 'scale(1.1)';
|
||||
button.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', () => {
|
||||
button.style.color = '#8b7355';
|
||||
button.style.transform = 'scale(1)';
|
||||
button.style.backgroundColor = 'transparent';
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up event listeners for the end screen modal
|
||||
*/
|
||||
function setupEventListeners(onRestart?: () => void): void {
|
||||
if (!endScreenModalOverlay) return;
|
||||
|
||||
const closeButton = endScreenModalOverlay.querySelector('.end-screen-close-button');
|
||||
const handleClose = () => {
|
||||
closeEndScreenModal();
|
||||
onRestart?.();
|
||||
};
|
||||
|
||||
// Close button click (only if not in playing mode)
|
||||
if (!gameState.isPlaying) {
|
||||
closeButton?.addEventListener('click', handleClose);
|
||||
|
||||
// Escape key
|
||||
const handleKeydown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
handleClose();
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', handleKeydown);
|
||||
|
||||
// Click outside to close
|
||||
endScreenModalOverlay.addEventListener('click', (e) => {
|
||||
if (e.target === endScreenModalOverlay) {
|
||||
handleClose();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -79,9 +79,9 @@ function rotateToNextDisplay(): void {
|
|||
|
||||
// Determine next display type
|
||||
switch (currentDisplayType) {
|
||||
// case DisplayType.SC_HISTORY_CHART:
|
||||
// currentDisplayType = DisplayType.RELATIONSHIP_HISTORY_CHART;
|
||||
// break;
|
||||
case DisplayType.SC_HISTORY_CHART:
|
||||
currentDisplayType = DisplayType.RELATIONSHIP_HISTORY_CHART;
|
||||
break;
|
||||
case DisplayType.RELATIONSHIP_HISTORY_CHART:
|
||||
currentDisplayType = DisplayType.SC_HISTORY_CHART;
|
||||
break;
|
||||
|
|
@ -155,6 +155,9 @@ function renderSCHistoryChartView(
|
|||
container: HTMLElement,
|
||||
gameData: GameSchemaType
|
||||
): void {
|
||||
|
||||
// TODO: This likely needs to not be a custom rendered svg. There are plenty of charting libraries to use to do this instead.
|
||||
//
|
||||
// Create header
|
||||
const header = document.createElement('div');
|
||||
header.innerHTML = `<strong>Supply Center History</strong>`;
|
||||
|
|
|
|||
|
|
@ -40,13 +40,6 @@ export function showVictoryModal(options: VictoryModalOptions): void {
|
|||
// Set up event listeners
|
||||
setupEventListeners(onClose);
|
||||
|
||||
// Auto-dismiss in playing mode after delay
|
||||
if (gameState.isPlaying) {
|
||||
setTimeout(() => {
|
||||
closeVictoryModal();
|
||||
onClose?.();
|
||||
}, 5000); // 5 second display in playing mode
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -55,12 +48,10 @@ export function showVictoryModal(options: VictoryModalOptions): void {
|
|||
export function closeVictoryModal(): void {
|
||||
if (victoryModalOverlay) {
|
||||
victoryModalOverlay.classList.add('fade-out');
|
||||
setTimeout(() => {
|
||||
if (victoryModalOverlay?.parentNode) {
|
||||
victoryModalOverlay.parentNode.removeChild(victoryModalOverlay);
|
||||
}
|
||||
victoryModalOverlay = null;
|
||||
}, 300);
|
||||
if (victoryModalOverlay?.parentNode) {
|
||||
victoryModalOverlay.parentNode.removeChild(victoryModalOverlay);
|
||||
}
|
||||
victoryModalOverlay = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +240,7 @@ function createStandingsElement(finalStandings: Array<{ power: string; centers:
|
|||
const standingItem = document.createElement('div');
|
||||
const medal = index === 0 ? "🥇" : index === 1 ? "🥈" : index === 2 ? "🥉" : `${index + 1}.`;
|
||||
const displayName = getPowerDisplayName(entry.power as PowerENUM);
|
||||
|
||||
|
||||
standingItem.innerHTML = `
|
||||
<span style="font-size: 18px; margin-right: 8px;">${medal}</span>
|
||||
<span class="power-${entry.power.toLowerCase()}" style="font-weight: bold;">${displayName}</span>
|
||||
|
|
@ -346,4 +337,4 @@ function setupEventListeners(onClose?: () => void): void {
|
|||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
export const config = {
|
||||
// Default speed in milliseconds for animations and transitions
|
||||
playbackSpeed: 500,
|
||||
|
||||
victoryModalDisplayMs: 10000,
|
||||
// Streaming mode specific timing
|
||||
get streamingPlaybackSpeed(): number {
|
||||
const isStreamingMode = import.meta.env.MODE === 'production'
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import * as THREE from "three"
|
|||
import { updateRotatingDisplay } from "./components/rotatingDisplay";
|
||||
import { type CoordinateData, CoordinateDataSchema, PowerENUM } from "./types/map"
|
||||
import type { GameSchemaType } from "./types/gameState";
|
||||
import { debugMenuInstance } from "./debug/debugMenu.ts"
|
||||
import { config } from "./config.ts"
|
||||
import { GameSchema } from "./types/gameState";
|
||||
import { prevBtn, nextBtn, playBtn, speedSelector, mapView, updateGameIdDisplay } from "./domElements";
|
||||
import { createChatWindows } from "./domElements/chatWindows";
|
||||
|
|
@ -11,6 +13,7 @@ import { displayInitialPhase, togglePlayback } from "./phase";
|
|||
import { Tween, Group as TweenGroup } from "@tweenjs/tween.js";
|
||||
import { MomentsDataSchema, Moment, NormalizedMomentsData } from "./types/moments";
|
||||
import { updateLeaderboard } from "./components/leaderboard";
|
||||
import { closeVictoryModal } from "./components/victoryModal.ts";
|
||||
|
||||
//FIXME: This whole file is a mess. Need to organize and format
|
||||
|
||||
|
|
@ -123,7 +126,7 @@ class GameState {
|
|||
this.phaseIndex = 0
|
||||
this.boardName = boardName
|
||||
this.currentPower = null;
|
||||
this.gameId = 12
|
||||
this.gameId = 16
|
||||
|
||||
this.momentsData = null; // Initialize as null, will be loaded later
|
||||
// State locks
|
||||
|
|
@ -226,6 +229,7 @@ class GameState {
|
|||
|
||||
// Update game ID display
|
||||
updateGameIdDisplay();
|
||||
|
||||
})
|
||||
resolve()
|
||||
} else {
|
||||
|
|
@ -300,16 +304,19 @@ class GameState {
|
|||
/*
|
||||
* Loads the next game in the order, reseting the board and gameState
|
||||
*/
|
||||
loadNextGame = () => {
|
||||
loadNextGame = (setPlayback: boolean = false) => {
|
||||
|
||||
let gameId = this.gameId + 1
|
||||
let contPlaying = false
|
||||
if (this.isPlaying) {
|
||||
if (setPlayback || this.isPlaying) {
|
||||
contPlaying = true
|
||||
}
|
||||
this.loadGameFile(gameId).then(() => {
|
||||
|
||||
gameState.gameId = gameId
|
||||
if (contPlaying) {
|
||||
togglePlayback(true)
|
||||
setTimeout(() => {
|
||||
togglePlayback(true)
|
||||
}, config.victoryModalDisplayMs)
|
||||
}
|
||||
}).catch(() => {
|
||||
console.warn("caught error trying to advance game. Setting gameId to 0 and restarting...")
|
||||
|
|
@ -317,7 +324,7 @@ class GameState {
|
|||
if (contPlaying) {
|
||||
togglePlayback(true)
|
||||
}
|
||||
})
|
||||
}).finally(closeVictoryModal)
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -348,6 +355,9 @@ class GameState {
|
|||
this.gameId = gameId
|
||||
updateGameIdDisplay();
|
||||
updateLeaderboard();
|
||||
if (config.isDebugMode) {
|
||||
debugMenuInstance.updateTools()
|
||||
}
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,18 +2,15 @@ import * as THREE from "three";
|
|||
import "./style.css"
|
||||
import { initMap } from "./map/create";
|
||||
import { gameState } from "./gameState";
|
||||
import { logger } from "./logger";
|
||||
import { loadBtn, prevBtn, nextBtn, speedSelector, fileInput, playBtn, mapView, loadGameBtnFunction } from "./domElements";
|
||||
import { updateChatWindows } from "./domElements/chatWindows";
|
||||
import { displayPhaseWithAnimation, advanceToNextPhase, resetToPhase, nextPhase, previousPhase, togglePlayback, _setPhase } from "./phase";
|
||||
import { config } from "./config";
|
||||
import { Tween, Group, Easing } from "@tweenjs/tween.js";
|
||||
import { initRotatingDisplay, updateRotatingDisplay } from "./components/rotatingDisplay";
|
||||
import { closeTwoPowerConversation, showTwoPowerConversation } from "./components/twoPowerConversation";
|
||||
import { PowerENUM } from "./types/map";
|
||||
import { initRotatingDisplay, } from "./components/rotatingDisplay";
|
||||
import { debugMenuInstance } from "./debug/debugMenu";
|
||||
import { initializeBackgroundAudio, startBackgroundAudio } from "./backgroundAudio";
|
||||
import { updateLeaderboard } from "./components/leaderboard";
|
||||
import { _setPhase } from "./phase";
|
||||
import { togglePlayback } from "./phase";
|
||||
|
||||
//TODO: Create a function that finds a suitable unit location within a given polygon, for placing units better
|
||||
// Currently the location for label, unit, and SC are all the same manually picked location
|
||||
|
|
@ -161,7 +158,6 @@ function animate() {
|
|||
// FIXME: This is a dumb patch for us not being able to find the unit we expect to find.
|
||||
// We should instead bee figuring out why units aren't where we expect them to be when the engine has said that is a valid move
|
||||
nextPhase()
|
||||
gameState.nextPhaseScheduled;
|
||||
}
|
||||
}, config.effectivePlaybackSpeed);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,14 @@ const MOMENT_DISPLAY_TIMEOUT_MS = config.isDebugMode || config.isInstantMode ? 1
|
|||
|
||||
// FIXME: Going to previous phases is borked. Units do not animate properly, map doesn't update.
|
||||
export function _setPhase(phaseIndex: number) {
|
||||
console.log(`[Phase] _setPhase called with index: ${phaseIndex}`);
|
||||
if (phaseIndex < 0) {
|
||||
throw new Error(`Provided invalid phaseIndex, cannot setPhase to ${phaseIndex} - game has ${gameState.gameData.phases.length} phases`)
|
||||
}
|
||||
if (phaseIndex >= gameState.gameData.phases.length - 1) {
|
||||
gameState.phaseIndex = gameState.gameData.phases.length - 1
|
||||
displayFinalPhase()
|
||||
return
|
||||
}
|
||||
|
||||
// Store the old phase index at the very beginning
|
||||
const oldPhaseIndex = gameState.phaseIndex;
|
||||
|
|
@ -29,10 +36,9 @@ export function _setPhase(phaseIndex: number) {
|
|||
debugMenuInstance.updateTools()
|
||||
}
|
||||
const gameLength = gameState.gameData.phases.length
|
||||
|
||||
|
||||
// Validate that the phaseIndex is within the bounds of the game length.
|
||||
if (phaseIndex >= gameLength || phaseIndex < 0) {
|
||||
throw new Error(`Provided invalid phaseIndex, cannot setPhase to ${phaseIndex} - game has ${gameState.gameData.phases.length} phases`)
|
||||
}
|
||||
if (phaseIndex - gameState.phaseIndex != 1) {
|
||||
// We're moving more than one Phase forward, or any number of phases backward, to do so clear the board and reInit the units on the correct phase
|
||||
gameState.unitAnimations = [];
|
||||
|
|
@ -56,12 +62,7 @@ export function _setPhase(phaseIndex: number) {
|
|||
console.log(`Moving to phase ${gameState.gameData.phases[gameState.phaseIndex].name}`);
|
||||
}
|
||||
|
||||
if (phaseIndex === gameLength - 1) {
|
||||
displayFinalPhase()
|
||||
} else {
|
||||
displayPhase()
|
||||
}
|
||||
gameState.nextPhaseScheduled = false;
|
||||
displayPhase()
|
||||
}
|
||||
|
||||
// Finally, update the gameState with the current phaseIndex
|
||||
|
|
@ -235,6 +236,8 @@ export function displayPhase(skipMessages = false) {
|
|||
logger.log("No animations for this phase transition");
|
||||
gameState.messagesPlaying = false;
|
||||
}
|
||||
gameState.nextPhaseScheduled = false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -242,7 +245,6 @@ export function displayPhase(skipMessages = false) {
|
|||
* Used when first loading a game
|
||||
*/
|
||||
export function displayInitialPhase() {
|
||||
gameState.phaseIndex = 0;
|
||||
initUnits(0);
|
||||
displayPhase(true);
|
||||
}
|
||||
|
|
@ -316,8 +318,6 @@ export function advanceToNextPhase() {
|
|||
nextPhase();
|
||||
}
|
||||
|
||||
// Reset the nextPhaseScheduled flag to allow scheduling the next phase
|
||||
gameState.nextPhaseScheduled = false;
|
||||
}
|
||||
|
||||
function displayFinalPhase() {
|
||||
|
|
@ -360,27 +360,11 @@ function displayFinalPhase() {
|
|||
winner,
|
||||
maxCenters,
|
||||
finalStandings,
|
||||
onClose: () => {
|
||||
// Only proceed to next game if in playing mode
|
||||
if (gameState.isPlaying) {
|
||||
gameState.loadNextGame();
|
||||
}
|
||||
}
|
||||
});
|
||||
//setTimeout(closeVictoryModal, 10000)
|
||||
setTimeout(() => {
|
||||
gameState.loadNextGame(true)
|
||||
}, config.victoryModalDisplayMs)
|
||||
|
||||
// Log the victory
|
||||
logger.log(`Victory! ${winner} wins the game with ${maxCenters} supply centers.`);
|
||||
|
||||
// Display final standings in console
|
||||
console.log("Final Standings:");
|
||||
finalStandings.forEach((entry, index) => {
|
||||
const medal = index === 0 ? "🥇" : index === 1 ? "🥈" : index === 2 ? "🥉" : " ";
|
||||
console.log(`${medal} ${entry.power}: ${entry.centers} centers`);
|
||||
});
|
||||
|
||||
// Show victory in info panel
|
||||
logger.updateInfoPanel(`🏆 ${winner} VICTORIOUS! 🏆\n\nFinal Score: ${maxCenters} supply centers\n\nCheck console for full standings.`);
|
||||
} else {
|
||||
logger.log("Could not determine game winner");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"DOM.Iterable"
|
||||
],
|
||||
// Turn the below off later, just for now we're not full TS yet
|
||||
"noCheck": true,
|
||||
"noCheck": false,
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue