Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cbd1389
lobby fill time added to stats
ryanbarlow97 Nov 4, 2025
2842bd4
Merge branch 'main' into lobbytime
ryanbarlow97 Nov 5, 2025
a539ae4
Merge branch 'main' into lobbytime
ryanbarlow97 Nov 5, 2025
0af2e96
Merge branch 'main' into lobbytime
ryanbarlow97 Nov 6, 2025
d5f990d
Merge branch 'main' into lobbytime
ryanbarlow97 Nov 7, 2025
1d96e75
Merge branch 'main' into lobbytime
evanpelle Nov 8, 2025
e562a91
removed changes to compress in localserver
ryanbarlow97 Nov 9, 2025
146342b
Directional Bombs - Press "U"
ryanbarlow97 Nov 11, 2025
b188c75
Merge branch 'openfrontio:main' into swapdirection
ryanbarlow97 Nov 11, 2025
28b8069
remove incorrect comment
ryanbarlow97 Nov 11, 2025
d755514
Merge branch 'swapdirection' of https://github.com/ryanbarlow97/OpenF…
ryanbarlow97 Nov 11, 2025
60ddacf
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 11, 2025
17c10a9
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 11, 2025
1cddfcd
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 11, 2025
18845ef
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 13, 2025
2a07538
added instructions for new mechanic to hotkeys list
ryanbarlow97 Nov 14, 2025
6b12c03
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 15, 2025
ea6a05b
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 17, 2025
2973fb9
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 18, 2025
d37ffc4
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 19, 2025
78566c7
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 19, 2025
895f9ee
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 20, 2025
a209e7f
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 21, 2025
b55aae5
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 22, 2025
de4f36f
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 24, 2025
90734fa
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 25, 2025
487c2fe
Merge branch 'main' into swapdirection
ryanbarlow97 Nov 26, 2025
c72eeb9
Merge branch 'main' into swapdirection
ryanbarlow97 Dec 1, 2025
fdafa19
Merge branch 'main' into swapdirection
ryanbarlow97 Dec 2, 2025
95a5850
Merge branch 'main' into swapdirection
ryanbarlow97 Dec 4, 2025
9fbf157
Merge branch 'main' into swapdirection
ryanbarlow97 Dec 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/client/InputHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export class GhostStructureChangedEvent implements GameEvent {
constructor(public readonly ghostStructure: UnitType | null) {}
}

export class SwapRocketDirectionEvent implements GameEvent {}

export class ShowBuildMenuEvent implements GameEvent {
constructor(
public readonly x: number,
Expand Down Expand Up @@ -200,6 +202,7 @@ export class InputHandler {
attackRatioUp: "KeyY",
boatAttack: "KeyB",
groundAttack: "KeyG",
swapDirection: "KeyU",
modifierKey: isMac ? "MetaLeft" : "ControlLeft",
altKey: "AltLeft",
buildCity: "Digit1",
Expand Down Expand Up @@ -417,6 +420,12 @@ export class InputHandler {
this.setGhostStructure(UnitType.MIRV);
}

// Tab to swap rocket direction
if (e.code === this.keybinds.swapDirection) {
e.preventDefault();
this.eventBus.emit(new SwapRocketDirectionEvent());
}

// Shift-D to toggle performance overlay
console.log(e.code, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey);
if (e.code === "KeyD" && e.shiftKey) {
Expand Down
2 changes: 2 additions & 0 deletions src/client/Transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export class BuildUnitIntentEvent implements GameEvent {
constructor(
public readonly unit: UnitType,
public readonly tile: TileRef,
public readonly rocketDirectionUp?: boolean,
) {}
}

Expand Down Expand Up @@ -549,6 +550,7 @@ export class Transport {
clientID: this.lobbyConfig.clientID,
unit: event.unit,
tile: event.tile,
rocketDirectionUp: event.rocketDirectionUp,
});
}

Expand Down
9 changes: 7 additions & 2 deletions src/client/graphics/GameRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ export function createRenderer(
const transformHandler = new TransformHandler(game, eventBus, canvas);
const userSettings = new UserSettings();

const uiState = { attackRatio: 20, ghostStructure: null } as UIState;
const uiState = {
attackRatio: 20,
ghostStructure: null,
rocketDirectionUp: true,
} as UIState;

//hide when the game renders
const startingModal = document.querySelector(
Expand All @@ -72,6 +76,7 @@ export function createRenderer(
}
buildMenu.game = game;
buildMenu.eventBus = eventBus;
buildMenu.uiState = uiState;
buildMenu.transformHandler = transformHandler;

const leaderboard = document.querySelector("leader-board") as Leaderboard;
Expand Down Expand Up @@ -244,7 +249,7 @@ export function createRenderer(
new UnitLayer(game, eventBus, transformHandler),
new FxLayer(game),
new UILayer(game, eventBus, transformHandler),
new NukeTrajectoryPreviewLayer(game, eventBus, transformHandler),
new NukeTrajectoryPreviewLayer(game, eventBus, transformHandler, uiState),
new StructureIconsLayer(game, eventBus, uiState, transformHandler),
new NameLayer(game, transformHandler, eventBus),
eventsDisplay,
Expand Down
1 change: 1 addition & 0 deletions src/client/graphics/UIState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import { UnitType } from "../../core/game/Game";
export interface UIState {
attackRatio: number;
ghostStructure: UnitType | null;
rocketDirectionUp: boolean;
}
11 changes: 10 additions & 1 deletion src/client/graphics/layers/BuildMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
} from "../../Transport";
import { renderNumber } from "../../Utils";
import { TransformHandler } from "../TransformHandler";
import { UIState } from "../UIState";
import { Layer } from "./Layer";

export interface BuildItemDisplay {
Expand Down Expand Up @@ -125,6 +126,7 @@ export const flattenedBuildTable = buildTable.flat();
export class BuildMenu extends LitElement implements Layer {
public game: GameView;
public eventBus: EventBus;
public uiState: UIState;
private clickedTile: TileRef;
public playerActions: PlayerActions | null;
private filteredBuildTable: BuildItemDisplay[][] = buildTable;
Expand Down Expand Up @@ -395,7 +397,14 @@ export class BuildMenu extends LitElement implements Layer {
),
);
} else if (buildableUnit.canBuild) {
this.eventBus.emit(new BuildUnitIntentEvent(buildableUnit.type, tile));
const rocketDirectionUp =
buildableUnit.type === UnitType.AtomBomb ||
buildableUnit.type === UnitType.HydrogenBomb
? this.uiState.rocketDirectionUp
: undefined;
this.eventBus.emit(
new BuildUnitIntentEvent(buildableUnit.type, tile, rocketDirectionUp),
);
}
this.hideMenu();
}
Expand Down
15 changes: 14 additions & 1 deletion src/client/graphics/layers/NukeTrajectoryPreviewLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ import { UnitType } from "../../../core/game/Game";
import { TileRef } from "../../../core/game/GameMap";
import { GameView } from "../../../core/game/GameView";
import { ParabolaPathFinder } from "../../../core/pathfinding/PathFinding";
import { GhostStructureChangedEvent, MouseMoveEvent } from "../../InputHandler";
import {
GhostStructureChangedEvent,
MouseMoveEvent,
SwapRocketDirectionEvent,
} from "../../InputHandler";
import { TransformHandler } from "../TransformHandler";
import { UIState } from "../UIState";
import { Layer } from "./Layer";

/**
Expand All @@ -24,6 +29,7 @@ export class NukeTrajectoryPreviewLayer implements Layer {
private game: GameView,
private eventBus: EventBus,
private transformHandler: TransformHandler,
private uiState: UIState,
) {}

shouldTransform(): boolean {
Expand All @@ -47,6 +53,12 @@ export class NukeTrajectoryPreviewLayer implements Layer {
this.cachedSpawnTile = null;
}
});
this.eventBus.on(SwapRocketDirectionEvent, () => {
// Toggle rocket direction
this.uiState.rocketDirectionUp = !this.uiState.rocketDirectionUp;
// Force trajectory recalculation
this.lastTargetTile = null;
});
}

tick() {
Expand Down Expand Up @@ -207,6 +219,7 @@ export class NukeTrajectoryPreviewLayer implements Layer {
targetTile,
speed,
distanceBasedHeight,
this.uiState.rocketDirectionUp,
);

this.trajectoryPoints = pathFinder.allTiles();
Expand Down
8 changes: 7 additions & 1 deletion src/client/graphics/layers/StructureIconsLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,10 +334,16 @@ export class StructureIconsLayer implements Layer {
),
);
} else if (this.ghostUnit.buildableUnit.canBuild) {
const unitType = this.ghostUnit.buildableUnit.type;
const rocketDirectionUp =
unitType === UnitType.AtomBomb || unitType === UnitType.HydrogenBomb
? this.uiState.rocketDirectionUp
: undefined;
this.eventBus.emit(
new BuildUnitIntentEvent(
this.ghostUnit.buildableUnit.type,
unitType,
this.game.ref(tile.x, tile.y),
rocketDirectionUp,
),
);
}
Expand Down
1 change: 1 addition & 0 deletions src/core/Schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ export const BuildUnitIntentSchema = BaseIntentSchema.extend({
type: z.literal("build_unit"),
unit: z.enum(UnitType),
tile: z.number(),
rocketDirectionUp: z.boolean().optional(),
});

export const UpgradeStructureIntentSchema = BaseIntentSchema.extend({
Expand Down
11 changes: 10 additions & 1 deletion src/core/execution/ConstructionExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class ConstructionExecution implements Execution {
private player: Player,
private constructionType: UnitType,
private tile: TileRef,
private rocketDirectionUp?: boolean,
) {}

init(mg: Game, ticks: number): void {
Expand Down Expand Up @@ -104,7 +105,15 @@ export class ConstructionExecution implements Execution {
case UnitType.AtomBomb:
case UnitType.HydrogenBomb:
this.mg.addExecution(
new NukeExecution(this.constructionType, player, this.tile),
new NukeExecution(
this.constructionType,
player,
this.tile,
null,
-1,
0,
this.rocketDirectionUp,
),
);
break;
case UnitType.MIRV:
Expand Down
7 changes: 6 additions & 1 deletion src/core/execution/ExecutionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,12 @@ export class Executor {
case "embargo_all":
return new EmbargoAllExecution(player, intent.action);
case "build_unit":
return new ConstructionExecution(player, intent.unit, intent.tile);
return new ConstructionExecution(
player,
intent.unit,
intent.tile,
intent.rocketDirectionUp,
);
case "allianceExtension": {
return new AllianceExtensionExecution(player, intent.recipient);
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/execution/NukeExecution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class NukeExecution implements Execution {
private src?: TileRef | null,
private speed: number = -1,
private waitTicks = 0,
private rocketDirectionUp: boolean = true,
) {}

init(mg: Game, ticks: number): void {
Expand Down Expand Up @@ -115,6 +116,7 @@ export class NukeExecution implements Execution {
this.dst,
this.speed,
this.nukeType !== UnitType.MIRVWarhead,
this.rocketDirectionUp,
);
this.nuke = this.player.buildUnit(this.nukeType, spawn, {
targetTile: this.dst,
Expand Down
21 changes: 18 additions & 3 deletions src/core/pathfinding/PathFinding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class ParabolaPathFinder {
dst: TileRef,
increment: number = 3,
distanceBasedHeight = true,
directionUp = true,
) {
const p0 = { x: this.mg.x(orig), y: this.mg.y(orig) };
const p3 = { x: this.mg.x(dst), y: this.mg.y(dst) };
Expand All @@ -25,14 +26,28 @@ export class ParabolaPathFinder {
const maxHeight = distanceBasedHeight
? Math.max(distance / 3, parabolaMinHeight)
: 0;
// Use a bezier curve always pointing up
// Use a bezier curve pointing up or down based on directionUp parameter
const heightMultiplier = directionUp ? -1 : 1;
const mapHeight = this.mg.height();
const p1 = {
x: p0.x + (p3.x - p0.x) / 4,
y: Math.max(p0.y + (p3.y - p0.y) / 4 - maxHeight, 0),
y: Math.max(
0,
Math.min(
p0.y + (p3.y - p0.y) / 4 + heightMultiplier * maxHeight,
mapHeight - 1,
),
),
};
const p2 = {
x: p0.x + ((p3.x - p0.x) * 3) / 4,
y: Math.max(p0.y + ((p3.y - p0.y) * 3) / 4 - maxHeight, 0),
y: Math.max(
0,
Math.min(
p0.y + ((p3.y - p0.y) * 3) / 4 + heightMultiplier * maxHeight,
mapHeight - 1,
),
),
};

this.curve = new DistanceBasedBezierCurve(p0, p1, p2, p3, increment);
Expand Down
2 changes: 1 addition & 1 deletion tests/InputHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe("InputHandler AutoUpgrade", () => {
eventBus = new EventBus();

inputHandler = new InputHandler(
{ attackRatio: 20, ghostStructure: null },
{ attackRatio: 20, ghostStructure: null, rocketDirectionUp: true },
mockCanvas,
eventBus,
);
Expand Down
Loading