mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 08:00:43 +00:00
add difficulties
This commit is contained in:
+28
-25
@@ -1,18 +1,18 @@
|
|||||||
import {Executor} from "../core/execution/ExecutionManager";
|
import { Executor } from "../core/execution/ExecutionManager";
|
||||||
import {Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TileEvent, Player, Game, BoatEvent, Tile, PlayerType, GameMap} from "../core/game/Game";
|
import { Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TileEvent, Player, Game, BoatEvent, Tile, PlayerType, GameMap, Difficulty } from "../core/game/Game";
|
||||||
import {createGame} from "../core/game/GameImpl";
|
import { createGame } from "../core/game/GameImpl";
|
||||||
import {EventBus} from "../core/EventBus";
|
import { EventBus } from "../core/EventBus";
|
||||||
import {Config, getConfig} from "../core/configuration/Config";
|
import { Config, getConfig } from "../core/configuration/Config";
|
||||||
import {createRenderer, GameRenderer} from "./graphics/GameRenderer";
|
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";
|
||||||
import {InputHandler, MouseUpEvent, ZoomEvent, DragEvent, MouseDownEvent} from "./InputHandler"
|
import { InputHandler, MouseUpEvent, ZoomEvent, DragEvent, MouseDownEvent } from "./InputHandler"
|
||||||
import {ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, ClientLeaveMessageSchema, ClientMessageSchema, GameID, Intent, ServerMessage, ServerMessageSchema, ServerSyncMessage, Turn} from "../core/Schemas";
|
import { ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, ClientLeaveMessageSchema, ClientMessageSchema, GameID, Intent, ServerMessage, ServerMessageSchema, ServerSyncMessage, Turn } from "../core/Schemas";
|
||||||
import {loadTerrainMap, TerrainMap} from "../core/game/TerrainMapLoader";
|
import { loadTerrainMap, TerrainMap } from "../core/game/TerrainMapLoader";
|
||||||
import {and, bfs, dist, manhattanDist} from "../core/Util";
|
import { and, bfs, dist, manhattanDist } from "../core/Util";
|
||||||
import {WinCheckExecution} from "../core/execution/WinCheckExecution";
|
import { WinCheckExecution } from "../core/execution/WinCheckExecution";
|
||||||
import {SendAttackIntentEvent, SendSpawnIntentEvent, Transport} from "./Transport";
|
import { SendAttackIntentEvent, SendSpawnIntentEvent, Transport } from "./Transport";
|
||||||
import {createCanvas} from "./graphics/Utils";
|
import { createCanvas } from "./graphics/Utils";
|
||||||
import {DisplayMessageEvent, MessageType} from "./graphics/layers/EventsDisplay";
|
import { DisplayMessageEvent, MessageType } from "./graphics/layers/EventsDisplay";
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
|
||||||
export interface LobbyConfig {
|
export interface LobbyConfig {
|
||||||
@@ -21,13 +21,14 @@ export interface LobbyConfig {
|
|||||||
gameID: GameID
|
gameID: GameID
|
||||||
ip: string | null
|
ip: string | null
|
||||||
map: GameMap | null
|
map: GameMap | null
|
||||||
|
difficulty: Difficulty | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GameConfig {
|
export interface GameConfig {
|
||||||
map: GameMap
|
map: GameMap
|
||||||
|
difficulty: Difficulty
|
||||||
clientID: ClientID,
|
clientID: ClientID,
|
||||||
gameID: GameID,
|
gameID: GameID,
|
||||||
ip: string | null,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function joinLobby(lobbyConfig: LobbyConfig, onjoin: () => void): () => void {
|
export function joinLobby(lobbyConfig: LobbyConfig, onjoin: () => void): () => void {
|
||||||
@@ -35,11 +36,11 @@ export function joinLobby(lobbyConfig: LobbyConfig, onjoin: () => void): () => v
|
|||||||
const playerID = uuidv4()
|
const playerID = uuidv4()
|
||||||
const eventBus = new EventBus()
|
const eventBus = new EventBus()
|
||||||
const config = getConfig()
|
const config = getConfig()
|
||||||
const transport = new Transport(lobbyConfig.isLocal, eventBus, lobbyConfig.gameID, clientID, playerID, config, lobbyConfig.playerName)
|
const transport = new Transport(lobbyConfig.isLocal, eventBus, lobbyConfig.gameID, lobbyConfig.ip, clientID, playerID, config, lobbyConfig.playerName)
|
||||||
|
|
||||||
const onconnect = () => {
|
const onconnect = () => {
|
||||||
console.log('Joined game lobby!');
|
console.log('Joined game lobby!');
|
||||||
transport.joinGame(clientID, 0)
|
transport.joinGame(0)
|
||||||
};
|
};
|
||||||
const onmessage = (message: ServerMessage) => {
|
const onmessage = (message: ServerMessage) => {
|
||||||
if (message.type == "start") {
|
if (message.type == "start") {
|
||||||
@@ -47,6 +48,7 @@ export function joinLobby(lobbyConfig: LobbyConfig, onjoin: () => void): () => v
|
|||||||
onjoin()
|
onjoin()
|
||||||
const gameConfig = {
|
const gameConfig = {
|
||||||
map: message.config?.gameMap || lobbyConfig.map,
|
map: message.config?.gameMap || lobbyConfig.map,
|
||||||
|
difficulty: message.config?.difficulty || lobbyConfig.difficulty,
|
||||||
clientID: clientID,
|
clientID: clientID,
|
||||||
gameID: lobbyConfig.gameID,
|
gameID: lobbyConfig.gameID,
|
||||||
ip: lobbyConfig.ip,
|
ip: lobbyConfig.ip,
|
||||||
@@ -71,14 +73,16 @@ export async function createClientGame(gameConfig: GameConfig, eventBus: EventBu
|
|||||||
const canvas = createCanvas()
|
const canvas = createCanvas()
|
||||||
let gameRenderer = createRenderer(canvas, game, eventBus, gameConfig.clientID)
|
let gameRenderer = createRenderer(canvas, game, eventBus, gameConfig.clientID)
|
||||||
|
|
||||||
|
|
||||||
|
console.log(`creating private game got difficulty: ${gameConfig.difficulty}`)
|
||||||
|
|
||||||
return new GameRunner(
|
return new GameRunner(
|
||||||
gameConfig.clientID,
|
gameConfig,
|
||||||
gameConfig.ip,
|
|
||||||
eventBus,
|
eventBus,
|
||||||
game,
|
game,
|
||||||
gameRenderer,
|
gameRenderer,
|
||||||
new InputHandler(canvas, eventBus),
|
new InputHandler(canvas, eventBus),
|
||||||
new Executor(game, gameConfig.gameID),
|
new Executor(game, gameConfig.difficulty, gameConfig.gameID),
|
||||||
transport,
|
transport,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -96,8 +100,7 @@ export class GameRunner {
|
|||||||
private hasJoined = false
|
private hasJoined = false
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private id: ClientID,
|
private gameConfig: GameConfig,
|
||||||
private clientIP: string | null,
|
|
||||||
private eventBus: EventBus,
|
private eventBus: EventBus,
|
||||||
private gs: Game,
|
private gs: Game,
|
||||||
private renderer: GameRenderer,
|
private renderer: GameRenderer,
|
||||||
@@ -122,7 +125,7 @@ export class GameRunner {
|
|||||||
|
|
||||||
const onconnect = () => {
|
const onconnect = () => {
|
||||||
console.log('Connected to game server!');
|
console.log('Connected to game server!');
|
||||||
this.transport.joinGame(this.clientIP, this.turns.length)
|
this.transport.joinGame(this.turns.length)
|
||||||
};
|
};
|
||||||
const onmessage = (message: ServerMessage) => {
|
const onmessage = (message: ServerMessage) => {
|
||||||
if (message.type == "start") {
|
if (message.type == "start") {
|
||||||
@@ -170,7 +173,7 @@ export class GameRunner {
|
|||||||
|
|
||||||
private playerEvent(event: PlayerEvent) {
|
private playerEvent(event: PlayerEvent) {
|
||||||
console.log('received new player event!')
|
console.log('received new player event!')
|
||||||
if (event.player.clientID() == this.id) {
|
if (event.player.clientID() == this.gameConfig.clientID) {
|
||||||
console.log('setting name')
|
console.log('setting name')
|
||||||
this.myPlayer = event.player
|
this.myPlayer = event.player
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import {LitElement, html, css} from 'lit';
|
import { LitElement, html, css } from 'lit';
|
||||||
import {customElement, property, state} from 'lit/decorators.js';
|
import { customElement, property, state } from 'lit/decorators.js';
|
||||||
import {GameMap} from '../core/game/Game';
|
import { Difficulty, GameMap } from '../core/game/Game';
|
||||||
import {Lobby} from '../core/Schemas';
|
import { Lobby } from '../core/Schemas';
|
||||||
|
|
||||||
@customElement('host-lobby-modal')
|
@customElement('host-lobby-modal')
|
||||||
export class HostLobbyModal extends LitElement {
|
export class HostLobbyModal extends LitElement {
|
||||||
@state() private isModalOpen = false;
|
@state() private isModalOpen = false;
|
||||||
@state() private selectedMap: GameMap = GameMap.World;
|
@state() private selectedMap: GameMap = GameMap.World;
|
||||||
|
@state() private selectedDiffculty: Difficulty = Difficulty.Medium;
|
||||||
@state() private lobbyId = 'a345d';
|
@state() private lobbyId = 'a345d';
|
||||||
@state() private copySuccess = false;
|
@state() private copySuccess = false;
|
||||||
|
|
||||||
@@ -120,6 +121,18 @@ export class HostLobbyModal extends LitElement {
|
|||||||
`)}
|
`)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="map-select">Difficulty: </label>
|
||||||
|
<select id="map-select" @change=${this.handleDifficultyChange}>
|
||||||
|
${Object.entries(Difficulty)
|
||||||
|
.filter(([key]) => isNaN(Number(key)))
|
||||||
|
.map(([key, value]) => html`
|
||||||
|
<option value=${value} ?selected=${this.selectedDiffculty === value}>
|
||||||
|
${key}
|
||||||
|
</option>
|
||||||
|
`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<button @click=${this.startGame}>Start Game</button>
|
<button @click=${this.startGame}>Start Game</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,6 +151,7 @@ export class HostLobbyModal extends LitElement {
|
|||||||
id: this.lobbyId,
|
id: this.lobbyId,
|
||||||
},
|
},
|
||||||
map: this.selectedMap,
|
map: this.selectedMap,
|
||||||
|
difficulty: this.selectedDiffculty,
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
@@ -155,15 +169,25 @@ export class HostLobbyModal extends LitElement {
|
|||||||
private async handleMapChange(e: Event) {
|
private async handleMapChange(e: Event) {
|
||||||
this.selectedMap = Number((e.target as HTMLSelectElement).value) as GameMap;
|
this.selectedMap = Number((e.target as HTMLSelectElement).value) as GameMap;
|
||||||
console.log(`updating map to ${this.selectedMap}`)
|
console.log(`updating map to ${this.selectedMap}`)
|
||||||
|
this.putGameConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleDifficultyChange(e: Event) {
|
||||||
|
this.selectedDiffculty = Number((e.target as HTMLSelectElement).value) as Difficulty;
|
||||||
|
console.log(`updating difficulty to ${this.selectedDiffculty}`)
|
||||||
|
this.putGameConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async putGameConfig() {
|
||||||
const response = await fetch(`/private_lobby/${this.lobbyId}`, {
|
const response = await fetch(`/private_lobby/${this.lobbyId}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({gameMap: this.selectedMap})
|
body: JSON.stringify({ gameMap: this.selectedMap, difficulty: this.selectedDiffculty })
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async startGame() {
|
private async startGame() {
|
||||||
console.log(`Starting private game with map: ${GameMap[this.selectedMap]}`);
|
console.log(`Starting private game with map: ${GameMap[this.selectedMap]}`);
|
||||||
this.close();
|
this.close();
|
||||||
|
|||||||
+7
-6
@@ -1,14 +1,14 @@
|
|||||||
import {GameRunner, joinLobby} from "./ClientGame";
|
import { GameRunner, joinLobby } from "./ClientGame";
|
||||||
import backgroundImage from '../../resources/images/TerrainMapFrontPage.png';
|
import backgroundImage from '../../resources/images/TerrainMapFrontPage.png';
|
||||||
import favicon from '../../resources/images/Favicon.png';
|
import favicon from '../../resources/images/Favicon.png';
|
||||||
|
|
||||||
import './PublicLobby';
|
import './PublicLobby';
|
||||||
import './UsernameInput';
|
import './UsernameInput';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
import {UsernameInput} from "./UsernameInput";
|
import { UsernameInput } from "./UsernameInput";
|
||||||
import {SinglePlayerModal} from "./SinglePlayerModal";
|
import { SinglePlayerModal } from "./SinglePlayerModal";
|
||||||
import {HostLobbyModal as HostPrivateLobbyModal} from "./HostLobbyModal";
|
import { HostLobbyModal as HostPrivateLobbyModal } from "./HostLobbyModal";
|
||||||
import {JoinPrivateLobbyModal} from "./JoinPrivateLobbyModal";
|
import { JoinPrivateLobbyModal } from "./JoinPrivateLobbyModal";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -77,6 +77,7 @@ class Client {
|
|||||||
gameID: lobby.id,
|
gameID: lobby.id,
|
||||||
ip: clientIP,
|
ip: clientIP,
|
||||||
map: event.detail.map,
|
map: event.detail.map,
|
||||||
|
difficulty: event.detail.difficulty,
|
||||||
},
|
},
|
||||||
() => this.joinModal.close()
|
() => this.joinModal.close()
|
||||||
);
|
);
|
||||||
@@ -115,7 +116,7 @@ async function getClientIP(timeoutMs: number = 1000): Promise<string | null> {
|
|||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: {ip: string} = await response.json();
|
const data: { ip: string } = await response.json();
|
||||||
return data.ip;
|
return data.ip;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {LitElement, html, css} from 'lit';
|
import { LitElement, html, css } from 'lit';
|
||||||
import {customElement, state} from 'lit/decorators.js';
|
import { customElement, state } from 'lit/decorators.js';
|
||||||
import {Lobby} from "../core/Schemas";
|
import { Lobby } from "../core/Schemas";
|
||||||
import {GameMap} from '../core/game/Game';
|
import { Difficulty, GameMap } from '../core/game/Game';
|
||||||
|
|
||||||
@customElement('public-lobby')
|
@customElement('public-lobby')
|
||||||
export class PublicLobby extends LitElement {
|
export class PublicLobby extends LitElement {
|
||||||
@@ -113,13 +113,14 @@ export class PublicLobby extends LitElement {
|
|||||||
lobby: lobby,
|
lobby: lobby,
|
||||||
singlePlayer: false,
|
singlePlayer: false,
|
||||||
map: GameMap.World,
|
map: GameMap.World,
|
||||||
|
difficulty: Difficulty.Medium,
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
this.dispatchEvent(new CustomEvent('leave-lobby', {
|
this.dispatchEvent(new CustomEvent('leave-lobby', {
|
||||||
detail: {lobby: this.currLobby},
|
detail: { lobby: this.currLobby },
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import {LitElement, html, css} from 'lit';
|
import { LitElement, html, css } from 'lit';
|
||||||
import {customElement, property, state} from 'lit/decorators.js';
|
import { customElement, property, state } from 'lit/decorators.js';
|
||||||
import {GameMap} from '../core/game/Game';
|
import { Difficulty, GameMap } from '../core/game/Game';
|
||||||
|
|
||||||
@customElement('single-player-modal')
|
@customElement('single-player-modal')
|
||||||
export class SinglePlayerModal extends LitElement {
|
export class SinglePlayerModal extends LitElement {
|
||||||
@state() private isModalOpen = false;
|
@state() private isModalOpen = false;
|
||||||
@state() private selectedMap: GameMap = GameMap.World;
|
@state() private selectedMap: GameMap = GameMap.World;
|
||||||
|
@state() private selectedDifficulty: Difficulty = Difficulty.Medium;
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
@@ -87,6 +88,19 @@ export class SinglePlayerModal extends LitElement {
|
|||||||
`)}
|
`)}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="map-select">Difficulty: </label>
|
||||||
|
<select id="map-select" @change=${this.handleDifficultyChange}>
|
||||||
|
${Object.entries(Difficulty)
|
||||||
|
.filter(([key]) => isNaN(Number(key)))
|
||||||
|
.map(([key, value]) => html`
|
||||||
|
<option value=${value} ?selected=${this.selectedDifficulty === value}>
|
||||||
|
${key}
|
||||||
|
</option>
|
||||||
|
`)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button @click=${this.startGame}>Start Game</button>
|
<button @click=${this.startGame}>Start Game</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -104,7 +118,9 @@ export class SinglePlayerModal extends LitElement {
|
|||||||
private handleMapChange(e: Event) {
|
private handleMapChange(e: Event) {
|
||||||
this.selectedMap = Number((e.target as HTMLSelectElement).value) as GameMap;
|
this.selectedMap = Number((e.target as HTMLSelectElement).value) as GameMap;
|
||||||
}
|
}
|
||||||
|
private handleDifficultyChange(e: Event) {
|
||||||
|
this.selectedDifficulty = Number((e.target as HTMLSelectElement).value) as Difficulty;
|
||||||
|
}
|
||||||
private startGame() {
|
private startGame() {
|
||||||
console.log(`Starting single player game with map: ${GameMap[this.selectedMap]}`);
|
console.log(`Starting single player game with map: ${GameMap[this.selectedMap]}`);
|
||||||
this.dispatchEvent(new CustomEvent('join-lobby', {
|
this.dispatchEvent(new CustomEvent('join-lobby', {
|
||||||
@@ -114,6 +130,7 @@ export class SinglePlayerModal extends LitElement {
|
|||||||
id: "LOCAL",
|
id: "LOCAL",
|
||||||
},
|
},
|
||||||
map: this.selectedMap,
|
map: this.selectedMap,
|
||||||
|
difficulty: this.selectedDifficulty
|
||||||
},
|
},
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ export class Transport {
|
|||||||
private isLocal: boolean,
|
private isLocal: boolean,
|
||||||
private eventBus: EventBus,
|
private eventBus: EventBus,
|
||||||
private gameID: GameID,
|
private gameID: GameID,
|
||||||
|
private clientIP: string | null,
|
||||||
private clientID: ClientID,
|
private clientID: ClientID,
|
||||||
private playerID: PlayerID,
|
private playerID: PlayerID,
|
||||||
private config: Config,
|
private config: Config,
|
||||||
@@ -156,14 +157,14 @@ export class Transport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
joinGame(clientIP: string | null, numTurns: number) {
|
joinGame(numTurns: number) {
|
||||||
this.sendMsg(
|
this.sendMsg(
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
ClientJoinMessageSchema.parse({
|
ClientJoinMessageSchema.parse({
|
||||||
type: "join",
|
type: "join",
|
||||||
gameID: this.gameID,
|
gameID: this.gameID,
|
||||||
clientID: this.clientID,
|
clientID: this.clientID,
|
||||||
clientIP: clientIP,
|
clientIP: this.clientIP,
|
||||||
lastTurn: numTurns
|
lastTurn: numTurns
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag() {dataLayer.push(arguments);}
|
function gtag() { dataLayer.push(arguments); }
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
gtag('config', 'AW-16702609763');
|
gtag('config', 'AW-16702609763');
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<h1 class="text-7xl sm:text-5xl md:text-6xl lg:text-7xl mb-2">OpenFront.io</h1>
|
<h1 class="text-7xl sm:text-5xl md:text-6xl lg:text-7xl mb-2">OpenFront.io</h1>
|
||||||
<h2 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl mb-4">(v0.7.1)</h2>
|
<h2 class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl mb-4">(v0.7.2)</h2>
|
||||||
<div class="flex justify-center items-start">
|
<div class="flex justify-center items-start">
|
||||||
<div class="w-full max-w-3xl p-4 space-y-4">
|
<div class="w-full max-w-3xl p-4 space-y-4">
|
||||||
<username-input></username-input>
|
<username-input></username-input>
|
||||||
|
|||||||
+4
-3
@@ -1,5 +1,5 @@
|
|||||||
import {z} from 'zod';
|
import { z } from 'zod';
|
||||||
import {GameMap, PlayerType} from './game/Game';
|
import { Difficulty, GameMap, PlayerType } from './game/Game';
|
||||||
|
|
||||||
export type GameID = string
|
export type GameID = string
|
||||||
export type ClientID = string
|
export type ClientID = string
|
||||||
@@ -53,7 +53,8 @@ export interface Lobby {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GameConfigSchema = z.object({
|
const GameConfigSchema = z.object({
|
||||||
gameMap: z.nativeEnum(GameMap)
|
gameMap: z.nativeEnum(GameMap),
|
||||||
|
difficulty: z.nativeEnum(Difficulty)
|
||||||
})
|
})
|
||||||
|
|
||||||
const EmojiSchema = z.string().refine(
|
const EmojiSchema = z.string().refine(
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tick, Tile} from "../game/Game";
|
import { Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tick, Tile } from "../game/Game";
|
||||||
import {GameID} from "../Schemas";
|
import { GameID } from "../Schemas";
|
||||||
import {simpleHash, within} from "../Util";
|
import { simpleHash, within } from "../Util";
|
||||||
import {Config, Theme} from "./Config";
|
import { Config, Theme } from "./Config";
|
||||||
import {pastelTheme} from "./PastelTheme";
|
import { pastelTheme } from "./PastelTheme";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -55,9 +55,9 @@ export class DefaultConfig implements Config {
|
|||||||
lobbyLifetime(): number {
|
lobbyLifetime(): number {
|
||||||
return 120 * 1000
|
return 120 * 1000
|
||||||
}
|
}
|
||||||
theme(): Theme {return pastelTheme;}
|
theme(): Theme { return pastelTheme; }
|
||||||
|
|
||||||
attackLogic(attackTroops: number, attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): {attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number} {
|
attackLogic(attackTroops: number, attacker: Player, defender: Player | TerraNullius, tileToConquer: Tile): { attackerTroopLoss: number; defenderTroopLoss: number; tilesPerTickUsed: number } {
|
||||||
let mag = 0
|
let mag = 0
|
||||||
let speed = 0
|
let speed = 0
|
||||||
switch (tileToConquer.terrain()) {
|
switch (tileToConquer.terrain()) {
|
||||||
@@ -125,7 +125,7 @@ export class DefaultConfig implements Config {
|
|||||||
return 10000
|
return 10000
|
||||||
}
|
}
|
||||||
if (playerInfo.playerType == PlayerType.FakeHuman) {
|
if (playerInfo.playerType == PlayerType.FakeHuman) {
|
||||||
return 25000
|
return 2500 // start troops * strength * difficulty
|
||||||
}
|
}
|
||||||
return 25000
|
return 25000
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerInfo, TerraNullius, Tile, PlayerType, Alliance, AllianceRequestReplyEvent} from "../game/Game";
|
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerInfo, TerraNullius, Tile, PlayerType, Alliance, AllianceRequestReplyEvent, Difficulty} from "../game/Game";
|
||||||
import {AttackIntent, BoatAttackIntentSchema, GameID, Intent, Turn} from "../Schemas";
|
import {AttackIntent, BoatAttackIntentSchema, GameID, Intent, Turn} from "../Schemas";
|
||||||
import {AttackExecution} from "./AttackExecution";
|
import {AttackExecution} from "./AttackExecution";
|
||||||
import {SpawnExecution} from "./SpawnExecution";
|
import {SpawnExecution} from "./SpawnExecution";
|
||||||
@@ -26,7 +26,7 @@ export class Executor {
|
|||||||
// private random = new PseudoRandom(999)
|
// private random = new PseudoRandom(999)
|
||||||
private random: PseudoRandom = null
|
private random: PseudoRandom = null
|
||||||
|
|
||||||
constructor(private gs: Game, private gameID: GameID) {
|
constructor(private gs: Game, private difficulty: Difficulty, private gameID: GameID) {
|
||||||
// Add one to avoid id collisions with bots.
|
// Add one to avoid id collisions with bots.
|
||||||
this.random = new PseudoRandom(simpleHash(gameID) + 1)
|
this.random = new PseudoRandom(simpleHash(gameID) + 1)
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ export class Executor {
|
|||||||
this.random.nextID()
|
this.random.nextID()
|
||||||
),
|
),
|
||||||
nation.cell,
|
nation.cell,
|
||||||
nation.strength
|
nation.strength * this.difficulty
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
return execs
|
return execs
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile} from "../game/Game"
|
import { Cell, Execution, MutableGame, MutablePlayer, Player, PlayerInfo, PlayerType, TerrainType, TerraNullius, Tile } from "../game/Game"
|
||||||
import {PseudoRandom} from "../PseudoRandom"
|
import { PseudoRandom } from "../PseudoRandom"
|
||||||
import {and, bfs, dist, simpleHash} from "../Util";
|
import { and, bfs, dist, simpleHash } from "../Util";
|
||||||
import {AttackExecution} from "./AttackExecution";
|
import { AttackExecution } from "./AttackExecution";
|
||||||
import {BoatAttackExecution} from "./BoatAttackExecution";
|
import { BoatAttackExecution } from "./BoatAttackExecution";
|
||||||
import {SpawnExecution} from "./SpawnExecution";
|
import { SpawnExecution } from "./SpawnExecution";
|
||||||
|
|
||||||
export class FakeHumanExecution implements Execution {
|
export class FakeHumanExecution implements Execution {
|
||||||
|
|
||||||
|
private firstMove = true
|
||||||
|
|
||||||
private active = true
|
private active = true
|
||||||
private random: PseudoRandom;
|
private random: PseudoRandom;
|
||||||
private attackRate: number
|
private attackRate: number
|
||||||
@@ -56,6 +58,11 @@ export class FakeHumanExecution implements Execution {
|
|||||||
this.player.setTroops(this.player.troops() * this.strength)
|
this.player.setTroops(this.player.troops() * this.strength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.firstMove) {
|
||||||
|
this.firstMove = false
|
||||||
|
this.sendAttack(this.mg.terraNullius())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (this.player.troops() < this.mg.config().maxTroops(this.player) / 4) {
|
if (this.player.troops() < this.mg.config().maxTroops(this.player) / 4) {
|
||||||
return
|
return
|
||||||
@@ -132,7 +139,7 @@ export class FakeHumanExecution implements Execution {
|
|||||||
handleAllianceRequests() {
|
handleAllianceRequests() {
|
||||||
for (const req of this.player.incomingAllianceRequests()) {
|
for (const req of this.player.incomingAllianceRequests()) {
|
||||||
|
|
||||||
if (req.requestor().numTilesOwned() > this.player.numTilesOwned() * 2) {
|
if (req.requestor().numTilesOwned() > this.player.numTilesOwned() * 2) {
|
||||||
req.accept()
|
req.accept()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-8
@@ -1,10 +1,10 @@
|
|||||||
import {info} from "console"
|
import { info } from "console"
|
||||||
import {Config} from "../configuration/Config"
|
import { Config } from "../configuration/Config"
|
||||||
import {GameEvent} from "../EventBus"
|
import { GameEvent } from "../EventBus"
|
||||||
import {ClientID, GameID} from "../Schemas"
|
import { ClientID, GameID } from "../Schemas"
|
||||||
import {DisplayMessageEvent, MessageType} from "../../client/graphics/layers/EventsDisplay"
|
import { DisplayMessageEvent, MessageType } from "../../client/graphics/layers/EventsDisplay"
|
||||||
import {BreakAllianceExecution} from "../execution/alliance/BreakAllianceExecution"
|
import { BreakAllianceExecution } from "../execution/alliance/BreakAllianceExecution"
|
||||||
import {DonateExecution} from "../execution/DonateExecution"
|
import { DonateExecution } from "../execution/DonateExecution"
|
||||||
|
|
||||||
export type PlayerID = string
|
export type PlayerID = string
|
||||||
export type Tick = number
|
export type Tick = number
|
||||||
@@ -12,6 +12,13 @@ export type Currency = number
|
|||||||
|
|
||||||
export const AllPlayers = "AllPlayers" as const;
|
export const AllPlayers = "AllPlayers" as const;
|
||||||
|
|
||||||
|
export enum Difficulty {
|
||||||
|
Easy = 1,
|
||||||
|
Medium = 3,
|
||||||
|
Hard = 6,
|
||||||
|
Impossible = 12,
|
||||||
|
}
|
||||||
|
|
||||||
export enum GameMap {
|
export enum GameMap {
|
||||||
World,
|
World,
|
||||||
Europe
|
Europe
|
||||||
@@ -45,7 +52,7 @@ export class Cell {
|
|||||||
this.strRepr = `Cell[${this.x},${this.y}]`
|
this.strRepr = `Cell[${this.x},${this.y}]`
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {return this.strRepr}
|
toString(): string { return this.strRepr }
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TerrainType {
|
export enum TerrainType {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {Config} from "../core/configuration/Config";
|
import { Config } from "../core/configuration/Config";
|
||||||
import {ClientID, GameConfig, GameID} from "../core/Schemas";
|
import { ClientID, GameConfig, GameID } from "../core/Schemas";
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import {Client} from "./Client";
|
import { Client } from "./Client";
|
||||||
import {GamePhase, GameServer} from "./GameServer";
|
import { GamePhase, GameServer } from "./GameServer";
|
||||||
import {GameMap} from "../core/game/Game";
|
import { Difficulty, GameMap } from "../core/game/Game";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export class GameManager {
|
|||||||
|
|
||||||
createPrivateGame(): string {
|
createPrivateGame(): string {
|
||||||
const id = genSmallGameID()
|
const id = genSmallGameID()
|
||||||
this.games.push(new GameServer(id, Date.now(), false, this.config, {gameMap: GameMap.World}))
|
this.games.push(new GameServer(id, Date.now(), false, this.config, { gameMap: GameMap.World, difficulty: Difficulty.Medium }))
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ export class GameManager {
|
|||||||
if (now > this.lastNewLobby + this.config.gameCreationRate()) {
|
if (now > this.lastNewLobby + this.config.gameCreationRate()) {
|
||||||
this.lastNewLobby = now
|
this.lastNewLobby = now
|
||||||
const id = uuidv4()
|
const id = uuidv4()
|
||||||
lobbies.push(new GameServer(id, now, true, this.config, {gameMap: GameMap.World}))
|
lobbies.push(new GameServer(id, now, true, this.config, { gameMap: GameMap.World, difficulty: Difficulty.Medium }))
|
||||||
}
|
}
|
||||||
|
|
||||||
active.filter(g => !g.hasStarted() && g.isPublic).forEach(g => {
|
active.filter(g => !g.hasStarted() && g.isPublic).forEach(g => {
|
||||||
|
|||||||
@@ -30,12 +30,16 @@ export class GameServer {
|
|||||||
public readonly isPublic: boolean,
|
public readonly isPublic: boolean,
|
||||||
private config: Config,
|
private config: Config,
|
||||||
private gameConfig: GameConfig,
|
private gameConfig: GameConfig,
|
||||||
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public updateGameConfig(gameConfig: GameConfig): void {
|
public updateGameConfig(gameConfig: GameConfig): void {
|
||||||
if (gameConfig.gameMap != null) {
|
if (gameConfig.gameMap != null) {
|
||||||
this.gameConfig.gameMap = gameConfig.gameMap
|
this.gameConfig.gameMap = gameConfig.gameMap
|
||||||
}
|
}
|
||||||
|
if(gameConfig.difficulty != null) {
|
||||||
|
this.gameConfig.difficulty = gameConfig.difficulty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public addClient(client: Client, lastTurn: number) {
|
public addClient(client: Client, lastTurn: number) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ app.post('/start_private_lobby/:id', (req, res) => {
|
|||||||
|
|
||||||
app.put('/private_lobby/:id', (req, res) => {
|
app.put('/private_lobby/:id', (req, res) => {
|
||||||
const lobbyID = req.params.id
|
const lobbyID = req.params.id
|
||||||
gm.updateGameConfig(lobbyID, {gameMap: req.body.gameMap})
|
gm.updateGameConfig(lobbyID, {gameMap: req.body.gameMap, difficulty: req.body.difficulty})
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/lobby/:id/exists', (req, res) => {
|
app.get('/lobby/:id/exists', (req, res) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user