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 );"); 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 ]); // Render the finished page! echo render('install/layout', ['title' => 'Finished!', 'step' => 'done', 'name' => $_POST['username'], 'complete' => $_POST['complete'] ?? false]); // Create the .installed file in the server folder file_put_contents(SERVER.'/.installed', 'Installed on '.date('Y-m-d H:i:s')); } private static function fourOhFour() { echo render('install/layout', ['title' => 'Four Oh Four', 'step' => 'four']); } }