Private
Public Access
1
0

refacto: Changing gameplay so teams don't know what the other team got + both teams can now chart the same cell without knowing + planet capture gameplay implemented

This commit is contained in:
gauvainboiche
2026-04-01 17:17:52 +02:00
parent 5aa347eb13
commit 99d34c58c6
12 changed files with 432 additions and 186 deletions

View File

@@ -1,6 +1,7 @@
import { pool } from "./pools.js";
import { loadConfigFile, getConfig } from "../configLoader.js";
import { computeWorldSeedState } from "../worldSeed.js";
import { nextNoonUtc, resetAllUserActions } from "./usersDb.js";
let lastSeedSlot = null;
@@ -113,6 +114,32 @@ export async function initGameSchema() {
quota_reset_at TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00'
);
`);
// ── Per-team cell visibility (who has revealed what) ──────────────────────
await pool.query(`
CREATE TABLE IF NOT EXISTS team_cell_visibility (
world_seed TEXT NOT NULL,
team TEXT NOT NULL CHECK (team IN ('blue', 'red')),
x SMALLINT NOT NULL,
y SMALLINT NOT NULL,
PRIMARY KEY (world_seed, team, x, y)
);
CREATE INDEX IF NOT EXISTS idx_tcv_seed_team ON team_cell_visibility (world_seed, team);
`);
// ── Make discovered_by nullable (NULL = neutral, uncaptured) ─────────────
await pool.query(`
ALTER TABLE grid_cells ALTER COLUMN discovered_by DROP NOT NULL;
ALTER TABLE grid_cells ALTER COLUMN discovered_by DROP DEFAULT;
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'grid_cells_discovered_by_check'
) THEN
ALTER TABLE grid_cells DROP CONSTRAINT grid_cells_discovered_by_check;
END IF;
END $$;
ALTER TABLE grid_cells ADD CONSTRAINT grid_cells_discovered_by_check
CHECK (discovered_by IS NULL OR discovered_by IN ('blue', 'red'));
`);
}
// ── World-seed epoch ──────────────────────────────────────────────────────────
@@ -153,6 +180,19 @@ export async function ensureSeedEpoch() {
await pool.query("DELETE FROM team_element_bonus WHERE world_seed != $1", [worldSeed]);
await pool.query("DELETE FROM team_military_deductions WHERE world_seed != $1", [worldSeed]);
await pool.query("DELETE FROM cell_attack_log WHERE world_seed != $1", [worldSeed]);
await pool.query("DELETE FROM team_cell_visibility WHERE world_seed != $1", [worldSeed]);
// Reset both team and user quotas to server defaults (no bonuses) for the new period
const cfg = getConfig();
const nextNoon = nextNoonUtc().toISOString();
await pool.query(
`INSERT INTO team_action_quota (team, actions_remaining, quota_reset_at)
VALUES ('blue', $1, $2), ('red', $1, $2)
ON CONFLICT (team) DO UPDATE
SET actions_remaining = $1,
quota_reset_at = $2`,
[cfg.teamActionQuota, nextNoon]
);
await resetAllUserActions(cfg.dailyActionQuota, nextNoon);
console.log(`[world] Slot ${lastSeedSlot}${seedSlot}; grid wiped, old cooldowns cleared.`);
lastSeedSlot = seedSlot;
}
@@ -170,17 +210,52 @@ export async function getGridCells(worldSeed) {
return rows;
}
export async function insertCell(seed, x, y, exploitable, hasPlanet, planetJson, team) {
export async function insertCell(seed, x, y, exploitable, hasPlanet, planetJson) {
const { rows } = await pool.query(
`INSERT INTO grid_cells (world_seed, x, y, exploitable, has_planet, planet_json, discovered_by)
VALUES ($1, $2, $3, $4, $5, $6, $7)
VALUES ($1, $2, $3, $4, $5, $6, NULL)
ON CONFLICT (world_seed, x, y) DO NOTHING
RETURNING x, y, exploitable, has_planet, planet_json, discovered_by`,
[seed, x, y, exploitable, hasPlanet, planetJson, team]
[seed, x, y, exploitable, hasPlanet, planetJson]
);
return rows[0] ?? null;
}
// ── Team cell visibility ──────────────────────────────────────────────────────
/** Returns true if team has already revealed this cell. */
export async function checkTeamVisibility(worldSeed, team, x, y) {
const { rows } = await pool.query(
`SELECT 1 FROM team_cell_visibility WHERE world_seed = $1 AND team = $2 AND x = $3 AND y = $4`,
[worldSeed, team, x, y]
);
return rows.length > 0;
}
/** Inserts a visibility record. Returns true if newly inserted (first reveal). */
export async function insertTeamVisibility(worldSeed, team, x, y) {
const { rowCount } = await pool.query(
`INSERT INTO team_cell_visibility (world_seed, team, x, y)
VALUES ($1, $2, $3, $4)
ON CONFLICT (world_seed, team, x, y) DO NOTHING`,
[worldSeed, team, x, y]
);
return rowCount > 0;
}
/** 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
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
WHERE gc.world_seed = $1 AND tcv.team = $2`,
[worldSeed, team]
);
return rows;
}
export async function getExistingCell(seed, x, y) {
const { rows } = await pool.query(
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
@@ -296,7 +371,7 @@ export async function getVictoryPoints() {
export async function getScores(worldSeed) {
const { rows } = await pool.query(
`SELECT discovered_by, COUNT(*) AS cnt
FROM grid_cells WHERE world_seed = $1
FROM grid_cells WHERE world_seed = $1 AND discovered_by IS NOT NULL
GROUP BY discovered_by`,
[worldSeed]
);
@@ -398,3 +473,18 @@ export async function decrementTeamActions(team) {
);
return rows[0] ?? null;
}
/**
* Atomically decrements team actions_remaining by `amount` if sufficient.
* Returns the updated row, or null if not enough actions.
*/
export async function decrementTeamActionsBy(team, amount) {
const { rows } = await pool.query(
`UPDATE team_action_quota
SET actions_remaining = actions_remaining - $2
WHERE team = $1 AND actions_remaining >= $2
RETURNING actions_remaining`,
[team, amount]
);
return rows[0] ?? null;
}

View File

@@ -111,4 +111,19 @@ export async function decrementUserActions(userId) {
[userId]
);
return rows[0] ?? null;
}
/**
* Resets ALL users' quota to a given value (used on world-seed wipeout).
* Users who have no row yet get one inserted.
*/
export async function resetAllUserActions(actionsRemaining, quotaResetAt) {
await usersPool.query(
`INSERT INTO user_action_quota (user_id, actions_remaining, quota_reset_at)
SELECT id, $1, $2 FROM users
ON CONFLICT (user_id) DO UPDATE
SET actions_remaining = $1,
quota_reset_at = $2`,
[actionsRemaining, quotaResetAt]
);
}