diff --git a/TODO.txt b/TODO.txt index ec3eafe5f..72661e48a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -4,8 +4,11 @@ * render player info efficiently DONE 8/11/2024 * better troop addition logic DONE 8/11/2024 * better expansion, add back directed expansion DONE 8/11/2024 -* use pastel theme for territories +* use pastel theme for territories DONE 8/11/2024 +* cache border in AttackExecution for perf * harder to expand on other players (defense) +* lose troops when attacked +* fix boat bugs * add username in front page * improve front page * upload and start server diff --git a/src/client/graphics/NameRenderer.ts b/src/client/graphics/NameRenderer.ts index 49665ba0e..a04638f2e 100644 --- a/src/client/graphics/NameRenderer.ts +++ b/src/client/graphics/NameRenderer.ts @@ -85,13 +85,11 @@ export class NameRenderer { const centerX = box.min.x + ((box.max.x - box.min.x) / 2) const centerY = box.min.y + ((box.max.y - box.min.y) / 2) render.location = new Cell(centerX, centerY) - render.fontSize = Math.max(Math.min(box.max.x - box.min.x, box.max.y - box.min.y) / render.player.info().name.length / 2, 2) + render.fontSize = Math.max(Math.min(box.max.x - box.min.x, box.max.y - box.min.y) / render.player.info().name.length / 2, 1.5) return wasUpdated } renderPlayerInfo(render: RenderInfo, context: CanvasRenderingContext2D, scale: number, uppperLeft: Cell, bottomRight: Cell) { - - // console.log(`scale: ${scale}, fontSize: ${render.fontSize}, mult: ${scale * render.fontSize}`) if (render.fontSize * scale < 10) { return } @@ -103,18 +101,14 @@ export class NameRenderer { return } - // if (nameCenterX, ) { - - // } context.textRendering = "optimizeSpeed"; - context.font = `${render.fontSize}px Arial`; + context.font = `bold ${render.fontSize}px ${this.theme.font()}`; context.fillStyle = this.theme.playerInfoColor(render.player.id()).toHex(); context.textAlign = 'center'; context.textBaseline = 'middle'; - context.fillText(render.player.info().name, nameCenterX, nameCenterY - render.fontSize / 2); context.fillText(String(Math.floor(render.player.troops())), nameCenterX, nameCenterY + render.fontSize); } diff --git a/src/core/Settings.ts b/src/core/Settings.ts index 279def78e..e670d9b20 100644 --- a/src/core/Settings.ts +++ b/src/core/Settings.ts @@ -17,7 +17,6 @@ export interface Theme { terrainColor(tile: TerrainType): Colord; backgroundColor(): Colord; font(): string; - shaderArgs(): {name: string; args: {[key: string]: any}}[]; } export const defaultSettings = new class implements Settings { @@ -45,21 +44,72 @@ const pastelTheme = new class implements Theme { private land = colord({r: 244, g: 243, b: 198}); private water = colord({r: 160, g: 203, b: 231}); private territory = colord({r: 173, g: 216, b: 230}); - + private territoryColors: Colord[] = [ + colord({r: 255, g: 179, b: 186}), // Vibrant Light Pink + colord({r: 255, g: 223, b: 186}), // Vibrant Peach + colord({r: 190, g: 255, b: 190}), // Vibrant Light Green + colord({r: 173, g: 216, b: 255}), // Vibrant Light Blue + colord({r: 224, g: 187, b: 255}), // Vibrant Light Purple + colord({r: 255, g: 191, b: 230}), // Vibrant Pink + colord({r: 210, g: 255, b: 210}), // Vibrant Mint Green + colord({r: 255, g: 213, b: 179}), // Vibrant Light Orange + colord({r: 198, g: 198, b: 255}), // Vibrant Lavender + colord({r: 255, g: 255, b: 186}), // Vibrant Light Yellow + colord({r: 186, g: 255, b: 201}), // Vibrant Seafoam Green + colord({r: 255, g: 186, b: 255}), // Vibrant Light Magenta + colord({r: 210, g: 255, b: 210}), // Vibrant Pale Green + colord({r: 255, g: 202, b: 202}), // Vibrant Salmon Pink + colord({r: 206, g: 206, b: 255}), // Vibrant Periwinkle + colord({r: 255, g: 234, b: 186}), // Vibrant Cream + colord({r: 186, g: 255, b: 255}), // Vibrant Light Cyan + colord({r: 238, g: 210, b: 255}), // Vibrant Lilac + colord({r: 206, g: 255, b: 238}), // Vibrant Pale Turquoise + colord({r: 255, g: 209, b: 186}), // Vibrant Peach + colord({r: 186, g: 216, b: 255}), // Vibrant Baby Blue + colord({r: 246, g: 255, b: 186}), // Vibrant Pale Yellow + colord({r: 220, g: 186, b: 255}), // Vibrant Light Violet + colord({r: 255, g: 186, b: 213}), // Vibrant Rose + colord({r: 186, g: 255, b: 226}), // Vibrant Honeydew + colord({r: 206, g: 236, b: 255}), // Vibrant Sky Blue + colord({r: 255, g: 232, b: 206}), // Vibrant Wheat + colord({r: 206, g: 255, b: 255}), // Vibrant Pale Cyan + colord({r: 255, g: 216, b: 216}), // Vibrant Misty Rose + colord({r: 216, g: 216, b: 255}), // Vibrant Pale Lavender + colord({r: 255, g: 250, b: 205}), // Vibrant Pale Goldenrod + colord({r: 216, g: 255, b: 216}), // Vibrant Pale Mint + colord({r: 255, g: 216, b: 255}), // Vibrant Pale Plum + colord({r: 220, g: 255, b: 220}), // Vibrant Mint Cream + colord({r: 255, g: 220, b: 220}), // Vibrant Pale Pink + colord({r: 220, g: 220, b: 255}), // Vibrant Pale Blue + colord({r: 255, g: 255, b: 220}), // Vibrant Light Goldenrod + colord({r: 220, g: 255, b: 255}), // Vibrant Light Azure + colord({r: 255, g: 220, b: 255}), // Vibrant Pale Magenta + colord({r: 230, g: 255, b: 230}), // Vibrant Honeydew + colord({r: 255, g: 230, b: 230}), // Vibrant Lavender Blush + colord({r: 230, g: 230, b: 255}), // Vibrant Ghost White + colord({r: 255, g: 239, b: 219}), // Vibrant Seashell + colord({r: 219, g: 255, b: 239}), // Vibrant Mint Cream + colord({r: 239, g: 219, b: 255}), // Vibrant Pale Lavender + colord({r: 255, g: 250, b: 230}), // Vibrant Floral White + colord({r: 230, g: 255, b: 250}), // Vibrant Azure Mist + colord({r: 250, g: 230, b: 255}), // Vibrant Pale Purple + colord({r: 250, g: 255, b: 230}), // Vibrant Ivory + colord({r: 230, g: 250, b: 255}) // Vibrant Alice Blue + ]; playerInfoColor(id: PlayerID): Colord { return colord({r: 0, g: 0, b: 0}) } territoryColor(id: PlayerID): Colord { - return colord({r: (id * 10) % 250, g: (id * 100) % 250, b: (id) % 250}); + return this.territoryColors[id % this.territoryColors.length] } borderColor(id: PlayerID): Colord { const tc = this.territoryColor(id).rgba; return colord({ - r: Math.min(tc.r + 20, 255), - g: Math.min(tc.g + 20, 255), - b: Math.min(tc.b + 20, 255) + r: Math.max(tc.r - 20, 0), + g: Math.max(tc.g - 20, 0), + b: Math.max(tc.b - 20, 0) }) } @@ -75,10 +125,6 @@ const pastelTheme = new class implements Theme { } font(): string { - return "Overpass"; - } - - shaderArgs(): {name: string; args: {[key: string]: any}}[] { - throw new Error("Method not implemented."); + return "Arial"; } } \ No newline at end of file diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index 566bfe895..cb0f390ef 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -14,6 +14,7 @@ export class AttackExecution implements Execution { private mg: MutableGame private numTilesWithEnemy = 0 + private borderTiles: Set = new Set() constructor( private troops: number, @@ -35,31 +36,22 @@ export class AttackExecution implements Execution { if (!this.active) { return } - // const t = this.mg.tile(new Cell(0, 0)) - // this.toConquer.add(new TileContainer(t, 4)) - // this.toConquer.add(new TileContainer(t, 1)) - // this.toConquer.add(new TileContainer(t, 2)) - // this.toConquer.add(new TileContainer(t, 3)) - // while (this.toConquer.size() > 0) { - // console.log(`!!! got ${this.toConquer.poll().priority}`) - // } - - - let numTilesPerTick = this.numTilesWithEnemy / 2 + let numTilesPerTick = this.numTilesWithEnemy / 4 if (this.targetCell != null) { numTilesPerTick /= 2 } + let badTiles = 0 while (numTilesPerTick > 0) { if (this.troops < 1) { this.active = false return } - if (this.toConquer.size() < this.numTilesWithEnemy / 2) { + if (this.toConquer.size() < this.numTilesWithEnemy / 1.5) { this.calculateToConquer() } - if (this.toConquer.size() == 0) { + if (this.toConquer.size() == 0 || badTiles > 100) { this.active = false this._owner.addTroops(this.troops) return @@ -69,6 +61,7 @@ export class AttackExecution implements Execution { const tileToConquer: Tile = toConquerContainer.tile const onBorder = tileToConquer.neighbors().filter(t => t.owner() == this._owner).length > 0 if (tileToConquer.owner() != this.target || !onBorder) { + badTiles++ continue } this._owner.conquer(tileToConquer) @@ -79,62 +72,21 @@ export class AttackExecution implements Execution { private calculateToConquer() { this.numTilesWithEnemy = 0 - // console.profile('calc_to_conquer') - - - - // let closestTile: Tile; - // let closestDist: number = Number.POSITIVE_INFINITY; - // for (const enemyTile of enemyBorder) { - // const dist = manhattanDist(enemyTile.cell(), this.targetCell) - // if (dist < closestDist) { - // closestTile = enemyTile - // } - // } - - // tileByDist.forEach(t => console.log(`tile dist: ${manhattanDist(t.cell(), closestTile.cell())}`)) - // let tileByDist = [] - // if (this.targetCell == null) { - // tileByDist = Array.from(enemyBorder).slice().sort((a, b) => this.random.next() - .5) - // } else { - // } - // for (let i = 0; i < Math.min(enemyBorder.size / 2, tileByDist.length); i++) { - // const enemyTile = tileByDist[i] - // const numOwnedByMe = enemyTile.neighbors() - // .filter(t => t.terrain() == TerrainTypes.Land) - // .filter(t => t.owner() == this._owner) - // .length - // // this.toConquer.add(new TileContainer(enemyTile, numOwnedByMe + (this.random.next() % 5) + (-5 * i / tileByDist.length))) - // const r = this.random.next() % 4 - // this.toConquer.add(new TileContainer(enemyTile, r + numOwnedByMe * 1000)) - // } this.toConquer.clear() - - // if (this.targetCell != null) { - // let tiles = Array.from(enemyBorder) - // tiles = tiles.slice().sort((a, b) => manhattanDist(a.cell(), this.targetCell) - manhattanDist(b.cell(), this.targetCell)) - // for (let i = 0; i < tiles.length; i++) { - // const numOwnedByMe = tiles[i].neighbors() - // .filter(t => t.terrain() == TerrainTypes.Land) - // .filter(t => t.owner() == this._owner) - // .length - - // let distModifer = 0 - // if (this.targetCell != null) { - // distModifer = i / tiles.length * 2 - // } - // this.toConquer.add(new TileContainer(tiles[i], distModifer - numOwnedByMe + this.random.nextInt(0, 2))) - // // this.toConquer.add(new TileContainer(tiles[i], i)) - // } - // } else { - for (const tile of this._owner.borderTiles()) { + const newBorder: Set = new Set() + let existingBorder: ReadonlySet = this.borderTiles + if (existingBorder.size == 0) { + existingBorder = this._owner.borderTiles() + } + for (const tile of existingBorder) { for (const neighbor of tile.neighbors()) { if (neighbor.terrain() == TerrainTypes.Water || neighbor.owner() != this.target) { continue } + newBorder.add(neighbor) this.numTilesWithEnemy += 1 - const numOwnedByMe = tile.neighbors() + let numOwnedByMe = tile.neighbors() .filter(t => t.terrain() == TerrainTypes.Land) .filter(t => t.owner() == this._owner) .length @@ -145,11 +97,7 @@ export class AttackExecution implements Execution { this.toConquer.add(new TileContainer(neighbor, dist + -numOwnedByMe + (tile.cell().x * tile.cell().y) % 2)) } } - // } - - // console.profileEnd('calc_to_conquer') - - + this.borderTiles = newBorder } owner(): MutablePlayer {