big model changes

This commit is contained in:
Sky Johnson 2024-12-17 22:10:49 -06:00
parent 3291c1caa6
commit 169e617989
12 changed files with 340 additions and 163 deletions

View File

@ -7,15 +7,13 @@ require_once '../src/bootstrap.php';
$r = new Router;
$r->get('/', function() {
global $userrow;
if ($userrow["currentaction"] == "In Town") {
if (user()->currentaction === "In Town") {
$page = dotown();
$title = "In Town";
} elseif ($userrow["currentaction"] == "Exploring") {
} elseif (user()->currentaction === "Exploring") {
$page = doexplore();
$title = "Exploring";
} elseif ($userrow["currentaction"] == "Fighting") {
} elseif (user()->currentaction === "Fighting") {
redirect('/fight');
}
@ -51,15 +49,13 @@ $l['handler'](...$l['params'] ?? []);
function donothing()
{
global $userrow;
if ($userrow["currentaction"] == "In Town") {
if (user()->currentaction == "In Town") {
$page = dotown();
$title = "In Town";
} elseif ($userrow["currentaction"] == "Exploring") {
} elseif (user()->currentaction == "Exploring") {
$page = doexplore();
$title = "Exploring";
} elseif ($userrow["currentaction"] == "Fighting") {
} elseif (user()->currentaction == "Fighting") {
redirect('/fight');
}
@ -71,9 +67,9 @@ function donothing()
*/
function dotown()
{
global $userrow, $controlrow;
global $controlrow;
$townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("There is an error with your user account, or with the town data. Please try again.","Error");
$townrow["news"] = "";
@ -119,6 +115,11 @@ function dotown()
HTML;
}
$u = User::find(1);
$u->gold += 100;
$u->save();
var_dump($u->gold);
return render('towns', ['town' => $townrow]);
}
@ -145,7 +146,7 @@ function show_character_info(int $id = 0): void
{
global $controlrow, $userrow;
$userrow = ($id === 0) ? $userrow : get_user_by_id($id);
$userrow = ($id === 0) ? $userrow : get_user($id);
if ($userrow === false) exit('Failed to show info for user ID '.$id);
$levelrow = db()->query("SELECT `{$userrow["charclass"]}_exp` FROM levels WHERE id=? LIMIT 1;", [$userrow['level'] + 1])->fetchArray(SQLITE3_ASSOC);
@ -171,12 +172,10 @@ function show_character_info(int $id = 0): void
function showmap()
{
global $userrow;
$pos = sprintf(
'<div style="position: absolute; width: 5px; height: 5px; border-radius: 1000px; border: solid 1px black; background-color: red; left: %dpx; top: %dpx;"></div>',
round(258 + $userrow['longitude'] * (500 / 500) - 3),
round(258 - $userrow['latitude'] * (500 / 500) - 3)
round(258 + user()->longitude * (500 / 500) - 3),
round(258 - user()->latitude * (500 / 500) - 3)
);
echo render('minimal', [
@ -191,13 +190,11 @@ function showmap()
*/
function babblebox()
{
global $userrow;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$safecontent = make_safe($_POST["babble"]);
if (!empty($safecontent)) {
db()->query('INSERT INTO babble (posttime, author, babble) VALUES (CURRENT_TIMESTAMP, ?, ?);',
[$userrow['username'], $safecontent]);
[user()->username, $safecontent]);
}
redirect('/babblebox');
}

View File

@ -8,8 +8,7 @@ use Router;
function register_routes(Router $r): Router
{
global $userrow;
if (isset($userrow) && $userrow !== false && $userrow['authlevel'] === 1) {
if (user('authlevel') === 1) {
$r->get('/admin', 'Admin\donothing');
$r->form('/admin/main', 'Admin\primary');

View File

@ -2,35 +2,55 @@
// explore.php :: Handles all map exploring, chances to fight, etc.
function move()
{
global $userrow, $controlrow;
function move() {
global $controlrow;
if ($userrow["currentaction"] == "Fighting") { redirect('/fight'); }
// Early exit if fighting
if (user()->currentaction == 'Fighting') redirect('/fight');
$latitude = $userrow["latitude"];
$longitude = $userrow["longitude"];
// Validate direction
$form = validate($_POST, ['direction' => ['in:north,west,east,south']]);
if (!$form['valid']) display(ul_from_validate_errors($form['errors']), 'Move Error');
$form = validate($_POST, [
'direction' => ['in:north,west,east,south']
]);
if (!$form['valid']) display(ul_from_validate_errors($form['errors']), 'Move Error');
$d = $form['data']['direction'];
// Current game state
$game_size = $controlrow['gamesize'];
$latitude = user('latitude');
$longitude = user('longitude');
$direction = $form['data']['direction'];
if ($d === 'north') { $latitude++; if ($latitude > $controlrow["gamesize"]) { $latitude = $controlrow["gamesize"]; } }
if ($d === 'south') { $latitude--; if ($latitude < ($controlrow["gamesize"]*-1)) { $latitude = ($controlrow["gamesize"]*-1); } }
if ($d === 'east') { $longitude++; if ($longitude > $controlrow["gamesize"]) { $longitude = $controlrow["gamesize"]; } }
if ($d === 'west') { $longitude--; if ($longitude < ($controlrow["gamesize"]*-1)) { $longitude = ($controlrow["gamesize"]*-1); } }
// Calculate new coordinates with boundary checks
switch ($direction) {
case 'north':
$latitude = min($latitude + 1, $game_size);
break;
case 'south':
$latitude = max($latitude - 1, -$game_size);
break;
case 'east':
$longitude = min($longitude + 1, $game_size);
break;
case 'west':
$longitude = max($longitude - 1, -$game_size);
break;
}
$town = get_town_by_xy($longitude, $latitude);
// Check for town
$town = get_town_by_xy($longitude, $latitude);
if ($town !== false) {
Towns\travelto($town['id'], false);
return;
}
$chancetofight = rand(1, 5);
$action = $chancetofight === 1 ? "currentaction='Fighting', currentfight='1'," : "currentaction='Exploring',";
// Determine action (1 in 5 chance of fighting)
$action = (rand(1, 5) === 1)
? "currentaction='Fighting', currentfight='1',"
: "currentaction='Exploring',";
// Update user's position
db()->query(
"UPDATE users SET $action latitude = ?, longitude = ?, dropcode = 0 WHERE id = ?;",
[$latitude, $longitude, user()->id]
);
db()->query("UPDATE users SET $action latitude = ?, longitude = ?, dropcode = 0 WHERE id = ?;", [$latitude, $longitude, $userrow['id']]);
redirect('/');
}

View File

@ -25,20 +25,18 @@ function register_routes(Router $r): Router
*/
function inn()
{
global $userrow;
$townrow = get_town_by_xy($userrow["longitude"], $userrow["latitude"]);
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) { display("Cheat attempt detected.<br><br>Get a life, loser.", "Error"); }
if ($userrow["gold"] < $townrow["innprice"]) {
if (user()->gold < $townrow["innprice"]) {
display("You do not have enough gold to stay at this Inn tonight.<br><br>You may return to <a href=\"/\">town</a>, or use the direction buttons on the left to start exploring.", "Inn");
}
if (isset($_POST["submit"])) {
$newgold = $userrow["gold"] - $townrow["innprice"];
$newgold = user()->gold - $townrow["innprice"];
db()->query(
'UPDATE users SET gold=?, currenthp=?, currentmp=?, currenttp=? WHERE id=?',
[$newgold, $userrow['maxhp'], $userrow['maxmp'], $userrow['maxtp'], $userrow['id']
[$newgold, user()->maxhp, user()->maxmp, user()->maxtp, user()->id
]);
$title = "Inn";
$page = "You wake up feeling refreshed and ready for action.<br><br>You may return to <a href=\"/\">town</a>, or use the direction buttons on the left to start exploring.";
@ -63,9 +61,7 @@ function inn()
*/
function buy()
{
global $userrow;
$townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("Cheat attempt detected.<br><br>Get a life, loser.", "Error");
$items = db()->query("SELECT * FROM items WHERE id IN ({$townrow["itemslist"]});");
@ -79,7 +75,7 @@ function buy()
2 => '<img src="/img/icon_armor.gif" alt="armor" /></td>',
3 => '<img src="/img/icon_shield.gif" alt="shield" /></td>'
};
if ($userrow["weaponid"] == $itemsrow["id"] || $userrow["armorid"] == $itemsrow["id"] || $userrow["shieldid"] == $itemsrow["id"]) {
if (user()->weaponid == $itemsrow["id"] || user()->armorid == $itemsrow["id"] || user()->shieldid == $itemsrow["id"]) {
$page .= "<td width=\"32%\"><span class=\"light\">".$itemsrow["name"]."</span></td><td width=\"32%\"><span class=\"light\">$attrib ".$itemsrow["attribute"]."</span></td><td width=\"32%\"><span class=\"light\">Already purchased</span></td></tr>\n";
} else {
if ($itemsrow["special"] != "X") { $specialdot = "<span class=\"highlight\">&#42;</span>"; } else { $specialdot = ""; }
@ -98,21 +94,19 @@ function buy()
*/
function buy2($id)
{
global $userrow;
$townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("Cheat attempt detected.<br><br>Get a life, loser.", "Error");
$townitems = explode(",", $townrow["itemslist"]);
if (!in_array($id, $townitems)) display("Cheat attempt detected.<br><br>Get a life, loser.", "Error");
$item = get_item($id);
if ($userrow["gold"] < $item["buycost"]) {
if (user()->gold < $item["buycost"]) {
display("You do not have enough gold to buy this item.<br><br>You may return to <a href=\"/\">town</a>, <a href=\"/buy\">store</a>, or use the direction buttons on the left to start exploring.", "Buy Items");
}
$type_to_row_mapping = [1 => 'weaponid', 2 => 'armorid', 3 => 'shieldid'];
$current_equipped_id = $userrow[$type_to_row_mapping[$item['type']] ?? 0];
$current_equipped_id = user()[$type_to_row_mapping[$item['type']] ?? 0];
if ($current_equipped_id != 0) {
$item2 = get_item($current_equipped_id);
@ -132,16 +126,14 @@ function buy3($id)
if (isset($_POST["cancel"])) redirect('/');
global $userrow;
$townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("Cheat attempt detected.<br><br>Get a life, loser.", "Error");
$townitems = explode(",", $townrow["itemslist"]);
if (!in_array($id, $townitems)) display("Cheat attempt detected.<br><br>Get a life, loser.", "Error");
$item = get_item($id);
if ($userrow["gold"] < $item["buycost"]) {
if (user()->gold < $item["buycost"]) {
display("You do not have enough gold to buy this item.<br><br>You may return to <a href=\"/\">town</a>, <a href=\"/buy\">store</a>, or use the direction buttons on the left to start exploring.", "Buy Items");
}
@ -157,7 +149,7 @@ function buy3($id)
}
// Retrieve current equipped item or create a default
$current_equip_id = $userrow[$type_mapping[$item["type"]]['id']];
$current_equip_id = user()[$type_mapping[$item["type"]]['id']];
if ($current_equip_id != 0) {
$item2 = get_item($current_equip_id);
} else {
@ -175,9 +167,9 @@ function buy3($id)
$toChange = $special[0];
$changeAmount = $index === 0 ? $special[1] : -$special[1];
$userrow[$toChange] += $changeAmount;
user()[$toChange] += $changeAmount;
$specialFields[] = "$toChange = ?";
$specialValues[] = $userrow[$toChange];
$specialValues[] = user()[$toChange];
// Adjust attack or defense power
if ($toChange == "strength" || $toChange == "dexterity") {
@ -190,15 +182,15 @@ function buy3($id)
// Determine power and type-specific updates
$currentType = $type_mapping[$item["type"]];
$powerField = $currentType['power'];
$newPower = $userrow[$powerField] + $item["attribute"] - $item2["attribute"];
$newPower = user()[$powerField] + $item["attribute"] - $item2["attribute"];
// Calculate new gold with trade-in value
$newGold = $userrow["gold"] + ceil($item2["buycost"]/2) - $item["buycost"];
$newGold = user()->gold + ceil($item2["buycost"]/2) - $item["buycost"];
// Ensure current HP/MP/TP don't exceed max values
$newhp = min($userrow["currenthp"], $userrow["maxhp"]);
$newmp = min($userrow["currentmp"], $userrow["maxmp"]);
$newtp = min($userrow["currenttp"], $userrow["maxtp"]);
$newhp = min(user()->currenthp, user()->maxhp);
$newmp = min(user()->currentmp, user()->maxmp);
$newtp = min(user()->currenttp, user()->maxtp);
$updateFields = array_merge(
$specialFields,
@ -223,7 +215,7 @@ function buy3($id)
$newhp,
$newmp,
$newtp,
$userrow["id"]
user()->id
]
);
@ -238,9 +230,7 @@ function buy3($id)
*/
function maps()
{
global $userrow;
$mappedtowns = explode(",", $userrow["towns"]);
$mappedtowns = explode(",", user()->towns);
$page = "Buying maps will put the town in your Travel To box, and it won't cost you as many TP to get there.<br><br>\n";
$page .= "Click a town name to purchase its map.<br><br>\n";
@ -272,11 +262,9 @@ function maps()
*/
function maps2($id)
{
global $userrow;
$townrow = get_town_by_id($id);
if ($userrow["gold"] < $townrow["mapprice"]) {
if (user()->gold < $townrow["mapprice"]) {
display("You do not have enough gold to buy this map.<br><br>You may return to <a href=\"/\">town</a>, <a href=\"/maps\">store</a>, or use the direction buttons on the left to start exploring.", "Buy Maps");
}
@ -292,18 +280,16 @@ function maps3($id)
{
if (isset($_POST["cancel"])) redirect('/');
global $userrow;
$townrow = get_town_by_id($id);
if ($userrow["gold"] < $townrow["mapprice"]) {
if (user()->gold < $townrow["mapprice"]) {
display("You do not have enough gold to buy this map.<br><br>You may return to <a href=\"/\">town</a>, <a href=\"/maps\">store</a>, or use the direction buttons on the left to start exploring.", "Buy Maps");
}
$mappedtowns = $userrow["towns"].",$id";
$newgold = $userrow["gold"] - $townrow["mapprice"];
$mappedtowns = user()->towns.",$id";
$newgold = user()->gold - $townrow["mapprice"];
db()->query('UPDATE users SET towns=?, gold=? WHERE id=?;', [$mappedtowns, $newgold, $userrow['id']]);
db()->query('UPDATE users SET towns=?, gold=? WHERE id=?;', [$mappedtowns, $newgold, user()->id]);
display("Thank you for purchasing this map.<br><br>You may return to <a href=\"/\">town</a>, <a href=\"/maps\">store</a>, or use the direction buttons on the left to start exploring.", "Buy Maps");
}
@ -313,32 +299,30 @@ function maps3($id)
*/
function travelto($id, bool $usepoints = true)
{
global $userrow;
if ($userrow["currentaction"] == "Fighting") redirect('/fight');
if (user()->currentaction == "Fighting") redirect('/fight');
$townrow = get_town_by_id($id);
if ($usepoints) {
if ($userrow["currenttp"] < $townrow["travelpoints"]) {
if (user()->currenttp < $townrow["travelpoints"]) {
display("You do not have enough TP to travel here. Please go back and try again when you get more TP.", "Travel To");
}
$mapped = explode(",",$userrow["towns"]);
$mapped = explode(",",user()->towns);
if (!in_array($id, $mapped)) { display("Cheat attempt detected.<br><br>Get a life, loser.", "Error"); }
}
if (($userrow["latitude"] == $townrow["latitude"]) && ($userrow["longitude"] == $townrow["longitude"])) {
if ((user()->latitude == $townrow["latitude"]) && (user()->longitude == $townrow["longitude"])) {
display("You are already in this town. <a href=\"/\">Click here</a> to return to the main town screen.", "Travel To");
}
$newtp = ($usepoints) ? $userrow["currenttp"] - $townrow["travelpoints"] : $userrow["currenttp"];
$newtp = ($usepoints) ? user()->currenttp - $townrow["travelpoints"] : user()->currenttp;
$newlat = $townrow["latitude"];
$newlon = $townrow["longitude"];
$newid = $userrow["id"];
$newid = user()->id;
// If they got here by exploring, add this town to their map.
$mapped = explode(",",$userrow["towns"]);
$mapped = explode(",",user()->towns);
$town = false;
foreach($mapped as $b) if ($b == $id) $town = true;
$mapped = implode(",", $mapped);

View File

@ -21,6 +21,8 @@ function register_routes(Router $r): Router
*/
function login()
{
global $auth;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form = validate($_POST, [
'username' => ['length:3-18', 'alpha-spaces'],
@ -33,11 +35,8 @@ function login()
}
$form = $form['data'];
$query = db()->query('SELECT id, username, password FROM users WHERE username = ? COLLATE NOCASE LIMIT 1;', [$form['username']]);
$row = $query ? $query->fetchArray(SQLITE3_ASSOC) : false;
if ($row === false || !password_verify($_POST['password'] ?? '', $row['password']))
$row = get_user($form['username']);
if ($row === false || !$auth->login($form['username'], $form['password']))
die("Invalid username or password. Please go back and try again.");
$expiretime = $form['remember'] ? time() + 31536000 : 0;
@ -56,6 +55,8 @@ function login()
*/
function logout()
{
global $auth;
$auth->logout();
set_cookie("dkgame", "", -3600);
redirect('/login');
}
@ -186,8 +187,6 @@ function changepassword()
function settings()
{
global $userrow;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form = validate($_POST, [
'game_skin' => ['in:0,1']
@ -195,7 +194,8 @@ function settings()
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
$form = $form['data'];
db()->query('UPDATE users SET game_skin=? WHERE id=?;', [$form['game_skin'], $userrow['id']]);
user()->game_skin = $form['game_skin'];
user()->save();
$alert = '<div class="alert">Settings updated</div>';
display($alert . render('settings'), "Account Settings");

104
src/auth.php Normal file
View File

@ -0,0 +1,104 @@
<?php
/*
This is an experimental new class for handling user auth. The idea is to rely as much as possible on PHP's native
session handling. When authenticated, the class will store use data in GLOBALS state.
*/
class Auth
{
/**
* Set up the auth manager; adjust PHP session settings on the fly to improve security. Starts the session for
* this request.
*/
public function __construct()
{
// enhance the native session's sessid cryptography
ini_set('session.sid_length', 64);
ini_set('session.sid_bits_per_character', 6);
session_set_cookie_params([
'lifetime' => 2592000, // 30 days
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
session_start();
$this->validate();
}
private function validate(): void
{
// Check for IP address change
if (!isset($_SESSION['ip_address'])) {
$_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
} elseif ($_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
$this->destroy(); // Possible hijacking
exit;
}
// Check for User-Agent change
if (!isset($_SESSION['user_agent'])) {
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
} elseif ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
$this->destroy(); // Possible hijacking
exit;
}
// Regenerate session ID periodically for security
if (!isset($_SESSION['last_regeneration'])) {
$_SESSION['last_regeneration'] = time();
} elseif (time() - $_SESSION['last_regeneration'] > 300) { // Every 5 minutes
$this->regenerate();
}
}
public function login(string $username, string $password): bool
{
$user = get_user($username);
if ($user === false) return false;
if (password_verify($password, $user['password'])) {
$_SESSION['authenticated'] = true;
$_SESSION['user_id'] = $user['id'];
$_SESSION['login_time'] = time();
$this->regenerate();
return true;
}
return false;
}
public function good(): bool
{
return isset($_SESSION['authenticated']) && $_SESSION['authenticated'] === true;
}
public function logout(): void
{
$this->destroy();
}
private function regenerate(): void
{
session_regenerate_id(true);
$_SESSION['last_regeneration'] = time();
}
public function destroy(): void
{
$_SESSION = [];
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
}
session_destroy();
}
}

View File

@ -2,6 +2,7 @@
require_once 'lib.php';
require_once 'router.php';
require_once 'auth.php';
require_once 'mail.php';
require_once 'actions/explore.php';
require_once 'actions/heal.php';
@ -12,11 +13,14 @@ require_once 'actions/fight.php';
require_once 'actions/forum.php';
require_once 'actions/install.php';
require_once 'actions/admin.php';
require_once 'models/model.php';
require_once 'models/user.php';
env_load('../.env');
$uri = uri();
$GLOBALS['cache'] = [];
$GLOBALS['state'] = [];
if (!file_exists('../.installed') && $uri[0] !== 'install') {
redirect('/install');
@ -29,24 +33,26 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
display("The game is currently closed for maintanence. Please check back later.", "Game Closed");
}
$auth = new Auth;
// Login (or verify) if not logged in.
if (($userrow = checkcookies()) === false) {
if (user() === false) {
if (!in_array($uri[0], ['login', 'register', 'verify', 'lostpassword', 'help'])) {
redirect('/login');
}
} else {
// Block user if he/she has been banned.
if ($userrow["authlevel"] === 2) {
if (user()->authlevel === 2) {
exit("Your account has been banned.");
}
// Force verify if the user isn't verified yet.
if ($controlrow['verifyemail'] && $userrow['verify'] !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
if ($controlrow['verifyemail'] && user()->verify !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
redirect('/verify');
}
// Ensure the user can't use the admin panel.
if ($userrow['authlevel'] !== 1 && $uri[0] === 'admin') {
if (user()->authlevel !== 1 && $uri[0] === 'admin') {
redirect('/');
}
}

View File

@ -99,10 +99,10 @@ function display_admin($content, $title)
*/
function display($content, $title, bool $topnav = true, bool $leftnav = true, bool $rightnav = true): void
{
global $userrow, $controlrow;
global $controlrow;
if ($topnav == true) {
if ($userrow !== false) { // user should be logged in
if (user() !== false) { // user should be logged in
$topnav = <<<HTML
<a href='/logout'><img src='/img/button_logout.gif' alt='Log Out' title='Log Out'></a>
<a href='/help'><img src='/img/button_help.gif' alt='Help' title='Help'></a>
@ -118,75 +118,60 @@ function display($content, $title, bool $topnav = true, bool $leftnav = true, bo
$topnav = '';
}
if (isset($userrow) && $userrow !== false) {
// Get userrow again, in case something has been updated.
$userquery = db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$userrow['id']]);
unset($userrow);
$userrow = $userquery->fetchArray(SQLITE3_ASSOC);
// Current town name.
if ($userrow['currentaction'] == 'In Town') {
$townrow = get_town_by_xy($userrow['latitude'], $userrow['longitude']);
$userrow['currenttown'] = "Welcome to <b>{$townrow['name']}</b>.<br><br>";
if (user() !== false) {
if (user()->currentaction == 'In Town') {
$town = get_town_by_xy(user()->latitude, user()->longitude);
$current_town = "Welcome to <b>{$town['name']}</b>.<br><br>";
} else {
$userrow['currenttown'] = '';
$current_town = '';
}
$userrow['forumslink'] = '<a href="/forum">Forum</a><br>';
// Format various userrow stuffs...
if ($userrow["latitude"] < 0) { $userrow["latitude"] = $userrow["latitude"] * -1 . "S"; } else { $userrow["latitude"] .= "N"; }
if ($userrow["longitude"] < 0) { $userrow["longitude"] = $userrow["longitude"] * -1 . "W"; } else { $userrow["longitude"] .= "E"; }
$userrow["experience"] = number_format($userrow["experience"]);
$userrow["gold"] = number_format($userrow["gold"]);
if ($userrow["authlevel"] == 1) { $userrow["adminlink"] = "<a href=\"/admin\">Admin</a><br>"; } else { $userrow["adminlink"] = ""; }
// HP/MP/TP bars.
$userrow['statbars'] = create_stat_table($userrow);
if (user()->latitude < 0) { user()->latitude = user()->latitude * -1 . "S"; } else { user()->latitude .= "N"; }
if (user()->longitude < 0) { user()->longitude = user()->longitude * -1 . "W"; } else { user()->longitude .= "E"; }
user()->experience = number_format(user()->experience);
user()->gold = number_format(user()->gold);
// Now make numbers stand out if they're low.
if ($userrow["currenthp"] <= ($userrow["maxhp"]/5)) { $userrow["currenthp"] = "<blink><span class=\"highlight\"><b>*".$userrow["currenthp"]."*</b></span></blink>"; }
if ($userrow["currentmp"] <= ($userrow["maxmp"]/5)) { $userrow["currentmp"] = "<blink><span class=\"highlight\"><b>*".$userrow["currentmp"]."*</b></span></blink>"; }
if (user()->currenthp <= (user()->maxhp/5)) { user()->currenthp = "<blink><span class=\"highlight\"><b>*".user()->currenthp."*</b></span></blink>"; }
if (user()->currentmp <= (user()->maxmp/5)) { user()->currentmp = "<blink><span class=\"highlight\"><b>*".user()->currentmp."*</b></span></blink>"; }
$user_spells = explode(',', $userrow['spells']);
$user_spells = explode(',', user()->spells);
$spellquery = get_spells_from_list($user_spells);
$userrow['magiclist'] = '';
user()->magiclist = '';
while ($spell = $spellquery->fetchArray(SQLITE3_ASSOC)) {
$spell = false;
foreach($user_spells as $id) {
if ($id === $spell['id'] && $spell['type'] == 1) $spell = true;
}
if ($spell == true) {
$userrow['magiclist'] .= "<a href=\"/spell/{$spell['id']}\">".$spell['name']."</a><br>";
user()->magiclist .= "<a href=\"/spell/{$spell['id']}\">".$spell['name']."</a><br>";
}
}
if ($userrow["magiclist"] == "") { $userrow["magiclist"] = "None"; }
if (user()->magiclist == "") { user()->magiclist = "None"; }
// Travel To list.
$townslist = explode(",",$userrow["towns"]);
$townslist = explode(",",user()->towns);
$townquery2 = db()->query('SELECT * FROM towns ORDER BY id;');
$userrow["townslist"] = "";
$town_list_html = '';
while ($townrow2 = $townquery2->fetchArray(SQLITE3_ASSOC)) {
$town = false;
foreach($townslist as $a => $b) {
if ($b == $townrow2["id"]) { $town = true; }
foreach($townslist as $id) {
if ($id == $townrow2["id"]) { $town = true; }
}
if ($town == true) {
$userrow["townslist"] .= "<a href=\"/gotown/{$townrow2["id"]}\">".$townrow2["name"]."</a><br>\n";
$town_list_html .= "<a href=\"/gotown/{$townrow2["id"]}\">".$townrow2["name"]."</a><br>\n";
}
}
} else {
$userrow = [];
}
echo render('primary', [
"dkgamename" => $controlrow["gamename"],
"title" => $title,
"content" => $content,
"game_skin" => $userrow['game_skin'] ??= '0',
'rightnav' => $rightnav ? render('rightnav', ['user' => $userrow]) : '',
"leftnav" => $leftnav ? render('leftnav', ['user' => $userrow]) : '',
"game_skin" => user()->game_skin ??= '0',
'rightnav' => $rightnav ? render('rightnav', ['statbars' => create_stat_table(user())]) : '',
"leftnav" => $leftnav ? render('leftnav', ['town_list' => $town_list_html, 'current_town' => $current_town]) : '',
"topnav" => $topnav,
"totaltime" => round(microtime(true) - START, 4),
"numqueries" => db()->count,
@ -271,11 +256,14 @@ function get_town_by_id(int $id): array|false
}
/**
* Get a user's data by their ID.
* Get a user's data by their ID, username or email.
*/
function get_user_by_id(int $id): array|false
function get_user(int|string $id, string $data = '*'): array|false
{
$query = db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$id]);
$query = db()->query(
"SELECT $data FROM users WHERE id=? OR username=? COLLATE NOCASE OR email=? COLLATE NOCASE LIMIT 1;",
[$id, $id, $id]
);
if ($query === false) return false;
return $query->fetchArray(SQLITE3_ASSOC);
}
@ -610,11 +598,20 @@ function create_stat_table($userrow)
{
$stat_table = '<div class="stat-table">' .
'<div class="stat-row">' .
'<div class="stat-col">' . generate_stat_bar($userrow['currenthp'], $userrow['maxhp']) . '<div>HP</div></div>' .
'<div class="stat-col">' . generate_stat_bar($userrow['currentmp'], $userrow['maxmp']) . '<div>MP</div></div>' .
'<div class="stat-col">' . generate_stat_bar($userrow['currenttp'], $userrow['maxtp']) . '<div>TP</div></div>' .
'<div class="stat-col">' . generate_stat_bar(user()->currenthp, user()->maxhp) . '<div>HP</div></div>' .
'<div class="stat-col">' . generate_stat_bar(user()->currentmp, user()->maxmp) . '<div>MP</div></div>' .
'<div class="stat-col">' . generate_stat_bar(user()->currenttp, user()->maxtp) . '<div>TP</div></div>' .
'</div>' .
'</div>';
return $stat_table;
}
/**
* Returns the user in the GLOBALS state, if there is one. If not, populates it if there is a SESSION user_id.
*/
function user(): User|false
{
$GLOBALS['state']['user'] ??= ($_SESSION['user_id'] ? User::find($_SESSION['user_id']) : false);
return $GLOBALS['state']['user'];
}

42
src/models/model.php Normal file
View File

@ -0,0 +1,42 @@
<?php
class Model
{
protected string $table_name = '';
protected array $original_data = [];
protected array $changes = [];
public function __construct(array $data)
{
$this->original_data = $data;
$this->changes = [];
}
public function __get(string $key): mixed
{
return array_key_exists($key, $this->changes) ? $this->changes[$key] : $this->original_data[$key] ?? false;
}
public function __set(string $key, mixed $value): void
{
if (array_key_exists($key, $this->original_data)) $this->changes[$key] = $value;
}
public function save(): bool
{
if (empty($this->changes)) return true;
$placeholders = [];
$values = [];
foreach ($this->changes as $key => $value) {
$placeholders[] = "$key=?";
$values[] = $value;
}
$values[] = $this->id;
$query = 'UPDATE ' . $this->table_name . ' SET ' . implode(', ', $placeholders) . ' WHERE id = ?;';
$result = db()->query($query, $values);
return $result === false ? false : true;
}
}

21
src/models/user.php Normal file
View File

@ -0,0 +1,21 @@
<?php
class User extends Model
{
protected string $table_name = 'users';
/**
* Find a user by their ID, username or email. Returns false on any failure.
*/
public static function find(int|string $id): User|false
{
$query = db()->query(
"SELECT * FROM users WHERE id=? OR username=? COLLATE NOCASE OR email=? COLLATE NOCASE LIMIT 1;",
[$id, $id, $id]
);
if ($query === false) return false;
$data = $query->fetchArray(SQLITE3_ASSOC);
if ($data === false) return false;
return new User($data);
}
}

View File

@ -1,8 +1,8 @@
<section>
<div class="title"><img src="/img/button_location.gif" alt="Location" title="Location"></div>
Currently: <?= $user['currentaction'] ?><br>
Latitude: <?= $user['latitude'] ?><br>
Longitude: <?= $user['longitude'] ?><br>
Currently: <?= user()->currentaction ?><br>
Latitude: <?= user()->latitude ?><br>
Longitude: <?= user()->longitude ?><br>
<a href="javascript:openmappopup()">View Map</a><br>
<form action="/move" method="post" class="move-compass">
<button type="submit" name="direction" value="north" class="north">North</button>
@ -16,18 +16,25 @@
<section>
<div class="title"><img src="/img/button_towns.gif" alt="Towns" title="Towns"></div>
<?= $user['currenttown'] ?>
<?php
if (user()->currentaction == 'In Town') {
$town = get_town_by_xy((int) user()->latitude, (int) user()->longitude);
echo "Welcome to <b>{$town['name']}</b>.<br><br>";
}
?>
Travel To:<br>
<?= $user['townslist'] ?>
<?= $town_list ?>
</section>
<section>
<div class="title"><img src="/img/button_functions.gif" alt="Functions" title="Functions"></div>
<a href="/">Home</a><br>
<?= $user['forumslink'] ?>
<?= $user['adminlink'] ?>
<a href="/forum">Forum</a><br>
<a href="/settings">Settings</a><br>
<a href="/changepassword">Change Password</a><br>
<a href="/logout">Log Out</a><br>
<?php if (user()->authlevel === 1): ?>
<a href="/admin">Admin</a><br>
<?php endif; ?>
<a href="/help">Help</a>
</section>

View File

@ -1,13 +1,13 @@
<section>
<div class="title"><img src="/img/button_character.gif" alt="Character" title="Character"></div>
<b><?= $user['username'] ?></b><br>
Level: <?= $user['level'] ?><br>
Exp: <?= $user['experience'] ?><br>
Gold: <?= $user['gold'] ?><br>
HP: <?= $user['currenthp'] ?><br>
MP: <?= $user['currentmp'] ?><br>
TP: <?= $user['currenttp'] ?><br><br>
<?= $user['statbars'] ?><br>
<b><?= user()->username ?></b><br>
Level: <?= user()->level ?><br>
Exp: <?= user()->experience ?><br>
Gold: <?= user()->gold ?><br>
HP: <?= user()->currenthp ?><br>
MP: <?= user()->currentmp ?><br>
TP: <?= user()->currenttp ?><br><br>
<?= $statbars ?><br>
<a href="javascript:opencharpopup()">Extended Stats</a>
</section>