Add gold fx when a tradeship lands (#1322)

## Description:

Add a text popup FX when a tradeship lands in your port.
They are only displayed for the current player.


https://github.com/user-attachments/assets/586ded57-5311-4394-a322-903ecea89bd6


## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

## Please put your Discord username so you can be contacted if a bug or
regression is found:

IngloriousTom

---------

Co-authored-by: Tom Rouillard <trouilla@mathworks.com>
Co-authored-by: evanpelle <evanpelle@gmail.com>
This commit is contained in:
DevelopingTom
2025-07-04 04:26:36 +02:00
committed by GitHub
parent 08f51f7a8b
commit 29170321e4
7 changed files with 22 additions and 34 deletions
-9
View File
@@ -1,14 +1,5 @@
import { Fx } from "./Fx";
// Shorten a number by replacing thousands with "k"
export function shortenNumber(num: number): string {
if (num >= 1_000) {
return (num / 1_000).toFixed(1).replace(/\.0$/, "") + "k";
} else {
return num.toString();
}
}
export class TextFx implements Fx {
private lifeTime: number = 0;
+7 -6
View File
@@ -6,11 +6,12 @@ import {
RailroadUpdate,
} from "../../../core/game/GameUpdates";
import { GameView, UnitView } from "../../../core/game/GameView";
import { renderNumber } from "../../Utils";
import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader";
import { Fx, FxType } from "../fx/Fx";
import { nukeFxFactory, ShockwaveFx } from "../fx/NukeFx";
import { SpriteFx } from "../fx/SpriteFx";
import { shortenNumber, TextFx } from "../fx/TextFx";
import { TextFx } from "../fx/TextFx";
import { UnitExplosionFx } from "../fx/UnitExplosionFx";
import { Layer } from "./Layer";
export class FxLayer implements Layer {
@@ -69,25 +70,25 @@ export class FxLayer implements Layer {
const workers = bonus.workers;
if (gold > 0) {
const shortened = shortenNumber(gold);
this.addTextFx(`+ ${shortened} gold`, x, y);
const shortened = renderNumber(gold);
this.addTextFx(`+ ${shortened}`, x, y);
y += 10; // increase y so the next popup starts bellow
}
if (troops > 0) {
const shortened = shortenNumber(troops);
const shortened = renderNumber(troops);
this.addTextFx(`+ ${shortened} troops`, x, y);
y += 10;
}
if (workers > 0) {
const shortened = shortenNumber(workers);
const shortened = renderNumber(workers);
this.addTextFx(`+ ${shortened} workers`, x, y);
}
}
addTextFx(text: string, x: number, y: number) {
const textFx = new TextFx(text, x, y, 500, 20);
const textFx = new TextFx(text, x, y, 1000, 20);
this.allFx.push(textFx);
}
+2 -2
View File
@@ -129,7 +129,7 @@ export class TradeShipExecution implements Execution {
const gold = this.mg.config().tradeShipGold(this.tilesTraveled);
if (this.wasCaptured) {
this.tradeShip!.owner().addGold(gold);
this.tradeShip!.owner().addGold(gold, this._dstPort.tile());
this.mg.displayMessage(
`Received ${renderNumber(gold)} gold from ship captured from ${this.origOwner.displayName()}`,
MessageType.CAPTURED_ENEMY_UNIT,
@@ -138,7 +138,7 @@ export class TradeShipExecution implements Execution {
);
} else {
this.srcPort.owner().addGold(gold);
this._dstPort.owner().addGold(gold);
this._dstPort.owner().addGold(gold, this._dstPort.tile());
this.mg.displayMessage(
`Received ${renderNumber(gold)} gold from trade with ${this.srcPort.owner().displayName()}`,
MessageType.RECEIVED_GOLD_FROM_TRADE,
+1 -1
View File
@@ -502,7 +502,7 @@ export interface Player {
workers(): number;
troops(): number;
targetTroopRatio(): number;
addGold(toAdd: Gold): void;
addGold(toAdd: Gold, tile?: TileRef): void;
removeGold(toRemove: Gold): Gold;
addWorkers(toAdd: number): void;
removeWorkers(toRemove: number): void;
+10 -1
View File
@@ -698,8 +698,17 @@ export class PlayerImpl implements Player {
return this._gold;
}
addGold(toAdd: Gold): void {
addGold(toAdd: Gold, tile?: TileRef): void {
this._gold += toAdd;
if (tile) {
this.mg.addUpdate({
type: GameUpdateType.BonusEvent,
tile,
gold: Number(toAdd),
workers: 0,
troops: 0,
});
}
}
removeGold(toRemove: Gold): Gold {
+1 -8
View File
@@ -21,14 +21,7 @@ class CityStopHandler implements TrainStopHandler {
trainExecution: TrainExecution,
): void {
const goldBonus = mg.config().trainGold();
station.unit.owner().addGold(goldBonus);
mg.addUpdate({
type: GameUpdateType.BonusEvent,
tile: station.tile(),
gold: Number(goldBonus),
workers: 0,
troops: 0,
});
station.unit.owner().addGold(goldBonus, station.tile());
}
}
+1 -7
View File
@@ -44,13 +44,7 @@ describe("TrainStation", () => {
station.onTrainStop(trainExecution);
expect(unit.owner().addGold).toHaveBeenCalledWith(10);
expect(game.addUpdate).toHaveBeenCalledWith(
expect.objectContaining({
type: expect.any(Number),
gold: 10,
}),
);
expect(unit.owner().addGold).toHaveBeenCalledWith(10, unit.tile());
});
it("handles Port stop", () => {