diff --git a/database/create/auth.sql b/database/create/auth.sql new file mode 100644 index 0000000..41be045 --- /dev/null +++ b/database/create/auth.sql @@ -0,0 +1,28 @@ +DROP TABLE IF EXISTS users; +CREATE TABLE users ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `username` TEXT NOT NULL UNIQUE, + `email` TEXT NOT NULL UNIQUE, + `password` TEXT NOT NULL, + `auth` INT NOT NULL DEFAULT 0, + `char_id` INTEGER NOT NULL DEFAULT 0, + `char_slots` INTEGER NOT NULL DEFAULT 2, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `last_login` DATETIME DEFAULT CURRENT_TIMESTAMP +); + +DROP TABLE IF EXISTS sessions; +CREATE TABLE sessions ( + `user_id` INTEGER NOT NULL, + `token` TEXT NOT NULL UNIQUE, + `expires` INTEGER NOT NULL +); +CREATE INDEX idx_sessions_user_id ON sessions (`user_id`); + +DROP TABLE IF EXISTS tokens; +CREATE TABLE tokens ( + `user_id` INTEGER NOT NULL, + `token` TEXT NOT NULL UNIQUE, + `created` INTEGER NOT NULL +); +CREATE INDEX idx_tokens_user_id ON tokens (`user_id`); diff --git a/database/create/blueprints.sql b/database/create/blueprints.sql new file mode 100644 index 0000000..4e348fb --- /dev/null +++ b/database/create/blueprints.sql @@ -0,0 +1,56 @@ +DROP TABLE IF EXISTS items; +CREATE TABLE items ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `type` INTEGER NOT NULL DEFAULT 0, + `subtype` INTEGER NOT NULL DEFAULT 0, + `slot` INTEGER NOT NULL DEFAULT 0, + `rarity` INTEGER NOT NULL DEFAULT 0, + `value` INTEGER NOT NULL DEFAULT 0, + `consumable` INTEGER NOT NULL DEFAULT 0, + `duration` INTEGER NOT NULL DEFAULT 0, + `durability` INTEGER NOT NULL DEFAULT 0, + `pow` INTEGER NOT NULL DEFAULT 0, -- Power + `acc` INTEGER NOT NULL DEFAULT 0, -- Accuracy + `pen` INTEGER NOT NULL DEFAULT 0, -- Penetration + `foc` INTEGER NOT NULL DEFAULT 0, -- Focus + `tou` INTEGER NOT NULL DEFAULT 0, -- Toughness + `arm` INTEGER NOT NULL DEFAULT 0, -- Armor + `res` INTEGER NOT NULL DEFAULT 0, -- Resist + `pre` INTEGER NOT NULL DEFAULT 0, -- Precision + `fer` INTEGER NOT NULL DEFAULT 0, -- Ferocity + `luck` INTEGER NOT NULL DEFAULT 0, + `reqs` TEXT NOT NULL DEFAULT "", + `traits` TEXT NOT NULL DEFAULT "", + `lore` TEXT NOT NULL DEFAULT "", + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); + +DROP TABLE IF EXISTS mobs; +CREATE TABLE mobs ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `type` INTEGER NOT NULL, + `rank` INTEGER NOT NULL, + `level` INTEGER NOT NULL, + `hp` INTEGER NOT NULL, + `m_hp` INTEGER NOT NULL, + `mp` INTEGER NOT NULL, + `m_mp` INTEGER NOT NULL, + `pow` INTEGER NOT NULL, -- Power + `acc` INTEGER NOT NULL, -- Accuracy + `pen` INTEGER NOT NULL, -- Penetration + `foc` INTEGER NOT NULL, -- Focus + `tou` INTEGER NOT NULL, -- Toughness + `arm` INTEGER NOT NULL, -- Armor + `res` INTEGER NOT NULL, -- Resist + `pre` INTEGER NOT NULL, -- Precision + `fer` INTEGER NOT NULL, -- Ferocity + `xp` INTEGER NOT NULL, + `silver` INTEGER NOT NULL, + `loot` TEXT NOT NULL, + `lore` TEXT NOT NULL, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); diff --git a/database/create/fights.sql b/database/create/fights.sql new file mode 100644 index 0000000..c565c39 --- /dev/null +++ b/database/create/fights.sql @@ -0,0 +1,103 @@ +/* + @PvE +*/ +DROP TABLE IF EXISTS pve; +CREATE TABLE pve ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `char_id` INTEGER NOT NULL, + `char_hp` INTEGER NOT NULL, + `char_m_hp` INTEGER NOT NULL, + `char_mp` INTEGER NOT NULL, + `char_m_mp` INTEGER NOT NULL, + `char_pow` INTEGER NOT NULL, -- Power + `char_acc` INTEGER NOT NULL, -- Accuracy + `char_pen` INTEGER NOT NULL, -- Penetration + `char_foc` INTEGER NOT NULL, -- Focus + `char_tou` INTEGER NOT NULL, -- Toughness + `char_arm` INTEGER NOT NULL, -- Armor + `char_res` INTEGER NOT NULL, -- Resist + `char_pre` INTEGER NOT NULL, -- Precision + `char_fer` INTEGER NOT NULL, -- Ferocity + `mob_id` INTEGER NOT NULL, + `mob_level` INTEGER NOT NULL, + `mob_rank` INTEGER NOT NULL, + `mob_hp` INTEGER NOT NULL, + `mob_m_hp` INTEGER NOT NULL, + `mob_mp` INTEGER NOT NULL, + `mob_m_mp` INTEGER NOT NULL, + `mob_pow` INTEGER NOT NULL, -- Power + `mob_acc` INTEGER NOT NULL, -- Accuracy + `mob_pen` INTEGER NOT NULL, -- Penetration + `mob_foc` INTEGER NOT NULL, -- Focus + `mob_tou` INTEGER NOT NULL, -- Toughness + `mob_arm` INTEGER NOT NULL, -- Armor + `mob_res` INTEGER NOT NULL, -- Resist + `mob_pre` INTEGER NOT NULL, -- Precision + `mob_fer` INTEGER NOT NULL, -- Ferocity + `first_turn` INTEGER NOT NULL, + `turn` INTEGER NOT NULL default 1, + `winner` INTEGER NOT NULL default 0, + `can_flee` INTEGER NOT NULL default 1, + `escaped` INTEGER NOT NULL default 0, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_pve_char_id ON pve (`char_id`); + +DROP TABLE IF EXISTS pve_logs; +CREATE TABLE pve_logs ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `fight_id` INTEGER NOT NULL, + `info` TEXT NOT NULL +); +CREATE INDEX idx_pve_logs_fight_id ON pve_logs (`fight_id`); + +/* + @PvP +*/ +DROP TABLE IF EXISTS pvp; +CREATE TABLE pvp ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `char1_id` INTEGER NOT NULL, + `char1_hp` INTEGER NOT NULL, + `char1_max_hp` INTEGER NOT NULL, + `char1_mp` INTEGER NOT NULL, + `char1_max_mp` INTEGER NOT NULL, + `char1_pow` INTEGER NOT NULL, -- Power + `char1_acc` INTEGER NOT NULL, -- Accuracy + `char1_pen` INTEGER NOT NULL, -- Penetration + `char1_foc` INTEGER NOT NULL, -- Focus + `char1_tou` INTEGER NOT NULL, -- Toughness + `char1_arm` INTEGER NOT NULL, -- Armor + `char1_res` INTEGER NOT NULL, -- Resist + `char1_pre` INTEGER NOT NULL, -- Precision + `char1_fer` INTEGER NOT NULL, -- Ferocity + `char2_id` INTEGER NOT NULL, + `char2_hp` INTEGER NOT NULL, + `char2_m_hp` INTEGER NOT NULL, + `char2_mp` INTEGER NOT NULL, + `char2_m_mp` INTEGER NOT NULL, + `char2_pow` INTEGER NOT NULL, -- Power + `char2_acc` INTEGER NOT NULL, -- Accuracy + `char2_pen` INTEGER NOT NULL, -- Penetration + `char2_foc` INTEGER NOT NULL, -- Focus + `char2_tou` INTEGER NOT NULL, -- Toughness + `char2_arm` INTEGER NOT NULL, -- Armor + `char2_res` INTEGER NOT NULL, -- Resist + `char2_pre` INTEGER NOT NULL, -- Precision + `char2_fer` INTEGER NOT NULL, -- Ferocity + `first_turn` INTEGER NOT NULL, + `turn` INTEGER NOT NULL default 1, + `winner` INTEGER NOT NULL default 0, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_pvp_char1_id ON pvp (`char1_id`); +CREATE INDEX idx_pvp_char2_id ON pvp (`char2_id`); + +CREATE TABLE pvp_logs ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `fight_id` INTEGER NOT NULL, + `info` TEXT NOT NULL +); +CREATE INDEX idx_pvp_logs_fight_id ON pvp_logs (`fight_id`); diff --git a/database/create/live.sql b/database/create/live.sql new file mode 100644 index 0000000..3e40e02 --- /dev/null +++ b/database/create/live.sql @@ -0,0 +1,329 @@ +/* + @BLOG +*/ +DROP TABLE IF EXISTS blog; +CREATE TABLE blog ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `author_id` INTEGER NOT NULL, + `title` TEXT NOT NULL, + `slug` TEXT NOT NULL UNIQUE, + `content` TEXT NOT NULL, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_blog_author_id ON blog (`author_id`); +CREATE INDEX idx_blog_slug ON blog (`slug`); + +/* + @CHARS +*/ +DROP TABLE IF EXISTS characters; +CREATE TABLE characters ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `user_id` INTEGER NOT NULL, + `name` TEXT NOT NULL UNIQUE, + `title_id` INTEGER NOT NULL DEFAULT 1, + `level` INTEGER NOT NULL DEFAULT 1, + `xp` INTEGER NOT NULL DEFAULT 0, + `xp_to_level` INTEGER NOT NULL DEFAULT 100, + `hp` INTEGER NOT NULL DEFAULT 20, + `m_hp` INTEGER NOT NULL DEFAULT 20, + `mp` INTEGER NOT NULL DEFAULT 10, + `m_mp` INTEGER NOT NULL DEFAULT 10, + `tp` INTEGER NOT NULL DEFAULT 1, + `m_tp` INTEGER NOT NULL DEFAULT 1, + `pow` INTEGER NOT NULL DEFAULT 0, -- Power + `acc` INTEGER NOT NULL DEFAULT 0, -- Accuracy + `pen` INTEGER NOT NULL DEFAULT 0, -- Penetration + `foc` INTEGER NOT NULL DEFAULT 0, -- Focus + `tou` INTEGER NOT NULL DEFAULT 0, -- Toughness + `arm` INTEGER NOT NULL DEFAULT 0, -- Armor + `res` INTEGER NOT NULL DEFAULT 0, -- Resist + `pre` INTEGER NOT NULL DEFAULT 0, -- Precision + `fer` INTEGER NOT NULL DEFAULT 0, -- Ferocity + `luck` INTEGER NOT NULL DEFAULT 0, -- Luck + `inv_slots` INTEGER NOT NULL DEFAULT 10, + `att_points` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_characters_user_id ON characters (`user_id`); + +/* + @CHARGEAR +*/ +DROP TABLE IF EXISTS char_gear; +CREATE TABLE char_gear ( + `char_id` INTEGER NOT NULL, + `head` INTEGER NOT NULL DEFAULT 0, + `chest` INTEGER NOT NULL DEFAULT 0, + `boots` INTEGER NOT NULL DEFAULT 0, + `hands` INTEGER NOT NULL DEFAULT 0, + `m_hand` INTEGER NOT NULL DEFAULT 0, + `o_hand` INTEGER NOT NULL DEFAULT 0, + `rune` INTEGER NOT NULL DEFAULT 0, + `ring` INTEGER NOT NULL DEFAULT 0, + `amulet` INTEGER NOT NULL DEFAULT 0, + `pow` INTEGER NOT NULL DEFAULT 0, -- Power + `acc` INTEGER NOT NULL DEFAULT 0, -- Accuracy + `pen` INTEGER NOT NULL DEFAULT 0, -- Penetration + `foc` INTEGER NOT NULL DEFAULT 0, -- Focus + `tou` INTEGER NOT NULL DEFAULT 0, -- Toughness + `arm` INTEGER NOT NULL DEFAULT 0, -- Armor + `res` INTEGER NOT NULL DEFAULT 0, -- Resist + `pre` INTEGER NOT NULL DEFAULT 0, -- Precision + `fer` INTEGER NOT NULL DEFAULT 0, -- Ferocity + `luck` INTEGER NOT NULL DEFAULT 0, -- Luck + `max_hp` INTEGER NOT NULL DEFAULT 0, + `max_mp` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_char_gear_char_id ON char_gear (`char_id`); + +/* + @CHARINV +*/ +DROP TABLE IF EXISTS char_inventory; +CREATE TABLE char_inventory ( + `char_id` INTEGER NOT NULL, + `item_id` INTEGER NOT NULL +); +CREATE INDEX idx_inventory_char_id ON char_inventory (`char_id`); + +/* + @WALLETS +*/ +DROP TABLE IF EXISTS wallets; +CREATE TABLE wallets ( + `user_id` INTEGER NOT NULL, + `silver` INTEGER NOT NULL DEFAULT 10, + `stargem` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_wallets_user_id ON wallets (`user_id`); + +/* + @CHARBANK +*/ +DROP TABLE IF EXISTS char_bank; +CREATE TABLE char_bank ( + `char_id` INTEGER NOT NULL, + `slots` INTEGER NOT NULL DEFAULT 5, + `silver` INTEGER NOT NULL DEFAULT 0, + `tier` INTEGER NOT NULL DEFAULT 0, + `can_collect` INTEGER NOT NULL DEFAULT 1, + `last_collect` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_bank_char_id ON char_bank (`char_id`); + +/* + @CHARBANKITEMS +*/ +DROP TABLE IF EXISTS char_banked_items; +CREATE TABLE char_banked_items ( + `char_id` INTEGER NOT NULL, + `item_id` INTEGER NOT NULL +); +CREATE INDEX idx_banked_items_char_id ON char_banked_items (`char_id`); +CREATE INDEX idx_banked_items_item_id ON char_banked_items (`item_id`); + +/* + @TOWNS +*/ +DROP TABLE IF EXISTS towns; +CREATE TABLE towns ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `x` INTEGER NOT NULL, + `y` INTEGER NOT NULL, + `type` INTEGER NOT NULL, + `lore` TEXT NOT NULL, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_towns_location ON towns (`x`, `y`); + +/* + @SHOPS +*/ +DROP TABLE IF EXISTS shops; +CREATE TABLE shops ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `type` INTEGER NOT NULL, + `lore` TEXT NOT NULL, + `x` INTEGER NOT NULL, + `y` INTEGER NOT NULL, + `items` TEXT NOT NULL, + `gear` TEXT NOT NULL, + `materials` TEXT NOT NULL, + `b_mod` INTEGER NOT NULL DEFAULT 100, + `s_mod` INTEGER NOT NULL DEFAULT 100, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_shops_location ON shops (`x`, `y`); + +/* + @INNS +*/ +DROP TABLE IF EXISTS inns; +CREATE TABLE inns ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `type` INTEGER NOT NULL, + `lore` TEXT NOT NULL, + `x` INTEGER NOT NULL, + `y` INTEGER NOT NULL, + `cost` INTEGER NOT NULL, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_inns_location ON inns (`x`, `y`); + +/* + @GUILDS +*/ +DROP TABLE IF EXISTS guilds; +CREATE TABLE guilds ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `lore` TEXT NOT NULL DEFAULT "", + `leader_id` INTEGER NOT NULL, + `silver` INTEGER NOT NULL DEFAULT 0, + `rep` INTEGER NOT NULL DEFAULT 0, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_guilds_leader_id ON guilds (`leader_id`); + +/* + @GUILDRANKS +*/ +DROP TABLE IF EXISTS guild_ranks; +CREATE TABLE guild_ranks ( + `guild_id` INTEGER NOT NULL, + `order` INTEGER NOT NULL, + `name` TEXT NOT NULL, + `permissions` TEXT NOT NULL, + `leader` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_guild_ranks_guild_id ON guild_ranks (`guild_id`); + +/* + @GUILDMEMBERS +*/ +DROP TABLE IF EXISTS guild_members; +CREATE TABLE guild_members ( + `guild_id` INTEGER NOT NULL, + `char_id` INTEGER NOT NULL, + `rank` INTEGER NOT NULL, + `rep` INTEGER NOT NULL DEFAULT 0, + `donated` INTEGER NOT NULL DEFAULT 0, + `joined` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_guild_members_guild_id ON guild_members (`guild_id`); +CREATE INDEX idx_guild_members_char_id ON guild_members (`char_id`); + +/* + @NPCS +*/ +DROP TABLE IF EXISTS npcs; +CREATE TABLE npcs ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `type` INTEGER NOT NULL, + `lore` TEXT NOT NULL, + `conversation` TEXT NOT NULL, + `x` INTEGER NOT NULL, + `y` INTEGER NOT NULL, + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_npcs_location ON npcs (`x`, `y`); + +/* + @TOWNREP +*/ +DROP TABLE IF EXISTS char_town_rep; +CREATE TABLE char_town_rep ( + `char_id` INTEGER NOT NULL, + `town_id` INTEGER NOT NULL, + `rep` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_char_town_rep_char_id ON char_town_rep (`char_id`); + +/* + @ITEMS +*/ +DROP TABLE IF EXISTS items; +CREATE TABLE items ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + `type` TEXT NOT NULL DEFAULT 0, + `rarity` INTEGER NOT NULL DEFAULT 0, + `forged` INTEGER NOT NULL DEFAULT 0, + `quality` INTEGER NOT NULL DEFAULT 0, + `value` INTEGER NOT NULL DEFAULT 0, + `consumable` INTEGER NOT NULL DEFAULT 0, + `duration` INTEGER NOT NULL DEFAULT 0, + `durability` INTEGER NOT NULL DEFAULT 0, + `m_durability` INTEGER NOT NULL DEFAULT 0, + `pow` INTEGER NOT NULL DEFAULT 0, -- Power + `acc` INTEGER NOT NULL DEFAULT 0, -- Accuracy + `pen` INTEGER NOT NULL DEFAULT 0, -- Penetration + `foc` INTEGER NOT NULL DEFAULT 0, -- Focus + `tou` INTEGER NOT NULL DEFAULT 0, -- Toughness + `arm` INTEGER NOT NULL DEFAULT 0, -- Armor + `res` INTEGER NOT NULL DEFAULT 0, -- Resist + `pre` INTEGER NOT NULL DEFAULT 0, -- Precision + `fer` INTEGER NOT NULL DEFAULT 0, -- Ferocity + `luck` INTEGER NOT NULL DEFAULT 0, -- Luck + `reqs` TEXT NOT NULL DEFAULT "", + `traits` TEXT NOT NULL DEFAULT "", + `lore` TEXT NOT NULL DEFAULT "", + `created` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updated` DATETIME DEFAULT CURRENT_TIMESTAMP +); + +/* + @CHARTRAITS +*/ +DROP TABLE IF EXISTS char_traits; +CREATE TABLE char_traits ( + `char_id` INTEGER NOT NULL, + `trait_id` INTEGER NOT NULL, + `value` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_char_traits_char_id ON char_traits (`char_id`); + +/* + @CHARLOCATIONS +*/ +DROP TABLE IF EXISTS char_locations; +CREATE TABLE char_locations ( + `char_id` INTEGER NOT NULL, + `x` INTEGER NOT NULL, + `y` INTEGER NOT NULL, + `currently` INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX idx_char_locations_char_id ON char_locations (`char_id`); +CREATE INDEX idx_char_locations_location ON char_locations (`x`, `y`); + +/* + @TITLES +*/ +DROP TABLE IF EXISTS titles; +CREATE TABLE titles ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL DEFAULT 'Title', + `lore` TEXT +); + +/* + @OWNEDTITLES +*/ +DROP TABLE IF EXISTS owned_titles; +CREATE TABLE owned_titles ( + `title_id` INTEGER NOT NULL, + `char_id` INTEGER NOT NULL, + `awarded` DATETIME DEFAULT CURRENT_TIMESTAMP +); +CREATE INDEX idx_owned_titles_char_id ON owned_titles (`char_id`); +CREATE INDEX idx_owned_titles_owned ON owned_titles (`char_id`, `title_id`); diff --git a/database/live.db-shm b/database/live.db-shm new file mode 100644 index 0000000..c35ed50 Binary files /dev/null and b/database/live.db-shm differ diff --git a/database/live.db-wal b/database/live.db-wal new file mode 100644 index 0000000..9231e61 Binary files /dev/null and b/database/live.db-wal differ diff --git a/database/manage.sh b/database/manage.sh new file mode 100755 index 0000000..beb21de --- /dev/null +++ b/database/manage.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# Directories for schema and population scripts +CREATE_DIR="create" +POPULATE_DIR="populate" + +# List of databases +DATABASES=("auth" "blueprints" "fights" "live") + +# Function to create a database and apply the schema +create_db() { + for db in "${DATABASES[@]}"; do + db_file="${db}.db" + schema_file="${CREATE_DIR}/${db}.sql" + + if [[ -f "$schema_file" ]]; then + echo "Creating $db_file and applying schema from $schema_file..." + sqlite3 "$db_file" < "$schema_file" + else + echo "Schema file for $db not found. Skipping." + fi + done +} + +# Function to populate the database with data +populate_db() { + for db in "${DATABASES[@]}"; do + db_file="${db}.db" + populate_file="${POPULATE_DIR}/${db}.sql" + + if [[ -f "$populate_file" ]]; then + echo "Populating $db_file using data from $populate_file..." + sqlite3 "$db_file" < "$populate_file" + else + echo "Population file for $db not found. Skipping." + fi + done +} + +# Function to drop (delete) the databases +drop_db() { + for db in "${DATABASES[@]}"; do + db_file="${db}.db" + + if [[ -f "$db_file" ]]; then + echo "Dropping $db_file..." + rm "$db_file" + else + echo "$db_file does not exist. Skipping." + fi + done +} + +# Function for a full reset (create and populate) +full_reset() { + create_db + populate_db +} + +# Main script +case $1 in + create) + create_db + ;; + populate) + populate_db + ;; + reset) + full_reset + ;; + drop) + drop_db + ;; + *) + echo "Usage: $0 {create|populate|reset}" + ;; +esac diff --git a/database/populate/live.sql b/database/populate/live.sql new file mode 100644 index 0000000..9269fe7 --- /dev/null +++ b/database/populate/live.sql @@ -0,0 +1 @@ +INSERT INTO titles (`name`, `lore`) VALUES ('Adventurer', 'A risk-taker hunting for glory and loot!'); diff --git a/database/scripts/create.php b/database/scripts/create.php deleted file mode 100644 index 82c083e..0000000 --- a/database/scripts/create.php +++ /dev/null @@ -1,666 +0,0 @@ - -*/ - -require_once __DIR__ . '/../../color.php'; - -const AUTH = 'auth.db'; -const LIVE = 'live.db'; -const FIGHTS = 'fights.db'; -const BPS = 'blueprints.db'; - -/** - * Echo a string with a newline. - */ -function eln($string) -{ - echo $string . PHP_EOL; -} - -// pick the database to create -if (!isset($argv[1])) { - eln(red('Missing database name.')); - eln(blue('Usage: ') . 'php create.php auth.db|live.db|fight.db|blueprints.db [-d]'); - exit(1); -} - -// make sure it's a valid database -if (!in_array($argv[1], [AUTH, LIVE, FIGHTS, BPS, 'reset'])) { - eln(red('Invalid database: ') . $argv[1]); - exit(1); -} - -$database = $argv[1]; -// whether the -d flag is set -$drop = isset($argv[2]) && $argv[2] === '-d'; - -/* - ================================================================================ - Databases - ================================================================================ -*/ - -/* - The Auth database is used to store user information - not player info, but user info. - Usernames, passwords, email, session tokens, etc. -*/ -if ($database === AUTH || $database === 'reset') { - if ($drop || $database === 'reset') { - unlink(__DIR__ . '/../' . AUTH); - eln(red('Dropped database: ') . 'auth.db'); - } - $db = new SQLite3(__DIR__ . '/../' . AUTH); - - // Users table - $db->exec('DROP TABLE IF EXISTS users'); - $r = $db->exec('CREATE TABLE users ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - username TEXT NOT NULL UNIQUE, - email TEXT NOT NULL UNIQUE, - password TEXT NOT NULL, - auth INT NOT NULL DEFAULT 0, - char_id INTEGER NOT NULL DEFAULT 0, - char_slots INTEGER NOT NULL DEFAULT 300, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - last_login DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - - created_or_error($r, 'users'); - - // Sessions table - $db->exec('DROP TABLE IF EXISTS sessions'); - $r = $db->exec('CREATE TABLE sessions ( - user_id INTEGER NOT NULL, - token TEXT NOT NULL UNIQUE, - expires INTEGER NOT NULL - )'); - $db->exec('CREATE INDEX idx_sessions_user_id ON sessions (user_id)'); - - created_or_error($r, 'sessions'); - - // Verification tokens - $db->exec('DROP TABLE IF EXISTS tokens'); - $r = $db->exec('CREATE TABLE tokens ( - user_id INTEGER NOT NULL, - token TEXT NOT NULL UNIQUE, - created INTEGER NOT NULL - )'); - $db->exec('CREATE INDEX idx_tokens_user_id ON tokens (user_id)'); - - created_or_error($r, 'tokens'); - - eln(green('Created database: ') . 'auth.db'); - - if ($database !== 'reset') exit(0); -} - -/* - The Fights database is used to store information about fights. - A fight is a battle between two characters; players or NPCs. -*/ -if ($database === FIGHTS || $database === 'reset') { - if ($drop || $database === 'reset') { - unlink(__DIR__ . '/../' . FIGHTS); - eln(red('Dropped database: ') . 'fights.db'); - } - $db = new SQLite3(__DIR__ . '/../' . FIGHTS); - - // PvE fights - $db->exec('DROP TABLE IF EXISTS pve'); - $r = $db->exec('CREATE TABLE pve ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - char_id INTEGER NOT NULL, - char_hp INTEGER NOT NULL, - char_max_hp INTEGER NOT NULL, - char_mp INTEGER NOT NULL, - char_max_mp INTEGER NOT NULL, - char_power INTEGER NOT NULL, - char_accuracy INTEGER NOT NULL, - char_penetration INTEGER NOT NULL DEFAULT 0, - char_focus INTEGER NOT NULL DEFAULT 0, - char_toughness INTEGER NOT NULL, - char_armor INTEGER NOT NULL, - char_resist INTEGER NOT NULL, - char_crit INTEGER NOT NULL, - char_precision INTEGER NOT NULL, - char_ferocity INTEGER NOT NULL, - mob_id INTEGER NOT NULL, - mob_level INTEGER NOT NULL, - mob_rank INTEGER NOT NULL, - mob_hp INTEGER NOT NULL, - mob_max_hp INTEGER NOT NULL, - mob_mp INTEGER NOT NULL, - mob_max_mp INTEGER NOT NULL, - mob_power INTEGER NOT NULL, - mob_toughness INTEGER NOT NULL, - mob_armor INTEGER NOT NULL, - mob_precision INTEGER NOT NULL, - mob_penetration INTEGER NOT NULL DEFAULT 0, - mob_focus INTEGER NOT NULL DEFAULT 0, - mob_crit INTEGER NOT NULL, - mob_ferocity INTEGER NOT NULL, - mob_vitality INTEGER NOT NULL, - first_turn INTEGER NOT NULL, - turn INTEGER NOT NULL default 1, - winner INTEGER NOT NULL default 0, - flee INTEGER NOT NULL default 1, - escaped INTEGER NOT NULL default 0, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // create an index for char_id - $db->exec('CREATE INDEX idx_pve_char_id ON pve (char_id)'); - - created_or_error($r, 'pve'); - - // PvP fights - $db->exec('DROP TABLE IF EXISTS pvp'); - $r = $db->exec('CREATE TABLE pvp ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - char1_id INTEGER NOT NULL, - char1_hp INTEGER NOT NULL, - char1_max_hp INTEGER NOT NULL, - char1_mp INTEGER NOT NULL, - char1_max_mp INTEGER NOT NULL, - char1_power INTEGER NOT NULL, - char1_accuracy INTEGER NOT NULL, - char1_penetration INTEGER NOT NULL DEFAULT 0, - char1_focus INTEGER NOT NULL DEFAULT 0, - char1_toughness INTEGER NOT NULL, - char1_armor INTEGER NOT NULL, - char1_resist INTEGER NOT NULL, - char1_crit INTEGER NOT NULL, - char1_precision INTEGER NOT NULL, - char1_ferocity INTEGER NOT NULL, - char2_id INTEGER NOT NULL, - char2_hp INTEGER NOT NULL, - char2_max_hp INTEGER NOT NULL, - char2_mp INTEGER NOT NULL, - char2_max_mp INTEGER NOT NULL, - char2_power INTEGER NOT NULL, - char2_accuracy INTEGER NOT NULL, - char2_penetration INTEGER NOT NULL DEFAULT 0, - char2_focus INTEGER NOT NULL DEFAULT 0, - char2_toughness INTEGER NOT NULL, - char2_armor INTEGER NOT NULL, - char2_resist INTEGER NOT NULL, - char2_crit INTEGER NOT NULL, - char2_precision INTEGER NOT NULL, - char2_ferocity INTEGER NOT NULL, - first_turn INTEGER NOT NULL, - turn INTEGER NOT NULL default 1, - winner INTEGER NOT NULL default 0, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for char1_id - $db->exec('CREATE INDEX idx_pvp_char1_id ON pvp (char1_id)'); - // Create an index for char2_id - $db->exec('CREATE INDEX idx_pvp_char2_id ON pvp (char2_id)'); - - created_or_error($r, 'pvp'); - - // PvE fight logs - $db->exec('DROP TABLE IF EXISTS pve_logs'); - $r = $db->exec('CREATE TABLE pve_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - fight_id INTEGER NOT NULL, - info TEXT NOT NULL - )'); - // Create an index for fight_id - $db->exec('CREATE INDEX idx_pve_logs_fight_id ON pve_logs (fight_id)'); - - created_or_error($r, 'pve_logs'); - - // PvP fight logs - $db->exec('DROP TABLE IF EXISTS pvp_logs'); - $r = $db->exec('CREATE TABLE pvp_logs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - fight_id INTEGER NOT NULL, - info TEXT NOT NULL - )'); - // Create an index for fight_id - $db->exec('CREATE INDEX idx_pvp_logs_fight_id ON pvp_logs (fight_id)'); - - created_or_error($r, 'pvp_logs'); - - eln(green('Created database: ') . 'fights.db'); - - if ($database !== 'reset') exit(0); -} - -/* - The Blueprints database is used to store information about items, weapons, armor, etc. -*/ -if ($database === BPS || $database === 'reset') { - if ($drop || $database === 'reset') { - unlink(__DIR__ . '/../' . BPS); - eln(red('Dropped database: ') . 'blueprints.db'); - } - - $db = new SQLite3(__DIR__ . '/../' . BPS); - - // Items - $db->exec('DROP TABLE IF EXISTS items'); - $r = $db->exec('CREATE TABLE items ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - type INTEGER NOT NULL DEFAULT 0, - subtype INTEGER NOT NULL DEFAULT 0, - slot INTEGER NOT NULL DEFAULT 0, - rarity INTEGER NOT NULL DEFAULT 0, - value INTEGER NOT NULL DEFAULT 0, - consumable INTEGER NOT NULL DEFAULT 0, - duration INTEGER NOT NULL DEFAULT 0, - durability INTEGER NOT NULL DEFAULT 0, - power INTEGER NOT NULL DEFAULT 0, - accuracy INTEGER NOT NULL DEFAULT 0, - penetration INTEGER NOT NULL DEFAULT 0, - focus INTEGER NOT NULL DEFAULT 0, - toughness INTEGER NOT NULL DEFAULT 0, - armor INTEGER NOT NULL DEFAULT 0, - resist INTEGER NOT NULL DEFAULT 0, - crit INTEGER NOT NULL DEFAULT 0, - precision INTEGER NOT NULL DEFAULT 0, - ferocity INTEGER NOT NULL DEFAULT 0, - luck INTEGER NOT NULL DEFAULT 0, - reqs TEXT NOT NULL DEFAULT "", - traits TEXT NOT NULL DEFAULT "", - lore TEXT NOT NULL DEFAULT "", - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - - created_or_error($r, 'items'); - - // Mobs - $db->exec('DROP TABLE IF EXISTS mobs'); - $r = $db->exec('CREATE TABLE mobs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - type INTEGER NOT NULL, - rank INTEGER NOT NULL, - level INTEGER NOT NULL, - hp INTEGER NOT NULL, - max_hp INTEGER NOT NULL, - mp INTEGER NOT NULL, - max_mp INTEGER NOT NULL, - power INTEGER NOT NULL, - toughness INTEGER NOT NULL, - armor INTEGER NOT NULL, - precision INTEGER NOT NULL, - crit INTEGER NOT NULL, - ferocity INTEGER NOT NULL, - vitality INTEGER NOT NULL, - xp INTEGER NOT NULL, - silver INTEGER NOT NULL, - loot TEXT NOT NULL, - lore TEXT NOT NULL, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - - created_or_error($r, 'mobs'); - - eln(green('Created database: ') . 'blueprints.db'); - - if ($database !== 'reset') exit(0); -} - -/* - The Live database is used to store information about players, NPCs, guilds, etc. -*/ -if ($database === LIVE || $database === 'reset') { - if ($drop || $database === 'reset') { - unlink(__DIR__ . '/../' . LIVE); - eln(red('Dropped database: ') . 'live.db'); - } - - $db = new SQLite3(__DIR__ . '/../' . LIVE); - - // Blog posts - $db->exec('DROP TABLE IF EXISTS blog'); - $r = $db->exec('CREATE TABLE blog ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - author_id INTEGER NOT NULL, - title TEXT NOT NULL, - slug TEXT NOT NULL UNIQUE, - content TEXT NOT NULL, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for author_id - $db->exec('CREATE INDEX idx_blog_author_id ON blog (author_id)'); - // Create an index for the slug - $db->exec('CREATE INDEX idx_blog_slug ON blog (slug)'); - - created_or_error($r, 'blog'); - - // Characters - $db->exec('DROP TABLE IF EXISTS characters'); - $r = $db->exec('CREATE TABLE characters ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL, - name TEXT NOT NULL UNIQUE, - title_id INTEGER NOT NULL DEFAULT 0, - level INTEGER NOT NULL DEFAULT 1, - xp INTEGER NOT NULL DEFAULT 0, - xp_to_level INTEGER NOT NULL DEFAULT 100, - current_hp INTEGER NOT NULL DEFAULT 20, - max_hp INTEGER NOT NULL DEFAULT 20, - current_mp INTEGER NOT NULL DEFAULT 10, - max_mp INTEGER NOT NULL DEFAULT 10, - current_tp INTEGER NOT NULL DEFAULT 1, - max_tp INTEGER NOT NULL DEFAULT 1, - power INTEGER NOT NULL DEFAULT 0, - accuracy INTEGER NOT NULL DEFAULT 0, - penetration INTEGER NOT NULL DEFAULT 0, - focus INTEGER NOT NULL DEFAULT 0, - toughness INTEGER NOT NULL DEFAULT 0, - armor INTEGER NOT NULL DEFAULT 0, - resist INTEGER NOT NULL DEFAULT 0, - precision INTEGER NOT NULL DEFAULT 0, - ferocity INTEGER NOT NULL DEFAULT 0, - luck INTEGER NOT NULL DEFAULT 0, - inv_slots INTEGER NOT NULL DEFAULT 10, - attrib_points INTEGER NOT NULL DEFAULT 0 - )'); - // Create an index for user_id - $db->exec('CREATE INDEX idx_characters_user_id ON characters (user_id)'); - - created_or_error($r, 'characters'); - - // Player gear - $db->exec('DROP TABLE IF EXISTS char_gear'); - $r = $db->exec('CREATE TABLE char_gear ( - char_id INTEGER NOT NULL, - head INTEGER NOT NULL DEFAULT 0, - chest INTEGER NOT NULL DEFAULT 0, - boots INTEGER NOT NULL DEFAULT 0, - hands INTEGER NOT NULL DEFAULT 0, - main_hand INTEGER NOT NULL DEFAULT 0, - off_hand INTEGER NOT NULL DEFAULT 0, - rune INTEGER NOT NULL DEFAULT 0, - ring INTEGER NOT NULL DEFAULT 0, - amulet INTEGER NOT NULL DEFAULT 0, - power INTEGER NOT NULL DEFAULT 0, - accuracy INTEGER NOT NULL DEFAULT 0, - penetration INTEGER NOT NULL DEFAULT 0, - focus INTEGER NOT NULL DEFAULT 0, - toughness INTEGER NOT NULL DEFAULT 0, - armor INTEGER NOT NULL DEFAULT 0, - resist INTEGER NOT NULL DEFAULT 0, - crit INTEGER NOT NULL DEFAULT 0, - precision INTEGER NOT NULL DEFAULT 0, - ferocity INTEGER NOT NULL DEFAULT 0, - luck INTEGER NOT NULL DEFAULT 0, - max_hp INTEGER NOT NULL DEFAULT 0, - max_mp INTEGER NOT NULL DEFAULT 0 - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_char_gear_char_id ON char_gear (char_id)'); - - created_or_error($r, 'char_gear'); - - // Player inventory - $db->exec('DROP TABLE IF EXISTS char_inventory'); - $r = $db->exec('CREATE TABLE char_inventory ( - char_id INTEGER NOT NULL, - item_id INTEGER NOT NULL - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_inventory_char_id ON char_inventory (char_id)'); - - created_or_error($r, 'char_inventory'); - - // Player wallet - $db->exec('DROP TABLE IF EXISTS wallets'); - $r = $db->exec('CREATE TABLE wallets ( - user_id INTEGER NOT NULL, - silver INTEGER NOT NULL DEFAULT 10, - stargem INTEGER NOT NULL DEFAULT 0 - )'); - // Create an index for user_id - $db->exec('CREATE INDEX idx_wallets_user_id ON wallets (user_id)'); - - created_or_error($r, 'wallets'); - - // Player bank - $db->exec('DROP TABLE IF EXISTS char_bank'); - $r = $db->exec('CREATE TABLE char_bank ( - char_id INTEGER NOT NULL, - slots INTEGER NOT NULL DEFAULT 5, - silver INTEGER NOT NULL DEFAULT 0, - tier INTEGER NOT NULL DEFAULT 0, - can_collect INTEGER NOT NULL DEFAULT 1, - last_collected DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_bank_char_id ON char_bank (char_id)'); - - created_or_error($r, 'char_bank'); - - // Banked items - $db->exec('DROP TABLE IF EXISTS char_banked_items'); - $r = $db->exec('CREATE TABLE char_banked_items ( - char_id INTEGER NOT NULL, - item_id INTEGER NOT NULL - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_banked_items_char_id ON char_banked_items (char_id)'); - // Create an index for item_id - $db->exec('CREATE INDEX idx_banked_items_item_id ON char_banked_items (item_id)'); - - created_or_error($r, 'char_banked_items'); - - // Towns - $db->exec('DROP TABLE IF EXISTS towns'); - $r = $db->exec('CREATE TABLE towns ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - x INTEGER NOT NULL, - y INTEGER NOT NULL, - type INTEGER NOT NULL, - lore TEXT NOT NULL, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for the x, y location - $db->exec('CREATE INDEX idx_towns_location ON towns (x, y)'); - - created_or_error($r, 'towns'); - - // Shops - $db->exec('DROP TABLE IF EXISTS shops'); - $r = $db->exec('CREATE TABLE shops ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - type INTEGER NOT NULL, - lore TEXT NOT NULL, - x INTEGER NOT NULL, - y INTEGER NOT NULL, - items TEXT NOT NULL, - gear TEXT NOT NULL, - materials TEXT NOT NULL, - buy_modifier INTEGER NOT NULL DEFAULT 100, - sell_modifier INTEGER NOT NULL DEFAULT 100, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for the x, y location - $db->exec('CREATE INDEX idx_shops_location ON shops (x, y)'); - - created_or_error($r, 'shops'); - - // Inns - $db->exec('DROP TABLE IF EXISTS inns'); - $r = $db->exec('CREATE TABLE inns ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - type INTEGER NOT NULL, - lore TEXT NOT NULL, - x INTEGER NOT NULL, - y INTEGER NOT NULL, - cost INTEGER NOT NULL, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for the x, y location - $db->exec('CREATE INDEX idx_inns_location ON inns (x, y)'); - - created_or_error($r, 'inns'); - - // Guilds - $db->exec('DROP TABLE IF EXISTS guilds'); - $r = $db->exec('CREATE TABLE guilds ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - lore TEXT NOT NULL DEFAULT "", - leader_id INTEGER NOT NULL, - silver INTEGER NOT NULL DEFAULT 0, - rep INTEGER NOT NULL DEFAULT 0, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for leader_id - $db->exec('CREATE INDEX idx_guilds_leader_id ON guilds (leader_id)'); - - created_or_error($r, 'guilds'); - - // Guild ranks - $db->exec('DROP TABLE IF EXISTS guild_ranks'); - $r = $db->exec('CREATE TABLE guild_ranks ( - guild_id INTEGER NOT NULL, - rank INTEGER NOT NULL, - name TEXT NOT NULL, - permissions TEXT NOT NULL - )'); - // Create an index for guild_id - $db->exec('CREATE INDEX idx_guild_ranks_guild_id ON guild_ranks (guild_id)'); - - created_or_error($r, 'guild_ranks'); - - // Guild members - $db->exec('DROP TABLE IF EXISTS guild_members'); - $r = $db->exec('CREATE TABLE guild_members ( - guild_id INTEGER NOT NULL, - char_id INTEGER NOT NULL, - rank INTEGER NOT NULL, - rep INTEGER NOT NULL DEFAULT 0, - donated INTEGER NOT NULL DEFAULT 0, - joined DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for guild_id - $db->exec('CREATE INDEX idx_guild_members_guild_id ON guild_members (guild_id)'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_guild_members_char_id ON guild_members (char_id)'); - - created_or_error($r, 'guild_members'); - - // NPCs - $db->exec('DROP TABLE IF EXISTS npcs'); - $r = $db->exec('CREATE TABLE npcs ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - type INTEGER NOT NULL, - lore TEXT NOT NULL, - conversation TEXT NOT NULL, - x INTEGER NOT NULL, - y INTEGER NOT NULL, - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - // Create an index for the x, y location - $db->exec('CREATE INDEX idx_npcs_location ON npcs (x, y)'); - - created_or_error($r, 'npcs'); - - // Town reputation - $db->exec('DROP TABLE IF EXISTS char_town_rep'); - $r = $db->exec('CREATE TABLE char_town_rep ( - char_id INTEGER NOT NULL, - town_id INTEGER NOT NULL, - rep INTEGER NOT NULL DEFAULT 0 - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_char_town_rep_char_id ON char_town_rep (char_id)'); - - created_or_error($r, 'char_town_rep'); - - // Items - $db->exec('DROP TABLE IF EXISTS items'); - $r = $db->exec('CREATE TABLE items ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - type TEXT NOT NULL DEFAULT 0, - rarity INTEGER NOT NULL DEFAULT 0, - forged INTEGER NOT NULL DEFAULT 0, - quality INTEGER NOT NULL DEFAULT 0, - value INTEGER NOT NULL DEFAULT 0, - consumable INTEGER NOT NULL DEFAULT 0, - duration INTEGER NOT NULL DEFAULT 0, - durability INTEGER NOT NULL DEFAULT 0, - max_durability INTEGER NOT NULL DEFAULT 0, - power INTEGER NOT NULL DEFAULT 0, - accuracy INTEGER NOT NULL DEFAULT 0, - penetration INTEGER NOT NULL DEFAULT 0, - focus INTEGER NOT NULL DEFAULT 0, - toughness INTEGER NOT NULL DEFAULT 0, - armor INTEGER NOT NULL DEFAULT 0, - resist INTEGER NOT NULL DEFAULT 0, - crit INTEGER NOT NULL DEFAULT 0, - precision INTEGER NOT NULL DEFAULT 0, - ferocity INTEGER NOT NULL DEFAULT 0, - luck INTEGER NOT NULL DEFAULT 0, - reqs TEXT NOT NULL DEFAULT "", - traits TEXT NOT NULL DEFAULT "", - lore TEXT NOT NULL DEFAULT "", - created DATETIME DEFAULT CURRENT_TIMESTAMP, - updated DATETIME DEFAULT CURRENT_TIMESTAMP - )'); - - created_or_error($r, 'items'); - - // Player traits - $db->exec('DROP TABLE IF EXISTS char_traits'); - $r = $db->exec('CREATE TABLE char_traits ( - char_id INTEGER NOT NULL, - trait_id INTEGER NOT NULL, - value INTEGER NOT NULL DEFAULT 0 - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_char_traits_char_id ON char_traits (char_id)'); - - created_or_error($r, 'char_traits'); - - // Character location - $db->exec('DROP TABLE IF EXISTS char_locations'); - $r = $db->exec('CREATE TABLE char_locations ( - char_id INTEGER NOT NULL, - x INTEGER NOT NULL, - y INTEGER NOT NULL, - currently INTEGER NOT NULL DEFAULT 0 - )'); - // Create an index for char_id - $db->exec('CREATE INDEX idx_char_locations_char_id ON char_locations (char_id)'); - // Create an index for x, y location - $db->exec('CREATE INDEX idx_char_locations_location ON char_locations (x, y)'); - - created_or_error($r, 'char_locations'); - - eln(green('Created database: ') . 'live.db'); - - if ($database !== 'reset') exit(0); -} - -function created_or_error($result, $table) -{ - if ($result === false) { - eln(red('Failed to create table: ') . $table); - exit(1); - } - eln(yellow('Created table: ') . $table); -} diff --git a/public/assets/css/dragon.css b/public/assets/css/dragon.css index cb7900f..fab85e7 100644 --- a/public/assets/css/dragon.css +++ b/public/assets/css/dragon.css @@ -1 +1 @@ -:root{font-size:16px}*{box-sizing:border-box;margin:0;padding:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.container-960{width:960px;margin:0 auto}.ui.button{cursor:pointer;color:#111;text-align:center;user-select:none;-webkit-tap-highlight-color:transparent;background:#f7f8fa linear-gradient(#fff0,#0000001a);border:none;border-radius:3px;padding:.5rem 1rem;font-size:1rem;text-decoration:none;transition:opacity .1s,background-color .1s,color .1s,background .1s;display:inline-block;box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb;&:hover{color:#000c;background-color:#e0e0e0;background-image:linear-gradient(#fff0,#0000001a);box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb}&.badge{padding:.1rem .25rem;font-size:10px}&.primary{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3;&:hover{background-color:#fac847;border-color:#c59f43 #aa8326 #957321}}&.secondary{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&:hover{background-color:#4e5964;border-color:#32373e #24282d #212429}}&.danger{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3;&:hover{background-color:#d95c5c;border-color:#b71c1c #a52727 #8e1f1f}}}.form.control{appearance:none;color:#fff;background-color:#0003;border:1px solid #0000;border-radius:4px;outline:none;width:100%;padding:.5rem;font-size:1rem;display:block;box-shadow:inset 0 1px 4px #0000001a;&::placeholder{color:#ffffffb3}&:hover{background-color:#0000004d}&:focus{background-color:#00000080;border-color:#000c}&.error{background-color:#ff2b2b33;&:hover{background-color:#ff2b2b4d}&:focus{background-color:#ff2b2b4d;border-color:#ff2b2bcc}}}.form.group{margin-bottom:1rem;&>label{margin-bottom:.5rem;display:block}&>.form.control:not(:last-child){margin-bottom:.5rem}}.character-select>.radio-block{background-color:#0003;border-radius:.15rem;display:inline-block;&:not(:last-child){margin-bottom:.25rem}&>input[type=radio]{display:none}&>label{cursor:pointer;background-image:linear-gradient(#fff0,#0000);border:1px solid #0000;border-radius:.15rem;align-items:center;width:100%;padding:.5rem;transition:color,background-color,border-color,background-image .2s;display:flex;&:hover{color:#fff;background-color:#0000004d}&>.badge{margin-left:.25rem}&>span.selected{display:none}&>.char-icon{margin-right:.25rem}}&.active>label{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&>span.selected{display:inline-block}}&>input[type=radio]:checked+label{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}&>input[type=radio]:disabled+label{cursor:default}}.character-select:not(:has(input[type=radio]:checked))>.buttons{display:none}body{background-color:#bcc6cf;background-image:url(/assets/img/bg.jpg);background-position:top;background-repeat:no-repeat;background-attachment:fixed;max-width:1640px;margin:0 auto;font-family:Cambria,Cochin,Georgia,Times,Times New Roman,serif}header{color:#fff;background-image:url(/assets/img/header.jpg);justify-content:space-between;align-items:center;height:76px;padding:0 1rem;display:flex;& h1{margin:0;padding:0}& .right{align-items:center;display:flex;& p{margin-right:1rem}}}main{gap:2rem;width:100%;padding:1rem;display:flex;& #center{flex:1}}aside{min-width:200px;& .box{background-color:#0003;border-radius:.15rem;padding:.5rem}}aside#left nav{&>:not(:last-child){margin-bottom:.25rem}& div.stack{background-color:#0003;border-radius:.15rem;& input[type=checkbox]{display:none;&:checked~div.list{display:block}&:checked+label{color:#fff;background-color:#00000080}}& label{color:#000;cursor:pointer;border-radius:.15rem;align-items:center;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:flex;& img{height:18px;margin-right:.25rem}& span.text{width:100%;display:block}&:hover{color:#fff;background-color:#0000004d}& span.arrow{position:relative;top:5px}}& div.list{display:none;&>a{color:#000;border-radius:.15rem;width:100%;padding:.5rem 1rem .5rem 1.35rem;text-decoration:none;transition:color,background-color .2s;display:block;&:not(:last-child):before{content:"├";margin-right:.25rem;display:inline-block}&:last-child:before{content:"└";margin-right:.25rem;display:inline-block;position:relative;top:3px}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}}&>a{color:#000;background-color:#0003;border-radius:.15rem;width:100%;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:block;&:has(img){align-items:center;display:flex;& img{height:18px;margin-right:.25rem}}&:hover,&.active{color:#fff}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}footer{text-align:center;color:#666;justify-content:center;align-items:center;margin:1rem 0;padding:1rem;display:flex;&>p:not(:last-child){margin-right:2rem}}#char-bar{color:#fff;background-image:url(/assets/img/bar.jpg);justify-content:space-around;align-items:center;gap:1rem;height:34px;padding:0 1rem;display:flex;&>div.container{align-items:center;gap:1rem;display:flex;&>div{align-items:center;display:flex;& .icon{width:18px;margin-right:.5rem}}}}span.badge{color:#111;background-color:#f7f8fa;border-radius:.25rem;padding:.1rem .25rem;font-size:10px;box-shadow:inset 0 0 0 1px #0000001a;&.dark{color:#fff;background-color:#444c55}&.green{background-color:#a6e3a1}}.char-meter{background-color:#000;border-radius:.1rem;min-width:100px;height:16px;position:relative;&>div{border-radius:.1rem;height:100%;overflow:hidden;&.hp{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3}&.mp{background-color:#5a9bd4;background-image:linear-gradient(#ffffff26,#3c64961a);border:1px solid #3a7a9c;border-color:#4a8ab0 #3a7a9c #2a6a88;box-shadow:inset 0 1px #fff3}&.tp{background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}}}.tooltip{color:#fff;text-align:center;background-color:#000;border:1px solid #666;border-radius:.1rem;padding:.5rem;font-size:14px;box-shadow:0 0 .5rem .1rem #0003}.tooltip-trigger{width:100%;height:100%;position:absolute;top:0;left:0}.debug-query-log{color:#666;padding:2rem;font-family:monospace;font-size:14px}#center section{&:not(:last-child){border-bottom:1px solid #0000001a;margin-bottom:1rem;padding-bottom:1rem}}h1:has(.badge),h2:has(.badge),h3:has(.badge),h4:has(.badge),h5:has(.badge),h6:has(.badge){align-items:center;display:flex;&>.badge{margin-left:.5rem}}.alert{color:#000000de;background:#f8f8f9;border-radius:.285714rem;justify-content:space-between;align-items:center;min-height:1rem;margin:1rem 0;padding:.5rem 1rem;line-height:1.4285rem;transition:opacity .1s,color .1s,background .1s,box-shadow .1s;display:flex;position:relative;box-shadow:inset 0 0 0 1px #22242638,0 0 #0000;&.success{color:#2c662d;background-color:#f0f9eb;border-color:#b3dc9d}&.danger{color:#9f3a38;background-color:#f9e9eb;border-color:#e0b4b4}&.warning{color:#573a08;background-color:#fff8e1;border-color:#f9e79f}&.info{color:#2c7fba;background-color:#f0f9fb;border-color:#b3d7f9}&.dark{color:#2c2c2c;background-color:#f0f0f0;border-color:#b3b3b3}& a[alert-close]{cursor:pointer;color:inherit;font-size:2rem;text-decoration:none}}a{color:#4c0515;text-decoration:none;transition:color .2s;&:hover{color:#6c0515;text-decoration:underline}}body::-webkit-scrollbar{width:.5rem}body::-webkit-scrollbar-track{background:#0000001a}body::-webkit-scrollbar-thumb{background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}#canvas-container{&>canvas{image-rendering:pixelated;image-rendering:crisp-edges;image-rendering:-webkit-optimize-contrast;width:100%;height:440px;display:block}}.char-icon{background-image:url(/assets/img/world/rogues.png);width:32px;height:32px;&.index-0{background-position:0 0}&.index-1{background-position:-32px 0}&.index-2{background-position:-64px 0}&.index-3{background-position:-96px 0}&.index-4{background-position:-128px 0}} \ No newline at end of file +:root{--main-font:Cambria,Cochin,Georgia,Times,"Times New Roman",serif;font-size:16px}*{box-sizing:border-box;margin:0;padding:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.container-960{width:960px;margin:0 auto}.ui.button{cursor:pointer;font-size:1rem;font-family:var(--main-font);color:#111;text-align:center;user-select:none;-webkit-tap-highlight-color:transparent;background:#f7f8fa linear-gradient(#fff0,#0000001a);border:none;border-radius:3px;padding:.5rem 1rem;text-decoration:none;transition:opacity .1s,background-color .1s,color .1s,background .1s;display:inline-block;box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb;&:hover{color:#000c;background-color:#e0e0e0;background-image:linear-gradient(#fff0,#0000001a);box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb}&.badge{padding:.1rem .25rem;font-size:10px}&.primary{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3;&:hover{background-color:#fac847;border-color:#c59f43 #aa8326 #957321}}&.secondary{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&:hover{background-color:#4e5964;border-color:#32373e #24282d #212429}}&.danger{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3;&:hover{background-color:#d95c5c;border-color:#b71c1c #a52727 #8e1f1f}}}.form.control{appearance:none;color:#fff;background-color:#0003;border:1px solid #0000;border-radius:4px;outline:none;width:100%;padding:.5rem;font-size:1rem;display:block;box-shadow:inset 0 1px 4px #0000001a;&::placeholder{color:#ffffffb3}&:hover{background-color:#0000004d}&:focus{background-color:#00000080;border-color:#000c}&.error{background-color:#ff2b2b33;&:hover{background-color:#ff2b2b4d}&:focus{background-color:#ff2b2b4d;border-color:#ff2b2bcc}}}.form.group{margin-bottom:1rem;&>label{margin-bottom:.5rem;display:block}&>.form.control:not(:last-child){margin-bottom:.5rem}}.character-select>.radio-block{background-color:#0003;border-radius:.15rem;display:inline-block;&:not(:last-child){margin-bottom:.25rem}&>input[type=radio]{display:none}&>label{cursor:pointer;background-image:linear-gradient(#fff0,#0000);border:1px solid #0000;border-radius:.15rem;align-items:center;width:100%;padding:.5rem;transition:color,background-color,border-color,background-image .2s;display:flex;&:hover{color:#fff;background-color:#0000004d}&>.badge{margin-left:.25rem}&>span.selected{display:none}&>.char-icon{margin-right:.25rem}}&.active>label{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&>span.selected{display:inline-block}}&>input[type=radio]:checked+label{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}&>input[type=radio]:disabled+label{cursor:default}}.character-select:not(:has(input[type=radio]:checked))>.buttons{display:none}section.profile{& header{text-align:center;margin-bottom:2rem;& h3{color:#0000004d;text-transform:uppercase;font-size:1rem}}& div.grid{gap:1rem;display:flex;&>section{width:50%;&>div:not(:last-child){margin-bottom:1rem}}}& div.avatar{justify-content:center;align-items:center;display:flex;& img{max-width:250px}}& h4{text-align:center;text-transform:uppercase;color:#0000004d}& div.stats{&>div{color:#fff;background-color:#0000004d;border-radius:.15rem;padding:.25rem}}}body{font-family:var(--main-font);background-color:#bcc6cf;background-image:url(/assets/img/bg.jpg);background-position:top;background-repeat:no-repeat;background-attachment:fixed;max-width:1640px;margin:0 auto}header#main-header{color:#fff;background-image:url(/assets/img/header.jpg);justify-content:space-between;align-items:center;height:76px;padding:0 1rem;display:flex;& h1{margin:0;padding:0}& .right{align-items:center;display:flex;& p{margin-right:1rem}}}main{gap:2rem;width:100%;padding:1rem;display:flex;& #center{flex:1}}aside{min-width:200px;& .box{background-color:#0003;border-radius:.15rem;padding:.5rem}}aside#left nav{&>:not(:last-child){margin-bottom:.25rem}& div.stack{background-color:#0003;border-radius:.15rem;& input[type=checkbox]{display:none;&:checked~div.list{display:block}&:checked+label{color:#fff;background-color:#00000080}}& label{color:#000;cursor:pointer;border-radius:.15rem;align-items:center;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:flex;& img{height:18px;margin-right:.25rem}& span.text{width:100%;display:block}&:hover{color:#fff;background-color:#0000004d}& span.arrow{position:relative;top:5px}}& div.list{display:none;&>a{color:#000;border-radius:.15rem;width:100%;padding:.5rem 1rem .5rem 1.35rem;text-decoration:none;transition:color,background-color .2s;display:block;&:not(:last-child):before{content:"├";margin-right:.25rem;display:inline-block}&:last-child:before{content:"└";margin-right:.25rem;display:inline-block;position:relative;top:3px}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}}&>a{color:#000;background-color:#0003;border-radius:.15rem;width:100%;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:block;&:has(img){align-items:center;display:flex;& img{height:18px;margin-right:.25rem}}&:hover,&.active{color:#fff}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}footer{text-align:center;color:#666;justify-content:center;align-items:center;margin:1rem 0;padding:1rem;display:flex;&>p:not(:last-child){margin-right:2rem}}#char-bar{color:#fff;background-image:url(/assets/img/bar.jpg);justify-content:space-around;align-items:center;gap:1rem;height:34px;padding:0 1rem;display:flex;&>div.container{align-items:center;gap:1rem;display:flex;&>div{align-items:center;display:flex;& .icon{width:18px;margin-right:.5rem}}}}span.badge{color:#111;background-color:#f7f8fa;border-radius:.25rem;padding:.1rem .25rem;font-size:10px;box-shadow:inset 0 0 0 1px #0000001a;&.dark{color:#fff;background-color:#444c55}&.green{background-color:#a6e3a1}}.char-meter{background-color:#000;border-radius:.1rem;min-width:100px;height:16px;position:relative;&>div{border-radius:.1rem;height:100%;overflow:hidden;&.hp{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3}&.mp{background-color:#5a9bd4;background-image:linear-gradient(#ffffff26,#3c64961a);border:1px solid #3a7a9c;border-color:#4a8ab0 #3a7a9c #2a6a88;box-shadow:inset 0 1px #fff3}&.tp{background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}}}.tooltip{color:#fff;text-align:center;background-color:#000;border:1px solid #666;border-radius:.1rem;padding:.5rem;font-size:14px;box-shadow:0 0 .5rem .1rem #0003}.tooltip-trigger{width:100%;height:100%;position:absolute;top:0;left:0}.debug-query-log{color:#666;padding:2rem;font-family:monospace;font-size:14px}#center>section{&:not(:last-child){border-bottom:1px solid #0000001a;margin-bottom:1rem;padding-bottom:1rem}}h1:has(.badge),h2:has(.badge),h3:has(.badge),h4:has(.badge),h5:has(.badge),h6:has(.badge){align-items:center;display:flex;&>.badge{margin-left:.5rem}}.alert{color:#000000de;background:#f8f8f9;border-radius:.285714rem;justify-content:space-between;align-items:center;min-height:1rem;margin:1rem 0;padding:.5rem 1rem;line-height:1.4285rem;transition:opacity .1s,color .1s,background .1s,box-shadow .1s;display:flex;position:relative;box-shadow:inset 0 0 0 1px #22242638,0 0 #0000;&.success{color:#2c662d;background-color:#f0f9eb;border-color:#b3dc9d}&.danger{color:#9f3a38;background-color:#f9e9eb;border-color:#e0b4b4}&.warning{color:#573a08;background-color:#fff8e1;border-color:#f9e79f}&.info{color:#2c7fba;background-color:#f0f9fb;border-color:#b3d7f9}&.dark{color:#2c2c2c;background-color:#f0f0f0;border-color:#b3b3b3}& a[alert-close]{cursor:pointer;color:inherit;font-size:2rem;text-decoration:none}}a{color:#4c0515;text-decoration:none;transition:color .2s;&:hover{color:#6c0515;text-decoration:underline}}body::-webkit-scrollbar{width:.5rem}body::-webkit-scrollbar-track{background:#0000001a}body::-webkit-scrollbar-thumb{background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}#canvas-container{&>canvas{image-rendering:pixelated;image-rendering:crisp-edges;image-rendering:-webkit-optimize-contrast;width:100%;height:440px;display:block}}.char-icon{background-image:url(/assets/img/world/rogues.png);width:32px;height:32px;&.index-0{background-position:0 0}&.index-1{background-position:-32px 0}&.index-2{background-position:-64px 0}&.index-3{background-position:-96px 0}&.index-4{background-position:-128px 0}} \ No newline at end of file diff --git a/public/assets/css/src/buttons.css b/public/assets/css/src/buttons.css index deaf8df..f5e1d34 100644 --- a/public/assets/css/src/buttons.css +++ b/public/assets/css/src/buttons.css @@ -3,6 +3,7 @@ display: inline-block; border: none; font-size: 1rem; + font-family: var(--main-font); background: #f7f8fa linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1)); box-shadow: 0 1px 0 1px rgba(255, 255, 255, 0.3) inset, 0 0 0 1px #adb2bb inset; color: #111111; diff --git a/public/assets/css/src/main.css b/public/assets/css/src/main.css index b7635f9..cd39e30 100644 --- a/public/assets/css/src/main.css +++ b/public/assets/css/src/main.css @@ -1,6 +1,7 @@ @import 'utilities.css'; @import 'buttons.css'; @import 'forms.css'; +@import 'profile.css'; body { background-color: #bcc6cf; @@ -10,10 +11,10 @@ body { background-repeat: no-repeat; max-width: 1640px; margin: 0px auto; - font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; + font-family: var(--main-font); } -header { +header#main-header { height: 76px; color: white; display: flex; @@ -315,7 +316,7 @@ span.badge { font-family: monospace; } -#center section { +#center > section { &:not(:last-child) { padding-bottom: 1rem; border-bottom: 1px solid rgba(0, 0, 0, 0.1); diff --git a/public/assets/css/src/profile.css b/public/assets/css/src/profile.css new file mode 100644 index 0000000..8f313e2 --- /dev/null +++ b/public/assets/css/src/profile.css @@ -0,0 +1,49 @@ +section.profile { + header { + text-align: center; + margin-bottom: 2rem; + + h3 { + color: rgba(0, 0, 0, 0.3); + text-transform: uppercase; + font-size: 1rem; + } + } + + div.grid { + display: flex; + gap: 1rem; + + & > section { + width: 50%; + + & > div:not(:last-child) { + margin-bottom: 1rem; + } + } + } + + div.avatar { + display: flex; + align-items: center; + justify-content: center; + img { + max-width: 250px; + } + } + + h4 { + text-align: center; + text-transform: uppercase; + color: rgba(0, 0, 0, 0.3); + } + + div.stats { + & > div { + color: white; + background-color: rgba(0, 0, 0, 0.3); + border-radius: 0.15rem; + padding: 0.25rem; + } + } +} diff --git a/public/assets/css/src/utilities.css b/public/assets/css/src/utilities.css index 504cdf0..653019f 100644 --- a/public/assets/css/src/utilities.css +++ b/public/assets/css/src/utilities.css @@ -1,5 +1,6 @@ :root { font-size: 16px; + --main-font: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; } * { diff --git a/public/assets/img/rathalos.webp b/public/assets/img/rathalos.webp new file mode 100644 index 0000000..f4cb602 Binary files /dev/null and b/public/assets/img/rathalos.webp differ diff --git a/public/index.php b/public/index.php index be80561..24b9007 100644 --- a/public/index.php +++ b/public/index.php @@ -41,6 +41,12 @@ router_post($r, '/character/delete', 'char_controller_delete_post'); router_get($r, '/world', 'world_controller_get'); router_post($r, '/move', 'world_controller_move_post'); +/* + Profile +*/ +router_get($r, '/profile', 'profile_controller_get'); +router_get($r, '/profile/:id', 'profile_controller_show_get'); + /* Settings */ diff --git a/src/bootstrap.php b/src/bootstrap.php index c38e013..a829c0a 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -25,6 +25,7 @@ require_once SRC . '/controller/auth.php'; require_once SRC . '/controller/world.php'; require_once SRC . '/controller/settings.php'; require_once SRC . '/controller/auctions.php'; +require_once SRC . '/controller/profile.php'; // Track the start time of the request define('START_TIME', microtime(true)); diff --git a/src/controller/char.php b/src/controller/char.php index a957cdf..f34bb6b 100644 --- a/src/controller/char.php +++ b/src/controller/char.php @@ -164,6 +164,9 @@ function char_controller_create_post() char_location_create($char); char_gear_create($char); + // Award the Adventurer title. + char_award_title(1, $char); + // Set the character as the user's selected character change_user_character($char); diff --git a/src/controller/profile.php b/src/controller/profile.php new file mode 100644 index 0000000..ea5d48e --- /dev/null +++ b/src/controller/profile.php @@ -0,0 +1,24 @@ + $char]); +} diff --git a/src/helpers.php b/src/helpers.php index d606cf8..ee2ba9d 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -279,3 +279,11 @@ function json_response($data) echo json_encode($data); exit; } + +/** + * Return a title's [name, lore]. + */ +function title($title_id) +{ + return db_query(db_live(), 'SELECT * FROM titles WHERE id = :i', [':i' => $title_id])->fetchArray(); +} diff --git a/src/model/char.php b/src/model/char.php index 34496bc..a815096 100644 --- a/src/model/char.php +++ b/src/model/char.php @@ -73,11 +73,11 @@ function char_gear_create($char_id, $initialGear = []) } /** - * Get a charcter by their ID. Returns the character's data as an associative array, or false if not found. + * Get a charcter by their ID or name. Returns the character's data as an associative array, or false if not found. */ function char_find($char_id) { - $char = db_query(db_live(), "SELECT * FROM characters WHERE id = :id", [':id' => $char_id])->fetchArray(SQLITE3_ASSOC); + $char = db_query(db_live(), "SELECT * FROM characters WHERE id = :id OR name = :id", [':id' => $char_id])->fetchArray(SQLITE3_ASSOC); return $char === false ? false : $char; } @@ -235,3 +235,43 @@ function char_delete($char_id) } } } + +/** + * Award a character a title. + */ +function char_award_title($title_id, $char_id) +{ + $r = db_query( + db_live(), + 'INSERT INTO owned_titles (`title_id`, `char_id`) VALUES (:t, :c)', + [':t' => $title_id, ':c' => $char_id] + ); + if ($r === false) throw new Exception("Failed to award $char_id the title $title_id. (cat)"); +} + +/** + * Get the character's title's info and award date. Will use the currently logged in character's ID if $char_id is 0. + */ +function char_get_title($char_id = 0) +{ + $char = $char_id === 0 ? char() : char_find($char_id); + $title = title($char['title_id']); + + $stmt = db_query( + db_live(), + 'SELECT awarded FROM owned_titles WHERE char_id = :c AND title_id = :t LIMIT 1', + [':c' => $char['id'], ':t' => $char['title_id']] + ); + + // If the query failed, send back an array with only an error. + if ($stmt === false) return ['error' => "owned titles query failed {$char['id']} (cat) (1)"]; + + $award = $stmt->fetchArray(SQLITE3_ASSOC); + + // If no title, send back an empty array + if (!$award) return []; + + $title['awarded'] = $award['awarded']; + return $title; +} + diff --git a/templates/components/char_bar.php b/templates/components/char_bar.php index 2ec5199..a883717 100644 --- a/templates/components/char_bar.php +++ b/templates/components/char_bar.php @@ -3,29 +3,29 @@
User - 0): ?> - + 0): ?> +
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/templates/layouts/basic.php b/templates/layouts/basic.php index d8fac0f..9de68e5 100644 --- a/templates/layouts/basic.php +++ b/templates/layouts/basic.php @@ -8,7 +8,7 @@ -
+

Dragon Knight

diff --git a/templates/pages/profile/main.php b/templates/pages/profile/main.php new file mode 100644 index 0000000..680f9d6 --- /dev/null +++ b/templates/pages/profile/main.php @@ -0,0 +1,25 @@ +
+
+

+

Level

+
+ +
+
+
+ +
+ +
+

Stats

+
Power:
+
+
+ +
+
+ HELLO THERE MY FRIEND. +
+
+
+
diff --git a/templates/pages/profile/show.php b/templates/pages/profile/show.php new file mode 100644 index 0000000..0459442 --- /dev/null +++ b/templates/pages/profile/show.php @@ -0,0 +1,2 @@ +

Owned

+other