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_registration = true
|
||||
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
|
||||
$db->exec('DROP TABLE IF EXISTS users');
|
||||
$db->exec('CREATE TABLE 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,
|
||||
created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
last_login DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'users');
|
||||
created_or_error($r, 'users');
|
||||
|
||||
// Sessions table
|
||||
$db->exec('DROP TABLE IF EXISTS sessions');
|
||||
$db->exec('CREATE TABLE sessions (
|
||||
$r = $db->exec('CREATE TABLE sessions (
|
||||
user_id INTEGER NOT NULL,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
expires INTEGER NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'sessions');
|
||||
created_or_error($r, 'sessions');
|
||||
|
||||
// Verification tokens
|
||||
$db->exec('DROP TABLE IF EXISTS tokens');
|
||||
$db->exec('CREATE TABLE tokens (
|
||||
$r = $db->exec('CREATE TABLE tokens (
|
||||
user_id INTEGER NOT NULL,
|
||||
token TEXT NOT NULL UNIQUE,
|
||||
created INTEGER NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'tokens');
|
||||
created_or_error($r, 'tokens');
|
||||
|
||||
eln(green('Created database: ') . 'auth.db');
|
||||
|
||||
|
@ -105,20 +107,23 @@ if ($database === FIGHTS) {
|
|||
|
||||
// PvE fights
|
||||
$db->exec('DROP TABLE IF EXISTS pve');
|
||||
$db->exec('CREATE TABLE pve (
|
||||
$r = $db->exec('CREATE TABLE pve (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player_id INTEGER NOT NULL,
|
||||
player_hp INTEGER NOT NULL,
|
||||
player_max_hp INTEGER NOT NULL,
|
||||
player_mp INTEGER NOT NULL,
|
||||
player_max_mp INTEGER NOT NULL,
|
||||
player_power INTEGER NOT NULL,
|
||||
player_toughness INTEGER NOT NULL,
|
||||
player_armor INTEGER NOT NULL,
|
||||
player_precision INTEGER NOT NULL,
|
||||
player_crit INTEGER NOT NULL,
|
||||
player_ferocity INTEGER NOT NULL,
|
||||
player_vitality INTEGER NOT NULL,
|
||||
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,
|
||||
|
@ -130,6 +135,8 @@ if ($database === FIGHTS) {
|
|||
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,
|
||||
|
@ -142,36 +149,42 @@ if ($database === FIGHTS) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'pve');
|
||||
created_or_error($r, 'pve');
|
||||
|
||||
// PvP fights
|
||||
$db->exec('DROP TABLE IF EXISTS pvp');
|
||||
$db->exec('CREATE TABLE pvp (
|
||||
$r = $db->exec('CREATE TABLE pvp (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player1_id INTEGER NOT NULL,
|
||||
player1_hp INTEGER NOT NULL,
|
||||
player1_max_hp INTEGER NOT NULL,
|
||||
player1_mp INTEGER NOT NULL,
|
||||
player1_max_mp INTEGER NOT NULL,
|
||||
player1_power INTEGER NOT NULL,
|
||||
player1_toughness INTEGER NOT NULL,
|
||||
player1_armor INTEGER NOT NULL,
|
||||
player1_precision INTEGER NOT NULL,
|
||||
player1_crit INTEGER NOT NULL,
|
||||
player1_ferocity INTEGER NOT NULL,
|
||||
player1_vitality INTEGER NOT NULL,
|
||||
player2_id INTEGER NOT NULL,
|
||||
player2_hp INTEGER NOT NULL,
|
||||
player2_max_hp INTEGER NOT NULL,
|
||||
player2_mp INTEGER NOT NULL,
|
||||
player2_max_mp INTEGER NOT NULL,
|
||||
player2_power INTEGER NOT NULL,
|
||||
player2_toughness INTEGER NOT NULL,
|
||||
player2_armor INTEGER NOT NULL,
|
||||
player2_precision INTEGER NOT NULL,
|
||||
player2_crit INTEGER NOT NULL,
|
||||
player2_ferocity INTEGER NOT NULL,
|
||||
player2_vitality INTEGER NOT NULL,
|
||||
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,
|
||||
|
@ -179,27 +192,27 @@ if ($database === FIGHTS) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'pvp');
|
||||
created_or_error($r, 'pvp');
|
||||
|
||||
// PvE fight 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,
|
||||
fight_id INTEGER NOT NULL,
|
||||
info TEXT NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'pve_logs');
|
||||
created_or_error($r, 'pve_logs');
|
||||
|
||||
// PvP fight 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,
|
||||
fight_id INTEGER NOT NULL,
|
||||
info TEXT NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'pvp_logs');
|
||||
created_or_error($r, 'pvp_logs');
|
||||
|
||||
eln(green('Created database: ') . 'fights.db');
|
||||
|
||||
|
@ -219,7 +232,7 @@ if ($database === BPS) {
|
|||
|
||||
// Items
|
||||
$db->exec('DROP TABLE IF EXISTS items');
|
||||
$db->exec('CREATE TABLE items (
|
||||
$r = $db->exec('CREATE TABLE items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type INTEGER NOT NULL DEFAULT 0,
|
||||
|
@ -231,12 +244,16 @@ if ($database === BPS) {
|
|||
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,
|
||||
precision 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,
|
||||
vitality 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 "",
|
||||
|
@ -244,11 +261,11 @@ if ($database === BPS) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'items');
|
||||
created_or_error($r, 'items');
|
||||
|
||||
// Mobs
|
||||
$db->exec('DROP TABLE IF EXISTS mobs');
|
||||
$db->exec('CREATE TABLE mobs (
|
||||
$r = $db->exec('CREATE TABLE mobs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type INTEGER NOT NULL,
|
||||
|
@ -273,7 +290,7 @@ if ($database === BPS) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'mobs');
|
||||
created_or_error($r, 'mobs');
|
||||
|
||||
eln(green('Created database: ') . 'blueprints.db');
|
||||
|
||||
|
@ -291,13 +308,13 @@ if ($database === LIVE) {
|
|||
|
||||
$db = new SQLite3(__DIR__ . '/../' . LIVE);
|
||||
|
||||
// Players
|
||||
$db->exec('DROP TABLE IF EXISTS players');
|
||||
$db->exec('CREATE TABLE players (
|
||||
// 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,
|
||||
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,
|
||||
|
@ -308,21 +325,25 @@ if ($database === LIVE) {
|
|||
current_tp INTEGER NOT NULL DEFAULT 0,
|
||||
max_tp 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,
|
||||
precision INTEGER NOT NULL DEFAULT 0,
|
||||
crit INTEGER NOT NULL DEFAULT 0,
|
||||
ferocity INTEGER NOT NULL DEFAULT 0,
|
||||
vitality INTEGER NOT NULL DEFAULT 0,
|
||||
inv_slots INTEGER NOT NULL DEFAULT 10
|
||||
luck INTEGER NOT NULL DEFAULT 0,
|
||||
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
|
||||
$db->exec('DROP TABLE IF EXISTS player_gear');
|
||||
$db->exec('CREATE TABLE player_gear (
|
||||
player_id INTEGER NOT NULL,
|
||||
$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,
|
||||
|
@ -333,62 +354,66 @@ if ($database === LIVE) {
|
|||
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,
|
||||
precision 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,
|
||||
vitality 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,
|
||||
traits TEXT NOT NULL DEFAULT ""
|
||||
max_mp INTEGER NOT NULL DEFAULT 0
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'player_gear');
|
||||
created_or_error($r, 'char_gear');
|
||||
|
||||
// Player inventory
|
||||
$db->exec('DROP TABLE IF EXISTS player_inventory');
|
||||
$db->exec('CREATE TABLE inventory (
|
||||
player_id INTEGER NOT NULL,
|
||||
$db->exec('DROP TABLE IF EXISTS char_inventory');
|
||||
$r = $db->exec('CREATE TABLE inventory (
|
||||
char_id INTEGER NOT NULL,
|
||||
item_id INTEGER NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'inventory');
|
||||
created_or_error($r, 'inventory');
|
||||
|
||||
// Player wallet
|
||||
$db->exec('DROP TABLE IF EXISTS player_wallet');
|
||||
$db->exec('CREATE TABLE wallet (
|
||||
player_id INTEGER NOT NULL,
|
||||
$db->exec('DROP TABLE IF EXISTS char_wallets');
|
||||
$r = $db->exec('CREATE TABLE char_wallets (
|
||||
char_id INTEGER NOT NULL,
|
||||
silver INTEGER NOT NULL DEFAULT 10,
|
||||
stargem INTEGER NOT NULL DEFAULT 0
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'wallet');
|
||||
created_or_error($r, 'char_wallets');
|
||||
|
||||
// Player bank
|
||||
$db->exec('DROP TABLE IF EXISTS player_bank');
|
||||
$db->exec('CREATE TABLE bank (
|
||||
player_id INTEGER NOT NULL,
|
||||
$db->exec('DROP TABLE IF EXISTS char_bank');
|
||||
$r = $db->exec('CREATE TABLE bank (
|
||||
char_id INTEGER NOT NULL,
|
||||
slots INTEGER NOT NULL DEFAULT 5,
|
||||
silver INTEGER NOT NULL DEFAULT 0,
|
||||
tier INTEGER NOT NULL DEFAULT 1,
|
||||
interest INTEGER NOT NULL DEFAULT 0
|
||||
tier 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
|
||||
$db->exec('DROP TABLE IF EXISTS player_banked_items');
|
||||
$db->exec('CREATE TABLE banked_items (
|
||||
player_id INTEGER NOT NULL,
|
||||
$db->exec('DROP TABLE IF EXISTS char_banked_items');
|
||||
$r = $db->exec('CREATE TABLE banked_items (
|
||||
char_id INTEGER NOT NULL,
|
||||
item_id INTEGER NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'banked_items');
|
||||
created_or_error($r, 'banked_items');
|
||||
|
||||
// Towns
|
||||
$db->exec('DROP TABLE IF EXISTS towns');
|
||||
$db->exec('CREATE TABLE towns (
|
||||
$r = $db->exec('CREATE TABLE towns (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
x INTEGER NOT NULL,
|
||||
|
@ -399,11 +424,11 @@ if ($database === LIVE) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'towns');
|
||||
created_or_error($r, 'towns');
|
||||
|
||||
// Shops
|
||||
$db->exec('DROP TABLE IF EXISTS shops');
|
||||
$db->exec('CREATE TABLE shops (
|
||||
$r = $db->exec('CREATE TABLE shops (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type INTEGER NOT NULL,
|
||||
|
@ -419,11 +444,11 @@ if ($database === LIVE) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'shops');
|
||||
created_or_error($r, 'shops');
|
||||
|
||||
// Inns
|
||||
$db->exec('DROP TABLE IF EXISTS inns');
|
||||
$db->exec('CREATE TABLE inns (
|
||||
$r = $db->exec('CREATE TABLE inns (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type INTEGER NOT NULL,
|
||||
|
@ -435,11 +460,11 @@ if ($database === LIVE) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'inns');
|
||||
created_or_error($r, 'inns');
|
||||
|
||||
// Guilds
|
||||
$db->exec('DROP TABLE IF EXISTS guilds');
|
||||
$db->exec('CREATE TABLE guilds (
|
||||
$r = $db->exec('CREATE TABLE guilds (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
lore TEXT NOT NULL DEFAULT "",
|
||||
|
@ -450,35 +475,35 @@ if ($database === LIVE) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'guilds');
|
||||
created_or_error($r, 'guilds');
|
||||
|
||||
// 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,
|
||||
rank INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
permissions TEXT NOT NULL
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'guild_ranks');
|
||||
created_or_error($r, 'guild_ranks');
|
||||
|
||||
// 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,
|
||||
player_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
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'guild_members');
|
||||
created_or_error($r, 'guild_members');
|
||||
|
||||
// NPCs
|
||||
$db->exec('DROP TABLE IF EXISTS npcs');
|
||||
$db->exec('CREATE TABLE npcs (
|
||||
$r = $db->exec('CREATE TABLE npcs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type INTEGER NOT NULL,
|
||||
|
@ -490,22 +515,21 @@ if ($database === LIVE) {
|
|||
updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'npcs');
|
||||
created_or_error($r, 'npcs');
|
||||
|
||||
// Town reputation
|
||||
$db->exec('DROP TABLE IF EXISTS player_town_rep');
|
||||
$db->exec('CREATE TABLE town_rep (
|
||||
player_id INTEGER NOT NULL,
|
||||
$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
|
||||
)');
|
||||
|
||||
eln(yellow('Created table: ') . 'town_rep');
|
||||
created_or_error($r, 'char_town_rep');
|
||||
|
||||
// Items
|
||||
// Items
|
||||
$db->exec('DROP TABLE IF EXISTS items');
|
||||
$db->exec('CREATE TABLE items (
|
||||
$r = $db->exec('CREATE TABLE items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL DEFAULT 0,
|
||||
|
@ -518,12 +542,16 @@ if ($database === LIVE) {
|
|||
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,
|
||||
precision 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,
|
||||
vitality 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 "",
|
||||
|
@ -531,10 +559,39 @@ if ($database === LIVE) {
|
|||
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');
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
Setup
|
||||
*/
|
||||
define('SRC', __DIR__ . '/../src');
|
||||
require_once SRC . '/bootstrap.php';
|
||||
|
||||
$r = [];
|
||||
|
||||
/*
|
||||
Home
|
||||
*/
|
||||
router_get($r, '/', function () {
|
||||
echo render('layouts/basic', ['view' => 'pages/home']);
|
||||
});
|
||||
|
||||
router_get($r, '/auth/register', 'auth_register_get');
|
||||
router_post($r, '/auth/register', 'auth_register_post');
|
||||
router_get($r, '/auth/login', 'auth_login_get');
|
||||
router_post($r, '/auth/login', 'auth_login_post');
|
||||
router_post($r, '/auth/logout', 'auth_logout');
|
||||
/*
|
||||
Auth
|
||||
*/
|
||||
router_get($r, '/auth/register', 'auth_controller_register_get');
|
||||
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]
|
||||
$l = router_lookup($r, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
||||
|
||||
if ($l['code'] !== 200) router_error($l['code']);
|
||||
$l['handler'](...$l['params'] ?? []);
|
||||
|
||||
/*
|
||||
Cleanup
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -204,3 +52,20 @@ function auth_check(): bool
|
|||
|
||||
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/session.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.
|
||||
|
@ -32,3 +37,6 @@ csrf();
|
|||
|
||||
// Have a global counter for queries
|
||||
$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
|
||||
{
|
||||
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
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()): ?>
|
||||
Hello, oppai!
|
||||
<?php if (!user()): ?>
|
||||
<h2>Welcome!</h2>
|
||||
<a href="/auth/register">Register</a>
|
||||
<a href="/auth/login">Login</a>
|
||||
<?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">
|
||||
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
||||
<input type="submit" value="Logout">
|
||||
</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; ?>
|
||||
|
|
Loading…
Reference in New Issue
Block a user