Refactoring continues
This commit is contained in:
parent
4d061a8054
commit
5312b0dc7f
@ -394,14 +394,7 @@ const RoomView = (props: RoomProps) => {
|
|||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
{name && <PlayerList />}
|
{name && <PlayerList />}
|
||||||
{/* Trade is an untyped JS component; assert its type to avoid `any` */}
|
{tradeActive && <Trade />}
|
||||||
{(() => {
|
|
||||||
const TradeComponent = Trade as unknown as React.ComponentType<{
|
|
||||||
tradeActive: boolean;
|
|
||||||
setTradeActive: (v: boolean) => void;
|
|
||||||
}>;
|
|
||||||
return <TradeComponent tradeActive={tradeActive} setTradeActive={setTradeActive} />;
|
|
||||||
})()}
|
|
||||||
{name !== "" && <Chat />}
|
{name !== "" && <Chat />}
|
||||||
{/* name !== "" && <VideoFeeds/> */}
|
{/* name !== "" && <VideoFeeds/> */}
|
||||||
{loaded && (
|
{loaded && (
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Trade > * {
|
.Trade > * {
|
||||||
max-height: calc(100vh - 2rem);
|
max-height: calc(100dvh - 2rem);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 32em;
|
width: 32em;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@ -100,9 +100,6 @@
|
|||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Trade .Resource.None {
|
|
||||||
/* filter: brightness(70%); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.Trade .PlayerColor {
|
.Trade .PlayerColor {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
@ -601,8 +601,7 @@ const Trade: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Trade">
|
<Paper className="Trade">
|
||||||
<Paper>
|
|
||||||
<div className="PlayerList">{tradeElements}</div>
|
<div className="PlayerList">{tradeElements}</div>
|
||||||
{priv.resources === 0 && (
|
{priv.resources === 0 && (
|
||||||
<div>
|
<div>
|
||||||
@ -620,7 +619,6 @@ const Trade: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
} from "./games/constants";
|
} from "./games/constants";
|
||||||
|
|
||||||
import { getValidRoads, getValidCorners, isRuleEnabled } from "../util/validLocations";
|
import { getValidRoads, getValidCorners, isRuleEnabled } from "../util/validLocations";
|
||||||
import { Player, Game, Session, CornerPlacement, RoadPlacement } from "./games/types";
|
import { Player, Game, Session, CornerPlacement, RoadPlacement, Offer } from "./games/types";
|
||||||
import { newPlayer } from "./games/playerFactory";
|
import { newPlayer } from "./games/playerFactory";
|
||||||
import { normalizeIncoming, shuffleArray } from "./games/utils";
|
import { normalizeIncoming, shuffleArray } from "./games/utils";
|
||||||
// import type { GameState } from './games/state'; // unused import removed during typing pass
|
// import type { GameState } from './games/state'; // unused import removed during typing pass
|
||||||
@ -106,22 +106,27 @@ const processTies = (players: Player[]): boolean => {
|
|||||||
return ties;
|
return ties;
|
||||||
};
|
};
|
||||||
|
|
||||||
const processGameOrder = (game: any, player: any, dice: number): any => {
|
const processGameOrder = (game: Game, player: Player, dice: number): any => {
|
||||||
if (player.orderRoll) {
|
if (player.orderRoll) {
|
||||||
return `You have already rolled for game order and are not in a tie.`;
|
return `You have already rolled for game order and are not in a tie.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.orderRoll = dice;
|
player.orderRoll = dice;
|
||||||
player.order = player.order * 6 + dice;
|
player.order = (player.order || 0) * 6 + dice;
|
||||||
|
|
||||||
const players = [];
|
const players: Player[] = [];
|
||||||
|
|
||||||
let doneRolling = true;
|
let doneRolling = true;
|
||||||
for (let key in game.players) {
|
for (const key in game.players) {
|
||||||
if (!game.players[key].orderRoll) {
|
const p = game.players[key];
|
||||||
|
if (!p) {
|
||||||
|
doneRolling = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!p.orderRoll) {
|
||||||
doneRolling = false;
|
doneRolling = false;
|
||||||
}
|
}
|
||||||
players.push(game.players[key]);
|
players.push(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If 'doneRolling' is FALSE then there are still players to roll */
|
/* If 'doneRolling' is FALSE then there are still players to roll */
|
||||||
@ -155,12 +160,13 @@ const processGameOrder = (game: any, player: any, dice: number): any => {
|
|||||||
`Player order set to ` + players.map((player) => `${player.position}: ${player.name}`).join(", ") + `.`
|
`Player order set to ` + players.map((player) => `${player.position}: ${player.name}`).join(", ") + `.`
|
||||||
);
|
);
|
||||||
|
|
||||||
game.playerOrder = players.map((player) => player.color);
|
game.playerOrder = players.map((player) => player.color as string);
|
||||||
game.state = "initial-placement";
|
game.state = "initial-placement";
|
||||||
game.direction = "forward";
|
(game as any)["direction"] = "forward";
|
||||||
|
const first = players[0];
|
||||||
game.turn = {
|
game.turn = {
|
||||||
name: players[0].name,
|
name: first?.name as string,
|
||||||
color: players[0].color,
|
color: first?.color as string,
|
||||||
};
|
};
|
||||||
setForSettlementPlacement(game, getValidCorners(game, ""));
|
setForSettlementPlacement(game, getValidCorners(game, ""));
|
||||||
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
|
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
|
||||||
@ -170,7 +176,7 @@ const processGameOrder = (game: any, player: any, dice: number): any => {
|
|||||||
sendUpdateToPlayers(game, {
|
sendUpdateToPlayers(game, {
|
||||||
players: getFilteredPlayers(game),
|
players: getFilteredPlayers(game),
|
||||||
state: game.state,
|
state: game.state,
|
||||||
direction: game.direction,
|
direction: (game as any)["direction"],
|
||||||
turn: game.turn,
|
turn: game.turn,
|
||||||
chat: game.chat,
|
chat: game.chat,
|
||||||
activities: game.activities,
|
activities: game.activities,
|
||||||
@ -235,8 +241,8 @@ const processVolcano = (game: Game, session: Session, dice: number[]): any => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const roll = (game: any, session: any, dice?: number[] | undefined): any => {
|
const roll = (game: Game, session: Session, dice?: number[] | undefined): any => {
|
||||||
const player = session.player,
|
const player = session.player as Player,
|
||||||
name = session.name ? session.name : "Unnamed";
|
name = session.name ? session.name : "Unnamed";
|
||||||
|
|
||||||
if (!dice) {
|
if (!dice) {
|
||||||
@ -250,7 +256,7 @@ const roll = (game: any, session: any, dice?: number[] | undefined): any => {
|
|||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
case "game-order":
|
case "game-order":
|
||||||
game.startTime = Date.now();
|
(game as any)["startTime"] = Date.now();
|
||||||
addChatMessage(game, session, `${name} rolled ${dice[0]}.`);
|
addChatMessage(game, session, `${name} rolled ${dice[0]}.`);
|
||||||
if (typeof dice[0] !== "number") {
|
if (typeof dice[0] !== "number") {
|
||||||
return `Invalid roll value.`;
|
return `Invalid roll value.`;
|
||||||
@ -286,31 +292,29 @@ const roll = (game: any, session: any, dice?: number[] | undefined): any => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sessionFromColor = (game: any, color: string): any | undefined => {
|
const sessionFromColor = (game: Game, color: string): Session | undefined => {
|
||||||
for (let key in game.sessions) {
|
for (const key in game.sessions) {
|
||||||
if (game.sessions[key].color === color) {
|
const s = game.sessions[key];
|
||||||
return game.sessions[key];
|
if (s && s.color === color) {
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const distributeResources = (game: any, roll: number): void => {
|
const distributeResources = (game: Game, roll: number): void => {
|
||||||
console.log(`Roll: ${roll}`);
|
console.log(`Roll: ${roll}`);
|
||||||
/* Find which tiles have this roll */
|
/* Find which tiles have this roll */
|
||||||
let tiles = [];
|
const matchedTiles: { robber: boolean; index: number }[] = [];
|
||||||
for (let i = 0; i < game.pipOrder.length; i++) {
|
const pipOrder = game.pipOrder || [];
|
||||||
let index = game.pipOrder[i];
|
for (let i = 0; i < pipOrder.length; i++) {
|
||||||
if (staticData.pips?.[index] && staticData.pips[index].roll === roll) {
|
const index = pipOrder[i];
|
||||||
if (game.robber === i) {
|
if (typeof index === "number" && staticData.pips?.[index] && staticData.pips[index].roll === roll) {
|
||||||
tiles.push({ robber: true, index: i });
|
matchedTiles.push({ robber: game.robber === i, index: i });
|
||||||
} else {
|
|
||||||
tiles.push({ robber: false, index: i });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const receives: Record<string, any> = {
|
const receives: Record<string, Record<string, number>> = {
|
||||||
O: { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
O: { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
||||||
R: { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
R: { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
||||||
W: { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
W: { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 },
|
||||||
@ -319,65 +323,65 @@ const distributeResources = (game: any, roll: number): void => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Find which corners are on each tile */
|
/* Find which corners are on each tile */
|
||||||
tiles.forEach((tile) => {
|
matchedTiles.forEach((tile) => {
|
||||||
let shuffle = game.tileOrder[tile.index];
|
const tileOrder = game.tileOrder || [];
|
||||||
const resource = game.tiles[shuffle];
|
const gameTiles = game.tiles || [];
|
||||||
|
const shuffle = tileOrder[tile.index];
|
||||||
|
const resource = typeof shuffle === "number" ? gameTiles[shuffle] : undefined;
|
||||||
const tileLayout = layout.tiles?.[tile.index];
|
const tileLayout = layout.tiles?.[tile.index];
|
||||||
tileLayout?.corners.forEach((cornerIndex: number) => {
|
tileLayout?.corners.forEach((cornerIndex: number) => {
|
||||||
const active = game.placements.corners?.[cornerIndex];
|
const active = game.placements.corners?.[cornerIndex];
|
||||||
if (active && active.color) {
|
if (active && active.color && resource) {
|
||||||
const count = active.type === "settlement" ? 1 : 2;
|
const count = active.type === "settlement" ? 1 : 2;
|
||||||
if (!tile.robber) {
|
if (!tile.robber) {
|
||||||
receives[active.color][resource.type] += count;
|
if (!receives[active.color]) receives[active.color] = { wood: 0, brick: 0, sheep: 0, wheat: 0, stone: 0 };
|
||||||
|
if (resource && resource.type) (receives as any)[active.color][resource.type] += count;
|
||||||
} else {
|
} else {
|
||||||
if (isRuleEnabled(game, `robin-hood-robber`) && game.players[active.color].points <= 2) {
|
const victim = game.players[active.color];
|
||||||
|
if (isRuleEnabled(game, `robin-hood-robber`) && victim && (victim.points || 0) <= 2) {
|
||||||
addChatMessage(
|
addChatMessage(
|
||||||
game,
|
game,
|
||||||
null,
|
null,
|
||||||
`Robber does not steal ${count}
|
`Robber does not steal ${count} ${resource.type} from ${victim?.name} due to Robin Hood Robber house rule.`
|
||||||
${resource.type} from ${game.players[active.color].name} ` + `due to Robin Hood Robber house rule.`
|
|
||||||
);
|
);
|
||||||
console.log(`robin-hood-robber`, game.players[active.color], active.color);
|
if (resource && resource.type) (receives as any)[active.color][resource.type] += count;
|
||||||
receives[active.color][resource.type] += count;
|
|
||||||
} else {
|
} else {
|
||||||
trackTheft(game, active.color, "robber", resource.type, count);
|
trackTheft(game, active.color, "robber", resource.type, count);
|
||||||
receives["robber"][resource.type] += count;
|
if (resource && resource.type) (receives as any)["robber"][resource.type] += count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const robber = [];
|
const robberList: string[] = [];
|
||||||
for (let color in receives) {
|
for (const color in receives) {
|
||||||
const entry = receives[color];
|
const entry = receives[color];
|
||||||
if (!entry.wood && !entry.brick && !entry.sheep && !entry.wheat && !entry.stone) {
|
if (!entry || !(entry["wood"] || entry["brick"] || entry["sheep"] || entry["wheat"] || entry["stone"])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let messageParts: string[] = [],
|
const messageParts: string[] = [];
|
||||||
session;
|
let s: Session | undefined;
|
||||||
for (let type in entry) {
|
for (const type in entry) {
|
||||||
if (entry[type] === 0) {
|
if (entry[type] === 0) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color !== "robber") {
|
if (color !== "robber") {
|
||||||
session = sessionFromColor(game, color);
|
s = sessionFromColor(game, color);
|
||||||
session.player[type] += entry[type];
|
if (!s || !s.player) continue;
|
||||||
session.player.resources += entry[type];
|
(s.player as any)[type] = ((s.player as any)[type] || 0) + entry[type];
|
||||||
|
(s.player as any).resources = ((s.player as any).resources || 0) + entry[type];
|
||||||
messageParts.push(`${entry[type]} ${type}`);
|
messageParts.push(`${entry[type]} ${type}`);
|
||||||
} else {
|
} else {
|
||||||
robber.push(`${entry[type]} ${type}`);
|
robberList.push(`${entry[type]} ${type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session) {
|
if (s) {
|
||||||
addChatMessage(game, session, `${session.name} receives ${messageParts.join(", ")} for pip ${roll}.`);
|
addChatMessage(game, s, `${s.name} receives ${messageParts.join(", ")} for pip ${roll}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (robber.length) {
|
if (robberList.length) {
|
||||||
addChatMessage(game, null, `That pesky ${game.robberName} Robber Roberson stole ${robber.join(", ")}!`);
|
addChatMessage(game, null, `That pesky ${game.robberName} Robber Roberson stole ${robberList.join(", ")}!`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1579,9 +1583,15 @@ const calculateRoadLengths = (game: Game, session: Session): void => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCompatibleOffer = (player: any, offer: any): boolean => {
|
const isCompatibleOffer = (player: Player, offer: Offer): boolean => {
|
||||||
const isBank = offer.name === "The bank";
|
const isBank = (offer as any)["name"] === "The bank";
|
||||||
let valid = player.gets.length === offer.gives.length && player.gives.length === offer.gets.length;
|
|
||||||
|
const playerGetsLen = (player as any)["gets"] ? (player as any)["gets"].length : 0;
|
||||||
|
const playerGivesLen = (player as any)["gives"] ? (player as any)["gives"].length : 0;
|
||||||
|
const offerGetsLen = (offer as any)["gets"] ? (offer as any)["gets"].length : 0;
|
||||||
|
const offerGivesLen = (offer as any)["gives"] ? (offer as any)["gives"].length : 0;
|
||||||
|
|
||||||
|
let valid = playerGetsLen === offerGivesLen && playerGivesLen === offerGetsLen;
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
console.log(`Gives and gets lengths do not match!`);
|
console.log(`Gives and gets lengths do not match!`);
|
||||||
@ -1591,76 +1601,81 @@ const isCompatibleOffer = (player: any, offer: any): boolean => {
|
|||||||
console.log(
|
console.log(
|
||||||
{
|
{
|
||||||
player: "Submitting player",
|
player: "Submitting player",
|
||||||
gets: player.gets,
|
gets: (player as any)["gets"],
|
||||||
gives: player.gives,
|
gives: (player as any)["gives"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: offer.name,
|
name: (offer as any)["name"],
|
||||||
gets: offer.gets,
|
gets: (offer as any)["gets"],
|
||||||
gives: offer.gives,
|
gives: (offer as any)["gives"],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
player.gets.forEach((get: any) => {
|
for (const get of (player as any)["gets"] || []) {
|
||||||
if (!valid) {
|
if (
|
||||||
return;
|
!(offer as any)["gives"] ||
|
||||||
|
!(offer as any)["gives"].some((item: any) => (item.type === get.type || isBank) && item.count === get.count)
|
||||||
|
) {
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
valid =
|
|
||||||
offer.gives.find((item: any) => (item.type === get.type || isBank) && item.count === get.count) !== undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (valid)
|
if (valid) {
|
||||||
player.gives.forEach((give: any) => {
|
for (const give of (player as any)["gives"] || []) {
|
||||||
if (!valid) {
|
if (
|
||||||
return;
|
!(offer as any)["gets"] ||
|
||||||
|
!(offer as any)["gets"].some((item: any) => (item.type === give.type || isBank) && item.count === give.count)
|
||||||
|
) {
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
valid =
|
|
||||||
offer.gets.find((item: any) => (item.type === give.type || isBank) && item.count === give.count) !== undefined;
|
|
||||||
});
|
|
||||||
return valid;
|
return valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSameOffer = (player: any, offer: any): boolean => {
|
const isSameOffer = (player: Player, offer: Offer): boolean => {
|
||||||
const isBank = offer.name === "The bank";
|
const isBank = (offer as any)["name"] === "The bank";
|
||||||
if (isBank) {
|
if (isBank) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let same =
|
|
||||||
player.gets &&
|
|
||||||
player.gives &&
|
|
||||||
player.gets.length === offer.gets.length &&
|
|
||||||
player.gives.length === offer.gives.length;
|
|
||||||
|
|
||||||
if (!same) {
|
if (!(player as any)["gets"] || !(player as any)["gives"] || !(offer as any)["gets"] || !(offer as any)["gives"]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.gets.forEach((get: any) => {
|
if (
|
||||||
if (!same) {
|
(player as any)["gets"].length !== (offer as any)["gets"].length ||
|
||||||
return;
|
(player as any)["gives"].length !== (offer as any)["gives"].length
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
same = offer.gets.find((item: any) => item.type === get.type && item.count === get.count) !== undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (same)
|
for (const get of (player as any)["gets"]) {
|
||||||
player.gives.forEach((give: any) => {
|
if (!(offer as any)["gets"].find((item: any) => item.type === get.type && item.count === get.count)) {
|
||||||
if (!same) {
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
same = offer.gives.find((item: any) => item.type === give.type && item.count === give.count) !== undefined;
|
}
|
||||||
});
|
|
||||||
return same;
|
for (const give of (player as any)["gives"]) {
|
||||||
|
if (!(offer as any)["gives"].find((item: any) => item.type === give.type && item.count === give.count)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Verifies player can meet the offer */
|
/* Verifies player can meet the offer */
|
||||||
const checkPlayerOffer = (_game: any, player: any, offer: any): string | undefined => {
|
const checkPlayerOffer = (_game: Game, player: Player, offer: Offer): string | undefined => {
|
||||||
let error: string | undefined = undefined;
|
let error: string | undefined = undefined;
|
||||||
const name = player.name;
|
const name = player.name || "Unknown";
|
||||||
|
|
||||||
console.log({
|
console.log({
|
||||||
checkPlayerOffer: {
|
checkPlayerOffer: {
|
||||||
name: name,
|
name,
|
||||||
player: player,
|
player,
|
||||||
gets: offer.gets,
|
gets: offer.gets,
|
||||||
gives: offer.gives,
|
gives: offer.gives,
|
||||||
sheep: player.sheep,
|
sheep: player.sheep,
|
||||||
@ -1672,57 +1687,57 @@ const checkPlayerOffer = (_game: any, player: any, offer: any): string | undefin
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
offer.gives.forEach((give: any) => {
|
for (const give of (offer as any)["gives"] || []) {
|
||||||
if (error) {
|
if (error) break;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(give.type in player)) {
|
if (!(give.type in (player as any))) {
|
||||||
error = `${give.type} is not a valid resource!`;
|
error = `${give.type} is not a valid resource!`;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (give.count <= 0) {
|
if (give.count <= 0) {
|
||||||
error = `${give.count} must be more than 0!`;
|
error = `${give.count} must be more than 0!`;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player[give.type] < give.count) {
|
if ((player as any)[give.type] < give.count) {
|
||||||
error = `${name} does do not have ${give.count} ${give.type}!`;
|
error = `${name} does do not have ${give.count} ${give.type}!`;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offer.gets.find((get: any) => give.type === get.type)) {
|
if (((offer as any)["gets"] || []).find((get: any) => give.type === get.type)) {
|
||||||
error = `${name} can not give and get the same resource type!`;
|
error = `${name} can not give and get the same resource type!`;
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (!error)
|
if (!error) {
|
||||||
offer.gets.forEach((get: any) => {
|
for (const get of (offer as any)["gets"] || []) {
|
||||||
if (error) {
|
if (error) break;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (get.count <= 0) {
|
if (get.count <= 0) {
|
||||||
error = `${get.count} must be more than 0!`;
|
error = `${get.count} must be more than 0!`;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
if (offer.gives.find((give: any) => get.type === give.type)) {
|
if (((offer as any)["gives"] || []).find((give: any) => get.type === give.type)) {
|
||||||
error = `${name} can not give and get the same resource type!`;
|
error = `${name} can not give and get the same resource type!`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
};
|
};
|
||||||
|
|
||||||
const canMeetOffer = (player: any, offer: any): boolean => {
|
const canMeetOffer = (player: Player, offer: Offer): boolean => {
|
||||||
for (let i = 0; i < offer.gets.length; i++) {
|
for (const get of (offer as any)["gets"] || []) {
|
||||||
const get = offer.gets[i];
|
|
||||||
if (get.type === "bank") {
|
if (get.type === "bank") {
|
||||||
if (player[player.gives[0].type] < get.count || get.count <= 0) {
|
const giveType =
|
||||||
|
(player as any)["gives"] && (player as any)["gives"][0] ? (player as any)["gives"][0].type : undefined;
|
||||||
|
if (!giveType) return false;
|
||||||
|
if ((player as any)[giveType] < get.count || get.count <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (player[get.type] < get.count || get.count <= 0) {
|
} else if ((player as any)[get.type] < get.count || get.count <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1783,11 +1798,11 @@ const setGameFromSignature = (game: any, border: string, pip: string, tile: stri
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const offerToString = (offer: any): string => {
|
const offerToString = (offer: Offer): string => {
|
||||||
return (
|
return (
|
||||||
(offer.gives || []).map((item: any) => `${item.count} ${item.type}`).join(", ") +
|
(offer.gives || []).map((item) => `${item.count} ${item.type}`).join(", ") +
|
||||||
" in exchange for " +
|
" in exchange for " +
|
||||||
(offer.gets || []).map((item: any) => `${item.count} ${item.type}`).join(", ")
|
(offer.gets || []).map((item) => `${item.count} ${item.type}`).join(", ")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1820,7 +1835,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
return res.status(400).send(error);
|
return res.status(400).send(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
const startTrade = (game: any, session: any): string | undefined => {
|
const startTrade = (game: Game, session: Session): string | undefined => {
|
||||||
/* Only the active player can begin trading */
|
/* Only the active player can begin trading */
|
||||||
if (game.turn.name !== session.name) {
|
if (game.turn.name !== session.name) {
|
||||||
return `You cannot start trading negotiations when it is not your turn.`;
|
return `You cannot start trading negotiations when it is not your turn.`;
|
||||||
@ -1832,15 +1847,17 @@ const startTrade = (game: any, session: any): string | undefined => {
|
|||||||
game.turn.actions = ["trade"];
|
game.turn.actions = ["trade"];
|
||||||
game.turn.limits = {};
|
game.turn.limits = {};
|
||||||
for (let key in game.players) {
|
for (let key in game.players) {
|
||||||
game.players[key].gives = [];
|
const p = game.players[key];
|
||||||
game.players[key].gets = [];
|
if (!p) continue;
|
||||||
delete game.players[key].offerRejected;
|
(p as any)["gives"] = [];
|
||||||
|
(p as any)["gets"] = [];
|
||||||
|
delete (p as any)["offerRejected"];
|
||||||
}
|
}
|
||||||
addActivity(game, session, `${session.name} requested to begin trading negotiations.`);
|
addActivity(game, session, `${session.name} requested to begin trading negotiations.`);
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelTrade = (game: any, session: any): string | undefined => {
|
const cancelTrade = (game: Game, session: Session): string | undefined => {
|
||||||
/* TODO: Perhaps 'cancel' is how a player can remove an offer... */
|
/* TODO: Perhaps 'cancel' is how a player can remove an offer... */
|
||||||
if (game.turn.name !== session.name) {
|
if (game.turn.name !== session.name) {
|
||||||
return `Only the active player can cancel trading negotiations.`;
|
return `Only the active player can cancel trading negotiations.`;
|
||||||
@ -1851,39 +1868,35 @@ const cancelTrade = (game: any, session: any): string | undefined => {
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const processOffer = (game: any, session: any, offer: any): string | undefined => {
|
const processOffer = (game: Game, session: Session, offer: Offer): string | undefined => {
|
||||||
let warning = checkPlayerOffer(game, session.player, offer);
|
const player = session.player as Player;
|
||||||
|
let warning = checkPlayerOffer(game, player, offer);
|
||||||
if (warning) {
|
if (warning) {
|
||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
if (isSameOffer(player, offer)) {
|
||||||
if (isSameOffer(session.player, offer)) {
|
console.log(player);
|
||||||
console.log(session.player);
|
|
||||||
return `You already have a pending offer submitted for ${offerToString(offer)}.`;
|
return `You already have a pending offer submitted for ${offerToString(offer)}.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.player.gives = offer.gives;
|
(player as any)["gives"] = (offer as any)["gives"];
|
||||||
session.player.gets = offer.gets;
|
(player as any)["gets"] = (offer as any)["gets"];
|
||||||
session.player.offerRejected = {};
|
(player as any)["offerRejected"] = {};
|
||||||
|
|
||||||
if (game.turn.color === session.color) {
|
if ((game.turn as any)["color"] === session.color) {
|
||||||
game.turn.offer = offer;
|
(game.turn as any)["offer"] = offer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this offer matches what another player wants, clear rejection
|
/* If this offer matches what another player wants, clear rejection on that other player's offer */
|
||||||
* on of that other player's offer */
|
for (const color in game.players) {
|
||||||
for (let color in game.players) {
|
if (color === session.color) continue;
|
||||||
if (color === session.color) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const other = game.players[color];
|
const other = game.players[color];
|
||||||
if (other.status !== "Active") {
|
if (!other) continue;
|
||||||
continue;
|
if ((other as any)["status"] !== "Active") continue;
|
||||||
}
|
|
||||||
/* Comparison reverses give/get order */
|
/* Comparison reverses give/get order */
|
||||||
if (isSameOffer(other, { gives: offer.gets, gets: offer.gives })) {
|
if (isSameOffer(other, { gives: (offer as any)["gets"], gets: (offer as any)["gives"] } as Offer)) {
|
||||||
if (other.offerRejected) {
|
if ((other as any)["offerRejected"]) {
|
||||||
delete other.offerRejected[session.color];
|
delete (other as any)["offerRejected"][session.color as string];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1892,72 +1905,79 @@ const processOffer = (game: any, session: any, offer: any): string | undefined =
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rejectOffer = (game: any, session: any, offer: any): void => {
|
const rejectOffer = (game: Game, session: Session, offer: Offer): void => {
|
||||||
/* If the active player rejected an offer, they rejected another player */
|
/* If the active player rejected an offer, they rejected another player */
|
||||||
const other = game.players[offer.color];
|
const other = game.players[(offer as any)["color"] as string];
|
||||||
if (!other.offerRejected) {
|
if (!other) return;
|
||||||
other.offerRejected = {};
|
if (!(other as any)["offerRejected"]) {
|
||||||
|
(other as any)["offerRejected"] = {};
|
||||||
}
|
}
|
||||||
other.offerRejected[session.color] = true;
|
(other as any)["offerRejected"][session.color as string] = true;
|
||||||
if (!session.player.offerRejected) {
|
if (!session.player) session.player = {} as Player;
|
||||||
session.player.offerRejected = {};
|
if (!(session.player as any)["offerRejected"]) {
|
||||||
|
(session.player as any)["offerRejected"] = {};
|
||||||
}
|
}
|
||||||
session.player.offerRejected[offer.color] = true;
|
(session.player as any)["offerRejected"][(offer as any)["color"] as string] = true;
|
||||||
addActivity(game, session, `${session.name} rejected ${other.name}'s offer.`);
|
addActivity(game, session, `${session.name} rejected ${other.name}'s offer.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const acceptOffer = (game: any, session: any, offer: any): string | undefined => {
|
const acceptOffer = (game: Game, session: Session, offer: Offer): string | undefined => {
|
||||||
const name = session.name,
|
const name = session.name,
|
||||||
player = session.player;
|
player = session.player as Player;
|
||||||
|
|
||||||
if (game.turn.name !== name) {
|
if (game.turn.name !== name) {
|
||||||
return `Only the active player can accept an offer.`;
|
return `Only the active player can accept an offer.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let target;
|
let target: any = undefined;
|
||||||
|
|
||||||
console.log({ description: offerToString(offer) });
|
console.log({ description: offerToString(offer) });
|
||||||
|
|
||||||
let warning = checkPlayerOffer(game, session.player, offer);
|
let warning = checkPlayerOffer(game, player, offer);
|
||||||
if (warning) {
|
if (warning) {
|
||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isCompatibleOffer(session.player, {
|
!isCompatibleOffer(player, {
|
||||||
name: offer.name,
|
name: (offer as any)["name"],
|
||||||
gives: offer.gets,
|
gives: (offer as any)["gets"],
|
||||||
gets: offer.gives,
|
gets: (offer as any)["gives"],
|
||||||
})
|
} as Offer)
|
||||||
) {
|
) {
|
||||||
return `Unfortunately, trades were re-negotiated in transit and 1 ` + `the deal is invalid!`;
|
return `Unfortunately, trades were re-negotiated in transit and 1 ` + `the deal is invalid!`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify that the offer sent by the active player matches what
|
/* Verify that the offer sent by the active player matches what
|
||||||
* the latest offer was that was received by the requesting player */
|
* the latest offer was that was received by the requesting player */
|
||||||
if (!offer.name || offer.name !== "The bank") {
|
if (!(offer as any)["name"] || (offer as any)["name"] !== "The bank") {
|
||||||
target = game.players[offer.color];
|
target = game.players[(offer as any)["color"] as string];
|
||||||
if (target.offerRejected && offer.color in target.offerRejected) {
|
if (!target) return `Invalid trade target.`;
|
||||||
|
if ((target as any)["offerRejected"] && (offer as any)["color"] in (target as any)["offerRejected"]) {
|
||||||
return `${target.name} rejected this offer.`;
|
return `${target.name} rejected this offer.`;
|
||||||
}
|
}
|
||||||
if (!isCompatibleOffer(target, offer)) {
|
if (!isCompatibleOffer(target as Player, offer)) {
|
||||||
return `Unfortunately, trades were re-negotiated in transit and ` + `the deal is invalid!`;
|
return `Unfortunately, trades were re-negotiated in transit and ` + `the deal is invalid!`;
|
||||||
}
|
}
|
||||||
|
|
||||||
warning = checkPlayerOffer(game, target, {
|
warning = checkPlayerOffer(
|
||||||
|
game,
|
||||||
|
target as Player,
|
||||||
|
{
|
||||||
gives: offer.gets,
|
gives: offer.gets,
|
||||||
gets: offer.gives,
|
gets: offer.gives,
|
||||||
});
|
} as Offer
|
||||||
|
);
|
||||||
if (warning) {
|
if (warning) {
|
||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSameOffer(target, { gives: offer.gets, gets: offer.gives })) {
|
if (!isSameOffer(target as Player, { gives: (offer as any)["gets"], gets: (offer as any)["gives"] } as Offer)) {
|
||||||
console.log({ target, offer });
|
console.log({ target, offer });
|
||||||
return `These terms were not agreed to by ${target.name}!`;
|
return `These terms were not agreed to by ${target.name}!`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canMeetOffer(target, player)) {
|
if (!canMeetOffer(target as Player, player as any)) {
|
||||||
return `${target.name} cannot meet the terms.`;
|
return `${target.name} cannot meet the terms.`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1967,44 +1987,48 @@ const acceptOffer = (game: any, session: any, offer: any): string | undefined =>
|
|||||||
debugChat(game, "Before trade");
|
debugChat(game, "Before trade");
|
||||||
|
|
||||||
/* Transfer goods */
|
/* Transfer goods */
|
||||||
offer.gets.forEach((item: any) => {
|
for (const item of (offer as any)["gets"] || []) {
|
||||||
if (target.name !== "The bank") {
|
if ((target as any)["name"] !== "The bank") {
|
||||||
target[item.type] -= item.count;
|
(target as any)[item.type] -= item.count;
|
||||||
target.resources -= item.count;
|
(target as any).resources -= item.count;
|
||||||
}
|
}
|
||||||
player[item.type] += item.count;
|
(player as any)[item.type] += item.count;
|
||||||
player.resources += item.count;
|
(player as any).resources += item.count;
|
||||||
});
|
}
|
||||||
offer.gives.forEach((item: any) => {
|
for (const item of (offer as any)["gives"] || []) {
|
||||||
if (target.name !== "The bank") {
|
if ((target as any)["name"] !== "The bank") {
|
||||||
target[item.type] += item.count;
|
(target as any)[item.type] += item.count;
|
||||||
target.resources += item.count;
|
(target as any).resources += item.count;
|
||||||
|
}
|
||||||
|
(player as any)[item.type] -= item.count;
|
||||||
|
(player as any).resources -= item.count;
|
||||||
}
|
}
|
||||||
player[item.type] -= item.count;
|
|
||||||
player.resources -= item.count;
|
|
||||||
});
|
|
||||||
|
|
||||||
const from = offer.name === "The bank" ? "the bank" : offer.name;
|
const from = (offer as any)["name"] === "The bank" ? "the bank" : (offer as any)["name"];
|
||||||
addChatMessage(game, session, `${session.name} traded ` + ` ${offerToString(offer)} ` + `from ${from}.`);
|
addChatMessage(game, session, `${session.name} traded ` + ` ${offerToString(offer)} ` + `from ${from}.`);
|
||||||
addActivity(game, session, `${session.name} accepted a trade from ${from}.`);
|
addActivity(game, session, `${session.name} accepted a trade from ${from}.`);
|
||||||
delete game.turn.offer;
|
delete (game.turn as any)["offer"];
|
||||||
if (target) {
|
if (target) {
|
||||||
delete target.gives;
|
delete (target as any).gives;
|
||||||
delete target.gets;
|
delete (target as any).gets;
|
||||||
}
|
}
|
||||||
delete session.player.gives;
|
if (session.player) {
|
||||||
delete session.player.gets;
|
delete (session.player as any)["gives"];
|
||||||
delete game.turn.offer;
|
delete (session.player as any)["gets"];
|
||||||
|
}
|
||||||
|
delete (game.turn as any)["offer"];
|
||||||
|
|
||||||
debugChat(game, "After trade");
|
debugChat(game, "After trade");
|
||||||
|
|
||||||
/* Debug!!! */
|
/* Debug!!! */
|
||||||
for (let key in game.players) {
|
for (const key in game.players) {
|
||||||
if (game.players[key].state !== "Active") {
|
const p = game.players[key];
|
||||||
|
if (!p) continue;
|
||||||
|
if ((p as any)["state"] !== "Active") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
types.forEach((type) => {
|
types.forEach((type) => {
|
||||||
if (game.players[key][type] < 0) {
|
if ((p as any)[type] < 0) {
|
||||||
throw new Error(`Player resources are below zero! BUG BUG BUG!`);
|
throw new Error(`Player resources are below zero! BUG BUG BUG!`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2013,7 +2037,7 @@ const acceptOffer = (game: any, session: any, offer: any): string | undefined =>
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const trade = (game: any, session: any, action: string, offer: any) => {
|
const trade = (game: Game, session: Session, action: string, offer?: Offer): string | undefined => {
|
||||||
if (game.state !== "normal") {
|
if (game.state !== "normal") {
|
||||||
return `Game not in correct state to begin trading.`;
|
return `Game not in correct state to begin trading.`;
|
||||||
}
|
}
|
||||||
@ -2029,22 +2053,25 @@ const trade = (game: any, session: any, action: string, offer: any) => {
|
|||||||
|
|
||||||
/* Any player can make an offer */
|
/* Any player can make an offer */
|
||||||
if (action === "offer") {
|
if (action === "offer") {
|
||||||
return processOffer(game, session, offer);
|
return processOffer(game, session, offer as Offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Any player can reject an offer */
|
/* Any player can reject an offer */
|
||||||
if (action === "reject") {
|
if (action === "reject") {
|
||||||
return rejectOffer(game, session, offer);
|
rejectOffer(game, session, offer as Offer);
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only the active player can accept an offer */
|
/* Only the active player can accept an offer */
|
||||||
if (action === "accept") {
|
if (action === "accept") {
|
||||||
if (offer.name === "The bank") {
|
if (offer && (offer as any)["name"] === "The bank") {
|
||||||
session.player.gets = offer.gets;
|
if (!session.player) session.player = {} as Player;
|
||||||
session.player.gives = offer.gives;
|
(session.player as any)["gets"] = (offer as any)["gets"];
|
||||||
|
(session.player as any)["gives"] = (offer as any)["gives"];
|
||||||
}
|
}
|
||||||
return acceptOffer(game, session, offer);
|
return acceptOffer(game, session, offer as Offer);
|
||||||
}
|
}
|
||||||
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearTimeNotice = (game: any, session: any): string | undefined => {
|
const clearTimeNotice = (game: any, session: any): string | undefined => {
|
||||||
@ -2531,6 +2558,7 @@ const playCard = (game: any, session: any, card: any): string | undefined => {
|
|||||||
const placeSettlement = (game: Game, session: Session, index: number | string): string | undefined => {
|
const placeSettlement = (game: Game, session: Session, index: number | string): string | undefined => {
|
||||||
if (!session.player) return `You are not playing a player.`;
|
if (!session.player) return `You are not playing a player.`;
|
||||||
const player: any = session.player;
|
const player: any = session.player;
|
||||||
|
const anyGame: any = game as any;
|
||||||
if (typeof index === "string") index = parseInt(index);
|
if (typeof index === "string") index = parseInt(index);
|
||||||
|
|
||||||
if (game.state !== "initial-placement" && game.state !== "normal") {
|
if (game.state !== "initial-placement" && game.state !== "normal") {
|
||||||
@ -2542,7 +2570,11 @@ const placeSettlement = (game: Game, session: Session, index: number | string):
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* index out of range... */
|
/* index out of range... */
|
||||||
if (game.placements.corners[index] === undefined) {
|
if (
|
||||||
|
!anyGame.placements ||
|
||||||
|
anyGame.placements.corners === undefined ||
|
||||||
|
anyGame.placements.corners[index] === undefined
|
||||||
|
) {
|
||||||
return `You have requested to place a settlement illegally!`;
|
return `You have requested to place a settlement illegally!`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2550,9 +2582,11 @@ const placeSettlement = (game: Game, session: Session, index: number | string):
|
|||||||
if (!game.turn || !game.turn.limits || !game.turn.limits.corners || game.turn.limits.corners.indexOf(index) === -1) {
|
if (!game.turn || !game.turn.limits || !game.turn.limits.corners || game.turn.limits.corners.indexOf(index) === -1) {
|
||||||
return `You tried to cheat! You should not try to break the rules.`;
|
return `You tried to cheat! You should not try to break the rules.`;
|
||||||
}
|
}
|
||||||
const corner = game.placements.corners[index];
|
const corner = anyGame.placements.corners[index];
|
||||||
if (corner.color) {
|
if (corner.color) {
|
||||||
return `This location already has a settlement belonging to ${game.players[corner.color].name}!`;
|
const owner = game.players && game.players[corner.color];
|
||||||
|
const ownerName = owner ? owner.name : "unknown";
|
||||||
|
return `This location already has a settlement belonging to ${ownerName}!`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.banks) {
|
if (!player.banks) {
|
||||||
@ -2592,8 +2626,8 @@ const placeSettlement = (game: Game, session: Session, index: number | string):
|
|||||||
const banks = layout.corners?.[index]?.banks;
|
const banks = layout.corners?.[index]?.banks;
|
||||||
if (banks && banks.length) {
|
if (banks && banks.length) {
|
||||||
banks.forEach((bank: any) => {
|
banks.forEach((bank: any) => {
|
||||||
const border = game.borderOrder[Math.floor(bank / 3)],
|
const border = anyGame.borderOrder[Math.floor(bank / 3)],
|
||||||
type = game.borders?.[border]?.[bank % 3];
|
type = anyGame.borders?.[border]?.[bank % 3];
|
||||||
console.log(`${session.id}: Bank ${bank} = ${type}`);
|
console.log(`${session.id}: Bank ${bank} = ${type}`);
|
||||||
if (!type) {
|
if (!type) {
|
||||||
console.log(`${session.id}: Bank ${bank}`);
|
console.log(`${session.id}: Bank ${bank}`);
|
||||||
@ -2607,11 +2641,11 @@ const placeSettlement = (game: Game, session: Session, index: number | string):
|
|||||||
player.ports++;
|
player.ports++;
|
||||||
|
|
||||||
if (isRuleEnabled(game, "port-of-call")) {
|
if (isRuleEnabled(game, "port-of-call")) {
|
||||||
console.log(`Checking port-of-call`, player.ports, game.mostPorts);
|
console.log(`Checking port-of-call`, player.ports, anyGame.mostPorts);
|
||||||
if (player.ports >= 3 && (!game.mostPorts || player.ports > game.mostPortCount)) {
|
if (player.ports >= 3 && (!anyGame.mostPorts || player.ports > anyGame.mostPortCount)) {
|
||||||
if (game.mostPorts !== session.color) {
|
if (anyGame.mostPorts !== session.color) {
|
||||||
game.mostPorts = session.color;
|
anyGame.mostPorts = session.color;
|
||||||
game.mostPortCount = player.ports;
|
anyGame.mostPortCount = player.ports;
|
||||||
addChatMessage(game, session, `${session.name} now has the most ports (${player.ports})!`);
|
addChatMessage(game, session, `${session.name} now has the most ports (${player.ports})!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2627,17 +2661,17 @@ const placeSettlement = (game: Game, session: Session, index: number | string):
|
|||||||
}
|
}
|
||||||
calculateRoadLengths(game, session);
|
calculateRoadLengths(game, session);
|
||||||
} else if (game.state === "initial-placement") {
|
} else if (game.state === "initial-placement") {
|
||||||
if (game.direction && game.direction === "backward") {
|
if (anyGame.direction && anyGame.direction === "backward") {
|
||||||
session.initialSettlement = index;
|
(session as any).initialSettlement = index;
|
||||||
}
|
}
|
||||||
corner.color = session.color;
|
corner.color = session.color || "";
|
||||||
corner.type = "settlement";
|
corner.type = "settlement";
|
||||||
let bankType = undefined;
|
let bankType = undefined;
|
||||||
const banks2 = layout.corners?.[index]?.banks;
|
const banks2 = layout.corners?.[index]?.banks;
|
||||||
if (banks2 && banks2.length) {
|
if (banks2 && banks2.length) {
|
||||||
banks2.forEach((bank: any) => {
|
banks2.forEach((bank: any) => {
|
||||||
const border = game.borderOrder[Math.floor(bank / 3)],
|
const border = anyGame.borderOrder[Math.floor(bank / 3)],
|
||||||
type = game.borders?.[border]?.[bank % 3];
|
type = anyGame.borders?.[border]?.[bank % 3];
|
||||||
console.log(`${session.id}: Bank ${bank} = ${type}`);
|
console.log(`${session.id}: Bank ${bank} = ${type}`);
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return;
|
return;
|
||||||
@ -3273,53 +3307,37 @@ const placeCity = (game: any, session: any, index: any): string | undefined => {
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ping = (session: any) => {
|
const ping = (session: Session) => {
|
||||||
if (!session.ws) {
|
if (!session.ws) {
|
||||||
console.log(`[no socket] Not sending ping to ${session.name} -- connection does not exist.`);
|
console.log(`[no socket] Not sending ping to ${session.name} -- connection does not exist.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.ping = Date.now();
|
(session as any)["ping"] = Date.now();
|
||||||
// console.log(`Sending ping to ${session.name}`);
|
// console.log(`Sending ping to ${session.name}`);
|
||||||
session.ws.send(JSON.stringify({ type: "ping", ping: session.ping }));
|
try {
|
||||||
|
session.ws.send(JSON.stringify({ type: "ping", ping: (session as any)["ping"] }));
|
||||||
|
} catch (e) {
|
||||||
|
// ignore send errors
|
||||||
|
}
|
||||||
|
|
||||||
if (session.keepAlive) {
|
if (session.keepAlive) {
|
||||||
clearTimeout(session.keepAlive);
|
clearTimeout(session.keepAlive);
|
||||||
}
|
}
|
||||||
session.keepAlive = setTimeout(() => {
|
session.keepAlive = setTimeout(() => {
|
||||||
ping(session);
|
// mark the session as inactive if the keepAlive fires
|
||||||
}, 2500);
|
|
||||||
};
|
|
||||||
|
|
||||||
const wsInactive = (game: any, req: any) => {
|
|
||||||
void game; // referenced for API completeness
|
|
||||||
const playerCookie = req.cookies && (req.cookies as any)["player"] ? String((req.cookies as any)["player"]) : "";
|
|
||||||
const session = getSession(game, playerCookie || "");
|
|
||||||
|
|
||||||
if (session && session.ws) {
|
|
||||||
console.log(`Closing WebSocket to ${session.name} due to inactivity.`);
|
|
||||||
try {
|
try {
|
||||||
// Defensive: close only if a socket exists; swallow any errors from closing
|
|
||||||
if (session.ws) {
|
if (session.ws) {
|
||||||
try {
|
session.ws.close?.();
|
||||||
session.ws.close();
|
|
||||||
} catch (e) {
|
|
||||||
/* ignore close errors */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
/* ignore */
|
/* ignore */
|
||||||
}
|
}
|
||||||
session.ws = undefined;
|
session.ws = undefined;
|
||||||
}
|
}, 20000);
|
||||||
|
|
||||||
/* Prevent future pings */
|
|
||||||
if (req.keepAlive) {
|
|
||||||
clearTimeout(req.keepAlive);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// keep a void reference so linters/typecheckers don't complain about unused declarations
|
// wsInactive not present in this refactor; no-op placeholder removed
|
||||||
void wsInactive;
|
|
||||||
|
|
||||||
const setGameState = (game: any, session: any, state: any): string | undefined => {
|
const setGameState = (game: any, session: any, state: any): string | undefined => {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user