From 18ac34ae45a4217ab1097d32c30a4c55f94c8bd5 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 20 Nov 2024 19:55:42 -0800 Subject: [PATCH] Created hydrogen bomb --- TODO.txt | 3 ++- src/client/Transport.ts | 24 ++----------------- src/client/graphics/layers/UnitLayer.ts | 2 +- .../graphics/layers/radial/BuildMenu.ts | 14 +++++++---- .../graphics/layers/radial/RadialMenu.ts | 2 +- src/core/Schemas.ts | 13 +--------- src/core/configuration/DefaultConfig.ts | 7 +++++- src/core/execution/ExecutionManager.ts | 5 ++-- src/core/execution/NukeExecution.ts | 16 ++++++------- src/core/game/Game.ts | 3 ++- src/core/game/PlayerImpl.ts | 3 ++- 11 files changed, 37 insertions(+), 55 deletions(-) diff --git a/TODO.txt b/TODO.txt index f86820b8f..b55da9536 100644 --- a/TODO.txt +++ b/TODO.txt @@ -186,8 +186,9 @@ * nuke spawns from missile silo DONE 11/16/2024 * REFACTOR: move canbuild to player DONE 11/17/2024 * BUG: can build destroyer on land DONE 11/17/2024 -* fix pathfinding bug +* fix pathfinding bug DONE 11/20/2024 * make two nukes: atom & hydrogen +* NPC builds ports * destroyer can capture trade ships * add battleship * add defense post diff --git a/src/client/Transport.ts b/src/client/Transport.ts index c85cab3c2..deae97b93 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -75,14 +75,6 @@ export class SendDonateIntentEvent implements GameEvent { ) { } } -export class SendNukeIntentEvent implements GameEvent { - constructor( - public readonly sender: Player, - public readonly cell: Cell, - public readonly magnitude: number | null, - ) { } -} - export class SendSetTargetTroopRatioEvent implements GameEvent { constructor( public readonly ratio: number, @@ -120,9 +112,8 @@ export class Transport { this.eventBus.on(SendTargetPlayerIntentEvent, (e) => this.onSendTargetPlayerIntent(e)) this.eventBus.on(SendEmojiIntentEvent, (e) => this.onSendEmojiIntent(e)) this.eventBus.on(SendDonateIntentEvent, (e) => this.onSendDonateIntent(e)) - this.eventBus.on(SendNukeIntentEvent, (e) => this.onSendNukeIntent(e)) this.eventBus.on(SendSetTargetTroopRatioEvent, (e) => this.onSendSetTargetTroopRatioEvent(e)) - this.eventBus.on(BuildUnitIntentEvent, (e) => this.onCreateDestroyerIntent(e)) + this.eventBus.on(BuildUnitIntentEvent, (e) => this.onBuildUnitIntent(e)) } connect(onconnect: () => void, onmessage: (message: ServerMessage) => void) { @@ -302,17 +293,6 @@ export class Transport { }) } - private onSendNukeIntent(event: SendNukeIntentEvent) { - this.sendIntent({ - type: "nuke", - clientID: this.clientID, - sender: event.sender.id(), - x: event.cell.x, - y: event.cell.y, - magnitude: event.magnitude, - }) - } - private onSendSetTargetTroopRatioEvent(event: SendSetTargetTroopRatioEvent) { this.sendIntent({ type: "troop_ratio", @@ -322,7 +302,7 @@ export class Transport { }) } - private onCreateDestroyerIntent(event: BuildUnitIntentEvent) { + private onBuildUnitIntent(event: BuildUnitIntentEvent) { this.sendIntent({ type: "build_unit", clientID: this.clientID, diff --git a/src/client/graphics/layers/UnitLayer.ts b/src/client/graphics/layers/UnitLayer.ts index 156e2c82d..e6b01842a 100644 --- a/src/client/graphics/layers/UnitLayer.ts +++ b/src/client/graphics/layers/UnitLayer.ts @@ -80,7 +80,7 @@ export class UnitLayer implements Layer { break; case UnitType.TradeShip: this.handleTradeShipEvent(event) - case UnitType.Nuke: + case UnitType.AtomBomb: this.handleNuke(event) } } diff --git a/src/client/graphics/layers/radial/BuildMenu.ts b/src/client/graphics/layers/radial/BuildMenu.ts index 6ac949f8b..1af3e07f8 100644 --- a/src/client/graphics/layers/radial/BuildMenu.ts +++ b/src/client/graphics/layers/radial/BuildMenu.ts @@ -2,8 +2,9 @@ import { LitElement, html, css } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { EventBus } from '../../../../core/EventBus'; import { Cell, Game, Player, UnitType } from '../../../../core/game/Game'; -import { BuildUnitIntentEvent, SendNukeIntentEvent } from '../../../Transport'; -import nukeIcon from '../../../../../resources/images/NukeIconWhite.svg'; +import { BuildUnitIntentEvent } from '../../../Transport'; +import atomBombIcon from '../../../../../resources/images/NukeIconWhite.svg'; +import hydrogenBombIcon from '../../../../../resources/images/MushroomCloudIconWhite.svg'; import destroyerIcon from '../../../../../resources/images/DestroyerIconWhite.svg'; import missileSiloIcon from '../../../../../resources/images/MissileSiloIconWhite.svg'; import goldCoinIcon from '../../../../../resources/images/GoldCoinIcon.svg'; @@ -18,7 +19,8 @@ interface BuildItemDisplay { const buildTable: BuildItemDisplay[][] = [ [ - { unitType: UnitType.Nuke, icon: nukeIcon }, + { unitType: UnitType.AtomBomb, icon: atomBombIcon }, + { unitType: UnitType.HydrogenBomb, icon: hydrogenBombIcon }, { unitType: UnitType.Destroyer, icon: destroyerIcon }, { unitType: UnitType.Port, icon: portIcon }, { unitType: UnitType.MissileSilo, icon: missileSiloIcon } @@ -155,9 +157,11 @@ export class BuildMenu extends LitElement { public onBuildSelected = (item: BuildItemDisplay) => { switch (item.unitType) { - case UnitType.Nuke: - this.eventBus.emit(new SendNukeIntentEvent(this.myPlayer, this.clickedCell, null)) + case UnitType.AtomBomb: + this.eventBus.emit(new BuildUnitIntentEvent(UnitType.AtomBomb, this.clickedCell)) break + case UnitType.HydrogenBomb: + this.eventBus.emit(new BuildUnitIntentEvent(UnitType.HydrogenBomb, this.clickedCell)) case UnitType.Destroyer: this.eventBus.emit(new BuildUnitIntentEvent(UnitType.Destroyer, this.clickedCell)) break diff --git a/src/client/graphics/layers/radial/RadialMenu.ts b/src/client/graphics/layers/radial/RadialMenu.ts index febd0a07f..f71bdf00d 100644 --- a/src/client/graphics/layers/radial/RadialMenu.ts +++ b/src/client/graphics/layers/radial/RadialMenu.ts @@ -3,7 +3,7 @@ import { AllPlayers, Cell, Game, Player, UnitType } from "../../../../core/game/ import { ClientID } from "../../../../core/Schemas"; import { and, bfs, dist, manhattanDist, manhattanDistWrapped, sourceDstOceanShore, targetTransportTile } from "../../../../core/Util"; import { ContextMenuEvent, MouseUpEvent } from "../../../InputHandler"; -import { SendAllianceRequestIntentEvent, SendAttackIntentEvent, SendBoatAttackIntentEvent, SendBreakAllianceIntentEvent, SendDonateIntentEvent, SendEmojiIntentEvent, SendNukeIntentEvent, SendSpawnIntentEvent, SendTargetPlayerIntentEvent } from "../../../Transport"; +import { SendAllianceRequestIntentEvent, SendAttackIntentEvent, SendBoatAttackIntentEvent, SendBreakAllianceIntentEvent, SendDonateIntentEvent, SendEmojiIntentEvent, SendSpawnIntentEvent, SendTargetPlayerIntentEvent } from "../../../Transport"; import { TransformHandler } from "../../TransformHandler"; import { Layer } from "../Layer"; import * as d3 from 'd3'; diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 11133fbd6..62c04fd75 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -13,7 +13,6 @@ export type Intent = SpawnIntent | TargetPlayerIntent | EmojiIntent | DonateIntent - | NukeIntent | TargetTroopRatioIntent | BuildUnitIntent @@ -26,7 +25,6 @@ export type BreakAllianceIntent = z.infer export type TargetPlayerIntent = z.infer export type EmojiIntent = z.infer export type DonateIntent = z.infer -export type NukeIntent = z.infer export type TargetTroopRatioIntent = z.infer export type BuildUnitIntent = z.infer @@ -69,7 +67,7 @@ const EmojiSchema = z.string().refine( ); // Zod schemas const BaseIntentSchema = z.object({ - type: z.enum(['attack', 'spawn', 'boat', 'name', 'targetPlayer', 'emoji', 'nuke', 'troop_ratio', 'build_unit']), + type: z.enum(['attack', 'spawn', 'boat', 'name', 'targetPlayer', 'emoji', 'troop_ratio', 'build_unit']), clientID: z.string(), }); @@ -147,14 +145,6 @@ export const DonateIntentSchema = BaseIntentSchema.extend({ troops: z.number().nullable(), }) -export const NukeIntentSchema = BaseIntentSchema.extend({ - type: z.literal('nuke'), - sender: z.string(), - x: z.number(), - y: z.number(), - magnitude: z.number().nullable(), -}) - export const TargetTroopRatioIntentSchema = BaseIntentSchema.extend({ type: z.literal('troop_ratio'), player: z.string(), @@ -179,7 +169,6 @@ const IntentSchema = z.union([ TargetPlayerIntentSchema, EmojiIntentSchema, DonateIntentSchema, - NukeIntentSchema, TargetTroopRatioIntentSchema, BuildUnitIntentSchema, ]); diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 32d99617e..5caa2cffe 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -24,11 +24,16 @@ export class DefaultConfig implements Config { cost: 300_000, territoryBound: true } - case UnitType.Nuke: + case UnitType.AtomBomb: return { cost: 1_000_000, territoryBound: false } + case UnitType.HydrogenBomb: + return { + cost: 5_000_000, + territoryBound: false + } case UnitType.TradeShip: return { cost: 0, diff --git a/src/core/execution/ExecutionManager.ts b/src/core/execution/ExecutionManager.ts index 194b425d2..6c1e3a301 100644 --- a/src/core/execution/ExecutionManager.ts +++ b/src/core/execution/ExecutionManager.ts @@ -79,12 +79,13 @@ export class Executor { return new EmojiExecution(intent.sender, intent.recipient, intent.emoji); case "donate": return new DonateExecution(intent.sender, intent.recipient, intent.troops); - case "nuke": - return new NukeExecution(intent.sender, new Cell(intent.x, intent.y), intent.magnitude); case "troop_ratio": return new SetTargetTroopRatioExecution(intent.player, intent.ratio); case "build_unit": switch (intent.unit) { + case UnitType.AtomBomb: + case UnitType.HydrogenBomb: + return new NukeExecution(intent.unit, intent.player, new Cell(intent.x, intent.y)) case UnitType.Destroyer: return new DestroyerExecution(intent.player, new Cell(intent.x, intent.y)) case UnitType.Port: diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index c10e8ea6c..667687cb7 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -17,30 +17,27 @@ export class NukeExecution implements Execution { private pathFinder: PathFinder = new PathFinder(10_000, () => true) constructor( + private type: UnitType.AtomBomb | UnitType.HydrogenBomb, private senderID: PlayerID, private cell: Cell, - private magnitude: number | null ) { } init(mg: MutableGame, ticks: number): void { this.mg = mg this.player = mg.player(this.senderID) - if (this.magnitude == null) { - this.magnitude = 50 - } this.dst = this.mg.tile(this.cell) } tick(ticks: number): void { if (this.nuke == null) { - const spawn = this.player.canBuild(UnitType.Nuke, this.dst) + const spawn = this.player.canBuild(UnitType.AtomBomb, this.dst) if (spawn == false) { console.warn(`cannot build Nuke`) this.active = false return } - this.nuke = this.player.buildUnit(UnitType.Nuke, 0, spawn) + this.nuke = this.player.buildUnit(UnitType.AtomBomb, 0, spawn) } for (let i = 0; i < 4; i++) { @@ -64,11 +61,14 @@ export class NukeExecution implements Execution { } private detonate() { + const magnitude = this.type == UnitType.AtomBomb ? 25 : 100 + + const rand = new PseudoRandom(this.mg.ticks()) const tile = this.mg.tile(this.cell) const toDestroy = bfs(tile, (n: Tile) => { const d = euclideanDist(tile.cell(), n.cell()) - return (d <= this.magnitude || rand.chance(2)) && d <= this.magnitude + 40 + return (d <= magnitude || rand.chance(2)) && d <= magnitude * 2 }) const ratio = Object.fromEntries( @@ -85,7 +85,7 @@ export class NukeExecution implements Execution { } } for (const unit of this.mg.units()) { - if (euclideanDist(this.cell, unit.tile().cell()) < this.magnitude + 50) { + if (euclideanDist(this.cell, unit.tile().cell()) < magnitude * 2) { unit.delete() } } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 002405b10..ad015af17 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -32,7 +32,8 @@ export enum UnitType { TransportShip = "Transport", Destroyer = "Destroyer", Port = "Port", - Nuke = "Nuke", + AtomBomb = "Atom Bomb", + HydrogenBomb = "Hydrogen Bomb", TradeShip = "Trade Ship", MissileSilo = "Missile Silo", } diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 742768010..79b9b4aae 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -346,7 +346,8 @@ export class PlayerImpl implements MutablePlayer { return false } switch (unitType) { - case UnitType.Nuke: + case UnitType.AtomBomb: + case UnitType.HydrogenBomb: return this.nukeSpawn(targetTile) case UnitType.Port: return this.portSpawn(targetTile)