189 lines
5.3 KiB
TypeScript
189 lines
5.3 KiB
TypeScript
import type { Game, Session, Player } from "./types";
|
|
import { newPlayer } from "./playerFactory";
|
|
|
|
export const addActivity = (game: Game, session: Session | null, message: string): void => {
|
|
let date = Date.now();
|
|
if (!game.activities) game.activities = [] as any[];
|
|
if (game.activities.length && game.activities[game.activities.length - 1].date === date) {
|
|
date++;
|
|
}
|
|
game.activities.push({ color: session ? session.color : "", message, date });
|
|
if (game.activities.length > 30) {
|
|
game.activities.splice(0, game.activities.length - 30);
|
|
}
|
|
};
|
|
|
|
export const addChatMessage = (game: Game, session: Session | null, message: string, isNormalChat?: boolean) => {
|
|
let now = Date.now();
|
|
let lastTime = 0;
|
|
if (!game.chat) game.chat = [] as any[];
|
|
if (game.chat.length) {
|
|
lastTime = game.chat[game.chat.length - 1].date;
|
|
}
|
|
if (now <= lastTime) {
|
|
now = lastTime + 1;
|
|
}
|
|
|
|
const entry: any = {
|
|
date: now,
|
|
message: message,
|
|
};
|
|
if (isNormalChat) {
|
|
entry.normalChat = true;
|
|
}
|
|
if (session && session.name) {
|
|
entry.from = session.name;
|
|
}
|
|
if (session && session.color) {
|
|
entry.color = session.color;
|
|
}
|
|
game.chat.push(entry);
|
|
if (game.chat.length > 50) {
|
|
game.chat.splice(0, game.chat.length - 50);
|
|
}
|
|
};
|
|
|
|
export const getColorFromName = (game: Game, name: string): string => {
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.name === name) {
|
|
return s.color || "";
|
|
}
|
|
}
|
|
return "";
|
|
};
|
|
|
|
export const getLastPlayerName = (game: Game): string => {
|
|
const index = (game.playerOrder || []).length - 1;
|
|
const color = (game.playerOrder || [])[index];
|
|
if (!color) return "";
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.color === color) {
|
|
return s.name || "";
|
|
}
|
|
}
|
|
return "";
|
|
};
|
|
|
|
export const getFirstPlayerName = (game: Game): string => {
|
|
const color = (game.playerOrder || [])[0];
|
|
if (!color) return "";
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.color === color) {
|
|
return s.name || "";
|
|
}
|
|
}
|
|
return "";
|
|
};
|
|
|
|
export const getNextPlayerSession = (game: Game, name: string): Session | undefined => {
|
|
let color: string | undefined;
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.name === name) {
|
|
color = s.color;
|
|
break;
|
|
}
|
|
}
|
|
if (!color) return undefined;
|
|
|
|
const order = game.playerOrder || [];
|
|
let index = order.indexOf(color);
|
|
if (index === -1) return undefined;
|
|
index = (index + 1) % order.length;
|
|
const nextColor = order[index];
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.color === nextColor) {
|
|
return s;
|
|
}
|
|
}
|
|
console.error(`getNextPlayerSession -- no player found!`);
|
|
console.log(game.players);
|
|
return undefined;
|
|
};
|
|
|
|
export const getPrevPlayerSession = (game: Game, name: string): Session | undefined => {
|
|
let color: string | undefined;
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.name === name) {
|
|
color = s.color;
|
|
break;
|
|
}
|
|
}
|
|
if (!color) return undefined;
|
|
const order = game.playerOrder || [];
|
|
let index = order.indexOf(color);
|
|
if (index === -1) return undefined;
|
|
index = (index - 1 + order.length) % order.length;
|
|
const prevColor = order[index];
|
|
for (let id in game.sessions) {
|
|
const s = game.sessions[id];
|
|
if (s && s.color === prevColor) {
|
|
return s;
|
|
}
|
|
}
|
|
console.error(`getPrevPlayerSession -- no player found!`);
|
|
console.log(game.players);
|
|
return undefined;
|
|
};
|
|
|
|
export const clearPlayer = (player: Player) => {
|
|
const color = player.color;
|
|
for (let key in player) {
|
|
// delete all runtime fields
|
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
delete (player as any)[key];
|
|
}
|
|
|
|
// Use shared factory to ensure a single source of defaults
|
|
Object.assign(player, newPlayer(color || ""));
|
|
};
|
|
|
|
export const canGiveBuilding = (game: Game): string | undefined => {
|
|
if (!game.turn.roll) {
|
|
return `Admin cannot give a building until the dice have been rolled.`;
|
|
}
|
|
if (game.turn.actions && game.turn.actions.length !== 0) {
|
|
return `Admin cannot give a building while other actions in play: ${game.turn.actions.join(", ")}.`;
|
|
}
|
|
return undefined;
|
|
};
|
|
|
|
export const setForRoadPlacement = (game: Game, limits: any): void => {
|
|
game.turn.actions = ["place-road"];
|
|
game.turn.limits = { roads: limits };
|
|
};
|
|
|
|
export const setForCityPlacement = (game: Game, limits: any): void => {
|
|
game.turn.actions = ["place-city"];
|
|
game.turn.limits = { corners: limits };
|
|
};
|
|
|
|
export const setForSettlementPlacement = (game: Game, limits: number[] | undefined, _extra?: any): void => {
|
|
game.turn.actions = ["place-settlement"];
|
|
game.turn.limits = { corners: limits };
|
|
};
|
|
|
|
// Adjust a player's resource counts by a deltas map. Deltas may be negative.
|
|
export const adjustResources = (player: Player, deltas: Partial<Record<string, number>>): void => {
|
|
if (!player) return;
|
|
let total = player.resources || 0;
|
|
const keys = Object.keys(deltas || {});
|
|
keys.forEach((k) => {
|
|
const v = deltas[k] || 0;
|
|
// update named resource slot if present
|
|
try {
|
|
const current = (player as any)[k] || 0;
|
|
(player as any)[k] = current + v;
|
|
total += v;
|
|
} catch (e) {
|
|
// ignore unexpected keys
|
|
}
|
|
});
|
|
player.resources = total;
|
|
};
|