Add dev seed data: auto-creates campaign with Limpie and Brynn on fresh DB

This commit is contained in:
Aaron Wood 2026-04-09 12:34:08 -04:00
parent 3e2e43ca95
commit 28e57a77ee
2 changed files with 213 additions and 0 deletions

View file

@ -8,6 +8,7 @@ import characterRoutes from "./routes/characters.js";
import gameItemRoutes from "./routes/game-items.js";
import gameTalentRoutes from "./routes/game-talents.js";
import rollRoutes from "./routes/rolls.js";
import { seedDevData } from "./seed-dev-data.js";
const app = express();
const httpServer = createServer(app);
@ -30,6 +31,8 @@ app.use("/api/game-items", gameItemRoutes);
app.use("/api/game-talents", gameTalentRoutes);
app.use("/api/campaigns/:campaignId/rolls", rollRoutes);
seedDevData();
const PORT = process.env.PORT || 3000;
httpServer.listen(PORT, () => {
console.log(`Shadowdark server running on http://localhost:${PORT}`);

210
server/src/seed-dev-data.ts Normal file
View file

@ -0,0 +1,210 @@
import db from "./db.js";
export function seedDevData() {
const hasCampaigns = (
db.prepare("SELECT COUNT(*) as c FROM campaigns").get() as { c: number }
).c;
if (hasCampaigns > 0) return;
// Create campaign
db.prepare(
"INSERT INTO campaigns (name) VALUES ('Tomb of the Serpent King')",
).run();
const insertChar = db.prepare(`
INSERT INTO characters (campaign_id, name, class, ancestry, level, xp, hp_current, hp_max, ac, alignment, title, background, deity, languages, gp, sp, cp, color)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
const insertStat = db.prepare(
"INSERT INTO character_stats (character_id, stat_name, value) VALUES (?, ?, ?)",
);
const insertGear = db.prepare(
"INSERT INTO character_gear (character_id, name, type, slot_count, properties, effects, game_item_id) VALUES (?, ?, ?, ?, ?, ?, ?)",
);
const insertTalent = db.prepare(
"INSERT INTO character_talents (character_id, name, description, effect, game_talent_id) VALUES (?, ?, ?, ?, ?)",
);
// --- Limpie ---
const limpie = insertChar.run(
1,
"Limpie",
"Thief",
"Goblin",
1,
6,
1,
1,
10,
"Lawful",
"Footpad",
"Chirurgeo",
"Madeera the Covenant",
"Common, Goblin",
8,
0,
0,
"hsl(45, 60%, 65%)",
);
const limpieId = limpie.lastInsertRowid;
// Limpie stats
const limpieStats: [string, number][] = [
["STR", 11],
["DEX", 11],
["CON", 8],
["INT", 10],
["WIS", 14],
["CHA", 10],
];
for (const [name, value] of limpieStats) {
insertStat.run(limpieId, name, value);
}
// Limpie gear
insertGear.run(
limpieId,
"Shortsword",
"weapon",
1,
"{}",
'{"damage":"1d6","melee":true,"stat":"STR"}',
null,
);
insertGear.run(
limpieId,
"Shortbow",
"weapon",
1,
"{}",
'{"damage":"1d4","ranged":true,"stat":"DEX","two_handed":true}',
null,
);
insertGear.run(
limpieId,
"Leather Armor",
"armor",
1,
"{}",
'{"ac_base":11,"ac_dex":true}',
null,
);
insertGear.run(limpieId, "Shield", "armor", 1, "{}", '{"ac_bonus":2}', null);
insertGear.run(limpieId, "Arrows (20)", "gear", 1, "{}", "{}", null);
insertGear.run(limpieId, "Torch", "gear", 1, "{}", "{}", null);
insertGear.run(limpieId, "Rations", "gear", 1, "{}", "{}", null);
insertGear.run(limpieId, "Rope (60ft)", "gear", 1, "{}", "{}", null);
insertGear.run(limpieId, "Thieves' Tools", "gear", 1, "{}", "{}", null);
// Limpie talents
insertTalent.run(
limpieId,
"Backstab",
"Extra 1 + half level (round down) weapon dice of damage with surprise attacks",
'{"damage_bonus_surprise":true}',
null,
);
insertTalent.run(
limpieId,
"Thievery",
"Trained in climbing, sneaking, hiding, disguise, finding & disabling traps, delicate tasks",
"{}",
null,
);
insertTalent.run(
limpieId,
"Keen Senses",
"Can't be surprised",
'{"immune_surprise":true}',
null,
);
// --- Brynn ---
const brynn = insertChar.run(
1,
"Brynn",
"Fighter",
"Human",
2,
15,
8,
10,
10,
"Neutral",
"the Bold",
"Soldier",
"Gede",
"Common",
25,
5,
10,
"hsl(200, 60%, 65%)",
);
const brynnId = brynn.lastInsertRowid;
// Brynn stats
const brynnStats: [string, number][] = [
["STR", 16],
["DEX", 12],
["CON", 14],
["INT", 8],
["WIS", 10],
["CHA", 11],
];
for (const [name, value] of brynnStats) {
insertStat.run(brynnId, name, value);
}
// Brynn gear
insertGear.run(
brynnId,
"Longsword",
"weapon",
1,
"{}",
'{"damage":"1d8","melee":true,"stat":"STR"}',
null,
);
insertGear.run(
brynnId,
"Chainmail",
"armor",
1,
"{}",
'{"ac_base":13,"ac_dex":true}',
null,
);
insertGear.run(brynnId, "Shield", "armor", 1, "{}", '{"ac_bonus":2}', null);
insertGear.run(
brynnId,
"Javelin",
"weapon",
1,
"{}",
'{"damage":"1d4","melee":true,"stat":"STR","thrown":true,"range":"far"}',
null,
);
insertGear.run(brynnId, "Torch", "gear", 1, "{}", "{}", null);
insertGear.run(brynnId, "Rations", "gear", 1, "{}", "{}", null);
// Brynn talents
insertTalent.run(
brynnId,
"Weapon Mastery",
"+1 to attack and damage with longswords",
'{"attack_bonus":1,"damage_bonus":1}',
null,
);
insertTalent.run(
brynnId,
"Grit",
"+2 HP and +1 HP each level",
'{"hp_bonus":2}',
null,
);
console.log("Dev data seeded: campaign + 2 characters (Limpie & Brynn)");
}