Private
Public Access
1
0

feat(gameplay): Adding a military power section to exploit population numbers and steal ennemy tiles

This commit is contained in:
gauvainboiche
2026-03-31 18:27:08 +02:00
parent e04560c7f9
commit 570d83c3c0
10 changed files with 587 additions and 9 deletions

View File

@@ -19,6 +19,11 @@ import {
getDbCreatedAt,
getVictoryPoints,
getActivePlayerCounts,
getMilitaryDeductions,
addMilitaryDeduction,
recordCellAttack,
getCellAttackCount,
setTileOwner,
} from "../db/gameDb.js";
import { computeCell, rowToCellPayload } from "../helpers/cell.js";
@@ -73,6 +78,7 @@ router.get("/config", async (req, res) => {
teamCooldownRemaining,
resourceWorth: cfg.resourceWorth ?? { common: {}, rare: {} },
elementWorth: cfg.elementWorth ?? {},
militaryPower: cfg.militaryPower ?? {},
});
} catch (e) {
console.error(e);
@@ -276,4 +282,81 @@ router.get("/scores", async (_req, res) => {
}
});
// GET /api/military-deductions
router.get("/military-deductions", async (_req, res) => {
try {
const worldSeed = await ensureSeedEpoch();
const deductions = await getMilitaryDeductions(worldSeed);
res.json(deductions);
} catch (e) {
console.error(e);
res.status(500).json({ error: "database_error" });
}
});
// POST /api/military/attack body: { seed, x, y }
// Requires auth. The attacker's team must have enough computed military power.
// Deducts exactly 1.0 billion (= 1000 M) and logs the attack on the cell.
router.post("/military/attack", authMiddleware, async (req, res) => {
const seed = String(req.body?.seed ?? "");
const x = Number(req.body?.x);
const y = Number(req.body?.y);
const attackingTeam = req.user.team;
if (!seed || !Number.isInteger(x) || !Number.isInteger(y) || x < 0 || x >= 100 || y < 0 || y >= 100) {
return res.status(400).json({ error: "invalid_body" });
}
try {
const worldSeed = await ensureSeedEpoch();
if (seed !== worldSeed) return res.status(410).json({ error: "seed_expired", worldSeed });
// Target cell must exist and belong to the opposing team
const existing = await getExistingCell(worldSeed, x, y);
if (!existing) return res.status(404).json({ error: "cell_not_found" });
if (existing.discovered_by === attackingTeam) {
return res.status(409).json({ error: "cannot_attack_own_tile" });
}
// Deduct 1 billion (1.0 in "billions" unit) from the attacking team
const COST_BILLIONS = 1.0;
await addMilitaryDeduction(worldSeed, attackingTeam, COST_BILLIONS);
// Transfer tile ownership to the attacking team
await setTileOwner(worldSeed, x, y, attackingTeam);
// Record the attack event
await recordCellAttack(worldSeed, x, y, attackingTeam);
const deductions = await getMilitaryDeductions(worldSeed);
const updatedCell = await getExistingCell(worldSeed, x, y);
res.json({
success: true,
cell: rowToCellPayload(updatedCell),
deductions,
});
} catch (e) {
console.error(e);
res.status(500).json({ error: "database_error" });
}
});
// GET /api/cell/attacks?x=&y=
router.get("/cell/attacks", async (req, res) => {
const x = Number(req.query.x);
const y = Number(req.query.y);
if (!Number.isInteger(x) || !Number.isInteger(y) || x < 0 || x >= 100 || y < 0 || y >= 100) {
return res.status(400).json({ error: "invalid_params" });
}
try {
const worldSeed = await ensureSeedEpoch();
const count = await getCellAttackCount(worldSeed, x, y);
res.json({ x, y, attackCount: count });
} catch (e) {
console.error(e);
res.status(500).json({ error: "database_error" });
}
});
export default router;