feat: Adding the name of capturers of planets + displaying usernames for each team
This commit is contained in:
@@ -140,6 +140,10 @@ export async function initGameSchema() {
|
||||
ALTER TABLE grid_cells ADD CONSTRAINT grid_cells_discovered_by_check
|
||||
CHECK (discovered_by IS NULL OR discovered_by IN ('blue', 'red'));
|
||||
`);
|
||||
// ── Store the username of whoever last captured a tile ────────────────────
|
||||
await pool.query(`
|
||||
ALTER TABLE grid_cells ADD COLUMN IF NOT EXISTS captured_by TEXT;
|
||||
`);
|
||||
}
|
||||
|
||||
// ── World-seed epoch ──────────────────────────────────────────────────────────
|
||||
@@ -203,7 +207,7 @@ export async function ensureSeedEpoch() {
|
||||
|
||||
export async function getGridCells(worldSeed) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
|
||||
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by, captured_by
|
||||
FROM grid_cells WHERE world_seed = $1`,
|
||||
[worldSeed]
|
||||
);
|
||||
@@ -246,7 +250,7 @@ export async function insertTeamVisibility(worldSeed, team, x, y) {
|
||||
/** Returns all grid cells that are visible to a given team. */
|
||||
export async function getTeamVisibleCells(worldSeed, team) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT gc.x, gc.y, gc.exploitable, gc.has_planet, gc.planet_json, gc.discovered_by
|
||||
`SELECT gc.x, gc.y, gc.exploitable, gc.has_planet, gc.planet_json, gc.discovered_by, gc.captured_by
|
||||
FROM grid_cells gc
|
||||
JOIN team_cell_visibility tcv
|
||||
ON tcv.world_seed = gc.world_seed AND tcv.x = gc.x AND tcv.y = gc.y
|
||||
@@ -258,7 +262,7 @@ export async function getTeamVisibleCells(worldSeed, team) {
|
||||
|
||||
export async function getExistingCell(seed, x, y) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
|
||||
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by, captured_by
|
||||
FROM grid_cells WHERE world_seed = $1 AND x = $2 AND y = $3`,
|
||||
[seed, x, y]
|
||||
);
|
||||
@@ -431,13 +435,26 @@ export async function getCellAttackCount(worldSeed, x, y) {
|
||||
return rows[0]?.cnt ?? 0;
|
||||
}
|
||||
|
||||
export async function setTileOwner(worldSeed, x, y, team) {
|
||||
export async function setTileOwner(worldSeed, x, y, team, capturedBy = null) {
|
||||
await pool.query(
|
||||
`UPDATE grid_cells SET discovered_by = $1 WHERE world_seed = $2 AND x = $3 AND y = $4`,
|
||||
[team, worldSeed, x, y]
|
||||
`UPDATE grid_cells SET discovered_by = $1, captured_by = $2 WHERE world_seed = $3 AND x = $4 AND y = $5`,
|
||||
[team, capturedBy, worldSeed, x, y]
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns per-team lists of user IDs who have been active this seed epoch. */
|
||||
export async function getActivePlayerIds(worldSeed) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT team, user_id FROM user_cooldowns WHERE world_seed = $1`,
|
||||
[worldSeed]
|
||||
);
|
||||
const result = { blue: [], red: [] };
|
||||
for (const row of rows) {
|
||||
if (result[row.team]) result[row.team].push(row.user_id);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── Team action quota (daily, independent of world seed) ─────────────────────
|
||||
|
||||
export async function getTeamActionsRow(team) {
|
||||
|
||||
@@ -75,6 +75,16 @@ export async function getTeamPlayerCounts() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns username and team for each of the given user IDs. */
|
||||
export async function getUsersByIds(ids) {
|
||||
if (!ids.length) return [];
|
||||
const { rows } = await usersPool.query(
|
||||
`SELECT id, username, team FROM users WHERE id = ANY($1::int[])`,
|
||||
[ids]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
// ── User action quota ─────────────────────────────────────────────────────────
|
||||
|
||||
/** Returns the current quota row for a user, or null if it doesn't exist. */
|
||||
|
||||
@@ -51,5 +51,6 @@ export function rowToCellPayload(row) {
|
||||
hasPlanet: row.has_planet,
|
||||
planet: row.planet_json ?? null,
|
||||
discoveredBy: row.discovered_by,
|
||||
capturedBy: row.captured_by ?? null,
|
||||
};
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
getDbCreatedAt,
|
||||
getVictoryPoints,
|
||||
getActivePlayerCounts,
|
||||
getActivePlayerIds,
|
||||
getMilitaryDeductions,
|
||||
addMilitaryDeduction,
|
||||
recordCellAttack,
|
||||
@@ -37,6 +38,7 @@ import {
|
||||
getUserActionsRow,
|
||||
resetUserActions,
|
||||
decrementUserActions,
|
||||
getUsersByIds,
|
||||
} from "../db/usersDb.js";
|
||||
import { computeCell, rowToCellPayload } from "../helpers/cell.js";
|
||||
import { computeTeamMilitaryPower } from "../helpers/economy.js";
|
||||
@@ -252,7 +254,7 @@ router.post("/cell/capture", authMiddleware, async (req, res) => {
|
||||
}
|
||||
|
||||
// Transfer ownership to capturing team
|
||||
await setTileOwner(worldSeed, x, y, team);
|
||||
await setTileOwner(worldSeed, x, y, team, req.user.username);
|
||||
|
||||
const updatedCell = await getExistingCell(worldSeed, x, y);
|
||||
const updatedTeamRow = await getTeamActionsRow(team);
|
||||
@@ -391,6 +393,24 @@ router.get("/active-players", async (_req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/active-players/names
|
||||
router.get("/active-players/names", async (_req, res) => {
|
||||
try {
|
||||
const worldSeed = await ensureSeedEpoch();
|
||||
const playerIds = await getActivePlayerIds(worldSeed);
|
||||
const allIds = [...playerIds.blue, ...playerIds.red];
|
||||
const users = await getUsersByIds(allIds);
|
||||
const result = { blue: [], red: [] };
|
||||
for (const user of users) {
|
||||
if (result[user.team]) result[user.team].push(user.username);
|
||||
}
|
||||
res.json(result);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.status(500).json({ error: "database_error" });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/scores
|
||||
router.get("/scores", async (_req, res) => {
|
||||
try {
|
||||
@@ -449,7 +469,7 @@ router.post("/military/attack", authMiddleware, async (req, res) => {
|
||||
await addMilitaryDeduction(worldSeed, attackingTeam, COST_BILLIONS);
|
||||
|
||||
// Transfer tile ownership to the attacking team
|
||||
await setTileOwner(worldSeed, x, y, attackingTeam);
|
||||
await setTileOwner(worldSeed, x, y, attackingTeam, req.user.username);
|
||||
|
||||
// Record the attack event
|
||||
await recordCellAttack(worldSeed, x, y, attackingTeam);
|
||||
|
||||
Reference in New Issue
Block a user