Skip to content
1 change: 1 addition & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ export default {
global: { branches: 0, functions: 0, lines: 0, statements: 0 },
},
coverageReporters: ["text", "lcov", "html"],
setupFilesAfterEnv: ["<rootDir>/tests/setup.ts"],
};
5 changes: 4 additions & 1 deletion resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,9 @@
},
"messages": {
"airplane_intercepted": "Airplane intercepted",
"missile_failed_intercept": "Missile failed to intercept target"
"missile_failed_intercept": "Missile failed to intercept target",
"domestic_trade_summary": "You received {goldAmount} gold from domestic trade in the last 30 seconds.",
"international_trade_origin": "Your cargo truck successfully delivered goods to {destinationName}. You received {goldAmount} gold.",
"international_trade_destination": "A cargo truck from {originName} arrived. You received {goldAmount} gold."
}
}
17 changes: 17 additions & 0 deletions src/client/Transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PlayerType,
Tick,
UnitType,
UpgradeType,
} from "../core/game/Game";
import { TileRef } from "../core/game/GameMap";
import { PlayerView } from "../core/game/GameView";
Expand Down Expand Up @@ -92,6 +93,10 @@ export class BuildUnitIntentEvent implements GameEvent {
) {}
}

export class SendPurchaseUpgradeIntentEvent implements GameEvent {
constructor(public readonly upgrade: UpgradeType) {}
}

export class SendTargetPlayerIntentEvent implements GameEvent {
constructor(public readonly targetID: PlayerID) {}
}
Expand Down Expand Up @@ -254,6 +259,10 @@ export class Transport {
this.onSendSetAutoBombingEvent(e),
);

this.eventBus.on(SendPurchaseUpgradeIntentEvent, (e) =>
this.onSendPurchaseUpgradeIntent(e),
);

this.eventBus.on(BuildUnitIntentEvent, (e) => this.onBuildUnitIntent(e));

this.eventBus.on(PauseGameEvent, (e) => this.onPauseGameEvent(e));
Expand Down Expand Up @@ -579,6 +588,14 @@ export class Transport {
});
}

private onSendPurchaseUpgradeIntent(event: SendPurchaseUpgradeIntentEvent) {
this.sendIntent({
type: "purchase_upgrade",
clientID: this.lobbyConfig.clientID,
upgrade: event.upgrade,
});
}

private onPauseGameEvent(event: PauseGameEvent) {
if (!this.isLocal) {
console.log(`cannot pause multiplayer games`);
Expand Down
4 changes: 4 additions & 0 deletions src/client/graphics/GameRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
import { TransformHandler } from "./TransformHandler";
import { UIState } from "./UIState";
import { BuildMenu } from "./layers/BuildMenu";
import { CargoTruckLayer } from "./layers/CargoTruckLayer";
import { ChatDisplay } from "./layers/ChatDisplay";
import { ChatModal } from "./layers/ChatModal";
import { ControlPanel } from "./layers/ControlPanel";
Expand All @@ -23,6 +24,7 @@ import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay";
import { PlayerPanel } from "./layers/PlayerPanel";
import { RadialMenu } from "./layers/RadialMenu";
import { ReplayPanel } from "./layers/ReplayPanel";
import { RoadLayer } from "./layers/RoadLayer";
import { SpawnTimer } from "./layers/SpawnTimer";
import { StructureLayer } from "./layers/StructureLayer";
import { TeamStats } from "./layers/TeamStats";
Expand Down Expand Up @@ -217,6 +219,8 @@ export function createRenderer(
const layers: Layer[] = [
new TerrainLayer(game, transformHandler),
new TerritoryLayer(game, eventBus, transformHandler),
new RoadLayer(game, transformHandler),
new CargoTruckLayer(game, transformHandler),
structureLayer,
new UnitLayer(game, eventBus, transformHandler),
new FxLayer(game),
Expand Down
102 changes: 102 additions & 0 deletions src/client/graphics/layers/CargoTruckLayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {
CargoTrucksUpdate,
GameUpdateType,
SerializedCargoTruck,
} from "../../../core/game/GameUpdates";
import { GameView } from "../../../core/game/GameView";
import { TransformHandler } from "../TransformHandler";
import { Layer } from "./Layer";

export class CargoTruckLayer implements Layer {
private canvas: HTMLCanvasElement;
private ctx: CanvasRenderingContext2D;
private trucks = new Map<number, SerializedCargoTruck>();

constructor(
private game: GameView,
private transform: TransformHandler,
) {}

shouldTransform(): boolean {
return true;
}

init(): void {
this.canvas = document.createElement("canvas");
const ctx = this.canvas.getContext("2d");
if (!ctx) throw new Error("2D context not supported");
this.ctx = ctx;
this.canvas.width = this.game.width();
this.canvas.height = this.game.height();
}

tick(): void {
const updates = this.game.updatesSinceLastTick();
if (!updates) return;

const cargoTruckUpdatesArray = updates[
GameUpdateType.CargoTrucks
] as CargoTrucksUpdate[];
if (cargoTruckUpdatesArray) {
for (const cargoTruckUpdates of cargoTruckUpdatesArray) {
for (const addedTruck of cargoTruckUpdates.added) {
this.trucks.set(addedTruck.id, addedTruck);
}
for (const removedTruckId of cargoTruckUpdates.removed) {
this.trucks.delete(removedTruckId);
}
for (const updatedTruck of cargoTruckUpdates.updated) {
const existingTruck = this.trucks.get(updatedTruck.id);
if (existingTruck) {
// Preserve new properties that don't come in the 'updated' payload
existingTruck.position = updatedTruck.position;
existingTruck.progress = updatedTruck.progress;
}
}
}
}
}

renderLayer(context: CanvasRenderingContext2D): void {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
if (this.trucks.size === 0) return;

this.ctx.fillStyle = "#333333"; // Dark grey for all trucks
const truckSize = 0.5; // Half a tile size

for (const truck of this.trucks.values()) {
// Draw the main truck block
const x = truck.position[0];
const y = truck.position[1];
this.ctx.fillRect(
x + (1 - truckSize) / 2,
y + (1 - truckSize) / 2,
truckSize,
truckSize,
);

// If it's an international truck and not at the start of its path, draw a second "trailer" block.
if (truck.isInternational && truck.progress > 0) {
const trailerTile = truck.path[truck.progress - 1];
if (trailerTile) {
const trailerX = this.game.x(trailerTile);
const trailerY = this.game.y(trailerTile);
this.ctx.fillRect(
trailerX + (1 - truckSize) / 2,
trailerY + (1 - truckSize) / 2,
truckSize,
truckSize,
);
}
}
}

context.drawImage(
this.canvas,
-this.game.width() / 2,
-this.game.height() / 2,
this.game.width(),
this.game.height(),
);
}
}
Loading
Loading