fix bot attacks each other same time bug, improve spawns

This commit is contained in:
evanpelle
2024-08-28 20:51:49 -07:00
parent 09cd7e3648
commit 7b8c5c11dd
5 changed files with 54 additions and 40 deletions
+13 -9
View File
@@ -50,16 +50,20 @@
* store & delay tile updates for lag compensation DONE 8/26/2024
* BUG: error if don't spawn and then click after spawn mode DONE 8/26/2024
* BUG: change player name after join lobby DONE 8/26/2024
* REFACTOR: use new priority queue
* BUG: players attack each other same time creates islands
* add shader to dim border
* REFACTOR: remove player.info()
* REFACTOR: use new priority queue DONE 8/27/2024
* BUG: players attack each other same time creates islands DONE 8/28/2024
* make bot spawn better DONE 8/28/2024
* make UX for attacking TerraNullius by boat better
* make bots more likely to attack weaker players
* make bot territory less funky (more likely attack neighbors with larger border)
- maybe use bounding box, bots want to be circular?
* PERF: use hierarchical a* search for boats
* precompute spawns
* end game when no players left (or after 1 hour or so?)
* boats can go around the world
* Add terrain elevation to map
* use better favicon
* REFACTOR: give terranullius an ID, game.player() returns terranullius
* REFACTOR: ocean is considered TerraNullius ?
* REFACTOR: remove player config?
* PERF: use hierarchical a* search for boats
* PERF: render tiles more efficiently
* Add terrain elevation to map
* boats can go around the world
* make bots more likely to attack weaker players
* use better favicon
+5 -4
View File
@@ -287,8 +287,8 @@ export class GameImpl implements MutableGame {
}
tick() {
this.executions().forEach(e => {
if (!this.inSpawnPhase() || e.activeDuringSpawnPhase()) {
this.execs.forEach(e => {
if (e.isActive() && (!this.inSpawnPhase() || e.activeDuringSpawnPhase())) {
e.tick(this._ticks)
}
})
@@ -349,7 +349,7 @@ export class GameImpl implements MutableGame {
}
executions(): Execution[] {
return this.execs
return [...this.execs, ...this.unInitExecs]
}
addExecution(...exec: Execution[]) {
@@ -357,7 +357,8 @@ export class GameImpl implements MutableGame {
}
removeExecution(exec: Execution) {
this.execs.filter(execution => execution !== exec)
this.execs = this.execs.filter(execution => execution !== exec)
this.unInitExecs = this.unInitExecs.filter(execution => execution !== exec)
}
width(): number {
+18 -18
View File
@@ -3,24 +3,24 @@ import {PlayerConfig} from "./Config";
import {DefaultConfig, DefaultPlayerConfig, defaultPlayerConfig} from "./DefaultConfig";
export const devConfig = new class extends DefaultConfig {
// numSpawnPhaseTurns(): number {
// return 40
// }
// gameCreationRate(): number {
// return 3 * 1000
// }
// lobbyLifetime(): number {
// return 3 * 1000
// }
// turnIntervalMs(): number {
// return 100
// }
// player(): PlayerConfig {
// return devPlayerConfig
// }
// numBots(): number {
// return 250
// }
numSpawnPhaseTurns(): number {
return 40
}
gameCreationRate(): number {
return 3 * 1000
}
lobbyLifetime(): number {
return 3 * 1000
}
turnIntervalMs(): number {
return 100
}
player(): PlayerConfig {
return devPlayerConfig
}
numBots(): number {
return 250
}
}
export const devPlayerConfig = new class extends DefaultPlayerConfig {
+8 -4
View File
@@ -29,6 +29,10 @@ export class AttackExecution implements Execution {
}
init(mg: MutableGame, ticks: number) {
if (!this.active) {
return
}
// TODO: remove this and fix directed expansion.
this.targetCell = null
@@ -40,13 +44,13 @@ export class AttackExecution implements Execution {
this.mg = mg
for (const exec of mg.executions()) {
if (exec.isActive() && exec instanceof AttackExecution) {
if (exec.isActive() && exec instanceof AttackExecution && exec != this) {
const otherAttack = exec as AttackExecution
// Target has opposing attack, cancel them out
if (this.target.isPlayer() && otherAttack.target == this._owner && this.target == otherAttack._owner) {
if (this.target.isPlayer() && otherAttack.targetID == this._ownerID && this.targetID == otherAttack._ownerID) {
if (otherAttack.troops > this.troops) {
otherAttack.troops -= this.troops
otherAttack.calculateToConquer()
// otherAttack.calculateToConquer()
this.active = false
return
} else {
@@ -55,7 +59,7 @@ export class AttackExecution implements Execution {
}
}
// Existing attack on same target, add troops
if (otherAttack._owner == this._owner && otherAttack.target == this.target) {
if (otherAttack._owner == this._owner && otherAttack.targetID == this.targetID) {
otherAttack.troops += this.troops
otherAttack.calculateToConquer()
this.active = false
+10 -5
View File
@@ -1,11 +1,12 @@
import {Cell, Game} from "../Game";
import {PseudoRandom} from "../PseudoRandom";
import {SpawnIntent} from "../Schemas";
import {bfs} from "../Util";
import {getSpawnCells} from "./Util";
export class BotSpawner {
private cellToIndex;
private cellToIndex: Map<string, number>;
private freeTiles: Cell[];
private numFreeTiles;
private random = new PseudoRandom(123);
@@ -39,8 +40,7 @@ export class BotSpawner {
spawnBot(botName: string): SpawnIntent {
const rand = this.random.nextInt(0, this.numFreeTiles);
const spawn = this.freeTiles[rand];
const spawnCells = getSpawnCells(this.gs, spawn);
spawnCells.forEach(c => this.removeCell(c));
bfs(this.gs.tile(spawn), 50).forEach(t => this.removeCell(t.cell()))
const spawnIntent: SpawnIntent = {
type: 'spawn',
name: botName,
@@ -52,9 +52,14 @@ export class BotSpawner {
}
private removeCell(cell: Cell) {
const index = this.cellToIndex[cell.toString()];
if (!this.cellToIndex.has(cell.toString())) {
return
}
const index = this.cellToIndex.get(cell.toString());
this.cellToIndex.delete(cell.toString())
this.freeTiles[index] = this.freeTiles[this.numFreeTiles - 1];
this.cellToIndex[this.freeTiles[index].toString()] = index;
this.cellToIndex.set(this.freeTiles[index].toString(), index);
this.numFreeTiles--;
}
}