Add dynamic railroad fares based on segment length and congestion

- Track train counts per railroad segment
- expose a fare API on segments
- charge players when entering each segment with visual feedback
This commit is contained in:
scamiv
2025-11-21 16:19:14 +01:00
parent 1f1e0341cf
commit 2d2d0e8b5a
2 changed files with 58 additions and 0 deletions
+29
View File
@@ -1,6 +1,7 @@
import {
Execution,
Game,
MessageType,
Player,
TrainType,
Unit,
@@ -107,6 +108,29 @@ export class TrainExecution implements Execution {
};
}
private enterRailroad(railroad: OrientedRailroad) {
const rail = railroad.getRailroad();
rail.incrementTrainCount();
const fare = rail.getFare();
this.player.addGold(-fare, railroad.getStart().tile());
if (this.mg) {
this.mg.displayMessage(
"Paid railroad fare",
MessageType.RECEIVED_GOLD_FROM_TRADE,
this.player.id(),
-fare,
);
}
}
private leaveRailroad() {
if (!this.currentRailroad) {
return;
}
const rail = this.currentRailroad.getRailroad();
rail.decrementTrainCount();
}
init(mg: Game, ticks: number): void {
this.mg = mg;
@@ -215,6 +239,8 @@ export class TrainExecution implements Execution {
private deleteTrain() {
this.active = false;
this.leaveRailroad();
if (this.train?.isActive()) {
this.train.delete(false);
}
@@ -337,8 +363,11 @@ export class TrainExecution implements Execution {
// This should happen after arrival processing but before departure
this.journeyHopCount++;
// Move to the next station and railroad, updating fare/usage tracking
this.currentStation = nextHop;
this.leaveRailroad();
this.currentRailroad = railroad;
this.enterRailroad(railroad);
this.currentTile = 0;
}
+29
View File
@@ -4,6 +4,8 @@ import { GameUpdateType, RailTile, RailType } from "./GameUpdates";
import { TrainStation } from "./TrainStation";
export class Railroad {
private trainCount: number = 0;
constructor(
public from: TrainStation,
public to: TrainStation,
@@ -23,6 +25,29 @@ export class Railroad {
this.from.removeRailroad(this);
this.to.removeRailroad(this);
}
incrementTrainCount(): void {
this.trainCount++;
}
decrementTrainCount(): void {
this.trainCount = Math.max(0, this.trainCount - 1);
}
getLength(): number {
return this.tiles.length;
}
/**
* Dynamic fare based on railroad length and current busyness.
* Longer railroads cost more, but overcrowded edges become less profitable.
* Uses integer math to keep amounts precise.
*/
getFare(): bigint {
const baseFare = BigInt(this.getLength() * 100); // Base fare proportional to length
const busynessFactor = Math.max(1, 10 - this.trainCount); // 10,9,...,1 (capped)
return (baseFare * BigInt(busynessFactor)) / 10n;
}
}
export function getOrientedRailroad(
@@ -54,6 +79,10 @@ export class OrientedRailroad {
return this.tiles;
}
getRailroad(): Railroad {
return this.railroad;
}
getStart(): TrainStation {
return this.forward ? this.railroad.from : this.railroad.to;
}