step 9.2: done
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env node
|
||||
// seed-dev.js — Create a demo account + hero for local testing.
|
||||
// Safe to re-run (skips if demo user already exists).
|
||||
// Skipped entirely when NODE_ENV=production.
|
||||
// NOTE: NODE_ENV check must happen before any require() that loads config,
|
||||
// because config throws on placeholder SESSION_SECRET in production.
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.log('seed-dev: NODE_ENV=production — skipping.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const bcrypt = require('bcryptjs');
|
||||
const { runMigrations } = require('./migrate');
|
||||
const { getDb } = require('../src/db');
|
||||
const time = require('../src/utils/time');
|
||||
|
||||
const DEMO_USERNAME = 'demo';
|
||||
const DEMO_PASSWORD = 'demo123';
|
||||
const DEMO_HERO_NAME = 'Aldric';
|
||||
const DEMO_CLASS = 'warrior';
|
||||
|
||||
// Starter gear: a basic weapon + armor + potion for the demo hero.
|
||||
const STARTER_ITEMS = [
|
||||
{ slug: 'rusty-sword', qty: 1 }, // weapon, common, min_level 1
|
||||
{ slug: 'leather-jerkin', qty: 1 }, // armor, common, min_level 1
|
||||
{ slug: 'minor-healing-potion', qty: 2 }, // consumable, stackable
|
||||
];
|
||||
|
||||
function getOrCreateDemoUser(db) {
|
||||
const stmt = db.prepare(
|
||||
'SELECT id, username FROM users WHERE username = ? COLLATE NOCASE'
|
||||
);
|
||||
const existing = stmt.get(DEMO_USERNAME);
|
||||
if (existing) {
|
||||
console.log(` Demo user "${DEMO_USERNAME}" already exists (id=${existing.id}).`);
|
||||
return existing;
|
||||
}
|
||||
|
||||
const passwordHash = bcrypt.hashSync(DEMO_PASSWORD, 12);
|
||||
const result = db.prepare(
|
||||
'INSERT INTO users (username, password_hash, created_at) VALUES (?, ?, ?)'
|
||||
).run(DEMO_USERNAME, passwordHash, time.now());
|
||||
|
||||
console.log(` Created demo user "${DEMO_USERNAME}" (id=${result.lastInsertRowid}).`);
|
||||
return { id: result.lastInsertRowid, username: DEMO_USERNAME };
|
||||
}
|
||||
|
||||
function getOrCreateDemoHero(db, userId) {
|
||||
const heroCheck = db.prepare(
|
||||
'SELECT id FROM characters WHERE user_id = ?'
|
||||
).get(userId);
|
||||
if (heroCheck) {
|
||||
console.log(` Demo hero already exists for user ${userId}.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const heroNameCheck = db.prepare(
|
||||
'SELECT id FROM characters WHERE name = ? COLLATE NOCASE'
|
||||
).get(DEMO_HERO_NAME);
|
||||
if (heroNameCheck) {
|
||||
console.log(` Hero name "${DEMO_HERO_NAME}" already taken.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get base stats for the class
|
||||
const { getBaseStats } = require('../src/game/classes');
|
||||
const { calcDerived } = require('../src/game/stats');
|
||||
const baseStats = getBaseStats(DEMO_CLASS);
|
||||
const hpCurrent = calcDerived(baseStats, 1, DEMO_CLASS).maxHp;
|
||||
const { ENERGY_MAX } = require('../src/game/stats');
|
||||
const now = time.now();
|
||||
|
||||
const result = db.prepare(
|
||||
`INSERT INTO characters
|
||||
(user_id, name, class, level, xp, gold, str, agi, int, vit,
|
||||
unspent_points, hp_current, energy, energy_updated_at, kills, deaths, created_at)
|
||||
VALUES (?, ?, ?, 1, 0, 100, ?, ?, ?, ?, 0, ?, ?, ?, 0, 0, ?)`
|
||||
).run(
|
||||
userId, DEMO_HERO_NAME,
|
||||
DEMO_CLASS,
|
||||
baseStats.str, baseStats.agi, baseStats.int, baseStats.vit,
|
||||
hpCurrent, ENERGY_MAX, now, now
|
||||
);
|
||||
|
||||
console.log(` Created demo hero "${DEMO_HERO_NAME}" (id=${result.lastInsertRowid}, class=${DEMO_CLASS}).`);
|
||||
return { id: result.lastInsertRowid };
|
||||
}
|
||||
|
||||
function giveStarterGear(db, characterId) {
|
||||
const itemIds = [];
|
||||
for (const { slug, qty } of STARTER_ITEMS) {
|
||||
const item = db.prepare('SELECT id FROM items WHERE slug = ?').get(slug);
|
||||
if (!item) {
|
||||
console.warn(` WARNING: item "${slug}" not found in database.`);
|
||||
continue;
|
||||
}
|
||||
itemIds.push({ itemId: item.id, qty });
|
||||
}
|
||||
|
||||
const insertInv = db.prepare(
|
||||
'INSERT INTO inventory (character_id, item_id, quantity, acquired_at) VALUES (?, ?, ?, ?)'
|
||||
);
|
||||
|
||||
for (const { itemId, qty } of itemIds) {
|
||||
insertInv.run(characterId, itemId, qty, time.now());
|
||||
}
|
||||
|
||||
console.log(` Granted ${itemIds.length} starter item(s) to hero ${characterId}.`);
|
||||
}
|
||||
|
||||
function seedDev() {
|
||||
console.log('seed-dev: running migrations...');
|
||||
runMigrations();
|
||||
|
||||
const db = getDb();
|
||||
console.log('seed-dev: seeding demo account...');
|
||||
|
||||
const user = getOrCreateDemoUser(db);
|
||||
const hero = getOrCreateDemoHero(db, user.id);
|
||||
|
||||
if (hero) {
|
||||
giveStarterGear(db, hero.id);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('═══════════════════════════════════════');
|
||||
console.log(' Demo account ready!');
|
||||
console.log(` Username: ${DEMO_USERNAME}`);
|
||||
console.log(` Password: ${DEMO_PASSWORD}`);
|
||||
console.log('═══════════════════════════════════════');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
seedDev();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
module.exports = { seedDev };
|
||||
Reference in New Issue
Block a user