Skip to content
Closed

_ #2011

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions HOW_TO_RUN_THE_BOT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# 🤖 How to Run the OpenFront AI Bot

The AI bot has been **fully integrated** and is ready to use! Here's how to run it:

## 🚀 Quick Start (2 steps)

### 1. Start OpenFrontIO

```bash
npm start
```

### 2. Start a Singleplayer Game

- Go to "Single Player" in the main menu
- Choose any map and settings
- Start the game

**The bot is now available!** 🎉

## 🎮 Control the Bot

### Option A: Visual UI (Easiest)

1. **Look for the 🤖 icon** in the top-right corner of the game
2. **Click the icon** to open the bot control panel
3. **Click "Start Bot"** to activate AI assistance
4. **Watch the bot play!** It will:
- Automatically select optimal spawn locations
- Manage resources and troops
- Make strategic decisions
- Show real-time analysis

### Option B: Browser Console

1. **Open browser developer tools** (F12)
2. **Use these commands**:

```javascript
// Start the bot
openFrontBot.start();

// Check bot status
openFrontBot.status();

// Stop the bot
openFrontBot.stop();

// See detailed analysis
openFrontBot.analysis();

// Adjust difficulty
openFrontBot.updateConfig({ aggressiveness: 80 });
```

## 🎯 What the Bot Does

### ✅ Fully Working Features

- **Smart Spawning**: Analyzes the entire map to pick the best starting location
- **Resource Management**: Automatically adjusts troop/worker ratios
- **Strategic Analysis**: Comprehensive territory, threat, and opportunity assessment
- **Real-time Decisions**: Makes decisions every few seconds with explanations

### 🔄 Basic Implementation

- **Threat Detection**: Identifies incoming attacks and suggests responses
- **Expansion Planning**: Finds opportunities for territory growth
- **Diplomacy Analysis**: Evaluates alliance opportunities

### 🚧 Future Enhancements (Not Yet Implemented)

- Full attack execution
- Unit construction
- Naval operations
- Nuclear weapons
- Advanced diplomacy

## 🔧 Configuration
Comment on lines +71 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Doc conflict: “Nuclear weapons” listed as future work but also “enabled” on Hard

These two sections contradict each other. Please align them (either move “nuclear weapons” out of Hard or out of “Future Enhancements”).

- **Hard**: Aggressive, fast decisions, nuclear weapons enabled
+ **Hard**: Aggressive, fast decisions

Also applies to: 130-134

🧰 Tools
🪛 LanguageTool

[grammar] ~71-~71: There might be a mistake here.
Context: ...uture Enhancements (Not Yet Implemented) - Full attack execution - Unit constructio...

(QB_NEW_EN)


[grammar] ~73-~73: There might be a mistake here.
Context: ...et Implemented) - Full attack execution - Unit construction - Naval operations - N...

(QB_NEW_EN)


[grammar] ~74-~74: There might be a mistake here.
Context: ...ull attack execution - Unit construction - Naval operations - Nuclear weapons - Adv...

(QB_NEW_EN)


[grammar] ~75-~75: There might be a mistake here.
Context: ...n - Unit construction - Naval operations - Nuclear weapons - Advanced diplomacy ##...

(QB_NEW_EN)


[grammar] ~76-~76: There might be a mistake here.
Context: ...ion - Naval operations - Nuclear weapons - Advanced diplomacy ## 🔧 Configuration ...

(QB_NEW_EN)


[grammar] ~79-~79: There might be a mistake here.
Context: ... Advanced diplomacy ## 🔧 Configuration Customize bot behavior from the console:...

(QB_NEW_EN)

🤖 Prompt for AI Agents
In HOW_TO_RUN_THE_BOT.md around lines 71-79 (and also lines 130-134), the
document lists "Nuclear weapons" both as a future enhancement and as enabled in
the Hard configuration; remove the contradiction by deleting "Nuclear weapons"
from the "Future Enhancements" list and ensure the Hard configuration section
clearly documents that nuclear weapons are enabled (or, if the intended state is
disabled, instead remove/mark it disabled in the Hard config). Update both
locations (71-79 and 130-134) so only one place asserts the feature's status and
add a short note clarifying its current availability.


Customize bot behavior from the console:

```javascript
openFrontBot.updateConfig({
difficulty: "Hard", // Easy, Medium, Hard, Expert
aggressiveness: 75, // 0-100 (how often it attacks)
expansionRate: 80, // 0-100 (how fast it expands)
diplomaticStance: "Aggressive", // Peaceful, Neutral, Aggressive
});
```

## 🐛 Troubleshooting

### Bot Icon Not Showing?

- Make sure you're in a **singleplayer game** (bot doesn't work in multiplayer)
- Check browser console for "Initializing bot for singleplayer game" message

### Bot Not Making Decisions?

- Open console and run `openFrontBot.status()` to check if it's enabled
- Try `openFrontBot.forceTick()` to force a decision
- Check if the game is in spawn phase (bot waits for spawn to complete)

### Want More Debug Info?

```javascript
// See what the bot is thinking
openFrontBot.analysis();

// Check detailed status
openFrontBot.status();
```

## 🎭 Example Bot Session

```
1. Game starts → Bot icon (🤖) appears in top-right
2. Click icon → Control panel opens
3. Click "Start Bot" → Bot begins analysis
4. Spawn phase → Bot automatically selects best spawn location
5. Early game → Bot manages resources and looks for expansion
6. Mid game → Bot makes strategic decisions based on threats/opportunities
```

## 🏆 Advanced Usage

### Multiple Difficulty Levels

- **Easy**: Peaceful, slow, high confidence threshold
- **Medium**: Balanced approach (default)
- **Hard**: Aggressive, fast decisions, nuclear weapons enabled
- **Expert**: Very aggressive, risky plays, all features enabled

### Watch Bot Decisions

All bot actions are logged to the console with explanations:

```
PlayerBot: Spawning at (45, 32) with confidence 87%
Spawn reasons: Large land area (167 tiles), Isolated position, Good water access
```

---

**That's it!** The bot is ready to play OpenFrontIO. Start a singleplayer game and click the 🤖 icon to begin! 🎮
22 changes: 21 additions & 1 deletion src/client/ClientGameRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { createGameRecord } from "../core/Util";
import { ServerConfig } from "../core/configuration/Config";
import { getConfig } from "../core/configuration/ConfigLoader";
import { PlayerActions, UnitType } from "../core/game/Game";
import { GameType, PlayerActions, UnitType } from "../core/game/Game";
import { TileRef } from "../core/game/GameMap";
import { GameMapLoader } from "../core/game/GameMapLoader";
import {
Expand Down Expand Up @@ -45,6 +45,11 @@ import {
Transport,
} from "./Transport";
import { createCanvas } from "./Utils";
import {
getBotIntegration,
initializeBotIntegration,
} from "./bot/integration/BotIntegration";
import "./bot/ui/BotControlPanel"; // Import to register the web component
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";

export interface LobbyConfig {
Expand Down Expand Up @@ -205,6 +210,14 @@ export class ClientGameRunner {
private gameView: GameView,
) {
this.lastMessageTime = Date.now();

// Initialize bot integration for singleplayer games
if (this.lobby.gameStartInfo?.config.gameType === GameType.Singleplayer) {
console.log("Initializing bot for singleplayer game");
initializeBotIntegration(this.gameView, this.eventBus, {
autoStart: false, // Don't auto-start, let user control via console
});
}
Comment on lines +214 to +220
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Init looks good; add cleanup on stop() to prevent leaks.

When the game ends, the global bot instance persists. Call cleanup to stop timers and detach listeners.

Example change (outside this hunk, in stop()):

public stop(saveFullGame: boolean = false) {
  if (!this.isActive) return;
  this.isActive = false;
  // NEW: clean up bot integration if present
  try { getBotIntegration()?.cleanup(); } catch {}
  this.worker.cleanup();
  this.transport.leaveGame(saveFullGame);
  if (this.connectionCheckInterval) {
    clearInterval(this.connectionCheckInterval);
    this.connectionCheckInterval = null;
  }
}

I can wire this and add a regression test that ensures no timers remain after stop().

🤖 Prompt for AI Agents
In src/client/ClientGameRunner.ts around lines 214-220, the bot integration is
initialized for singleplayer games but never cleaned up on stop; update the
stop() method to detect and cleanup the bot integration instance before tearing
down the worker/transport (call the global getBotIntegration()?.cleanup() or
equivalent inside a try/catch), then proceed with existing cleanup
(worker.cleanup(), transport.leaveGame, clearInterval for
connectionCheckInterval) to ensure timers and listeners are removed and prevent
leaks.

}

private saveGame(update: WinUpdate) {
Expand Down Expand Up @@ -658,6 +671,13 @@ export class ClientGameRunner {
this.transport.reconnect();
}
}

/**
* Get bot integration instance for this game
*/
public getBotIntegration() {
return getBotIntegration();
}
}

function showErrorModal(
Expand Down
7 changes: 4 additions & 3 deletions src/client/SinglePlayerModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ import { renderUnitTypeOptions } from "./utilities/RenderUnitTypeOptions";

@customElement("single-player-modal")
export class SinglePlayerModal extends LitElement {
private maxBots = 4000;
@query("o-modal") private modalEl!: HTMLElement & {
open: () => void;
close: () => void;
};
@state() private selectedMap: GameMapType = GameMapType.World;
@state() private selectedDifficulty: Difficulty = Difficulty.Medium;
@state() private disableNPCs: boolean = false;
@state() private bots: number = 400;
@state() private bots: number = 2500;
@state() private infiniteGold: boolean = false;
@state() private donateGold: boolean = false;
@state() private infiniteTroops: boolean = false;
Expand Down Expand Up @@ -220,7 +221,7 @@ export class SinglePlayerModal extends LitElement {
type="range"
id="bots-count"
min="0"
max="400"
max=${this.maxBots}
step="1"
@input=${this.handleBotsChange}
@change=${this.handleBotsChange}
Expand Down Expand Up @@ -354,7 +355,7 @@ export class SinglePlayerModal extends LitElement {

private handleBotsChange(e: Event) {
const value = parseInt((e.target as HTMLInputElement).value);
if (isNaN(value) || value < 0 || value > 400) {
if (isNaN(value) || value < 0 || value > this.maxBots) {
return;
}
this.bots = value;
Expand Down
Loading
Loading