diff --git a/client/src/Activities.tsx b/client/src/Activities.tsx
index af1834f..e155d9a 100644
--- a/client/src/Activities.tsx
+++ b/client/src/Activities.tsx
@@ -246,7 +246,13 @@ const Activities: React.FC = () => {
{placement && (
- {who} must place a {placeRoad ? "road" : "settlement"}.
+ {who} must place {
+ (turn && (turn as any).active === "road-building" && (turn as any).freeRoads)
+ ? `${(turn as any).freeRoads} roads`
+ : placeRoad
+ ? "a road"
+ : "a settlement"
+ }.
)}
diff --git a/server/routes/games.ts b/server/routes/games.ts
index a02caac..39b5f72 100755
--- a/server/routes/games.ts
+++ b/server/routes/games.ts
@@ -2839,14 +2839,43 @@ const placeRoad = (game: Game, session: Session, index: number): string | undefi
road.color = session.color;
road.type = "road";
player.roads--;
+ /* Handle normal play road placement including Road Building free roads.
+ * If the turn is a road-building action, decrement freeRoads and
+ * only clear actions when no free roads remain. Otherwise, during
+ * initial placement we advance the initial-placement sequence. */
+ if (game.state === "normal") {
+ addActivity(game, session, `${session.name} placed a road.`);
+ calculateRoadLengths(game, session);
- /* During initial placement, placing a road advances the initial-placement
- * sequence. In forward direction we move to the next player; when the
- * last player places their road we flip to backward and begin the reverse
- * settlement placements. In backward direction we move to the previous
- * player and when the first player finishes, initial placement is done
- * and normal play begins. */
- if (game.state === "initial-placement") {
+ let resetLimits = true;
+ if (game.turn && (game.turn as any).active === "road-building") {
+ if ((game.turn as any).freeRoads !== undefined) {
+ (game.turn as any).freeRoads = (game.turn as any).freeRoads - 1;
+ }
+ if ((game.turn as any).freeRoads === 0) {
+ delete (game.turn as any).free;
+ delete (game.turn as any).active;
+ delete (game.turn as any).freeRoads;
+ }
+
+ const roads = getValidRoads(game, session.color as string);
+ if (!roads || roads.length === 0) {
+ delete (game.turn as any).active;
+ delete (game.turn as any).freeRoads;
+ addActivity(game, session, `${session.name} has another road to play, but there are no more valid locations.`);
+ } else if ((game.turn as any).freeRoads !== 0) {
+ (game.turn as any).free = true;
+ setForRoadPlacement(game, roads);
+ resetLimits = false;
+ }
+ }
+
+ if (resetLimits) {
+ delete (game.turn as any).free;
+ game.turn.actions = [];
+ game.turn.limits = {};
+ }
+ } else if (game.state === "initial-placement") {
const order: PlayerColor[] = game.playerOrder;
const idx = order.indexOf(session.color);
// defensive: if player not found, just clear actions and continue