Dragon-Knight/server/modules/InstallModule.php

313 lines
9.0 KiB
PHP

<?php
/*
The second URI segment determines the step/page we are on.
*/
class InstallModule
{
public static function handle()
{
$s = App::$req->uri(1) ?? ''; // second segment
$m = App::$req->method; // request method
if ($s == '' || $s == 'intro') return self::intro();
if ($s == 'database' && $m == 'POST') return self::database();
if ($s == 'finish' && $m == 'POST') return self::finish();
return self::fourOhFour();
}
private static function intro()
{
echo render('install/layout', ['title' => 'Intro', 'step' => 'first']);
}
private static function database()
{
$istart = microtime(true); // time the database setup
if (!isset($_POST['mode'])) redirect('/install'); // redirect if no mode
$complete = $_POST['mode'] == 'complete'; // complete or partial setup
$defaults = SERVER.'/database/packs/Default/';
// if the database already exists, have the app remake it
App::performDatabaseReset();
// @Settings
App::$db->q("CREATE TABLE IF NOT EXISTS 'settings' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'game_name' TEXT DEFAULT 'Dragon Knight',
'game_version' TEXT DEFAULT '1.0',
'game_dev' TEXT DEFAULT 'Sharkk',
'game_url' TEXT DEFAULT 'https://dragonknight.dev',
'game_size' INT DEFAULT 250,
'game_open' INT DEFAULT 1,
'admin_email' TEXT DEFAULT 'admin@dragonknight.dev',
'forum_type' INT DEFAULT 1,
'forum_url' TEXT DEFAULT '',
'verify_email' INT DEFAULT 1,
'show_news' INT DEFAULT 1,
'show_online' INT DEFAULT 1,
'show_babble' INT DEFAULT 1,
'tp_growth' INT DEFAULT 1,
'stat_point_gain' INT DEFAULT 5
);");
// insert default settings
App::$db->q("INSERT INTO settings DEFAULT VALUES;");
// @Classes
App::$db->q("CREATE TABLE IF NOT EXISTS 'classes' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'name' TEXT DEFAULT '',
'start_hp' INT DEFAULT 0,
'start_mp' INT DEFAULT 0,
'start_str' INT DEFAULT 0,
'start_atk' INT DEFAULT 0,
'start_dex' INT DEFAULT 0,
'start_def' INT DEFAULT 0,
'growth_hp' INT DEFAULT 0,
'growth_mp' INT DEFAULT 0,
'growth_str' INT DEFAULT 0,
'growth_atk' INT DEFAULT 0,
'growth_dex' INT DEFAULT 0,
'growth_def' INT DEFAULT 0
);");
if ($complete) {
// add default classes if complete install
App::$db->insertFromCSV('classes', "$defaults/classes.csv");
} else {
// there must be at least one class for user creation to work
App::$db->q("INSERT INTO classes (name) VALUES ('Adventurer');");
}
// @Babble
App::$db->q("CREATE TABLE IF NOT EXISTS 'babble' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'author' INTEGER NOT NULL,
'babble' TEXT NOT NULL,
'posted' DATETIME DEFAULT CURRENT_TIMESTAMP
);");
// @Drops
App::$db->q("CREATE TABLE IF NOT EXISTS 'drops' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'name' TEXT NOT NULL,
'level' INTEGER DEFAULT 1,
'type' INTEGER DEFAULT 1,
'attr' TEXT DEFAULT ''
);");
// add default drops if complete install
if ($complete) App::$db->insertFromCSV('drops', "$defaults/drops.csv");
// @Forum
App::$db->q("CREATE TABLE IF NOT EXISTS 'forum' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'posted' DATETIME DEFAULT CURRENT_TIMESTAMP,
'new_post' DATETIME DEFAULT CURRENT_TIMESTAMP,
'author' INTEGER NOT NULL,
'subject' TEXT DEFAULT '',
'message' TEXT DEFAULT '',
'locked' INTEGER DEFAULT 0,
'sticky' INTEGER DEFAULT 0,
'parent' INTEGER DEFAULT 0,
'posts' INTEGER DEFAULT 0,
'views' INTEGER DEFAULT 0,
'hidden' INTEGER DEFAULT 0
);");
// @Items
App::$db->q("CREATE TABLE IF NOT EXISTS 'items' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'type' INTEGER DEFAULT 1,
'name' TEXT NOT NULL,
'cost' INTEGER DEFAULT 0,
'attr' TEXT DEFAULT '',
'icon' TEXT DEFAULT ''
);");
// add default items if complete install
if ($complete) App::$db->insertFromCSV('items', "$defaults/items.csv");
// @Monsters
App::$db->q("CREATE TABLE IF NOT EXISTS 'monsters' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'name' TEXT NOT NULL,
'level' INTEGER DEFAULT 1,
'hp' INTEGER DEFAULT 1,
'atk' INTEGER DEFAULT 1,
'def' INTEGER DEFAULT 1,
'exp' INTEGER DEFAULT 1,
'gold' INTEGER DEFAULT 1,
'immune' INTEGER DEFAULT 0,
'image' TEXT DEFAULT ''
);");
// add default monsters if complete install
if ($complete) App::$db->insertFromCSV('monsters', "$defaults/monsters.csv");
// @News
App::$db->q("CREATE TABLE IF NOT EXISTS 'news' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'author' INTEGER DEFAULT 1,
'title' TEXT DEFAULT '',
'content' TEXT DEFAULT '',
'posted' DATETIME DEFAULT CURRENT_TIMESTAMP
);");
// @Spells
App::$db->q("CREATE TABLE IF NOT EXISTS 'spells' (
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
'name' TEXT NOT NULL,
'type' INTEGER DEFAULT 1,
'mp' INTEGER DEFAULT 0,
'effect' TEXT DEFAULT '',
'icon' TEXT DEFAULT ''
);");
// add default spells if complete install
if ($complete) App::$db->insertFromCSV('spells', "$defaults/spells.csv");
// @LearnedSpells
App::$db->q("CREATE TABLE IF NOT EXISTS 'class_spells' (
'level' INTEGER NOT NULL,
'class_id' INTEGER NOT NULL,
'spell_id' INTEGER NOT NULL
);");
// add default class spells if complete install
if ($complete) App::$db->insertFromCSV('class_spells', "$defaults/class_spells.csv");
// @Towns
App::$db->q("CREATE TABLE IF NOT EXISTS 'towns' (
'id' INTEGER PRIMARY KEY,
'name' TEXT NOT NULL,
'x' INTEGER DEFAULT 0,
'y' INTEGER DEFAULT 0,
'inn_cost' INTEGER DEFAULT 0,
'map_cost' INTEGER DEFAULT 5,
'tp_cost' INTEGER DEFAULT 0,
'shop_list' TEXT DEFAULT '',
'image' TEXT DEFAULT ''
);");
// add default towns if complete install
if ($complete) App::$db->insertFromCSV('towns', "$defaults/towns.csv");
// @Players
App::$db->q("CREATE TABLE IF NOT EXISTS 'players' (
'id' INTEGER PRIMARY KEY,
'username' TEXT NOT NULL,
'password' TEXT NOT NULL,
'email' TEXT DEFAULT '',
'verified' INTEGER DEFAULT 1,
'registered' DATETIME DEFAULT CURRENT_TIMESTAMP,
'last_online' DATETIME DEFAULT CURRENT_TIMESTAMP,
'currently' INTEGER DEFAULT 0,
'role' INTEGER DEFAULT 1,
'class_id' INTEGER DEFAULT 1,
'level' INTEGER DEFAULT 1,
'exp' INTEGER DEFAULT 0,
'exp2l' INTEGER DEFAULT 0,
'gold' INTEGER DEFAULT 0,
'stat_points' INTEGER DEFAULT 0,
'hp' INTEGER DEFAULT 0,
'max_hp' INTEGER DEFAULT 0,
'mp' INTEGER DEFAULT 0,
'max_mp' INTEGER DEFAULT 0,
'tp' INTEGER DEFAULT 5,
'max_tp' INTEGER DEFAULT 5,
'str' INTEGER DEFAULT 0,
'atk' INTEGER DEFAULT 0,
'dex' INTEGER DEFAULT 0,
'def' INTEGER DEFAULT 0,
'weapon_id' INTEGER DEFAULT 0,
'armor_id' INTEGER DEFAULT 0,
'shield_id' INTEGER DEFAULT 0,
'slot_1_id' INTEGER DEFAULT 0,
'slot_2_id' INTEGER DEFAULT 0,
'slot_3_id' INTEGER DEFAULT 0,
'spells' TEXT DEFAULT '',
'maps' TEXT DEFAULT ''
);");
// @Fights
App::$db->q("CREATE TABLE IF NOT EXISTS 'fights' (
'id' INTEGER PRIMARY KEY,
'p_id' INTEGER DEFAULT 1,
'm_id' INTEGER DEFAULT 1,
'turn' INTEGER DEFAULT 1,
'p_hp' INTEGER DEFAULT 0,
'p_maxhp' INTEGER DEFAULT 0,
'p_mp' INTEGER DEFAULT 0,
'p_maxmp' INTEGER DEFAULT 0,
'm_hp' INTEGER DEFAULT 0,
'm_maxhp' INTEGER DEFAULT 0,
'effects' TEXT DEFAULT ''
);");
// @Sessions
App::$db->q("CREATE TABLE IF NOT EXISTS 'sessions' (
'player_id' INTEGER NOT NULL UNIQUE,
'token' TEXT NOT NULL,
'expires' DATETIME NOT NULL
);");
// Create the .installed file in the server folder
file_put_contents(SERVER.'/.installed', 'Installed on '.date('Y-m-d H:i:s'));
echo render('install/layout', ['title' => 'Database Setup', 'step' => 'second', 'complete' => $complete, 'start' => $istart]);
}
private static function finish()
{
$errors = [];
// Make sure our info is at least mostly valid
if (!required(['username', 'password', 'email'])) {
$errors[] = 'All fields are required.';
} else {
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Invalid email address format.';
}
if (strlen($_POST['password']) < 6) {
$errors[] = 'Password must be at least 6 characters long.';
}
}
// Make sure the class selection is present
$class = $_POST['class'] ?? 1;
// If we have any errors, bail to the form and let the user know
if (!empty($errors)) {
echo render('install/layout', ['title' => 'Admin Account', 'step' => 'third', 'errors' => $errors, 'complete' => $_POST['complete'] ?? false]);
exit;
}
// Create the admin account
Player::create([
'username' => trim($_POST['username']),
'password' => password_hash($_POST['password'], PASSWORD_ARGON2ID),
'email' => trim($_POST['email']),
'class_id' => $class,
'verified' => 1,
'role' => 5,
'level' => $_POST['level'] ?? 1
]);
// login the admin
App::$auth->login($_POST['username'], $_POST['password']);
// Render the finished page!
echo render('install/layout', ['title' => 'Finished!', 'step' => 'done', 'name' => $_POST['username'], 'complete' => $_POST['complete'] ?? false]);
}
private static function fourOhFour()
{
echo render('install/layout', ['title' => 'Four Oh Four', 'step' => 'four']);
}
}