Revert "Add new bouncing trajectory for april fools (#3534)"

This reverts commit c92895620f.
This commit is contained in:
evanpelle
2026-04-01 19:36:18 -07:00
parent dc73e926ea
commit 54e29c5b4e
6 changed files with 16 additions and 197 deletions
@@ -5,7 +5,6 @@ import {
BonusEventUpdate, BonusEventUpdate,
ConquestUpdate, ConquestUpdate,
GameUpdateType, GameUpdateType,
TextEventUpdate,
} from "src/core/game/GameUpdates"; } from "src/core/game/GameUpdates";
import type { GameView, UnitView } from "../../../core/game/GameView"; import type { GameView, UnitView } from "../../../core/game/GameView";
import { MoveWarshipIntentEvent } from "../../Transport"; import { MoveWarshipIntentEvent } from "../../Transport";
@@ -63,32 +62,12 @@ export class DynamicUILayer implements Layer {
this.onBonusEvent(bonusEvent); this.onBonusEvent(bonusEvent);
}); });
updates[GameUpdateType.TextUIEvent]?.forEach((textEvent) => {
if (textEvent === undefined) return;
this.onTextEvent(textEvent);
});
updates[GameUpdateType.ConquestEvent]?.forEach((update) => { updates[GameUpdateType.ConquestEvent]?.forEach((update) => {
if (update === undefined) return; if (update === undefined) return;
this.onConquestEvent(update); this.onConquestEvent(update);
}); });
} }
onTextEvent(textEvent: TextEventUpdate) {
// Only display text fx for the current player
if (this.game.player(textEvent.player) !== this.game.myPlayer()) {
return;
}
const tile = textEvent.tile;
const x = this.game.x(tile);
const y = this.game.y(tile) + TEXT_OFFSET_Y;
const text = textEvent.text;
this.uiElements.push(
new TextIndicator(this.transformHandler, text, x, y, 500, 12),
);
}
onBonusEvent(bonus: BonusEventUpdate) { onBonusEvent(bonus: BonusEventUpdate) {
// Only display text fx for the current player // Only display text fx for the current player
if (this.game.player(bonus.player) !== this.game.myPlayer()) { if (this.game.player(bonus.player) !== this.game.myPlayer()) {
+1 -17
View File
@@ -2,11 +2,7 @@ import { Theme } from "../../../core/configuration/Config";
import { EventBus } from "../../../core/EventBus"; import { EventBus } from "../../../core/EventBus";
import { UnitType } from "../../../core/game/Game"; import { UnitType } from "../../../core/game/Game";
import { TileRef } from "../../../core/game/GameMap"; import { TileRef } from "../../../core/game/GameMap";
import { import { ConquestUpdate, GameUpdateType } from "../../../core/game/GameUpdates";
ConquestUpdate,
GameUpdateType,
TextEventUpdate,
} from "../../../core/game/GameUpdates";
import { GameView, UnitView } from "../../../core/game/GameView"; import { GameView, UnitView } from "../../../core/game/GameView";
import SoundManager, { SoundEffect } from "../../sound/SoundManager"; import SoundManager, { SoundEffect } from "../../sound/SoundManager";
import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader"; import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader";
@@ -60,12 +56,6 @@ export class FxLayer implements Layer {
if (update === undefined) return; if (update === undefined) return;
this.onConquestEvent(update); this.onConquestEvent(update);
}); });
this.game
.updatesSinceLastTick()
?.[GameUpdateType.TextUIEvent]?.forEach((update) => {
if (update === undefined) return;
this.onBoingEvent(update);
});
} }
onUnitEvent(unit: UnitView) { onUnitEvent(unit: UnitView) {
@@ -149,12 +139,6 @@ export class FxLayer implements Layer {
} }
} }
onBoingEvent(boing: TextEventUpdate) {
const x = this.game.x(boing.tile);
const y = this.game.y(boing.tile);
this.allFx.push(new ShockwaveFx(x, y, 1000, 20));
}
onConquestEvent(conquest: ConquestUpdate) { onConquestEvent(conquest: ConquestUpdate) {
// Only display fx for the current player // Only display fx for the current player
const conqueror = this.game.player(conquest.conquerorId); const conqueror = this.game.player(conquest.conquerorId);
+13 -32
View File
@@ -11,10 +11,7 @@ import {
} from "../game/Game"; } from "../game/Game";
import { TileRef } from "../game/GameMap"; import { TileRef } from "../game/GameMap";
import { UniversalPathFinding } from "../pathfinding/PathFinder"; import { UniversalPathFinding } from "../pathfinding/PathFinder";
import { import { ParabolaUniversalPathFinder } from "../pathfinding/PathFinder.Parabola";
BouncingParabolaUniversalPathFinder,
ParabolaUniversalPathFinder,
} from "../pathfinding/PathFinder.Parabola";
import { PathStatus } from "../pathfinding/types"; import { PathStatus } from "../pathfinding/types";
import { PseudoRandom } from "../PseudoRandom"; import { PseudoRandom } from "../PseudoRandom";
import { NukeType } from "../StatsSchemas"; import { NukeType } from "../StatsSchemas";
@@ -27,9 +24,7 @@ export class NukeExecution implements Execution {
private mg: Game; private mg: Game;
private nuke: Unit | null = null; private nuke: Unit | null = null;
private tilesToDestroyCache: Set<TileRef> | undefined; private tilesToDestroyCache: Set<TileRef> | undefined;
private pathFinder: private pathFinder: ParabolaUniversalPathFinder;
| BouncingParabolaUniversalPathFinder
| ParabolaUniversalPathFinder;
constructor( constructor(
private nukeType: NukeType, private nukeType: NukeType,
@@ -46,32 +41,18 @@ export class NukeExecution implements Execution {
if (this.speed === -1) { if (this.speed === -1) {
this.speed = this.mg.config().defaultNukeSpeed(); this.speed = this.mg.config().defaultNukeSpeed();
} }
this.pathFinder = UniversalPathFinding.Parabola(mg, {
const rand = new PseudoRandom(ticks); increment: this.speed,
if (rand.chance(6)) { distanceBasedHeight: this.nukeType !== UnitType.MIRVWarhead,
this.pathFinder = UniversalPathFinding.BouncingParabola( directionUp: this.rocketDirectionUp,
mg, });
this.player.id(),
{
increment: this.speed,
distanceBasedHeight: this.nukeType !== UnitType.MIRVWarhead,
directionUp: this.rocketDirectionUp,
},
);
} else {
this.pathFinder = UniversalPathFinding.Parabola(mg, {
increment: this.speed,
distanceBasedHeight: this.nukeType !== UnitType.MIRVWarhead,
directionUp: this.rocketDirectionUp,
});
}
} }
public target(): Player | TerraNullius { public target(): Player | TerraNullius {
return this.mg.owner(this.dst); return this.mg.owner(this.dst);
} }
private tilesToDestroy(explosionTile: TileRef): Set<TileRef> { private tilesToDestroy(): Set<TileRef> {
if (this.tilesToDestroyCache !== undefined) { if (this.tilesToDestroyCache !== undefined) {
return this.tilesToDestroyCache; return this.tilesToDestroyCache;
} }
@@ -82,8 +63,8 @@ export class NukeExecution implements Execution {
const rand = new PseudoRandom(this.mg.ticks()); const rand = new PseudoRandom(this.mg.ticks());
const inner2 = magnitude.inner * magnitude.inner; const inner2 = magnitude.inner * magnitude.inner;
const outer2 = magnitude.outer * magnitude.outer; const outer2 = magnitude.outer * magnitude.outer;
this.tilesToDestroyCache = this.mg.bfs(explosionTile, (_, n: TileRef) => { this.tilesToDestroyCache = this.mg.bfs(this.dst, (_, n: TileRef) => {
const d2 = this.mg?.euclideanDistSquared(explosionTile, n) ?? 0; const d2 = this.mg?.euclideanDistSquared(this.dst, n) ?? 0;
return d2 <= outer2 && (d2 <= inner2 || rand.chance(2)); return d2 <= outer2 && (d2 <= inner2 || rand.chance(2));
}); });
return this.tilesToDestroyCache; return this.tilesToDestroyCache;
@@ -212,7 +193,7 @@ export class NukeExecution implements Execution {
// Move to next tile // Move to next tile
const result = this.pathFinder.next(this.src!, this.dst, this.speed); const result = this.pathFinder.next(this.src!, this.dst, this.speed);
if (result.status === PathStatus.COMPLETE) { if (result.status === PathStatus.COMPLETE) {
this.detonate(result.node); this.detonate();
return; return;
} else if (result.status === PathStatus.NEXT) { } else if (result.status === PathStatus.NEXT) {
this.updateNukeTargetable(); this.updateNukeTargetable();
@@ -266,7 +247,7 @@ export class NukeExecution implements Execution {
); );
} }
private detonate(explosionTile: TileRef) { private detonate() {
if (this.nuke === null) { if (this.nuke === null) {
throw new Error("Not initialized"); throw new Error("Not initialized");
} }
@@ -275,7 +256,7 @@ export class NukeExecution implements Execution {
const config = mg.config(); const config = mg.config();
const magnitude = config.nukeMagnitudes(this.nuke.type()); const magnitude = config.nukeMagnitudes(this.nuke.type());
const toDestroy = this.tilesToDestroy(explosionTile); const toDestroy = this.tilesToDestroy();
// Retrieve all impacted players and the number of tiles // Retrieve all impacted players and the number of tiles
const tilesPerPlayers = new Map<Player, number>(); const tilesPerPlayers = new Map<Player, number>();
-9
View File
@@ -59,7 +59,6 @@ export enum GameUpdateType {
Hash, Hash,
UnitIncoming, UnitIncoming,
BonusEvent, BonusEvent,
TextUIEvent,
RailroadDestructionEvent, RailroadDestructionEvent,
RailroadConstructionEvent, RailroadConstructionEvent,
RailroadSnapEvent, RailroadSnapEvent,
@@ -84,7 +83,6 @@ export type GameUpdate =
| UnitIncomingUpdate | UnitIncomingUpdate
| AllianceExtensionUpdate | AllianceExtensionUpdate
| BonusEventUpdate | BonusEventUpdate
| TextEventUpdate
| RailroadConstructionUpdate | RailroadConstructionUpdate
| RailroadDestructionUpdate | RailroadDestructionUpdate
| RailroadSnapUpdate | RailroadSnapUpdate
@@ -100,13 +98,6 @@ export interface BonusEventUpdate {
troops: number; troops: number;
} }
export interface TextEventUpdate {
type: GameUpdateType.TextUIEvent;
player: PlayerID;
tile: TileRef;
text: string;
}
export interface RailroadConstructionUpdate { export interface RailroadConstructionUpdate {
type: GameUpdateType.RailroadConstructionEvent; type: GameUpdateType.RailroadConstructionEvent;
id: number; id: number;
+1 -108
View File
@@ -1,6 +1,4 @@
import { Game, PlayerID } from "../game/Game";
import { GameMap, TileRef } from "../game/GameMap"; import { GameMap, TileRef } from "../game/GameMap";
import { GameUpdateType } from "../game/GameUpdates";
import { within } from "../Util"; import { within } from "../Util";
import { DistanceBasedBezierCurve } from "../utilities/Line"; import { DistanceBasedBezierCurve } from "../utilities/Line";
import { PathResult, PathStatus, SteppingPathFinder } from "./types"; import { PathResult, PathStatus, SteppingPathFinder } from "./types";
@@ -9,7 +7,6 @@ export interface ParabolaOptions {
increment?: number; increment?: number;
distanceBasedHeight?: boolean; distanceBasedHeight?: boolean;
directionUp?: boolean; directionUp?: boolean;
minHeight?: number;
} }
const PARABOLA_MIN_HEIGHT = 50; const PARABOLA_MIN_HEIGHT = 50;
@@ -28,7 +25,6 @@ export class ParabolaUniversalPathFinder
private createCurve(from: TileRef, to: TileRef): DistanceBasedBezierCurve { private createCurve(from: TileRef, to: TileRef): DistanceBasedBezierCurve {
const increment = this.options?.increment ?? 3; const increment = this.options?.increment ?? 3;
const distanceBasedHeight = this.options?.distanceBasedHeight ?? true; const distanceBasedHeight = this.options?.distanceBasedHeight ?? true;
const minHeight = this.options?.minHeight ?? PARABOLA_MIN_HEIGHT;
const directionUp = this.options?.directionUp ?? true; const directionUp = this.options?.directionUp ?? true;
const p0 = { x: this.gameMap.x(from), y: this.gameMap.y(from) }; const p0 = { x: this.gameMap.x(from), y: this.gameMap.y(from) };
@@ -37,7 +33,7 @@ export class ParabolaUniversalPathFinder
const dy = p3.y - p0.y; const dy = p3.y - p0.y;
const distance = Math.sqrt(dx * dx + dy * dy); const distance = Math.sqrt(dx * dx + dy * dy);
const maxHeight = distanceBasedHeight const maxHeight = distanceBasedHeight
? Math.max(distance / 3, minHeight) ? Math.max(distance / 3, PARABOLA_MIN_HEIGHT)
: 0; : 0;
const heightMult = directionUp ? -1 : 1; const heightMult = directionUp ? -1 : 1;
const mapHeight = this.gameMap.height(); const mapHeight = this.gameMap.height();
@@ -92,106 +88,3 @@ export class ParabolaUniversalPathFinder
return this.curve?.getCurrentIndex() ?? 0; return this.curve?.getCurrentIndex() ?? 0;
} }
} }
export class BouncingParabolaUniversalPathFinder
implements SteppingPathFinder<TileRef>
{
private parabola: ParabolaUniversalPathFinder;
private bouncing = false;
private fromBounce: TileRef;
private toBounce: TileRef;
private previousIndex: number = 0;
constructor(
private mg: Game,
private playerId: PlayerID,
private options?: ParabolaOptions,
) {
this.parabola = new ParabolaUniversalPathFinder(mg.map(), options);
}
next(from: number, to: number, dist?: number): PathResult<TileRef> {
if (this.bouncing) {
return this.nextBounce(dist);
}
const result = this.parabola.next(from, to, dist);
if (result.status === PathStatus.COMPLETE) {
if (this.bounce(from, to)) {
return this.nextBounce();
}
}
return result;
}
private bounce(from: number, to: number): boolean {
const bounceDest = this.computeBounceDestination(from, to);
if (!bounceDest) {
return false;
}
this.previousIndex = this.parabola.currentIndex();
this.bouncing = true;
this.fromBounce = to;
this.toBounce = bounceDest;
this.mg.addUpdate({
type: GameUpdateType.TextUIEvent,
player: this.playerId,
tile: to,
text: "Boing",
});
this.parabola = new ParabolaUniversalPathFinder(this.mg.map(), {
increment: this.options?.increment ?? 3,
distanceBasedHeight: true,
directionUp: this.options?.directionUp ?? true,
minHeight: 25,
});
return true;
}
private nextBounce(dist?: number): PathResult<TileRef> {
return this.parabola.next(this.fromBounce, this.toBounce, dist);
}
invalidate(): void {
this.parabola.invalidate();
}
findPath(from: number | number[], to: number): number[] | null {
if (Array.isArray(from)) {
throw new Error(
"ParabolaUniversalPathFinder does not support multiple start points",
);
}
const tiles = this.parabola.findPath(from, to);
const newDest = this.computeBounceDestination(from, to);
if (tiles && newDest) {
const bounceTiles = this.parabola.findPath(to, newDest);
if (bounceTiles) {
return tiles?.concat(bounceTiles);
}
}
return tiles;
}
currentIndex(): number {
return this.parabola.currentIndex() + this.previousIndex;
}
private computeBounceDestination(src: TileRef, dst: TileRef): TileRef | null {
const destX = this.mg.x(dst);
const destY = this.mg.y(dst);
const srcX = this.mg.x(src);
const srcY = this.mg.y(src);
const newX = Math.min(
Math.floor(destX + (destX - srcX) / 2),
this.mg.width() - 1,
);
const newY = Math.min(
Math.floor(destY + (destY - srcY) / 2),
this.mg.height() - 1,
);
return this.mg.isValidCoord(newX, newY) ? this.mg.ref(newX, newY) : null;
}
}
+1 -10
View File
@@ -1,11 +1,10 @@
import { Game, PlayerID } from "../game/Game"; import { Game } from "../game/Game";
import { GameMap, TileRef } from "../game/GameMap"; import { GameMap, TileRef } from "../game/GameMap";
import { TrainStation } from "../game/TrainStation"; import { TrainStation } from "../game/TrainStation";
import { AStarRail } from "./algorithms/AStar.Rail"; import { AStarRail } from "./algorithms/AStar.Rail";
import { AStarWater } from "./algorithms/AStar.Water"; import { AStarWater } from "./algorithms/AStar.Water";
import { AirPathFinder } from "./PathFinder.Air"; import { AirPathFinder } from "./PathFinder.Air";
import { import {
BouncingParabolaUniversalPathFinder,
ParabolaOptions, ParabolaOptions,
ParabolaUniversalPathFinder, ParabolaUniversalPathFinder,
} from "./PathFinder.Parabola"; } from "./PathFinder.Parabola";
@@ -28,14 +27,6 @@ export class UniversalPathFinding {
): ParabolaUniversalPathFinder { ): ParabolaUniversalPathFinder {
return new ParabolaUniversalPathFinder(gameMap, options); return new ParabolaUniversalPathFinder(gameMap, options);
} }
static BouncingParabola(
mg: Game,
playerId: PlayerID,
options?: ParabolaOptions,
): BouncingParabolaUniversalPathFinder {
return new BouncingParabolaUniversalPathFinder(mg, playerId, options);
}
} }
/** /**