mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
fakehumans send boats, improved map
This commit is contained in:
@@ -97,10 +97,12 @@
|
||||
* more random names for game id & client id DONE 9/5/2024
|
||||
* BUG: attacks speed up DONE 9/6/2024
|
||||
* rebalance income DONE 9/7/2024
|
||||
* Make fake humans
|
||||
* Make more colors
|
||||
* BUG: fix tile per turn pacing issues
|
||||
|
||||
--- v3 Release
|
||||
|
||||
* Make fake humans
|
||||
* BUG: when clicking on enemy sometimes boat goes all the way around
|
||||
* names dissappear too much (maybe screen size)
|
||||
* directed expansion
|
||||
@@ -111,6 +113,7 @@
|
||||
* UI: event box
|
||||
* make random waves on ocean, dark spots
|
||||
* Load terrain dataImage in background
|
||||
* BUG: half encircle Antoartica causes capture
|
||||
|
||||
--- v4 Release
|
||||
|
||||
@@ -119,4 +122,3 @@
|
||||
* BUG: when sending boat to TerraNullius, only takes one tile
|
||||
* REFACTOR: give terranullius an ID, game.player() returns terranullius
|
||||
* REFACTOR: ocean is considered TerraNullius ?
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,266 @@
|
||||
Carja
|
||||
Reich3rd
|
||||
DEATH
|
||||
Ruby Rouse
|
||||
Femboy
|
||||
Syria
|
||||
UnitedKingdom
|
||||
kingdom
|
||||
British Empire
|
||||
I am better
|
||||
fullsender
|
||||
inlandmuse
|
||||
Enes32
|
||||
Emir
|
||||
Zephyr
|
||||
Crimson_Tide
|
||||
OBLIVION
|
||||
Sapphire_Siren
|
||||
Enby_Warrior
|
||||
Atlantis
|
||||
SovietUnion
|
||||
empire
|
||||
Aztec_Empire
|
||||
You_Shall_Not_Pass
|
||||
madlad
|
||||
coastaldreamer
|
||||
Nox42
|
||||
Pharaoh
|
||||
GoldenHorde
|
||||
Valhalla
|
||||
QuantumQuasar
|
||||
Ronin
|
||||
DawnBreaker
|
||||
NeonNightmare
|
||||
Byzantium
|
||||
CHAOS
|
||||
Jade_Dragon
|
||||
Comrade
|
||||
Sparta
|
||||
HolyRomanEmpire
|
||||
republic
|
||||
Inca_Sun
|
||||
Get_Rekt
|
||||
trickster
|
||||
urbannomad
|
||||
Loki69
|
||||
Sultan
|
||||
IronCurtain
|
||||
Nirvana
|
||||
CosmicDust
|
||||
Samurai
|
||||
Dusk_Reaper
|
||||
PlasmaPhantom
|
||||
Macedonia
|
||||
ANARCHY
|
||||
Onyx_Oracle
|
||||
Regent
|
||||
Troy
|
||||
OttomanEmpire
|
||||
federation
|
||||
Maya_Moon
|
||||
Unstoppable
|
||||
memester
|
||||
desertwalker
|
||||
Thor23
|
||||
Caliph
|
||||
SilkRoad
|
||||
Elysium
|
||||
StardustCrusader
|
||||
Ninja
|
||||
Twilight_Harbinger
|
||||
LunarSpecter
|
||||
Carthage
|
||||
HAVOC
|
||||
Amber_Assassin
|
||||
Monarch
|
||||
Camelot
|
||||
MongolHorde
|
||||
dominion
|
||||
Olmec_Jaguar
|
||||
Invincible
|
||||
madscientist
|
||||
mountaindweller
|
||||
Odin88
|
||||
Shogun
|
||||
Avalon
|
||||
Utopia
|
||||
NebulaNomad
|
||||
Ronin
|
||||
Shadow_Weaver
|
||||
AstralAvenger
|
||||
Pompeii
|
||||
MAYHEM
|
||||
Emerald_Enigma
|
||||
Overlord
|
||||
Asgard
|
||||
VikingRealm
|
||||
principality
|
||||
Phoenician_Trader
|
||||
memelord
|
||||
jungleexplorer
|
||||
Zeus55
|
||||
Rajah
|
||||
Shangri_La
|
||||
Arcadia
|
||||
GalacticEmissary
|
||||
Shinobi
|
||||
Void_Walker
|
||||
EclipseHarbinger
|
||||
SPQR
|
||||
Liam
|
||||
Eros
|
||||
Aztec
|
||||
Kaiser2nd
|
||||
VOID
|
||||
Scarlet Shadow
|
||||
Tomboy
|
||||
Egypt
|
||||
RussianFederation
|
||||
empire
|
||||
Roman Empire
|
||||
U cant win
|
||||
risktaker
|
||||
coastaldrift
|
||||
Murat55
|
||||
Sultan
|
||||
Breeze
|
||||
Sparta
|
||||
CHAOS
|
||||
Emerald Knight
|
||||
Enby
|
||||
Persia
|
||||
OttomanEmpire
|
||||
republic
|
||||
Mongol Horde
|
||||
Im unstoppable
|
||||
nightowl
|
||||
urbanlegend
|
||||
Fatih78
|
||||
Vizier
|
||||
Tempest
|
||||
Maya
|
||||
ANARCHY
|
||||
Obsidian Raven
|
||||
Androgynous
|
||||
Babylon
|
||||
ByzantineEmpire
|
||||
dominion
|
||||
Austro Hungarian
|
||||
You will lose
|
||||
daydreamer
|
||||
ruralnomad
|
||||
Osman41
|
||||
Pasha
|
||||
Cyclone
|
||||
Inca
|
||||
HAVOC
|
||||
Crimson Tide
|
||||
Nonbinary
|
||||
Carthage
|
||||
HolyRomanEmpire
|
||||
nation
|
||||
Viking Raiders
|
||||
Git gud
|
||||
madlad
|
||||
forestdweller
|
||||
Orhan63
|
||||
Bey
|
||||
Tsunami
|
||||
Olmec
|
||||
OBLIVION
|
||||
Azure Falcon
|
||||
Genderfluid
|
||||
Sumeria
|
||||
GoldenHorde
|
||||
sovereignty
|
||||
Zulu Kingdom
|
||||
Bow to me
|
||||
trickster
|
||||
desertroamer
|
||||
Selim90
|
||||
Khan
|
||||
Tornado
|
||||
Hittite
|
||||
MAYHEM
|
||||
Violet Viper
|
||||
Queer
|
||||
Assyria
|
||||
MongolEmpire
|
||||
realm
|
||||
Phoenician Traders
|
||||
L2P noob
|
||||
memester
|
||||
mountaintrekker
|
||||
Mehmet27
|
||||
Aga
|
||||
Hurricane
|
||||
Minoan
|
||||
ABYSS
|
||||
Indigo Serpent
|
||||
Genderqueer
|
||||
Akkad
|
||||
TimuridEmpire
|
||||
dynasty
|
||||
Hanseatic League
|
||||
EZ clap
|
||||
edgelord
|
||||
cavewanderer
|
||||
Yunus84
|
||||
Dey
|
||||
Sandstorm
|
||||
Mayan
|
||||
ENIGMA
|
||||
Amber Wraith
|
||||
Agender
|
||||
Parthia
|
||||
SassanidEmpire
|
||||
confederacy
|
||||
Venetian Republic
|
||||
Get rekt
|
||||
madcap
|
||||
islandexplorer
|
||||
Kemal52
|
||||
Raja
|
||||
Grizzly
|
||||
inlandmuse
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Anon
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 823 KiB After Width: | Height: | Size: 823 KiB |
@@ -80,7 +80,6 @@ class Client {
|
||||
const nextGame = document.getElementById('next-game');
|
||||
nextGame.textContent = `Next Game: ${nextLobby.id.substring(0, 3)}`
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async fetchLobbies(): Promise<Lobby[]> {
|
||||
|
||||
@@ -11,7 +11,6 @@ import {and, bfs, dist, manhattanDist} from "../core/Util";
|
||||
import {TerrainRenderer} from "./graphics/TerrainRenderer";
|
||||
|
||||
|
||||
|
||||
export function createClientGame(name: string, clientID: ClientID, playerID: PlayerID, ip: string | null, gameID: GameID, config: Config, terrainMap: TerrainMap): ClientGame {
|
||||
let eventBus = new EventBus()
|
||||
let game = createGame(terrainMap, eventBus, config)
|
||||
@@ -28,7 +27,7 @@ export function createClientGame(name: string, clientID: ClientID, playerID: Pla
|
||||
game,
|
||||
gameRenderer,
|
||||
new InputHandler(eventBus),
|
||||
new Executor(game)
|
||||
new Executor(game, gameID)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -118,6 +117,8 @@ export class ClientGame {
|
||||
}
|
||||
|
||||
public start() {
|
||||
console.log('version 3')
|
||||
|
||||
this.isActive = true
|
||||
// TODO: make each class do this, or maybe have client intercept all requests?
|
||||
//this.eventBus.on(TickEvent, (e) => this.tick(e))
|
||||
@@ -131,7 +132,8 @@ export class ClientGame {
|
||||
this.renderer.initialize()
|
||||
this.input.initialize()
|
||||
this.gs.addExecution(...this.executor.spawnBots(this.gs.config().numBots()))
|
||||
this.gs.addExecution(...this.executor.fakeHumanExecutions(1))
|
||||
console.log('!!! number fake humans 15')
|
||||
this.gs.addExecution(...this.executor.fakeHumanExecutions(15))
|
||||
|
||||
this.intervalID = setInterval(() => this.tick(), 10);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ export function largestRectangleInHistogram(widths: number[]): Rectangle {
|
||||
|
||||
export function calculateFontSize(rectangle: Rectangle, name: string): number {
|
||||
// This is a simplified calculation. You might want to adjust it based on your specific font and rendering system.
|
||||
const widthConstrained = rectangle.width / name.length;
|
||||
const widthConstrained = rectangle.width / name.length * 2;
|
||||
const heightConstrained = rectangle.height / 3;
|
||||
return Math.min(widthConstrained, heightConstrained);
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1>OpenFront.io</h1>
|
||||
<h2>(v0.3.5)</h2>
|
||||
<h2>(v0.3.6)</h2>
|
||||
<div id="username-container">
|
||||
<input type="text" id="username" placeholder="Enter your username">
|
||||
</div>
|
||||
|
||||
@@ -34,4 +34,16 @@ export class PseudoRandom {
|
||||
nextID(): string {
|
||||
return this.nextInt(0, 1000000).toString(36).padStart(5, '0');
|
||||
}
|
||||
|
||||
randElement<T>(arr: T[]): T {
|
||||
if (arr.length == 0) {
|
||||
throw new Error('array must not be empty')
|
||||
}
|
||||
return arr[this.nextInt(0, arr.length)];
|
||||
}
|
||||
|
||||
chance(odds: number): boolean {
|
||||
return this.nextInt(0, odds) == 0
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,6 +40,7 @@ export interface Config {
|
||||
tilesPerTickUsed: number
|
||||
}
|
||||
attackAmount(attacker: Player, defender: Player | TerraNullius): number
|
||||
maxTroops(player: Player): number
|
||||
boatAttackAmount(attacker: Player, defender: Player | TerraNullius): number
|
||||
boatMaxDistance(): number
|
||||
boatMaxNumber(): number
|
||||
|
||||
@@ -46,6 +46,16 @@ export class DefaultConfig implements Config {
|
||||
speed = 10
|
||||
break
|
||||
}
|
||||
|
||||
if (attacker.isPlayer() && defender.isPlayer()) {
|
||||
if (attacker.type() == PlayerType.Bot && defender.type() != PlayerType.Bot) {
|
||||
mag *= 1.2
|
||||
}
|
||||
if (attacker.type() != PlayerType.Bot && defender.type() == PlayerType.Bot) {
|
||||
mag *= .8
|
||||
}
|
||||
}
|
||||
|
||||
if (defender.isPlayer()) {
|
||||
return {
|
||||
attackerTroopLoss: within(defender.troops() / attacker.troops() * mag, 1, 1000),
|
||||
@@ -88,9 +98,13 @@ export class DefaultConfig implements Config {
|
||||
return 10000
|
||||
}
|
||||
|
||||
troopAdditionRate(player: Player): number {
|
||||
maxTroops(player: Player): number {
|
||||
let max = Math.sqrt(player.numTilesOwned()) * 3000 + 50000
|
||||
max = Math.min(max, 1_000_000)
|
||||
return Math.min(max, 1_000_000)
|
||||
}
|
||||
|
||||
troopAdditionRate(player: Player): number {
|
||||
let max = this.maxTroops(player)
|
||||
|
||||
let toAdd = 10 + (player.troops() + Math.sqrt(player.troops() * player.numTilesOwned())) / 100
|
||||
|
||||
@@ -98,8 +112,11 @@ export class DefaultConfig implements Config {
|
||||
toAdd *= ratio
|
||||
// console.log(`to add ${toAdd}`)
|
||||
|
||||
if (player.type() == PlayerType.FakeHuman) {
|
||||
toAdd *= 1.2
|
||||
}
|
||||
if (player.type() == PlayerType.Bot) {
|
||||
toAdd *= .7
|
||||
toAdd *= .6
|
||||
}
|
||||
|
||||
return Math.min(player.troops() + toAdd, max)
|
||||
|
||||
@@ -16,7 +16,7 @@ export const devConfig = new class extends DefaultConfig {
|
||||
}
|
||||
|
||||
numBots(): number {
|
||||
return 0
|
||||
return 400
|
||||
}
|
||||
|
||||
// startTroops(playerInfo: PlayerInfo): number {
|
||||
|
||||
@@ -85,7 +85,6 @@ export class BoatAttackExecution implements Execution {
|
||||
this.aStarPre.compute(5)
|
||||
this.path = this.aStarPre.reconstructPath()
|
||||
if (this.path != null) {
|
||||
console.log(`got path ${this.path.map(t => t.cell().toString())}`)
|
||||
this.boat = this.attacker.addBoat(this.troops, this.src, this.target)
|
||||
} else {
|
||||
console.log('got null path')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius} from "../Game"
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, PlayerType, TerraNullius} from "../Game"
|
||||
import {PseudoRandom} from "../PseudoRandom"
|
||||
import {simpleHash} from "../Util";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
@@ -59,7 +59,13 @@ export class BotExecution implements Execution {
|
||||
}
|
||||
|
||||
const toAttack = border[this.random.nextInt(0, border.length)]
|
||||
this.sendAttack(toAttack.owner())
|
||||
const owner = toAttack.owner()
|
||||
if (owner.isPlayer() && (owner.type() == PlayerType.FakeHuman || owner.type() == PlayerType.Human)) {
|
||||
if (this.random.nextInt(0, 1) == 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
this.sendAttack(owner)
|
||||
}
|
||||
|
||||
sendAttack(toAttack: Player | TerraNullius) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Cell, Execution, MutableGame, Game, MutablePlayer, PlayerInfo, TerraNullius, Tile, PlayerType} from "../Game";
|
||||
import {AttackIntent, BoatAttackIntentSchema, Intent, Turn} from "../Schemas";
|
||||
import {AttackIntent, BoatAttackIntentSchema, GameID, Intent, Turn} from "../Schemas";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
import {SpawnExecution} from "./SpawnExecution";
|
||||
import {BotSpawner} from "./BotSpawner";
|
||||
@@ -7,14 +7,20 @@ import {BoatAttackExecution} from "./BoatAttackExecution";
|
||||
import {PseudoRandom} from "../PseudoRandom";
|
||||
import {UpdateNameExecution} from "./UpdateNameExecution";
|
||||
import {FakeHumanExecution} from "./FakeHumanExecution";
|
||||
import Usernames from '../../../resources/Usernames.txt'
|
||||
import {simpleHash} from "../Util";
|
||||
|
||||
|
||||
|
||||
export class Executor {
|
||||
|
||||
private random = new PseudoRandom(999)
|
||||
private usernames = Usernames.split('\n')
|
||||
|
||||
constructor(private gs: Game) {
|
||||
// private random = new PseudoRandom(999)
|
||||
private random: PseudoRandom = null
|
||||
|
||||
constructor(private gs: Game, gameID: GameID) {
|
||||
this.random = new PseudoRandom(simpleHash(gameID))
|
||||
}
|
||||
|
||||
createExecs(turn: Turn): Execution[] {
|
||||
@@ -64,9 +70,9 @@ export class Executor {
|
||||
for (let i = 0; i < numFakes; i++) {
|
||||
execs.push(
|
||||
new FakeHumanExecution(new PlayerInfo(
|
||||
"fake_human" + i,
|
||||
this.usernames[this.random.nextInt(0, this.usernames.length)],
|
||||
PlayerType.FakeHuman,
|
||||
this.random.nextID(),
|
||||
null,
|
||||
this.random.nextID()
|
||||
))
|
||||
)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerraNullius, Tile} from "../Game"
|
||||
import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerrainType, TerraNullius, Tile} from "../Game"
|
||||
import {PseudoRandom} from "../PseudoRandom"
|
||||
import {simpleHash} from "../Util";
|
||||
import {and, bfs, dist, simpleHash} from "../Util";
|
||||
import {AttackExecution} from "./AttackExecution";
|
||||
import {BoatAttackExecution} from "./BoatAttackExecution";
|
||||
import {SpawnExecution} from "./SpawnExecution";
|
||||
|
||||
export class FakeHumanExecution implements Execution {
|
||||
@@ -11,11 +12,11 @@ export class FakeHumanExecution implements Execution {
|
||||
private attackRate: number
|
||||
private mg: MutableGame
|
||||
private neighborsTerraNullius = true
|
||||
private player: Player = null
|
||||
|
||||
|
||||
constructor(private playerInfo: PlayerInfo) {
|
||||
this.random = new PseudoRandom(simpleHash(playerInfo.id))
|
||||
this.attackRate = this.random.nextInt(10, 50)
|
||||
}
|
||||
|
||||
init(mg: MutableGame, ticks: number) {
|
||||
@@ -25,59 +26,123 @@ export class FakeHumanExecution implements Execution {
|
||||
tick(ticks: number) {
|
||||
|
||||
if (this.mg.inSpawnPhase()) {
|
||||
if (ticks % 10 == 0) {
|
||||
if (ticks % this.random.nextInt(5, 30) == 0) {
|
||||
this.mg.addExecution(new SpawnExecution(
|
||||
this.playerInfo,
|
||||
this.randomLand().cell()
|
||||
))
|
||||
}
|
||||
}
|
||||
if (this.player == null) {
|
||||
this.player = this.mg.players().find(p => p.id() == this.playerInfo.id)
|
||||
if (this.player == null) {
|
||||
//console.log(`player with id ${this.playerInfo.id} not found in FakeHumanExecution`)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (ticks % this.attackRate != 0) {
|
||||
if (this.player.troops() < this.mg.config().maxTroops(this.player) / 4) {
|
||||
return
|
||||
}
|
||||
|
||||
// if (this.neighborsTerraNullius) {
|
||||
// for (const b of this.bot.borderTiles()) {
|
||||
// for (const n of b.neighbors()) {
|
||||
// if (n.owner() == this.mg.terraNullius() && n.isLand()) {
|
||||
// this.sendAttack(this.mg.terraNullius())
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.neighborsTerraNullius = false
|
||||
// }
|
||||
if (ticks % this.random.nextInt(10, 30) != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// const border = Array.from(this.bot.borderTiles()).flatMap(t => t.neighbors()).filter(t => t.hasOwner() && t.owner() != this.bot)
|
||||
if (this.neighborsTerraNullius) {
|
||||
for (const b of this.player.borderTiles()) {
|
||||
for (const n of b.neighbors()) {
|
||||
if (n.owner() == this.mg.terraNullius() && n.isLand()) {
|
||||
this.sendAttack(this.mg.terraNullius())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
this.neighborsTerraNullius = false
|
||||
}
|
||||
|
||||
// if (border.length == 0) {
|
||||
// return
|
||||
// }
|
||||
const enemyborder = Array.from(this.player.borderTiles()).flatMap(t => t.neighbors()).filter(t => t.hasOwner() && t.owner() != this.player)
|
||||
|
||||
if (enemyborder.length == 0 || this.random.chance(5)) {
|
||||
this.sendBoat()
|
||||
return
|
||||
}
|
||||
|
||||
const enemies = enemyborder.map(t => t.owner()).filter(o => o.isPlayer()).map(o => o as Player).sort((a, b) => a.troops() - b.troops())
|
||||
|
||||
if (this.random.nextInt(0, 1) == 1) {
|
||||
this.sendAttack(enemies[0])
|
||||
} else {
|
||||
this.sendAttack(enemies[this.random.nextInt(0, enemies.length)])
|
||||
}
|
||||
}
|
||||
|
||||
sendBoat(tries: number = 0) {
|
||||
if (tries > 100) {
|
||||
return
|
||||
}
|
||||
|
||||
const oceanShore = Array.from(this.player.borderTiles()).filter(t => t.isOceanShore())
|
||||
if (oceanShore.length == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const src = this.random.randElement(oceanShore)
|
||||
const otherShore = Array.from(
|
||||
bfs(
|
||||
src,
|
||||
and((t) => t.isOcean() || t.isOceanShore(), dist(src, 200))
|
||||
)
|
||||
).filter(t => t.isOceanShore() && t.owner() != this.player)
|
||||
|
||||
if (otherShore.length == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const dst = this.random.randElement(otherShore)
|
||||
if (this.isSmallIsland(dst)) {
|
||||
continue
|
||||
}
|
||||
|
||||
this.mg.addExecution(new BoatAttackExecution(
|
||||
this.player.id(),
|
||||
dst.hasOwner() ? dst.owner().id() : null,
|
||||
dst.cell(),
|
||||
this.player.troops() / 5,
|
||||
))
|
||||
return
|
||||
}
|
||||
this.sendBoat(tries + 1)
|
||||
|
||||
// const toAttack = border[this.random.nextInt(0, border.length)]
|
||||
// this.sendAttack(toAttack.owner())
|
||||
}
|
||||
|
||||
randomLand(): Tile {
|
||||
while (true) {
|
||||
const cell = new Cell(this.random.nextInt(0, this.mg.width()), this.random.nextInt(0, this.mg.height()))
|
||||
const tile = this.mg.tile(cell)
|
||||
if (tile.isLand()) {
|
||||
if (tile.isLand() && !tile.hasOwner()) {
|
||||
if (tile.terrain() == TerrainType.Mountain && this.random.chance(2)) {
|
||||
continue
|
||||
}
|
||||
return tile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendAttack(toAttack: Player | TerraNullius) {
|
||||
// this.mg.addExecution(new AttackExecution(
|
||||
// this.bot.troops() / 20,
|
||||
// this.bot.id(),
|
||||
// toAttack.isPlayer() ? toAttack.id() : null,
|
||||
// null,
|
||||
// null
|
||||
// ))
|
||||
// }
|
||||
sendAttack(toAttack: Player | TerraNullius) {
|
||||
this.mg.addExecution(new AttackExecution(
|
||||
this.player.troops() / 5,
|
||||
this.player.id(),
|
||||
toAttack.isPlayer() ? toAttack.id() : null,
|
||||
null,
|
||||
null
|
||||
))
|
||||
}
|
||||
|
||||
isSmallIsland(tile: Tile): boolean {
|
||||
return bfs(tile, and((t) => t.isLand(), dist(tile, 50))).size < 50
|
||||
}
|
||||
|
||||
owner(): MutablePlayer {
|
||||
return null
|
||||
|
||||
@@ -97,7 +97,6 @@ export class PlayerExecution implements Execution {
|
||||
}
|
||||
|
||||
private removeCluster(cluster: Set<Tile>) {
|
||||
console.log('removing cluster!')
|
||||
const arr = Array.from(cluster)
|
||||
const mode = getMode(arr.flatMap(t => t.neighbors()).filter(t => t.hasOwner() && t.owner() != this.player).map(t => t.owner().id()))
|
||||
if (!this.mg.hasPlayer(mode)) {
|
||||
@@ -155,6 +154,6 @@ export class PlayerExecution implements Execution {
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.player.isAlive()
|
||||
return this.player == null || this.player.isAlive()
|
||||
}
|
||||
}
|
||||
Vendored
+4
@@ -19,3 +19,7 @@ declare module '*.bin' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
declare module '*.txt' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ export default (env, argv) => {
|
||||
test: /\.bin$/,
|
||||
use: 'raw-loader'
|
||||
},
|
||||
{
|
||||
test: /\.txt$/,
|
||||
use: 'raw-loader'
|
||||
},
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: 'ts-loader',
|
||||
|
||||
Reference in New Issue
Block a user