diff --git a/ai_animation/src/debug/debugMenu.ts b/ai_animation/src/debug/debugMenu.ts
index 8201979..71a47f2 100644
--- a/ai_animation/src/debug/debugMenu.ts
+++ b/ai_animation/src/debug/debugMenu.ts
@@ -5,6 +5,7 @@
import { updateNextMomentDisplay, initNextMomentTool } from "./nextMoment";
import { initDebugProvinceHighlighting } from "./provinceHighlight";
+import { initInstantChatTool } from "./instantChat";
export class DebugMenu {
private toggleBtn: HTMLButtonElement;
@@ -171,6 +172,7 @@ export class DebugMenu {
}
private initTools(): void {
+ initInstantChatTool(this);
initNextMomentTool(this);
initDebugProvinceHighlighting()
}
diff --git a/ai_animation/src/debug/instantChat.ts b/ai_animation/src/debug/instantChat.ts
new file mode 100644
index 0000000..d30424d
--- /dev/null
+++ b/ai_animation/src/debug/instantChat.ts
@@ -0,0 +1,54 @@
+/**
+ * Debug tool for making all chat messages appear instantly
+ * Provides a toggle to skip word-by-word animation during message playback
+ */
+
+import { config } from '../config';
+import { DebugMenu } from './debugMenu';
+
+// Flag to control instant chat behavior
+let instantChatEnabled = false;
+
+/**
+ * Gets whether instant chat is currently enabled
+ */
+export function isInstantChatEnabled(): boolean {
+ return instantChatEnabled;
+}
+
+/**
+ * Initializes the instant chat debug tool
+ * @param debugMenu - The debug menu instance to add this tool to
+ */
+export function initInstantChatTool(debugMenu: DebugMenu): void {
+ const content = `
+
+
+
+ Skip word-by-word animation and show all chat messages instantly
+
+
+ `;
+
+ debugMenu.addDebugTool('Chat Controls', content);
+
+ // Set up event listener for the toggle
+ const toggleElement = document.getElementById('instant-chat-toggle') as HTMLInputElement;
+ if (toggleElement) {
+ // Set initial state
+ toggleElement.checked = instantChatEnabled;
+
+ // Handle toggle changes
+ toggleElement.addEventListener('change', (e) => {
+ const target = e.target as HTMLInputElement;
+ instantChatEnabled = target.checked;
+
+ if (config.isDebugMode) {
+ console.log(`Instant chat ${instantChatEnabled ? 'enabled' : 'disabled'}`);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/ai_animation/src/domElements/chatWindows.ts b/ai_animation/src/domElements/chatWindows.ts
index a28202d..8c8ce0f 100644
--- a/ai_animation/src/domElements/chatWindows.ts
+++ b/ai_animation/src/domElements/chatWindows.ts
@@ -4,6 +4,7 @@ import { config } from "../config";
import { advanceToNextPhase } from "../phase";
import { getPowerDisplayName, getAllPowerDisplayNames } from '../utils/powerNames';
import { PowerENUM } from '../types/map';
+import { isInstantChatEnabled } from '../debug/instantChat';
//TODO: Sometimes the LLMs use lists, and they don't work in the chats. The just appear as bullets within a single line.
@@ -165,8 +166,8 @@ export function updateChatWindows(phase: any, stepMessages = false) {
console.log(`Found ${relevantMessages.length} messages for player ${gameState.currentPower} in phase ${phase.name}`);
}
- if (!stepMessages) {
- // Normal mode: show all messages at once
+ if (!stepMessages || isInstantChatEnabled()) {
+ // Normal mode or instant chat mode: show all messages at once
relevantMessages.forEach(msg => {
const isNew = addMessageToChat(msg, phase.name);
if (isNew) {
@@ -176,6 +177,65 @@ export function updateChatWindows(phase: any, stepMessages = false) {
}
});
gameState.messagesPlaying = false;
+
+ // If instant chat is enabled during stepwise mode, immediately proceed to next phase logic
+ if (stepMessages && isInstantChatEnabled()) {
+ // Trigger the same logic as the end of stepwise message display
+ if (gameState.isPlaying && !gameState.isSpeaking) {
+ if (gameState.gameData && gameState.gameData.phases) {
+ const currentPhase = gameState.gameData.phases[gameState.phaseIndex];
+
+ if (config.isDebugMode) {
+ console.log(`Instant chat enabled - processing end of phase ${currentPhase.name}`);
+ }
+
+ // Show summary first if available
+ if (currentPhase.summary?.trim()) {
+ addToNewsBanner(`(${currentPhase.name}) ${currentPhase.summary}`);
+ }
+
+ // Get previous phase for animations
+ const prevIndex = gameState.phaseIndex > 0 ? gameState.phaseIndex - 1 : null;
+ const previousPhase = prevIndex !== null ? gameState.gameData.phases[prevIndex] : null;
+
+ // Only schedule next phase if not already scheduled
+ if (!gameState.nextPhaseScheduled) {
+ gameState.nextPhaseScheduled = true;
+
+ // Show animations for current phase's orders
+ if (previousPhase) {
+ if (config.isDebugMode) {
+ console.log(`Animating orders from ${previousPhase.name} to ${currentPhase.name}`);
+ }
+
+ // After animations complete, advance to next phase with longer delay
+ gameState.playbackTimer = setTimeout(() => {
+ if (gameState.isPlaying) {
+ if (config.isDebugMode) {
+ console.log(`Animations complete, advancing from ${currentPhase.name}`);
+ }
+ advanceToNextPhase();
+ }
+ }, config.playbackSpeed + config.animationDuration); // Wait for both summary and animations
+ } else {
+ // For first phase, use shorter delay since there are no animations
+ if (config.isDebugMode) {
+ console.log(`First phase ${currentPhase.name} - no animations to wait for`);
+ }
+
+ gameState.playbackTimer = setTimeout(() => {
+ if (gameState.isPlaying) {
+ if (config.isDebugMode) {
+ console.log(`Advancing from first phase ${currentPhase.name}`);
+ }
+ advanceToNextPhase();
+ }
+ }, config.playbackSpeed); // Only wait for summary, no animation delay
+ }
+ }
+ }
+ }
+ }
} else {
// Stepwise mode: show one message at a time, animating word-by-word
gameState.messagesPlaying = true;
diff --git a/ai_animation/src/gameState.ts b/ai_animation/src/gameState.ts
index be280c7..658e0ba 100644
--- a/ai_animation/src/gameState.ts
+++ b/ai_animation/src/gameState.ts
@@ -290,7 +290,7 @@ class GameState {
// If there is more than one moment per turn, only return the largest one.
if (momentMatch.length > 1) {
momentMatch = momentMatch.sort((a, b) => {
- return a.interest_score - b.interest_score
+ return b.interest_score - a.interest_score
})
}
diff --git a/ai_animation/src/phase.ts b/ai_animation/src/phase.ts
index f729458..b9fbf6f 100644
--- a/ai_animation/src/phase.ts
+++ b/ai_animation/src/phase.ts
@@ -1,6 +1,6 @@
import { gameState } from "./gameState";
import { logger } from "./logger";
-import { debugMenu, updatePhaseDisplay } from "./domElements";
+import { updatePhaseDisplay } from "./domElements";
import { initUnits } from "./units/create";
import { updateSupplyCenterOwnership, updateLeaderboard, updateMapOwnership as _updateMapOwnership } from "./map/state";
import { updateChatWindows, addToNewsBanner } from "./domElements/chatWindows";
@@ -8,9 +8,12 @@ import { createAnimationsForNextPhase } from "./units/animate";
import { speakSummary } from "./speech";
import { config } from "./config";
import { debugMenuInstance } from "./debug/debugMenu";
-
+import { showTwoPowerConversation, closeTwoPowerConversation } from "./components/twoPowerConversation";
+import { PowerENUM } from "./types/map";
const MOMENT_THRESHOLD = 8.0
+// If we're in debug mode, show it quick, otherwise show it for 30 seconds
+const MOMENT_DISPLAY_TIMEOUT_MS = config.isDebugMode ? 5000 : 30000
// FIXME: Going to previous phases is borked. Units do not animate properly, map doesn't update.
function _setPhase(phaseIndex: number) {
@@ -67,11 +70,15 @@ export function nextPhase() {
setTimeout(() => {
closeTwoPowerConversation()
gameState.isDisplayingMoment = false
- }, 2000)
+ _setPhase(gameState.phaseIndex + 1)
+ }, MOMENT_DISPLAY_TIMEOUT_MS)
}
+ else {
+
+ _setPhase(gameState.phaseIndex + 1)
+ }
}
- _setPhase(gameState.phaseIndex + 1)
}
export function previousPhase() {