make players into characters, allow character selection
This commit is contained in:
parent
b063740547
commit
043a57cf86
2
.env
2
.env
|
@ -6,4 +6,4 @@ silver_modifier = 1
|
||||||
allow_pvp = true
|
allow_pvp = true
|
||||||
allow_registration = true
|
allow_registration = true
|
||||||
start_silver = 100
|
start_silver = 100
|
||||||
sp_per_level = 5
|
atts_per_level = 5
|
||||||
|
|
BIN
database/auth.db
BIN
database/auth.db
Binary file not shown.
BIN
database/live.db
BIN
database/live.db
Binary file not shown.
|
@ -56,36 +56,38 @@ if ($database === AUTH) {
|
||||||
|
|
||||||
// Users table
|
// Users table
|
||||||
$db->exec('DROP TABLE IF EXISTS users');
|
$db->exec('DROP TABLE IF EXISTS users');
|
||||||
$db->exec('CREATE TABLE users (
|
$r = $db->exec('CREATE TABLE users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
username TEXT NOT NULL UNIQUE,
|
||||||
email TEXT NOT NULL UNIQUE,
|
email TEXT NOT NULL UNIQUE,
|
||||||
password TEXT NOT NULL,
|
password TEXT NOT NULL,
|
||||||
auth INT NOT NULL DEFAULT 0,
|
auth INT NOT NULL DEFAULT 0,
|
||||||
|
char_id INTEGER NOT NULL DEFAULT 0,
|
||||||
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
last_login DATETIME DEFAULT CURRENT_TIMESTAMP
|
last_login DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'users');
|
created_or_error($r, 'users');
|
||||||
|
|
||||||
// Sessions table
|
// Sessions table
|
||||||
$db->exec('DROP TABLE IF EXISTS sessions');
|
$db->exec('DROP TABLE IF EXISTS sessions');
|
||||||
$db->exec('CREATE TABLE sessions (
|
$r = $db->exec('CREATE TABLE sessions (
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
token TEXT NOT NULL UNIQUE,
|
token TEXT NOT NULL UNIQUE,
|
||||||
expires INTEGER NOT NULL
|
expires INTEGER NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'sessions');
|
created_or_error($r, 'sessions');
|
||||||
|
|
||||||
// Verification tokens
|
// Verification tokens
|
||||||
$db->exec('DROP TABLE IF EXISTS tokens');
|
$db->exec('DROP TABLE IF EXISTS tokens');
|
||||||
$db->exec('CREATE TABLE tokens (
|
$r = $db->exec('CREATE TABLE tokens (
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
token TEXT NOT NULL UNIQUE,
|
token TEXT NOT NULL UNIQUE,
|
||||||
created INTEGER NOT NULL
|
created INTEGER NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'tokens');
|
created_or_error($r, 'tokens');
|
||||||
|
|
||||||
eln(green('Created database: ') . 'auth.db');
|
eln(green('Created database: ') . 'auth.db');
|
||||||
|
|
||||||
|
@ -105,20 +107,23 @@ if ($database === FIGHTS) {
|
||||||
|
|
||||||
// PvE fights
|
// PvE fights
|
||||||
$db->exec('DROP TABLE IF EXISTS pve');
|
$db->exec('DROP TABLE IF EXISTS pve');
|
||||||
$db->exec('CREATE TABLE pve (
|
$r = $db->exec('CREATE TABLE pve (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
player_hp INTEGER NOT NULL,
|
char_hp INTEGER NOT NULL,
|
||||||
player_max_hp INTEGER NOT NULL,
|
char_max_hp INTEGER NOT NULL,
|
||||||
player_mp INTEGER NOT NULL,
|
char_mp INTEGER NOT NULL,
|
||||||
player_max_mp INTEGER NOT NULL,
|
char_max_mp INTEGER NOT NULL,
|
||||||
player_power INTEGER NOT NULL,
|
char_power INTEGER NOT NULL,
|
||||||
player_toughness INTEGER NOT NULL,
|
char_accuracy INTEGER NOT NULL,
|
||||||
player_armor INTEGER NOT NULL,
|
char_penetration INTEGER NOT NULL DEFAULT 0,
|
||||||
player_precision INTEGER NOT NULL,
|
char_focus INTEGER NOT NULL DEFAULT 0,
|
||||||
player_crit INTEGER NOT NULL,
|
char_toughness INTEGER NOT NULL,
|
||||||
player_ferocity INTEGER NOT NULL,
|
char_armor INTEGER NOT NULL,
|
||||||
player_vitality 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_id INTEGER NOT NULL,
|
||||||
mob_level INTEGER NOT NULL,
|
mob_level INTEGER NOT NULL,
|
||||||
mob_rank INTEGER NOT NULL,
|
mob_rank INTEGER NOT NULL,
|
||||||
|
@ -130,6 +135,8 @@ if ($database === FIGHTS) {
|
||||||
mob_toughness INTEGER NOT NULL,
|
mob_toughness INTEGER NOT NULL,
|
||||||
mob_armor INTEGER NOT NULL,
|
mob_armor INTEGER NOT NULL,
|
||||||
mob_precision 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_crit INTEGER NOT NULL,
|
||||||
mob_ferocity INTEGER NOT NULL,
|
mob_ferocity INTEGER NOT NULL,
|
||||||
mob_vitality INTEGER NOT NULL,
|
mob_vitality INTEGER NOT NULL,
|
||||||
|
@ -142,36 +149,42 @@ if ($database === FIGHTS) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'pve');
|
created_or_error($r, 'pve');
|
||||||
|
|
||||||
// PvP fights
|
// PvP fights
|
||||||
$db->exec('DROP TABLE IF EXISTS pvp');
|
$db->exec('DROP TABLE IF EXISTS pvp');
|
||||||
$db->exec('CREATE TABLE pvp (
|
$r = $db->exec('CREATE TABLE pvp (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
player1_id INTEGER NOT NULL,
|
char1_id INTEGER NOT NULL,
|
||||||
player1_hp INTEGER NOT NULL,
|
char1_hp INTEGER NOT NULL,
|
||||||
player1_max_hp INTEGER NOT NULL,
|
char1_max_hp INTEGER NOT NULL,
|
||||||
player1_mp INTEGER NOT NULL,
|
char1_mp INTEGER NOT NULL,
|
||||||
player1_max_mp INTEGER NOT NULL,
|
char1_max_mp INTEGER NOT NULL,
|
||||||
player1_power INTEGER NOT NULL,
|
char1_power INTEGER NOT NULL,
|
||||||
player1_toughness INTEGER NOT NULL,
|
char1_accuracy INTEGER NOT NULL,
|
||||||
player1_armor INTEGER NOT NULL,
|
char1_penetration INTEGER NOT NULL DEFAULT 0,
|
||||||
player1_precision INTEGER NOT NULL,
|
char1_focus INTEGER NOT NULL DEFAULT 0,
|
||||||
player1_crit INTEGER NOT NULL,
|
char1_toughness INTEGER NOT NULL,
|
||||||
player1_ferocity INTEGER NOT NULL,
|
char1_armor INTEGER NOT NULL,
|
||||||
player1_vitality INTEGER NOT NULL,
|
char1_resist INTEGER NOT NULL,
|
||||||
player2_id INTEGER NOT NULL,
|
char1_crit INTEGER NOT NULL,
|
||||||
player2_hp INTEGER NOT NULL,
|
char1_precision INTEGER NOT NULL,
|
||||||
player2_max_hp INTEGER NOT NULL,
|
char1_ferocity INTEGER NOT NULL,
|
||||||
player2_mp INTEGER NOT NULL,
|
char2_id INTEGER NOT NULL,
|
||||||
player2_max_mp INTEGER NOT NULL,
|
char2_hp INTEGER NOT NULL,
|
||||||
player2_power INTEGER NOT NULL,
|
char2_max_hp INTEGER NOT NULL,
|
||||||
player2_toughness INTEGER NOT NULL,
|
char2_mp INTEGER NOT NULL,
|
||||||
player2_armor INTEGER NOT NULL,
|
char2_max_mp INTEGER NOT NULL,
|
||||||
player2_precision INTEGER NOT NULL,
|
char2_power INTEGER NOT NULL,
|
||||||
player2_crit INTEGER NOT NULL,
|
char2_accuracy INTEGER NOT NULL,
|
||||||
player2_ferocity INTEGER NOT NULL,
|
char2_penetration INTEGER NOT NULL DEFAULT 0,
|
||||||
player2_vitality INTEGER NOT NULL,
|
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,
|
first_turn INTEGER NOT NULL,
|
||||||
turn INTEGER NOT NULL default 1,
|
turn INTEGER NOT NULL default 1,
|
||||||
winner INTEGER NOT NULL default 0,
|
winner INTEGER NOT NULL default 0,
|
||||||
|
@ -179,27 +192,27 @@ if ($database === FIGHTS) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'pvp');
|
created_or_error($r, 'pvp');
|
||||||
|
|
||||||
// PvE fight logs
|
// PvE fight logs
|
||||||
$db->exec('DROP TABLE IF EXISTS pve_logs');
|
$db->exec('DROP TABLE IF EXISTS pve_logs');
|
||||||
$db->exec('CREATE TABLE pve_logs (
|
$r = $db->exec('CREATE TABLE pve_logs (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
fight_id INTEGER NOT NULL,
|
fight_id INTEGER NOT NULL,
|
||||||
info TEXT NOT NULL
|
info TEXT NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'pve_logs');
|
created_or_error($r, 'pve_logs');
|
||||||
|
|
||||||
// PvP fight logs
|
// PvP fight logs
|
||||||
$db->exec('DROP TABLE IF EXISTS pvp_logs');
|
$db->exec('DROP TABLE IF EXISTS pvp_logs');
|
||||||
$db->exec('CREATE TABLE pvp_logs (
|
$r = $db->exec('CREATE TABLE pvp_logs (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
fight_id INTEGER NOT NULL,
|
fight_id INTEGER NOT NULL,
|
||||||
info TEXT NOT NULL
|
info TEXT NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'pvp_logs');
|
created_or_error($r, 'pvp_logs');
|
||||||
|
|
||||||
eln(green('Created database: ') . 'fights.db');
|
eln(green('Created database: ') . 'fights.db');
|
||||||
|
|
||||||
|
@ -219,7 +232,7 @@ if ($database === BPS) {
|
||||||
|
|
||||||
// Items
|
// Items
|
||||||
$db->exec('DROP TABLE IF EXISTS items');
|
$db->exec('DROP TABLE IF EXISTS items');
|
||||||
$db->exec('CREATE TABLE items (
|
$r = $db->exec('CREATE TABLE items (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type INTEGER NOT NULL DEFAULT 0,
|
type INTEGER NOT NULL DEFAULT 0,
|
||||||
|
@ -231,12 +244,16 @@ if ($database === BPS) {
|
||||||
duration INTEGER NOT NULL DEFAULT 0,
|
duration INTEGER NOT NULL DEFAULT 0,
|
||||||
durability INTEGER NOT NULL DEFAULT 0,
|
durability INTEGER NOT NULL DEFAULT 0,
|
||||||
power 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,
|
toughness INTEGER NOT NULL DEFAULT 0,
|
||||||
armor INTEGER NOT NULL DEFAULT 0,
|
armor INTEGER NOT NULL DEFAULT 0,
|
||||||
precision INTEGER NOT NULL DEFAULT 0,
|
resist INTEGER NOT NULL DEFAULT 0,
|
||||||
crit INTEGER NOT NULL DEFAULT 0,
|
crit INTEGER NOT NULL DEFAULT 0,
|
||||||
|
precision INTEGER NOT NULL DEFAULT 0,
|
||||||
ferocity INTEGER NOT NULL DEFAULT 0,
|
ferocity INTEGER NOT NULL DEFAULT 0,
|
||||||
vitality INTEGER NOT NULL DEFAULT 0,
|
luck INTEGER NOT NULL DEFAULT 0,
|
||||||
reqs TEXT NOT NULL DEFAULT "",
|
reqs TEXT NOT NULL DEFAULT "",
|
||||||
traits TEXT NOT NULL DEFAULT "",
|
traits TEXT NOT NULL DEFAULT "",
|
||||||
lore TEXT NOT NULL DEFAULT "",
|
lore TEXT NOT NULL DEFAULT "",
|
||||||
|
@ -244,11 +261,11 @@ if ($database === BPS) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'items');
|
created_or_error($r, 'items');
|
||||||
|
|
||||||
// Mobs
|
// Mobs
|
||||||
$db->exec('DROP TABLE IF EXISTS mobs');
|
$db->exec('DROP TABLE IF EXISTS mobs');
|
||||||
$db->exec('CREATE TABLE mobs (
|
$r = $db->exec('CREATE TABLE mobs (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type INTEGER NOT NULL,
|
type INTEGER NOT NULL,
|
||||||
|
@ -273,7 +290,7 @@ if ($database === BPS) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'mobs');
|
created_or_error($r, 'mobs');
|
||||||
|
|
||||||
eln(green('Created database: ') . 'blueprints.db');
|
eln(green('Created database: ') . 'blueprints.db');
|
||||||
|
|
||||||
|
@ -291,13 +308,13 @@ if ($database === LIVE) {
|
||||||
|
|
||||||
$db = new SQLite3(__DIR__ . '/../' . LIVE);
|
$db = new SQLite3(__DIR__ . '/../' . LIVE);
|
||||||
|
|
||||||
// Players
|
// Characters
|
||||||
$db->exec('DROP TABLE IF EXISTS players');
|
$db->exec('DROP TABLE IF EXISTS characters');
|
||||||
$db->exec('CREATE TABLE players (
|
$r = $db->exec('CREATE TABLE characters (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL UNIQUE,
|
name TEXT NOT NULL UNIQUE,
|
||||||
title_id INTEGER NOT NULL DEFAULT,
|
title_id INTEGER NOT NULL DEFAULT 0,
|
||||||
level INTEGER NOT NULL DEFAULT 1,
|
level INTEGER NOT NULL DEFAULT 1,
|
||||||
xp INTEGER NOT NULL DEFAULT 0,
|
xp INTEGER NOT NULL DEFAULT 0,
|
||||||
xp_to_level INTEGER NOT NULL DEFAULT 100,
|
xp_to_level INTEGER NOT NULL DEFAULT 100,
|
||||||
|
@ -308,21 +325,25 @@ if ($database === LIVE) {
|
||||||
current_tp INTEGER NOT NULL DEFAULT 0,
|
current_tp INTEGER NOT NULL DEFAULT 0,
|
||||||
max_tp INTEGER NOT NULL DEFAULT 0,
|
max_tp INTEGER NOT NULL DEFAULT 0,
|
||||||
power 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,
|
toughness INTEGER NOT NULL DEFAULT 0,
|
||||||
armor INTEGER NOT NULL DEFAULT 0,
|
armor INTEGER NOT NULL DEFAULT 0,
|
||||||
|
resist INTEGER NOT NULL DEFAULT 0,
|
||||||
precision INTEGER NOT NULL DEFAULT 0,
|
precision INTEGER NOT NULL DEFAULT 0,
|
||||||
crit INTEGER NOT NULL DEFAULT 0,
|
|
||||||
ferocity INTEGER NOT NULL DEFAULT 0,
|
ferocity INTEGER NOT NULL DEFAULT 0,
|
||||||
vitality INTEGER NOT NULL DEFAULT 0,
|
luck INTEGER NOT NULL DEFAULT 0,
|
||||||
inv_slots INTEGER NOT NULL DEFAULT 10
|
inv_slots INTEGER NOT NULL DEFAULT 10,
|
||||||
|
attrib_points INTEGER NOT NULL DEFAULT 0
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'players');
|
created_or_error($r, 'characters');
|
||||||
|
|
||||||
// Player gear
|
// Player gear
|
||||||
$db->exec('DROP TABLE IF EXISTS player_gear');
|
$db->exec('DROP TABLE IF EXISTS char_gear');
|
||||||
$db->exec('CREATE TABLE player_gear (
|
$r = $db->exec('CREATE TABLE char_gear (
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
head INTEGER NOT NULL DEFAULT 0,
|
head INTEGER NOT NULL DEFAULT 0,
|
||||||
chest INTEGER NOT NULL DEFAULT 0,
|
chest INTEGER NOT NULL DEFAULT 0,
|
||||||
boots INTEGER NOT NULL DEFAULT 0,
|
boots INTEGER NOT NULL DEFAULT 0,
|
||||||
|
@ -333,62 +354,66 @@ if ($database === LIVE) {
|
||||||
ring INTEGER NOT NULL DEFAULT 0,
|
ring INTEGER NOT NULL DEFAULT 0,
|
||||||
amulet INTEGER NOT NULL DEFAULT 0,
|
amulet INTEGER NOT NULL DEFAULT 0,
|
||||||
power 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,
|
toughness INTEGER NOT NULL DEFAULT 0,
|
||||||
armor INTEGER NOT NULL DEFAULT 0,
|
armor INTEGER NOT NULL DEFAULT 0,
|
||||||
precision INTEGER NOT NULL DEFAULT 0,
|
resist INTEGER NOT NULL DEFAULT 0,
|
||||||
crit INTEGER NOT NULL DEFAULT 0,
|
crit INTEGER NOT NULL DEFAULT 0,
|
||||||
|
precision INTEGER NOT NULL DEFAULT 0,
|
||||||
ferocity INTEGER NOT NULL DEFAULT 0,
|
ferocity INTEGER NOT NULL DEFAULT 0,
|
||||||
vitality INTEGER NOT NULL DEFAULT 0,
|
luck INTEGER NOT NULL DEFAULT 0,
|
||||||
max_hp INTEGER NOT NULL DEFAULT 0,
|
max_hp INTEGER NOT NULL DEFAULT 0,
|
||||||
max_mp INTEGER NOT NULL DEFAULT 0,
|
max_mp INTEGER NOT NULL DEFAULT 0
|
||||||
traits TEXT NOT NULL DEFAULT ""
|
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'player_gear');
|
created_or_error($r, 'char_gear');
|
||||||
|
|
||||||
// Player inventory
|
// Player inventory
|
||||||
$db->exec('DROP TABLE IF EXISTS player_inventory');
|
$db->exec('DROP TABLE IF EXISTS char_inventory');
|
||||||
$db->exec('CREATE TABLE inventory (
|
$r = $db->exec('CREATE TABLE inventory (
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
item_id INTEGER NOT NULL
|
item_id INTEGER NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'inventory');
|
created_or_error($r, 'inventory');
|
||||||
|
|
||||||
// Player wallet
|
// Player wallet
|
||||||
$db->exec('DROP TABLE IF EXISTS player_wallet');
|
$db->exec('DROP TABLE IF EXISTS char_wallets');
|
||||||
$db->exec('CREATE TABLE wallet (
|
$r = $db->exec('CREATE TABLE char_wallets (
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
silver INTEGER NOT NULL DEFAULT 10,
|
silver INTEGER NOT NULL DEFAULT 10,
|
||||||
stargem INTEGER NOT NULL DEFAULT 0
|
stargem INTEGER NOT NULL DEFAULT 0
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'wallet');
|
created_or_error($r, 'char_wallets');
|
||||||
|
|
||||||
// Player bank
|
// Player bank
|
||||||
$db->exec('DROP TABLE IF EXISTS player_bank');
|
$db->exec('DROP TABLE IF EXISTS char_bank');
|
||||||
$db->exec('CREATE TABLE bank (
|
$r = $db->exec('CREATE TABLE bank (
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
slots INTEGER NOT NULL DEFAULT 5,
|
slots INTEGER NOT NULL DEFAULT 5,
|
||||||
silver INTEGER NOT NULL DEFAULT 0,
|
silver INTEGER NOT NULL DEFAULT 0,
|
||||||
tier INTEGER NOT NULL DEFAULT 1,
|
tier INTEGER NOT NULL DEFAULT 0,
|
||||||
interest INTEGER NOT NULL DEFAULT 0
|
can_collect INTEGER NOT NULL DEFAULT 1,
|
||||||
|
last_collected DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'bank');
|
created_or_error($r, 'bank');
|
||||||
|
|
||||||
// Banked items
|
// Banked items
|
||||||
$db->exec('DROP TABLE IF EXISTS player_banked_items');
|
$db->exec('DROP TABLE IF EXISTS char_banked_items');
|
||||||
$db->exec('CREATE TABLE banked_items (
|
$r = $db->exec('CREATE TABLE banked_items (
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
item_id INTEGER NOT NULL
|
item_id INTEGER NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'banked_items');
|
created_or_error($r, 'banked_items');
|
||||||
|
|
||||||
// Towns
|
// Towns
|
||||||
$db->exec('DROP TABLE IF EXISTS towns');
|
$db->exec('DROP TABLE IF EXISTS towns');
|
||||||
$db->exec('CREATE TABLE towns (
|
$r = $db->exec('CREATE TABLE towns (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
x INTEGER NOT NULL,
|
x INTEGER NOT NULL,
|
||||||
|
@ -399,11 +424,11 @@ if ($database === LIVE) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'towns');
|
created_or_error($r, 'towns');
|
||||||
|
|
||||||
// Shops
|
// Shops
|
||||||
$db->exec('DROP TABLE IF EXISTS shops');
|
$db->exec('DROP TABLE IF EXISTS shops');
|
||||||
$db->exec('CREATE TABLE shops (
|
$r = $db->exec('CREATE TABLE shops (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type INTEGER NOT NULL,
|
type INTEGER NOT NULL,
|
||||||
|
@ -419,11 +444,11 @@ if ($database === LIVE) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'shops');
|
created_or_error($r, 'shops');
|
||||||
|
|
||||||
// Inns
|
// Inns
|
||||||
$db->exec('DROP TABLE IF EXISTS inns');
|
$db->exec('DROP TABLE IF EXISTS inns');
|
||||||
$db->exec('CREATE TABLE inns (
|
$r = $db->exec('CREATE TABLE inns (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type INTEGER NOT NULL,
|
type INTEGER NOT NULL,
|
||||||
|
@ -435,11 +460,11 @@ if ($database === LIVE) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'inns');
|
created_or_error($r, 'inns');
|
||||||
|
|
||||||
// Guilds
|
// Guilds
|
||||||
$db->exec('DROP TABLE IF EXISTS guilds');
|
$db->exec('DROP TABLE IF EXISTS guilds');
|
||||||
$db->exec('CREATE TABLE guilds (
|
$r = $db->exec('CREATE TABLE guilds (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
lore TEXT NOT NULL DEFAULT "",
|
lore TEXT NOT NULL DEFAULT "",
|
||||||
|
@ -450,35 +475,35 @@ if ($database === LIVE) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'guilds');
|
created_or_error($r, 'guilds');
|
||||||
|
|
||||||
// Guild ranks
|
// Guild ranks
|
||||||
$db->exec('DROP TABLE IF EXISTS guild_ranks');
|
$db->exec('DROP TABLE IF EXISTS guild_ranks');
|
||||||
$db->exec('CREATE TABLE guild_ranks (
|
$r = $db->exec('CREATE TABLE guild_ranks (
|
||||||
guild_id INTEGER NOT NULL,
|
guild_id INTEGER NOT NULL,
|
||||||
rank INTEGER NOT NULL,
|
rank INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
permissions TEXT NOT NULL
|
permissions TEXT NOT NULL
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'guild_ranks');
|
created_or_error($r, 'guild_ranks');
|
||||||
|
|
||||||
// Guild members
|
// Guild members
|
||||||
$db->exec('DROP TABLE IF EXISTS guild_members');
|
$db->exec('DROP TABLE IF EXISTS guild_members');
|
||||||
$db->exec('CREATE TABLE guild_members (
|
$r = $db->exec('CREATE TABLE guild_members (
|
||||||
guild_id INTEGER NOT NULL,
|
guild_id INTEGER NOT NULL,
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
rank INTEGER NOT NULL,
|
rank INTEGER NOT NULL,
|
||||||
rep INTEGER NOT NULL DEFAULT 0,
|
rep INTEGER NOT NULL DEFAULT 0,
|
||||||
donated INTEGER NOT NULL DEFAULT 0,
|
donated INTEGER NOT NULL DEFAULT 0,
|
||||||
joined DATETIME DEFAULT CURRENT_TIMESTAMP
|
joined DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'guild_members');
|
created_or_error($r, 'guild_members');
|
||||||
|
|
||||||
// NPCs
|
// NPCs
|
||||||
$db->exec('DROP TABLE IF EXISTS npcs');
|
$db->exec('DROP TABLE IF EXISTS npcs');
|
||||||
$db->exec('CREATE TABLE npcs (
|
$r = $db->exec('CREATE TABLE npcs (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type INTEGER NOT NULL,
|
type INTEGER NOT NULL,
|
||||||
|
@ -490,22 +515,21 @@ if ($database === LIVE) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'npcs');
|
created_or_error($r, 'npcs');
|
||||||
|
|
||||||
// Town reputation
|
// Town reputation
|
||||||
$db->exec('DROP TABLE IF EXISTS player_town_rep');
|
$db->exec('DROP TABLE IF EXISTS char_town_rep');
|
||||||
$db->exec('CREATE TABLE town_rep (
|
$r = $db->exec('CREATE TABLE char_town_rep (
|
||||||
player_id INTEGER NOT NULL,
|
char_id INTEGER NOT NULL,
|
||||||
town_id INTEGER NOT NULL,
|
town_id INTEGER NOT NULL,
|
||||||
rep INTEGER NOT NULL DEFAULT 0
|
rep INTEGER NOT NULL DEFAULT 0
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'town_rep');
|
created_or_error($r, 'char_town_rep');
|
||||||
|
|
||||||
// Items
|
|
||||||
// Items
|
// Items
|
||||||
$db->exec('DROP TABLE IF EXISTS items');
|
$db->exec('DROP TABLE IF EXISTS items');
|
||||||
$db->exec('CREATE TABLE items (
|
$r = $db->exec('CREATE TABLE items (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
type TEXT NOT NULL DEFAULT 0,
|
type TEXT NOT NULL DEFAULT 0,
|
||||||
|
@ -518,12 +542,16 @@ if ($database === LIVE) {
|
||||||
durability INTEGER NOT NULL DEFAULT 0,
|
durability INTEGER NOT NULL DEFAULT 0,
|
||||||
max_durability INTEGER NOT NULL DEFAULT 0,
|
max_durability INTEGER NOT NULL DEFAULT 0,
|
||||||
power 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,
|
toughness INTEGER NOT NULL DEFAULT 0,
|
||||||
armor INTEGER NOT NULL DEFAULT 0,
|
armor INTEGER NOT NULL DEFAULT 0,
|
||||||
precision INTEGER NOT NULL DEFAULT 0,
|
resist INTEGER NOT NULL DEFAULT 0,
|
||||||
crit INTEGER NOT NULL DEFAULT 0,
|
crit INTEGER NOT NULL DEFAULT 0,
|
||||||
|
precision INTEGER NOT NULL DEFAULT 0,
|
||||||
ferocity INTEGER NOT NULL DEFAULT 0,
|
ferocity INTEGER NOT NULL DEFAULT 0,
|
||||||
vitality INTEGER NOT NULL DEFAULT 0,
|
luck INTEGER NOT NULL DEFAULT 0,
|
||||||
reqs TEXT NOT NULL DEFAULT "",
|
reqs TEXT NOT NULL DEFAULT "",
|
||||||
traits TEXT NOT NULL DEFAULT "",
|
traits TEXT NOT NULL DEFAULT "",
|
||||||
lore TEXT NOT NULL DEFAULT "",
|
lore TEXT NOT NULL DEFAULT "",
|
||||||
|
@ -531,10 +559,39 @@ if ($database === LIVE) {
|
||||||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
)');
|
)');
|
||||||
|
|
||||||
eln(yellow('Created table: ') . 'items');
|
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
|
||||||
|
)');
|
||||||
|
|
||||||
|
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
|
||||||
|
)');
|
||||||
|
|
||||||
|
created_or_error($r, 'char_locations');
|
||||||
|
|
||||||
eln(green('Created database: ') . 'live.db');
|
eln(green('Created database: ') . 'live.db');
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function created_or_error(bool $result, string $table): void
|
||||||
|
{
|
||||||
|
if ($result === false) {
|
||||||
|
eln(red('Failed to create table: ') . $table);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
eln(yellow('Created table: ') . $table);
|
||||||
|
}
|
||||||
|
|
34
docs/attributes.md
Normal file
34
docs/attributes.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Attributes
|
||||||
|
|
||||||
|
## Power
|
||||||
|
Power is the attribute that determines overall strike damage. Damage from weapon attacks, spells, or other strikes and specific skills will be directly influenced by Power. Power is a linear measure, with 1 Power = 1 damage in most cases.
|
||||||
|
|
||||||
|
## Accuracy
|
||||||
|
Accuracy determines the chance your attack, spell, or other skill will actually land on your opponent.
|
||||||
|
|
||||||
|
## Penetration
|
||||||
|
Penetration as a value determines your ability to make it through physical defenses; i.e. the enemy's Toughness and Armor.
|
||||||
|
|
||||||
|
## Focus
|
||||||
|
Focus is the same as Penetration but for causing magical damage, and helps go through magical defenses; i.e. the enemy's Resist.
|
||||||
|
|
||||||
|
## Evasion
|
||||||
|
Evasion is the attribute responsible for determining your chance to dodge any kind of attack. When calculating the chance, at base every 2 Evasion is 0.1% chance. The enemy's Accuracy negatively impacts this stat. The chance to dodge is capped at 85%.
|
||||||
|
|
||||||
|
## Toughness
|
||||||
|
Toughness affects your health pool and baseline defensive capability to physical attacks, such as weapons, projectiles, and physical skills.
|
||||||
|
|
||||||
|
## Armor
|
||||||
|
Armor is an additional layer of physical protection over Toughness. All armor grants some level of Armor, and it's effect is linear; 1 Armor = 1 point of damage negated.
|
||||||
|
|
||||||
|
## Resist
|
||||||
|
Resist is your defensive capacity against magic such as spells, magic skills, and magic weapons. Like Armor, this is a linear stat.
|
||||||
|
|
||||||
|
## Precision
|
||||||
|
Precision determines your Uber (Critical) Hit chance. In general, 2 points of Precision = 0.1% chance. No matter how high this value, your Uber Hit chance caps at 90%. Some equipment grants straight Uber Hit chance.
|
||||||
|
|
||||||
|
## Ferocity
|
||||||
|
Ferocity is a linear modifier of your Uber Hit damage; 1 Ferocity = 1% Uber Hit damage. Uber Hit damage increases cap at 300%.
|
||||||
|
|
||||||
|
## Luck
|
||||||
|
Luck is a modifier for gained XP/Silver. Like Precision, 2 points of Luck = 0.1% increase of these gains.
|
|
@ -1,23 +1,44 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup
|
||||||
|
*/
|
||||||
define('SRC', __DIR__ . '/../src');
|
define('SRC', __DIR__ . '/../src');
|
||||||
require_once SRC . '/bootstrap.php';
|
require_once SRC . '/bootstrap.php';
|
||||||
|
|
||||||
$r = [];
|
$r = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
Home
|
||||||
|
*/
|
||||||
router_get($r, '/', function () {
|
router_get($r, '/', function () {
|
||||||
echo render('layouts/basic', ['view' => 'pages/home']);
|
echo render('layouts/basic', ['view' => 'pages/home']);
|
||||||
});
|
});
|
||||||
|
|
||||||
router_get($r, '/auth/register', 'auth_register_get');
|
/*
|
||||||
router_post($r, '/auth/register', 'auth_register_post');
|
Auth
|
||||||
router_get($r, '/auth/login', 'auth_login_get');
|
*/
|
||||||
router_post($r, '/auth/login', 'auth_login_post');
|
router_get($r, '/auth/register', 'auth_controller_register_get');
|
||||||
router_post($r, '/auth/logout', 'auth_logout');
|
router_post($r, '/auth/register', 'auth_controller_register_post');
|
||||||
|
router_get($r, '/auth/login', 'auth_controller_login_get');
|
||||||
|
router_post($r, '/auth/login', 'auth_controller_login_post');
|
||||||
|
router_post($r, '/auth/logout', 'auth_controller_logout_post');
|
||||||
|
|
||||||
|
/*
|
||||||
|
Characters
|
||||||
|
*/
|
||||||
|
router_post($r, '/character/create', 'char_controller_create_post');
|
||||||
|
router_post($r, '/character/select', 'auth_controller_change_character_post');
|
||||||
|
|
||||||
|
/*
|
||||||
|
Router
|
||||||
|
*/
|
||||||
// [code, handler, params]
|
// [code, handler, params]
|
||||||
$l = router_lookup($r, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
$l = router_lookup($r, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
||||||
|
|
||||||
if ($l['code'] !== 200) router_error($l['code']);
|
if ($l['code'] !== 200) router_error($l['code']);
|
||||||
$l['handler'](...$l['params'] ?? []);
|
$l['handler'](...$l['params'] ?? []);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cleanup
|
||||||
|
*/
|
||||||
clear_flashes();
|
clear_flashes();
|
||||||
|
|
169
src/auth.php
169
src/auth.php
|
@ -16,158 +16,6 @@ function auth_emailExists(string $email): bool
|
||||||
return db_exists(db_auth(), 'users', 'email', $email);
|
return db_exists(db_auth(), 'users', 'email', $email);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the registration page.
|
|
||||||
*/
|
|
||||||
function auth_register_get(): void
|
|
||||||
{
|
|
||||||
echo render('layouts/basic', ['view' => 'pages/auth/register']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the registration form submission.
|
|
||||||
*/
|
|
||||||
function auth_register_post(): void
|
|
||||||
{
|
|
||||||
csrf_ensure();
|
|
||||||
|
|
||||||
$errors = [];
|
|
||||||
|
|
||||||
$u = $_POST['username'] ?? '';
|
|
||||||
$e = $_POST['email'] ?? '';
|
|
||||||
$p = $_POST['password'] ?? '';
|
|
||||||
|
|
||||||
// Trim the input.
|
|
||||||
$u = trim($u);
|
|
||||||
$e = trim($e);
|
|
||||||
|
|
||||||
/*
|
|
||||||
A username is required.
|
|
||||||
A username must be at least 3 characters long and at most 25 characters long.
|
|
||||||
A username must contain only alphanumeric characters and spaces.
|
|
||||||
*/
|
|
||||||
if (empty($u) || strlen($u) < 3 || strlen($u) > 25 || !ctype_alnum(str_replace(' ', '', $u))) {
|
|
||||||
$errors['u'][] = 'Username is required and must be between 3 and 25 characters long and contain only
|
|
||||||
alphanumeric characters and spaces.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
An email is required.
|
|
||||||
An email must be at most 255 characters long.
|
|
||||||
An email must be a valid email address.
|
|
||||||
*/
|
|
||||||
if (empty($e) || strlen($e) > 255 || !filter_var($e, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$errors['e'][] = 'Email is required must be a valid email address.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
A password is required.
|
|
||||||
A password must be at least 6 characters long.
|
|
||||||
*/
|
|
||||||
if (empty($p) || strlen($p) < 6) {
|
|
||||||
$errors['p'][] = 'Password is required and must be at least 6 characters long.';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are errors at this point, send them to the page with errors flashed.
|
|
||||||
if (!empty($errors)) {
|
|
||||||
flash('errors', $errors);
|
|
||||||
redirect('/auth/register');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
A username must be unique.
|
|
||||||
*/
|
|
||||||
if (auth_usernameExists($u)) {
|
|
||||||
$errors['u'][] = 'Username is already taken.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
An email must be unique.
|
|
||||||
*/
|
|
||||||
if (auth_emailExists($e)) {
|
|
||||||
$errors['e'][] = 'Email is already taken.';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are errors at this point, send them to the page with errors flashed.
|
|
||||||
if (!empty($errors)) {
|
|
||||||
flash('errors', $errors);
|
|
||||||
redirect('/auth/register');
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = user_create($u, $e, $p);
|
|
||||||
if ($user === false) router_error(400);
|
|
||||||
|
|
||||||
$_SESSION['user'] = user_find($u);
|
|
||||||
redirect('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the login page.
|
|
||||||
*/
|
|
||||||
function auth_login_get(): void
|
|
||||||
{
|
|
||||||
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the login form submission.
|
|
||||||
*/
|
|
||||||
function auth_login_post(): void
|
|
||||||
{
|
|
||||||
csrf_ensure();
|
|
||||||
|
|
||||||
$errors = [];
|
|
||||||
|
|
||||||
$u = $_POST['username'] ?? '';
|
|
||||||
$p = $_POST['password'] ?? '';
|
|
||||||
|
|
||||||
// Trim the input.
|
|
||||||
$u = trim($u);
|
|
||||||
|
|
||||||
/*
|
|
||||||
A username is required.
|
|
||||||
*/
|
|
||||||
if (empty($u)) {
|
|
||||||
$errors['u'][] = 'Username is required.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
A password is required.
|
|
||||||
*/
|
|
||||||
if (empty($p)) {
|
|
||||||
$errors['p'][] = 'Password is required.';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there are errors at this point, send them to the page with errors flashed.
|
|
||||||
if (!empty($errors)) {
|
|
||||||
flash('errors', $errors);
|
|
||||||
redirect('/auth/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = user_find($u);
|
|
||||||
if ($user === false || !password_verify($p, $user['password'])) {
|
|
||||||
$errors['u'][] = 'Invalid username or password.';
|
|
||||||
flash('errors', $errors);
|
|
||||||
redirect('/auth/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['user'] = $user;
|
|
||||||
if ($_POST['remember'] ?? false) auth_rememberMe();
|
|
||||||
redirect('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the user out.
|
|
||||||
*/
|
|
||||||
function auth_logout(): void
|
|
||||||
{
|
|
||||||
csrf_ensure();
|
|
||||||
session_delete($_SESSION['user']['id']);
|
|
||||||
unset($_SESSION['user']);
|
|
||||||
set_cookie('remember_me', '', 1);
|
|
||||||
redirect('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a long-lived session for the user.
|
* Create a long-lived session for the user.
|
||||||
*/
|
*/
|
||||||
|
@ -204,3 +52,20 @@ function auth_check(): bool
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure a user is logged in, or redirect to the login page. This will also check for a remember me cookie and
|
||||||
|
* populate the $_SESSION['user'] array.
|
||||||
|
*/
|
||||||
|
function auth_ensure(): void
|
||||||
|
{
|
||||||
|
if (!auth_check()) redirect('/auth/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is a user logged in, redirect to the home page. Used for when we have a guest-only page.
|
||||||
|
*/
|
||||||
|
function auth_guest(): void
|
||||||
|
{
|
||||||
|
if (auth_check()) redirect('/');
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,11 @@ require_once SRC . '/router.php';
|
||||||
require_once SRC . '/models/user.php';
|
require_once SRC . '/models/user.php';
|
||||||
require_once SRC . '/models/session.php';
|
require_once SRC . '/models/session.php';
|
||||||
require_once SRC . '/models/token.php';
|
require_once SRC . '/models/token.php';
|
||||||
|
require_once SRC . '/models/char.php';
|
||||||
|
|
||||||
|
// Controllers
|
||||||
|
require_once SRC . '/controllers/char.php';
|
||||||
|
require_once SRC . '/controllers/auth.php';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Load env, set error reporting, etc.
|
Load env, set error reporting, etc.
|
||||||
|
@ -32,3 +37,6 @@ csrf();
|
||||||
|
|
||||||
// Have a global counter for queries
|
// Have a global counter for queries
|
||||||
$GLOBALS['queries'] = 0;
|
$GLOBALS['queries'] = 0;
|
||||||
|
|
||||||
|
// Run auth_check to see if we're logged in, since it populates the user data in SESSION
|
||||||
|
auth_check();
|
||||||
|
|
176
src/controllers/auth.php
Normal file
176
src/controllers/auth.php
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the registration page.
|
||||||
|
*/
|
||||||
|
function auth_controller_register_get(): void
|
||||||
|
{
|
||||||
|
auth_guest();
|
||||||
|
echo render('layouts/basic', ['view' => 'pages/auth/register']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the registration form submission.
|
||||||
|
*/
|
||||||
|
function auth_controller_register_post(): void
|
||||||
|
{
|
||||||
|
auth_guest();
|
||||||
|
csrf_ensure();
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$u = $_POST['username'] ?? '';
|
||||||
|
$e = $_POST['email'] ?? '';
|
||||||
|
$p = $_POST['password'] ?? '';
|
||||||
|
|
||||||
|
// Trim the input.
|
||||||
|
$u = trim($u);
|
||||||
|
$e = trim($e);
|
||||||
|
|
||||||
|
/*
|
||||||
|
A username is required.
|
||||||
|
A username must be at least 3 characters long and at most 18 characters long.
|
||||||
|
A username must contain only alphanumeric characters and spaces.
|
||||||
|
*/
|
||||||
|
if (empty($u) || strlen($u) < 3 || strlen($u) > 18 || !ctype_alnum(str_replace(' ', '', $u))) {
|
||||||
|
$errors['u'][] = 'Username is required and must be between 3 and 18 characters long and contain only
|
||||||
|
alphanumeric characters and spaces.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
An email is required.
|
||||||
|
An email must be at most 255 characters long.
|
||||||
|
An email must be a valid email address.
|
||||||
|
*/
|
||||||
|
if (empty($e) || strlen($e) > 255 || !filter_var($e, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$errors['e'][] = 'Email is required must be a valid email address.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A password is required.
|
||||||
|
A password must be at least 6 characters long.
|
||||||
|
*/
|
||||||
|
if (empty($p) || strlen($p) < 6) {
|
||||||
|
$errors['p'][] = 'Password is required and must be at least 6 characters long.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are errors at this point, send them to the page with errors flashed.
|
||||||
|
if (!empty($errors)) {
|
||||||
|
flash('errors', $errors);
|
||||||
|
redirect('/auth/register');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A username must be unique.
|
||||||
|
*/
|
||||||
|
if (auth_usernameExists($u)) {
|
||||||
|
$errors['u'][] = 'Username is already taken.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
An email must be unique.
|
||||||
|
*/
|
||||||
|
if (auth_emailExists($e)) {
|
||||||
|
$errors['e'][] = 'Email is already taken.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are errors at this point, send them to the page with errors flashed.
|
||||||
|
if (!empty($errors)) {
|
||||||
|
flash('errors', $errors);
|
||||||
|
redirect('/auth/register');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = user_create($u, $e, $p);
|
||||||
|
if ($user === false) router_error(400);
|
||||||
|
|
||||||
|
$_SESSION['user'] = user_find($u);
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the login page.
|
||||||
|
*/
|
||||||
|
function auth_controller_login_get(): void
|
||||||
|
{
|
||||||
|
auth_guest();
|
||||||
|
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the login form submission.
|
||||||
|
*/
|
||||||
|
function auth_controller_login_post(): void
|
||||||
|
{
|
||||||
|
auth_guest();
|
||||||
|
csrf_ensure();
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$u = $_POST['username'] ?? '';
|
||||||
|
$p = $_POST['password'] ?? '';
|
||||||
|
|
||||||
|
// Trim the input.
|
||||||
|
$u = trim($u);
|
||||||
|
|
||||||
|
/*
|
||||||
|
A username is required.
|
||||||
|
*/
|
||||||
|
if (empty($u)) {
|
||||||
|
$errors['u'][] = 'Username is required.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A password is required.
|
||||||
|
*/
|
||||||
|
if (empty($p)) {
|
||||||
|
$errors['p'][] = 'Password is required.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are errors at this point, send them to the page with errors flashed.
|
||||||
|
if (!empty($errors)) {
|
||||||
|
flash('errors', $errors);
|
||||||
|
redirect('/auth/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = user_find($u);
|
||||||
|
if ($user === false || !password_verify($p, $user['password'])) {
|
||||||
|
$errors['u'][] = 'Invalid username or password.';
|
||||||
|
flash('errors', $errors);
|
||||||
|
redirect('/auth/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['user'] = $user;
|
||||||
|
if ($_POST['remember'] ?? false) auth_rememberMe();
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the user out.
|
||||||
|
*/
|
||||||
|
function auth_controller_logout_post(): void
|
||||||
|
{
|
||||||
|
csrf_ensure();
|
||||||
|
session_delete($_SESSION['user']['id']);
|
||||||
|
unset($_SESSION['user']);
|
||||||
|
set_cookie('remember_me', '', 1);
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the user's currently selected character.
|
||||||
|
*/
|
||||||
|
function auth_controller_change_character_post(): void
|
||||||
|
{
|
||||||
|
auth_check();
|
||||||
|
csrf_ensure();
|
||||||
|
|
||||||
|
$char_id = (int) ($_POST['char_id'] ?? 0);
|
||||||
|
if (char_exists($char_id) === false) router_error(400);
|
||||||
|
|
||||||
|
$_SESSION['user']['char_id'] = $char_id;
|
||||||
|
if (db_query(db_auth(), 'UPDATE users SET char_id = :c WHERE id = :u', [
|
||||||
|
':c' => $char_id,
|
||||||
|
':u' => $_SESSION['user']['id']
|
||||||
|
]) === false) router_error(400);
|
||||||
|
redirect('/');
|
||||||
|
}
|
67
src/controllers/char.php
Normal file
67
src/controllers/char.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a player for the currently logged in user.
|
||||||
|
*/
|
||||||
|
function char_controller_create_post(): void
|
||||||
|
{
|
||||||
|
auth_ensure();
|
||||||
|
csrf_ensure();
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$name = $_POST['name'] ?? '';
|
||||||
|
|
||||||
|
// Trim the input.
|
||||||
|
$name = trim($name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
A name is required.
|
||||||
|
A name must be between 3 and 18 characters.
|
||||||
|
A name must contain only alphanumeric characters and spaces.
|
||||||
|
*/
|
||||||
|
if (empty($name) || strlen($name) < 3 || strlen($name) > 18 || !ctype_alnum(str_replace(' ', '', $name))) {
|
||||||
|
$errors['name'][] = 'Name is required and must be between 3 and 18 characters long and contain only alphanumeric characters and spaces.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A player's name must be unique.
|
||||||
|
*/
|
||||||
|
if (char_nameExists($name)) $errors['name'][] = 'Name is already taken.';
|
||||||
|
|
||||||
|
// If there are errors at this point, send them to the page with errors flashed.
|
||||||
|
if (!empty($errors)) {
|
||||||
|
flash('errors', $errors);
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the player
|
||||||
|
$player = char_create(user('id'), $name);
|
||||||
|
if ($player === false) router_error(400);
|
||||||
|
|
||||||
|
// Create the auxiliary tables
|
||||||
|
char_location_create($player);
|
||||||
|
char_wallet_create($player);
|
||||||
|
char_gear_create($player);
|
||||||
|
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the user's selected character.
|
||||||
|
*/
|
||||||
|
function char_controller_select_post(): void
|
||||||
|
{
|
||||||
|
auth_ensure();
|
||||||
|
csrf_ensure();
|
||||||
|
|
||||||
|
$char_id = (int) $_POST['char_id'] ?? 0;
|
||||||
|
|
||||||
|
// Ensure the character exists and belongs to the user
|
||||||
|
if (!char_exists($char_id)) router_error(400);
|
||||||
|
|
||||||
|
// Update the user's selected character
|
||||||
|
$_SESSION['user']['char_id'] = $char_id;
|
||||||
|
|
||||||
|
redirect('/');
|
||||||
|
}
|
|
@ -36,5 +36,5 @@ function env_load(string $filePath): void
|
||||||
*/
|
*/
|
||||||
function env(string $key, mixed $default = null): mixed
|
function env(string $key, mixed $default = null): mixed
|
||||||
{
|
{
|
||||||
return $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key) ?? $default;
|
return $_ENV[$key] ?? $_SERVER[$key] ?? (getenv($key) ?: $default);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,3 +108,21 @@ function set_cookie(string $name, string $value, int $expires): void
|
||||||
'samesite' => 'Strict' // Enforce SameSite=Strict
|
'samesite' => 'Strict' // Enforce SameSite=Strict
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current user's array from SESSION if it exists. Specify a key to get a specific value.
|
||||||
|
*/
|
||||||
|
function user(string $field = ''): mixed
|
||||||
|
{
|
||||||
|
if (empty($_SESSION['user'])) return false;
|
||||||
|
if ($field === '') return $_SESSION['user'];
|
||||||
|
return $_SESSION['user'][$field] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the user has selected a character. If so, return the character's ID.
|
||||||
|
*/
|
||||||
|
function char_selected(): int
|
||||||
|
{
|
||||||
|
return (int) $_SESSION['user']['char_id'];
|
||||||
|
}
|
||||||
|
|
201
src/models/char.php
Normal file
201
src/models/char.php
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
Players are the living, breathing entities that interact with the game world. They are inextricably linked to their
|
||||||
|
accounts, and are the primary means by which the player interacts with the game world. Separating the player from
|
||||||
|
the account allows for multiple players to be associated with a single account, and to prevent concurrency issues
|
||||||
|
when performing auth checks on the database.
|
||||||
|
|
||||||
|
When creating a player, we want to init all of the related data tables; wallets, inventory, bank, etc.
|
||||||
|
|
||||||
|
When retrieving a player, we will get the tables as-needed, to prevent allocating more memory than we need.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const currently = [
|
||||||
|
0 => 'Exploring',
|
||||||
|
1 => 'In Town',
|
||||||
|
2 => 'In Combat',
|
||||||
|
4 => 'In Shop',
|
||||||
|
5 => 'In Inn'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a player. Only a user ID and a name are required. All other fields are optional. Pass a key-value array
|
||||||
|
* of overrides to set additional fields. A player's name must be unique, but this function does not check for
|
||||||
|
* that. Returns the created player's ID.
|
||||||
|
*/
|
||||||
|
function char_create(int $user_id, string $name, array $overrides = []): int
|
||||||
|
{
|
||||||
|
// Prep the data and merge in any overrides
|
||||||
|
$data = ['user_id' => $user_id, 'name' => $name];
|
||||||
|
if (!empty($overrides)) $data = array_merge($data, $overrides);
|
||||||
|
|
||||||
|
// Prep the fields for the query
|
||||||
|
$k = array_keys($data);
|
||||||
|
$f = implode(', ', $k);
|
||||||
|
$v = implode(', ', array_map(fn($x) => ":$x", $k));
|
||||||
|
|
||||||
|
// Create the player!
|
||||||
|
if (db_query(db_live(), "INSERT INTO characters ($f) VALUES ($v)", $data) === false) {
|
||||||
|
// @TODO: Log this error
|
||||||
|
throw new Exception('Failed to create player.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the player ID
|
||||||
|
return db_live()->lastInsertRowID();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a player's location record. A player's location is where they are in the game world. A player can only be
|
||||||
|
* in one location at a time. Can define a starting location for the player. Default state is 'Exploring'.
|
||||||
|
*/
|
||||||
|
function char_location_create(int $char_id, int $x = 0, int $y = 0, int $currently = 0): void
|
||||||
|
{
|
||||||
|
if (db_query(db_live(), "INSERT INTO char_locations (char_id, x, y, currently) VALUES (:p, :x, :y, :c)", [
|
||||||
|
':p' => $char_id,
|
||||||
|
':x' => $x,
|
||||||
|
':y' => $y,
|
||||||
|
':c' => $currently
|
||||||
|
]) === false) {
|
||||||
|
throw new Exception('Failed to create player location.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a player's wallet. A player's wallet is where they store their currencies. Can optionally specify the
|
||||||
|
* starting balances of the wallet. Returns the created wallet's ID. If a currency is set to -1, the starting_silver
|
||||||
|
* or starting_star_gems fields from the env will be used.
|
||||||
|
*/
|
||||||
|
function char_wallet_create(int $char_id, int $silver = -1, int $starGems = -1): void
|
||||||
|
{
|
||||||
|
if (db_query(db_live(), "INSERT INTO char_wallets (char_id, silver, stargem) VALUES (:p, :s, :sg)", [
|
||||||
|
':p' => $char_id,
|
||||||
|
':s' => $silver === -1 ? env('start_silver', 10) : $silver,
|
||||||
|
':sg' => $starGems === -1 ? env('start_star_gems', 0) : $starGems
|
||||||
|
]) === false) {
|
||||||
|
throw new Exception('Failed to create player wallet.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the player's gear table. A player's gear is where they store their equipped items.
|
||||||
|
* @TODO: implement initial gear
|
||||||
|
*/
|
||||||
|
function char_gear_create(int $char_id, array $initialGear = []): void
|
||||||
|
{
|
||||||
|
if (db_query(db_live(), "INSERT INTO char_gear (char_id) VALUES (:p)", [':p' => $char_id]) === false) {
|
||||||
|
throw new Exception('Failed to create player gear.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the player's bank account. The bank stores items and currency, with an interest rate based on
|
||||||
|
* the bank account's tier. The bank account has a limited number of slots, which can be increased by upgrading
|
||||||
|
* the bank account. The bank account starts with 0 silver and 5 slots.
|
||||||
|
*/
|
||||||
|
function char_bank_create(int $char_id, int $slots = 5, int $silver = 0, int $tier = 0): void
|
||||||
|
{
|
||||||
|
if (db_query(db_live(), "INSERT INTO char_banks (char_id, slots, silver, tier) VALUES (:p, :s, :si, :t)", [
|
||||||
|
':p' => $char_id,
|
||||||
|
':s' => $slots,
|
||||||
|
':si' => $silver,
|
||||||
|
':t' => $tier
|
||||||
|
]) === false) {
|
||||||
|
throw new Exception('Failed to create player bank.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a player by their account ID. Returns the player's data as an associative array.
|
||||||
|
*/
|
||||||
|
function char_find(int $char_id): array
|
||||||
|
{
|
||||||
|
// Get the player
|
||||||
|
$player = db_query(db_live(), "SELECT * FROM characters WHERE id = :id", [':id' => $char_id])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
if ($player === false) {
|
||||||
|
throw new Exception('Character not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of players associated with an account ID.
|
||||||
|
*/
|
||||||
|
function char_count(int $user_id): int
|
||||||
|
{
|
||||||
|
// Get the count
|
||||||
|
$count = db_query(db_live(), "SELECT COUNT(*) FROM characters WHERE user_id = :u", [':u' => $user_id])->fetchArray(SQLITE3_NUM);
|
||||||
|
if ($count === false) {
|
||||||
|
throw new Exception('Failed to count players.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $count[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a an array of id => [name, level] for all players associated with an account ID.
|
||||||
|
*/
|
||||||
|
function char_list(int $user_id): array
|
||||||
|
{
|
||||||
|
// Get the players
|
||||||
|
$stmt = db_query(db_live(), "SELECT id, name, level FROM characters WHERE user_id = :u", [':u' => $user_id]);
|
||||||
|
if ($stmt === false) throw new Exception('Failed to list players.');
|
||||||
|
|
||||||
|
$players = [];
|
||||||
|
while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) {
|
||||||
|
$players[$row['id']] = ['name' => $row['name'], 'level' => $row['level']];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $players;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a player's location info by their player ID. Returns the location's data as an associative array.
|
||||||
|
*/
|
||||||
|
function char_get_location(int $char_id): array
|
||||||
|
{
|
||||||
|
// Get the location
|
||||||
|
$location = db_query(db_live(), "SELECT * FROM char_locations WHERE char_id = :p", [':p' => $char_id])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
if ($location === false) {
|
||||||
|
throw new Exception('Location not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a player's wallet by their player ID. Returns the wallet's data as an associative array.
|
||||||
|
*/
|
||||||
|
function char_get_wallet(int $char_id): array
|
||||||
|
{
|
||||||
|
// Get the wallet
|
||||||
|
$wallet = db_query(db_live(), "SELECT * FROM char_wallets WHERE char_id = :p", [':p' => $char_id])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
if ($wallet === false) {
|
||||||
|
throw new Exception('Wallet not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if a player name exists.
|
||||||
|
*/
|
||||||
|
function char_nameExists(string $name): bool
|
||||||
|
{
|
||||||
|
// Check for the name
|
||||||
|
$exists = db_query(db_live(), "SELECT COUNT(*) FROM characters WHERE name = :n", [':n' => $name])->fetchArray(SQLITE3_NUM);
|
||||||
|
if ($exists === false) {
|
||||||
|
throw new Exception('Failed to check for player name.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $exists[0] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a character exists at a certain ID.
|
||||||
|
*/
|
||||||
|
function char_exists(int $char_id): bool
|
||||||
|
{
|
||||||
|
return db_exists(db_live(), 'characters', 'id', $char_id);
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
Players are the living, breathing entities that interact with the game world. They are inextricably linked to their
|
|
||||||
accounts, and are the primary means by which the player interacts with the game world. Separating the player from
|
|
||||||
the account allows for multiple players to be associated with a single account, and to prevent concurrency issues
|
|
||||||
when performing auth checks on the database.
|
|
||||||
|
|
||||||
When creating a player, we want to init all of the related data tables; wallets, inventory, bank, etc.
|
|
||||||
|
|
||||||
When retrieving a player, we will get the tables as-needed, to prevent allocating more memory than we need.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a player. Only a user ID and a name are required. All other fields are optional. Pass a key-value array
|
|
||||||
* of overrides to set additional fields. A player's name must be unique, but this function does not check for that.
|
|
||||||
*/
|
|
||||||
function player_create(int $user_id, string $name, array $overrides = []): int
|
|
||||||
{
|
|
||||||
// Prep the data and merge in any overrides
|
|
||||||
$data = ['user_id' => $user_id, 'name' => $name];
|
|
||||||
if (!empty($overrides)) $data = array_merge($data, $overrides);
|
|
||||||
|
|
||||||
// Prep the fields for the query
|
|
||||||
$k = array_keys($data);
|
|
||||||
$f = implode(', ', array_keys($k));
|
|
||||||
$v = implode(', ', array_map(fn($x) => ":$x", $k));
|
|
||||||
|
|
||||||
// Create the player!
|
|
||||||
if (db_query(db_live(), "INSERT INTO players ($f) VALUES ($v)", $data) === false) {
|
|
||||||
// @TODO: Log this error
|
|
||||||
throw new Exception('Failed to create player.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the player ID
|
|
||||||
return db_live()->lastInsertRowID();
|
|
||||||
}
|
|
|
@ -1,11 +1,32 @@
|
||||||
<?php if (!auth_check()): ?>
|
<?php if (!user()): ?>
|
||||||
Hello, oppai!
|
<h2>Welcome!</h2>
|
||||||
<a href="/auth/register">Register</a>
|
<a href="/auth/register">Register</a>
|
||||||
<a href="/auth/login">Login</a>
|
<a href="/auth/login">Login</a>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
Hello, <?= $_SESSION['user']['username'] ?>!
|
<h2>Hello, <?= user('username') ?>!</h2>
|
||||||
|
<?php if (user('char_id') !== 0): ?>
|
||||||
|
<h3>Playing as <?= char_find(user('char_id'))['name'] ?></h3>
|
||||||
|
<?php endif; ?>
|
||||||
<form action="/auth/logout" method="post">
|
<form action="/auth/logout" method="post">
|
||||||
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
||||||
<input type="submit" value="Logout">
|
<input type="submit" value="Logout">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<?php if (char_count(user('id')) > 0): ?>
|
||||||
|
<h3>Characters</h3>
|
||||||
|
<form action="character/select" method="post">
|
||||||
|
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
||||||
|
<?php foreach (char_list(user('id')) as $id => $char): ?>
|
||||||
|
<input type="radio" name="char_id" value="<?= $id ?>" id="char_<?= $id ?>">
|
||||||
|
<label for="char_<?= $id ?>"><?= $char['name'] ?> (Level <?= $char['level'] ?>)</label><br>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<input type="submit" value="Select Character">
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="/character/create" method="post">
|
||||||
|
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
||||||
|
<input type="text" name="name" placeholder="Character Name">
|
||||||
|
<input type="submit" value="Create Character">
|
||||||
|
</form>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user