mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 14:00:54 +00:00
Created hydrogen bomb
This commit is contained in:
@@ -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
|
||||
|
||||
+2
-22
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
+1
-12
@@ -13,7 +13,6 @@ export type Intent = SpawnIntent
|
||||
| TargetPlayerIntent
|
||||
| EmojiIntent
|
||||
| DonateIntent
|
||||
| NukeIntent
|
||||
| TargetTroopRatioIntent
|
||||
| BuildUnitIntent
|
||||
|
||||
@@ -26,7 +25,6 @@ export type BreakAllianceIntent = z.infer<typeof BreakAllianceIntentSchema>
|
||||
export type TargetPlayerIntent = z.infer<typeof TargetPlayerIntentSchema>
|
||||
export type EmojiIntent = z.infer<typeof EmojiIntentSchema>
|
||||
export type DonateIntent = z.infer<typeof DonateIntentSchema>
|
||||
export type NukeIntent = z.infer<typeof NukeIntentSchema>
|
||||
export type TargetTroopRatioIntent = z.infer<typeof TargetTroopRatioIntentSchema>
|
||||
export type BuildUnitIntent = z.infer<typeof BuildUnitIntentSchema>
|
||||
|
||||
@@ -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,
|
||||
]);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user