diff --git a/README.md b/README.md
index 4ac9d1a..f324991 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,6 @@ Open `.env` and set every value — see [Environment variables](#environment-var
```
- `POSTGRES_PASSWORD`
- `POSTGRES_USERS_PASSWORD`
-- `ADMIN_PASSWORD`
### 3 — Review the game config
diff --git a/config/game.settings.json b/config/game.settings.json
index 36ba2f4..e2520fb 100644
--- a/config/game.settings.json
+++ b/config/game.settings.json
@@ -1,5 +1,5 @@
{
- "dailyActionQuota": 100,
+ "dailyActionQuota": 1000,
"teamActionQuota": 100,
"databaseWipeoutIntervalSeconds": 604800,
"configReloadIntervalSeconds": 30,
diff --git a/docker-compose.yml b/docker-compose.yml
index b835261..3f1bb17 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -43,7 +43,6 @@ services:
DATABASE_URL: "postgres://${POSTGRES_USER:-game}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-star_wars_grid}"
USERS_DATABASE_URL: "postgres://${POSTGRES_USERS_USER:-users}:${POSTGRES_USERS_PASSWORD}@users_db:5432/${POSTGRES_USERS_DB:-star_wars_users}"
JWT_SECRET: ${JWT_SECRET}
- ADMIN_PASSWORD: ${ADMIN_PASSWORD}
PORT: "${PORT:-8080}"
CONFIG_FILE_PATH: /app/config/game.settings.json
CORS_ORIGIN: ${CORS_ORIGIN:-*}
diff --git a/public/index.html b/public/index.html
index 435ee1c..d731b46 100644
--- a/public/index.html
+++ b/public/index.html
@@ -297,6 +297,7 @@
+
Cliquez sur une tuile. Les stats seront vides à moins de cliquer.
diff --git a/public/src/game.js b/public/src/game.js
index 936741d..d5617be 100644
--- a/public/src/game.js
+++ b/public/src/game.js
@@ -23,7 +23,6 @@ const COLOR_OPPONENT_GREY = "rgba(95, 98, 110, 0.72)";
export const GAME_CONFIG = {
dailyActionQuota: 100,
databaseWipeoutIntervalSeconds: 21600,
- debugModeForTeams: false,
configReloadIntervalSeconds: 30,
worldSeed: "",
seedPeriodEndsAtUtc: "",
@@ -237,6 +236,7 @@ const teamQuotaEl = document.getElementById("teamActionsRemaining");
const captorInfoEl = document.getElementById("captorInfo");
const playerListPopupEl = document.getElementById("playerListPopup");
const playerListContentEl = document.getElementById("playerListContent");
+const mapAnimEl = document.getElementById("mapAnim");
// ── Cell helpers ──────────────────────────────────────────────────────────────
export function cellKey(x, y) { return `${x},${y}`; }
@@ -260,7 +260,6 @@ export function isOwnTile(key) { const m = cellMeta(key); return m !== nul
export function applyConfigPayload(data) {
GAME_CONFIG.dailyActionQuota = Number(data.dailyActionQuota) || 100;
GAME_CONFIG.databaseWipeoutIntervalSeconds = Number(data.databaseWipeoutIntervalSeconds) || 21600;
- GAME_CONFIG.debugModeForTeams = Boolean(data.debugModeForTeams);
GAME_CONFIG.configReloadIntervalSeconds = Math.max(5, Number(data.configReloadIntervalSeconds) || 30);
GAME_CONFIG.worldSeed = String(data.worldSeed ?? "");
GAME_CONFIG.seedPeriodEndsAtUtc = String(data.seedPeriodEndsAtUtc ?? "");
@@ -837,6 +836,29 @@ export function draw() {
ctx.restore();
}
+// ── Map action animation ─────────────────────────────────────────────────────
+
+const mapAnimTextByType = {
+ "reveal-empty": "🔍",
+ "reveal-planet": "👁️",
+ "capture": "⚔️",
+};
+
+/**
+ * Triggers a spinning emoji animation at the centre of the map zone.
+ * @param {"reveal-empty"|"reveal-planet"|"capture"} type
+ */
+function triggerMapAnimation(type) {
+ if (!mapAnimEl) return;
+ mapAnimEl.textContent = mapAnimTextByType[type] || "🔍";
+ mapAnimEl.classList.remove("mapAnim--active");
+ void mapAnimEl.offsetWidth; // force reflow to restart the animation
+ mapAnimEl.classList.add("mapAnim--active");
+ mapAnimEl.addEventListener("animationend", () => {
+ mapAnimEl.classList.remove("mapAnim--active");
+ }, { once: true });
+}
+
// ── Cursor ────────────────────────────────────────────────────────────────────
function pickCell(ev) {
@@ -1040,6 +1062,7 @@ async function onCanvasClick(ev) {
}
if (!res.ok) throw new Error("reveal");
applyRevealPayload(await res.json());
+ triggerMapAnimation(cells.get(key)?.hasPlanet ? "reveal-planet" : "reveal-empty");
startCooldown();
updateEconomyDisplay();
draw();
@@ -1101,6 +1124,7 @@ async function onCanvasClick(ev) {
teamActionsRemaining = data.teamActionsRemaining;
updateTeamQuotaDisplay();
}
+ triggerMapAnimation("capture");
hint.textContent = `🏴 Planète (${cell.x},${cell.y}) capturée !`;
showLocalSelection(cell.x, cell.y);
updateEconomyDisplay();
diff --git a/public/style.css b/public/style.css
index 7f2e117..ab366fb 100644
--- a/public/style.css
+++ b/public/style.css
@@ -1295,4 +1295,31 @@ canvas {
.playerListEmpty {
color: rgba(233, 238, 246, 0.4);
font-style: italic;
+}
+
+/* ── Map action animation ─────────────────────────────────────────────────── */
+
+@keyframes mapAnimPop {
+ 0% { transform: translate(-50%, -50%) scale(0.1); opacity: 0; }
+ 20% { transform: translate(-50%, -50%) scale(1.1); opacity: 1; }
+ 80% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
+ 100% { transform: translate(-50%, -50%) scale(1.2); opacity: 0; }
+}
+
+.mapAnim {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 88px;
+ line-height: 1;
+ pointer-events: none;
+ z-index: 20;
+ display: none;
+ user-select: none;
+}
+
+.mapAnim--active {
+ display: block;
+ animation: mapAnimPop 0.5s ease-out forwards;
}
\ No newline at end of file
diff --git a/server/configLoader.js b/server/configLoader.js
index b767fdf..397bfe8 100644
--- a/server/configLoader.js
+++ b/server/configLoader.js
@@ -7,12 +7,11 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
const CONFIG_FILE_PATH =
process.env.CONFIG_FILE_PATH ?? path.join(__dirname, "..", "config", "game.settings.json");
-/** @type {{ dailyActionQuota: number, teamActionQuota: number, databaseWipeoutIntervalSeconds: number, debugModeForTeams: boolean, configReloadIntervalSeconds: number, resourceWorth: object, militaryPower: object }} */
+/** @type {{ dailyActionQuota: number, teamActionQuota: number, databaseWipeoutIntervalSeconds: number, configReloadIntervalSeconds: number, resourceWorth: object, militaryPower: object }} */
let cached = {
dailyActionQuota: 100,
teamActionQuota: 100,
databaseWipeoutIntervalSeconds: 21600,
- debugModeForTeams: true,
configReloadIntervalSeconds: 30,
elementWorth: {},
resourceWorth: { common: {}, rare: {} },
@@ -48,8 +47,6 @@ export function loadConfigFile() {
if (typeof j.databaseWipeoutIntervalSeconds === "number" && j.databaseWipeoutIntervalSeconds >= 60) {
cached.databaseWipeoutIntervalSeconds = j.databaseWipeoutIntervalSeconds;
}
- const dbg = parseBool(j.debugModeForTeams);
- if (dbg !== null) cached.debugModeForTeams = dbg;
if (typeof j.configReloadIntervalSeconds === "number" && j.configReloadIntervalSeconds >= 5) {
cached.configReloadIntervalSeconds = j.configReloadIntervalSeconds;
}
diff --git a/server/db/usersDb.js b/server/db/usersDb.js
index bd89dc3..b2403f0 100644
--- a/server/db/usersDb.js
+++ b/server/db/usersDb.js
@@ -9,7 +9,6 @@ export async function initUsersSchema() {
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
team TEXT NOT NULL CHECK (team IN ('blue', 'red')),
- role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin')),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
`);
@@ -44,7 +43,7 @@ export async function createUser(username, passwordHash, team) {
const { rows } = await usersPool.query(
`INSERT INTO users (username, password_hash, team)
VALUES ($1, $2, $3)
- RETURNING id, username, team, role`,
+ RETURNING id, username, team`,
[username, passwordHash, team]
);
return rows[0];
@@ -52,7 +51,7 @@ export async function createUser(username, passwordHash, team) {
export async function getUserByUsername(username) {
const { rows } = await usersPool.query(
- `SELECT id, username, team, role, password_hash FROM users WHERE username = $1`,
+ `SELECT id, username, team, password_hash FROM users WHERE username = $1`,
[username]
);
return rows[0] ?? null;
@@ -60,7 +59,7 @@ export async function getUserByUsername(username) {
export async function getUserById(id) {
const { rows } = await usersPool.query(
- `SELECT id, username, team, role FROM users WHERE id = $1`,
+ `SELECT id, username, team FROM users WHERE id = $1`,
[id]
);
return rows[0] ?? null;
diff --git a/server/index.js b/server/index.js
index dad02da..5a5d70d 100644
--- a/server/index.js
+++ b/server/index.js
@@ -15,7 +15,6 @@ function makeConfigSignature(cfg) {
dailyActionQuota: cfg.dailyActionQuota,
teamActionQuota: cfg.teamActionQuota,
databaseWipeoutIntervalSeconds: cfg.databaseWipeoutIntervalSeconds,
- debugModeForTeams: cfg.debugModeForTeams,
configReloadIntervalSeconds: cfg.configReloadIntervalSeconds,
elementWorth: cfg.elementWorth ?? {},
resourceWorth: cfg.resourceWorth ?? { common: {}, rare: {} },
@@ -43,7 +42,6 @@ function scheduleConfigPoll() {
dailyActionQuota: cfg.dailyActionQuota,
teamActionQuota: cfg.teamActionQuota,
databaseWipeoutIntervalSeconds: cfg.databaseWipeoutIntervalSeconds,
- debugModeForTeams: cfg.debugModeForTeams,
configReloadIntervalSeconds: cfg.configReloadIntervalSeconds,
elementWorth: cfg.elementWorth ?? {},
resourceWorth: cfg.resourceWorth ?? { common: {}, rare: {} },
diff --git a/server/routes/game.js b/server/routes/game.js
index bc0eecf..a02e94f 100644
--- a/server/routes/game.js
+++ b/server/routes/game.js
@@ -94,7 +94,6 @@ router.get("/config", async (req, res) => {
res.json({
dailyActionQuota: cfg.dailyActionQuota,
databaseWipeoutIntervalSeconds: rot,
- debugModeForTeams: cfg.debugModeForTeams,
configReloadIntervalSeconds: cfg.configReloadIntervalSeconds,
worldSeed,
seedPeriodEndsAtUtc: ws.seedPeriodEndsAtUtc,