From c9ff054426d0fde0443c9c043b2dd144bd99864b Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Wed, 16 Oct 2024 20:55:47 -0700 Subject: [PATCH] lots of db and css work, profiles --- database/create/auth.sql | 28 ++ database/create/blueprints.sql | 56 +++ database/create/fights.sql | 103 +++++ database/create/live.sql | 329 ++++++++++++++ database/live.db-shm | Bin 0 -> 32768 bytes database/live.db-wal | Bin 0 -> 61832 bytes database/manage.sh | 77 ++++ database/populate/live.sql | 1 + database/scripts/create.php | 666 ---------------------------- public/assets/css/dragon.css | 2 +- public/assets/css/src/buttons.css | 1 + public/assets/css/src/main.css | 7 +- public/assets/css/src/profile.css | 49 ++ public/assets/css/src/utilities.css | 1 + public/assets/img/rathalos.webp | Bin 0 -> 68632 bytes public/index.php | 6 + src/bootstrap.php | 1 + src/controller/char.php | 3 + src/controller/profile.php | 24 + src/helpers.php | 8 + src/model/char.php | 44 +- templates/components/char_bar.php | 16 +- templates/layouts/basic.php | 2 +- templates/pages/profile/main.php | 25 ++ templates/pages/profile/show.php | 2 + 25 files changed, 770 insertions(+), 681 deletions(-) create mode 100644 database/create/auth.sql create mode 100644 database/create/blueprints.sql create mode 100644 database/create/fights.sql create mode 100644 database/create/live.sql create mode 100644 database/live.db-shm create mode 100644 database/live.db-wal create mode 100755 database/manage.sh create mode 100644 database/populate/live.sql delete mode 100644 database/scripts/create.php create mode 100644 public/assets/css/src/profile.css create mode 100644 public/assets/img/rathalos.webp create mode 100644 src/controller/profile.php create mode 100644 templates/pages/profile/main.php create mode 100644 templates/pages/profile/show.php 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 0000000000000000000000000000000000000000..c35ed504979207f8da5289d30a4a227524df7192 GIT binary patch literal 32768 zcmeI)OG*Pl5C-6m@%8x`gk(>x_Q65eVLv;Je}Xajy`7NKkkoK zi)7#LrF5Tvm#cWn|K>T?yLCI(ov4ebJmqE7Zq#1X^8R=g0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0=)|4EDRw~Qy{0n2!WacIrB&e{HH+9*b)K+R$E}u4p#esPDh|OfwgwnTW^hP z3Jlvu%W0%Spq{{Hy(_yhfleT&OACRT0y#Hb2-FnVuX$~^CP07y0RjXF5FkK+009C7 W2oNAZfB*pk1PBlyK!5;&5&}O#l_(|v literal 0 HcmV?d00001 diff --git a/database/live.db-wal b/database/live.db-wal new file mode 100644 index 0000000000000000000000000000000000000000..9231e6189502b7e35c1f83596d100837ecfdd9b9 GIT binary patch literal 61832 zcmeI)&r6g+9LMozo_*A3Hft(3){M%EF5<@Ss%Q%e6?LdX(xJM9ls_sAELReVP=fw| zEt^y3ng9SSTdE9@Yc2NSbHGd=BtVo;C=_u2Qb&$BQNyU+Kvp1yo$ zs=M0zDO>f$+fH+ku00IagfB*sr zAb zz_dPhP)+Bg6h$L|00IagfB*srAbh?W oR=dQKQ7K(vhJN>laO>MTo7 -*/ - -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 0000000000000000000000000000000000000000..f4cb6022acbf3b9ecf7667fb73d37f61a0789967 GIT binary patch literal 68632 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�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 W;~6^Q3d7v5tB6~|+2$dmngjr`8|*{? literal 0 HcmV?d00001 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