mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 11:00:43 +00:00
25ea11114e
## Description: https://github.com/openfrontio/OpenFrontIO/issues/2352 This is my first PR in this project, and I’ll continue refining it based on feedback. <img width="1088" height="859" alt="image" src="https://github.com/user-attachments/assets/07f4f8b1-52fa-4136-add4-19b00aefd963" /> <img width="1157" height="783" alt="image" src="https://github.com/user-attachments/assets/1c5be80d-72f8-4ead-8d4b-706a3a04fd73" /> <img width="1488" height="777" alt="image" src="https://github.com/user-attachments/assets/4d743548-f0c3-4579-963b-43676f68fab1" /> <img width="1499" height="778" alt="image" src="https://github.com/user-attachments/assets/f808e44f-ef97-467f-9e41-812e2857c36e" /> ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: nikolaj_mykola --------- Co-authored-by: Evan <evanpelle@gmail.com>
84 lines
1.9 KiB
TypeScript
84 lines
1.9 KiB
TypeScript
import { Game, PlayerType } from "../../game/Game";
|
|
import { TileRef } from "../../game/GameMap";
|
|
import { PseudoRandom } from "../../PseudoRandom";
|
|
import { GameID } from "../../Schemas";
|
|
import { simpleHash } from "../../Util";
|
|
import { SpawnExecution } from "../SpawnExecution";
|
|
|
|
export class PlayerSpawner {
|
|
private random: PseudoRandom;
|
|
private players: SpawnExecution[] = [];
|
|
private static readonly MAX_SPAWN_TRIES = 10_000;
|
|
private static readonly MIN_SPAWN_DISTANCE = 30;
|
|
|
|
constructor(
|
|
private gm: Game,
|
|
gameID: GameID,
|
|
) {
|
|
this.random = new PseudoRandom(simpleHash(gameID));
|
|
}
|
|
|
|
private randTile(): TileRef {
|
|
const x = this.random.nextInt(0, this.gm.width());
|
|
const y = this.random.nextInt(0, this.gm.height());
|
|
|
|
return this.gm.ref(x, y);
|
|
}
|
|
|
|
private randomSpawnLand(): TileRef | null {
|
|
let tries = 0;
|
|
|
|
while (tries < PlayerSpawner.MAX_SPAWN_TRIES) {
|
|
tries++;
|
|
|
|
const tile = this.randTile();
|
|
|
|
if (
|
|
!this.gm.isLand(tile) ||
|
|
this.gm.hasOwner(tile) ||
|
|
this.gm.isBorder(tile)
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
let tooCloseToOtherPlayer = false;
|
|
for (const spawn of this.players) {
|
|
if (
|
|
this.gm.manhattanDist(spawn.tile, tile) <
|
|
PlayerSpawner.MIN_SPAWN_DISTANCE
|
|
) {
|
|
tooCloseToOtherPlayer = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tooCloseToOtherPlayer) {
|
|
continue;
|
|
}
|
|
|
|
return tile;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
spawnPlayers(): SpawnExecution[] {
|
|
for (const player of this.gm.allPlayers()) {
|
|
if (player.type() !== PlayerType.Human) {
|
|
continue;
|
|
}
|
|
|
|
const spawnLand = this.randomSpawnLand();
|
|
|
|
if (spawnLand === null) {
|
|
// TODO: this should normally not happen, additional logic may be needed, if this occurs
|
|
continue;
|
|
}
|
|
|
|
this.players.push(new SpawnExecution(player.info(), spawnLand));
|
|
}
|
|
|
|
return this.players;
|
|
}
|
|
}
|