Compare commits
4 Commits
3bc53c1a31
...
169e617989
Author | SHA1 | Date | |
---|---|---|---|
169e617989 | |||
3291c1caa6 | |||
f7f6e7fb97 | |||
ae0f0802cb |
6
.env.example
Normal file
6
.env.example
Normal file
|
@ -0,0 +1,6 @@
|
|||
debug = true
|
||||
smtp_host = smtp.foobar.com
|
||||
smtp_port = 546
|
||||
smtp_encryption = tls
|
||||
smtp_username = foo
|
||||
smtp_password = bar123
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
.installed
|
||||
database.db
|
||||
database.db-*
|
||||
.env
|
||||
logs
|
||||
|
|
|
@ -8,7 +8,11 @@ html {
|
|||
}
|
||||
|
||||
body {
|
||||
background-image: url('/img/background.jpg');
|
||||
background-image: url('/img/backgrounds/classic.jpg');
|
||||
|
||||
&.skin-1 {
|
||||
background-image: url('/img/backgrounds/snowstorm.jpg');
|
||||
}
|
||||
}
|
||||
|
||||
div#game-container {
|
||||
|
@ -179,3 +183,19 @@ div.town-content {
|
|||
div.town-content div.options, div.town-content div.news {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
div.stat-table div.stat-row {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
div.stat-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.stat-bar > div {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
BIN
public/img/backgrounds/snowstorm.jpg
Normal file
BIN
public/img/backgrounds/snowstorm.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 386 KiB |
|
@ -7,20 +7,18 @@ 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');
|
||||
}
|
||||
|
||||
display($page, $title);
|
||||
})->middleware('auth_only');
|
||||
});
|
||||
|
||||
$r->get('/ninja', function() {
|
||||
exit('NINJA! 🥷');
|
||||
|
@ -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"] = "";
|
||||
|
@ -89,7 +85,12 @@ function dotown()
|
|||
|
||||
// Who's Online. Currently just members. Guests maybe later.
|
||||
if ($controlrow["showonline"] == 1) {
|
||||
$onlinequery = db()->query("SELECT id, username FROM users WHERE strftime('%s', onlinetime) >= strftime('%s', 'now') - 600 ORDER BY username");
|
||||
$onlinequery = db()->query(<<<SQL
|
||||
SELECT id, username
|
||||
FROM users
|
||||
WHERE onlinetime >= datetime('now', '-600 seconds')
|
||||
ORDER BY username;
|
||||
SQL);
|
||||
|
||||
$online_count = 0;
|
||||
$online_rows = [];
|
||||
|
@ -114,6 +115,11 @@ function dotown()
|
|||
HTML;
|
||||
}
|
||||
|
||||
$u = User::find(1);
|
||||
$u->gold += 100;
|
||||
$u->save();
|
||||
var_dump($u->gold);
|
||||
|
||||
return render('towns', ['town' => $townrow]);
|
||||
}
|
||||
|
||||
|
@ -140,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);
|
||||
|
@ -166,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', [
|
||||
|
@ -186,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');
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
56
src/actions/explore.php
Normal file
56
src/actions/explore.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
// explore.php :: Handles all map exploring, chances to fight, etc.
|
||||
|
||||
function move() {
|
||||
global $controlrow;
|
||||
|
||||
// Early exit if fighting
|
||||
if (user()->currentaction == 'Fighting') redirect('/fight');
|
||||
|
||||
// Validate direction
|
||||
$form = validate($_POST, ['direction' => ['in:north,west,east,south']]);
|
||||
if (!$form['valid']) display(ul_from_validate_errors($form['errors']), 'Move Error');
|
||||
|
||||
// Current game state
|
||||
$game_size = $controlrow['gamesize'];
|
||||
$latitude = user('latitude');
|
||||
$longitude = user('longitude');
|
||||
$direction = $form['data']['direction'];
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Check for town
|
||||
$town = get_town_by_xy($longitude, $latitude);
|
||||
if ($town !== false) {
|
||||
Towns\travelto($town['id'], false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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]
|
||||
);
|
||||
|
||||
redirect('/');
|
||||
}
|
|
@ -41,6 +41,8 @@ function first()
|
|||
*/
|
||||
function second()
|
||||
{
|
||||
if (file_exists('../database.db')) unlink('../database.db');
|
||||
|
||||
echo "<html><head><title>Dragon Knight Installation</title></head><body><b>Dragon Knight Installation: Page Two</b><br><br>";
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
|
@ -52,7 +54,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Babble Box table created.<br>' : 'Error creating Babble Box table.';
|
||||
echo table_status_msg($query === true, 'Babble', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE control (
|
||||
|
@ -72,11 +74,14 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Control table created.<br>' : 'Error creating Control table.';
|
||||
echo table_status_msg($query === true, 'Control', 'create');
|
||||
|
||||
$query = db()->exec("INSERT INTO control VALUES (1, 'Dragon Knight', 250, 1, '', '', 'Mage', 'Warrior', 'Paladin', 1, 1, 1, 1);");
|
||||
$query = db()->query("INSERT INTO control VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [
|
||||
1, 'Dragon Knight', 250, 1, $_SERVER['SERVER_NAME'], 'noreply@'.$_SERVER['SERVER_NAME'],
|
||||
'Mage', 'Warrior', 'Paladin', 1, 1, 1, 1
|
||||
]);
|
||||
|
||||
echo $query === true ? 'Control table populated.<br>' : 'Error populating Control table.';
|
||||
echo table_status_msg($query !== false, 'Control', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE drops (
|
||||
|
@ -89,7 +94,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query == true ? 'Drops table created.<br>' : 'Error creating Drops table.';
|
||||
echo table_status_msg($query === true, 'Drops', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
INSERT INTO drops VALUES
|
||||
|
@ -127,7 +132,7 @@ function second()
|
|||
(32, 'Fortune Drop', 5, 1, 'goldbonus,10', 'X');
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Drops table populated.<br>' : 'Error populating Drops table.';
|
||||
echo table_status_msg($query === true, 'Drops', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE forum (
|
||||
|
@ -142,7 +147,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Forum table created.<br>' : 'Error creating Forum table.';
|
||||
echo table_status_msg($query === true, 'Forum', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE items (
|
||||
|
@ -155,7 +160,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Items table created.<br>' : 'Error creating Items table.';
|
||||
echo table_status_msg($query === true, 'Items', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
INSERT INTO items VALUES
|
||||
|
@ -194,7 +199,7 @@ function second()
|
|||
(33, 3, 'Destiny Aegis', 25000, 100, 'maxhp,50');
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Items table populated.<br>' : 'Error populating Items table.';
|
||||
echo table_status_msg($query === true, 'Drops', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE levels (
|
||||
|
@ -223,7 +228,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Levels table created.<br>' : 'Error creating Levels table.';
|
||||
echo table_status_msg($query === true, 'Levels', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
INSERT INTO levels VALUES
|
||||
|
@ -329,7 +334,7 @@ function second()
|
|||
(100, 16777215, 0, 0, 0, 0, 0, 0, 16777215, 0, 0, 0, 0, 0, 0, 16777215, 0, 0, 0, 0, 0, 0);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Levels table populated.<br>' : 'Error populating Levels table.';
|
||||
echo table_status_msg($query === true, 'Levels', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE monsters (
|
||||
|
@ -345,7 +350,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Monsters table created.<br>' : 'Error creating Monsters table.';
|
||||
echo table_status_msg($query === true, 'Monsters', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
INSERT INTO monsters VALUES
|
||||
|
@ -502,7 +507,7 @@ function second()
|
|||
(151, 'Lucifuge', 600, 600, 400, 50, 10000, 10000, 2);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Monsters table populated.<br>' : 'Error populating Monsters table.';
|
||||
echo table_status_msg($query === true, 'Monsters', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE news (
|
||||
|
@ -513,11 +518,11 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'News table created.<br>' : 'Error creating News table.';
|
||||
echo table_status_msg($query === true, 'News', 'create');
|
||||
|
||||
$query = db()->exec("INSERT INTO news (content) VALUES ('This is the first news post. Please use the admin control panel to add another one and make this one go away.');");
|
||||
|
||||
echo $query === true ? 'News table populated.<br>' : 'Error populating News table.';
|
||||
echo table_status_msg($query === true, 'News', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE spells (
|
||||
|
@ -529,7 +534,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Spells table created.<br>' : 'Error creating Spells table.';
|
||||
echo table_status_msg($query === true, 'Spells', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
INSERT INTO spells VALUES
|
||||
|
@ -554,7 +559,7 @@ function second()
|
|||
(19, 'Barrier', 30, 50, 5);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Spells table populated.<br>' : 'Error populating Spells table.';
|
||||
echo table_status_msg($query === true, 'Spells', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE towns (
|
||||
|
@ -569,7 +574,7 @@ function second()
|
|||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Towns table created.<br>' : 'Error creating Towns table.';
|
||||
echo table_status_msg($query === true, 'Towns', 'create');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
INSERT INTO towns VALUES
|
||||
|
@ -583,7 +588,7 @@ function second()
|
|||
(8, 'Endworld', -250, -250, 125, 9000, 160, '16,27,33');
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Towns table populated.<br>' : 'Error populating Towns table.';
|
||||
echo table_status_msg($query === true, 'Towns', 'populate');
|
||||
|
||||
$query = db()->exec(<<<SQL
|
||||
CREATE TABLE users (
|
||||
|
@ -635,11 +640,12 @@ function second()
|
|||
`slot3name` TEXT NOT NULL default 'None',
|
||||
`dropcode` INTEGER NOT NULL default 0,
|
||||
`spells` TEXT NOT NULL default '0',
|
||||
`towns` TEXT NOT NULL default '0'
|
||||
`towns` TEXT NOT NULL default '0',
|
||||
`game_skin` INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
SQL);
|
||||
|
||||
echo $query === true ? 'Users table created.<br>' : 'Error creating Users table.';
|
||||
echo table_status_msg($query === true, 'Users', 'create');
|
||||
|
||||
$time = round((microtime(true) - START), 4);
|
||||
echo "<br>Database setup complete in $time seconds.<br><br><a href=\"/install/third\">Click here to continue with installation.</a></body></html>";
|
||||
|
@ -691,7 +697,7 @@ function fourth()
|
|||
|
||||
$form = $form['data'];
|
||||
if (db()->query(
|
||||
"INSERT INTO users (username, password, email, verify, charclass, authlevel) VALUES (?, ?, ?, 1, ?, 1)",
|
||||
"INSERT INTO users (username, password, email, verify, charclass, authlevel) VALUES (?, ?, ?, 'g2g', ?, 1)",
|
||||
[$form['username'], password_hash($form['password'], PASSWORD_ARGON2ID), $form['email'], $form['charclass']]
|
||||
) === false) {
|
||||
exit("Failed to create user.");
|
||||
|
@ -742,3 +748,17 @@ function fifth()
|
|||
</html>
|
||||
HTML;
|
||||
}
|
||||
|
||||
function table_status_msg(bool $condition, string $table_name, string $verb): string
|
||||
{
|
||||
$verb = match($verb) {
|
||||
'create' => ['created', 'creating'],
|
||||
'populate' => ['populated', 'populating']
|
||||
};
|
||||
|
||||
if ($condition === false) {
|
||||
return "Error {$verb[1]} $table_name table. (".db()->lastErrorMsg().")<br>";
|
||||
}
|
||||
|
||||
return "$table_name table {$verb[0]}.<br>";
|
||||
}
|
||||
|
|
|
@ -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\">*</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);
|
||||
|
|
|
@ -12,6 +12,7 @@ function register_routes(Router $r): Router
|
|||
$r->form('/lostpassword', 'Users\lostpassword');
|
||||
$r->form('/changepassword', 'Users\changepassword');
|
||||
$r->form('/verify', 'Users\verify');
|
||||
$r->form('/settings', 'Users\settings');
|
||||
return $r;
|
||||
}
|
||||
|
||||
|
@ -20,7 +21,7 @@ function register_routes(Router $r): Router
|
|||
*/
|
||||
function login()
|
||||
{
|
||||
if (checkcookies() !== false) redirect('/');
|
||||
global $auth;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$form = validate($_POST, [
|
||||
|
@ -34,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;
|
||||
|
@ -57,6 +55,8 @@ function login()
|
|||
*/
|
||||
function logout()
|
||||
{
|
||||
global $auth;
|
||||
$auth->logout();
|
||||
set_cookie("dkgame", "", -3600);
|
||||
redirect('/login');
|
||||
}
|
||||
|
@ -185,75 +185,58 @@ function changepassword()
|
|||
display(render('changepassword'), "Change Password", true, false, false);
|
||||
}
|
||||
|
||||
function settings()
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$form = validate($_POST, [
|
||||
'game_skin' => ['in:0,1']
|
||||
]);
|
||||
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
|
||||
$form = $form['data'];
|
||||
|
||||
user()->game_skin = $form['game_skin'];
|
||||
user()->save();
|
||||
|
||||
$alert = '<div class="alert">Settings updated</div>';
|
||||
display($alert . render('settings'), "Account Settings");
|
||||
}
|
||||
|
||||
display(render('settings'), "Account Settings");
|
||||
}
|
||||
|
||||
function sendpassemail($emailaddress, $password)
|
||||
{
|
||||
global $controlrow;
|
||||
extract($controlrow);
|
||||
|
||||
$email = <<<HTML
|
||||
You or someone using your email address submitted a Lost Password application on the $gamename server, located at $gameurl.
|
||||
You or someone using your email address submitted a Lost Password application on the $gamename server, located at $gameurl.
|
||||
|
||||
We have issued you a new password so you can log back into the game.
|
||||
We have issued you a new password so you can log back into the game.
|
||||
|
||||
Your new password is: $password
|
||||
Your new password is: $password
|
||||
|
||||
Thanks for playing.
|
||||
Thanks for playing.
|
||||
HTML;
|
||||
|
||||
$status = mymail($emailaddress, "$gamename Lost Password", $email);
|
||||
return $status;
|
||||
return send_email($emailaddress, "$gamename Lost Password", $email);
|
||||
}
|
||||
|
||||
function sendregmail($emailaddress, $vercode)
|
||||
{
|
||||
global $controlrow;
|
||||
extract($controlrow);
|
||||
$verurl = $gameurl . "?do=verify";
|
||||
$verurl = $gameurl . "/verify";
|
||||
|
||||
$email = <<<HTML
|
||||
You or someone using your email address recently signed up for an account on the $gamename server, located at $gameurl.
|
||||
You or someone using your email address recently signed up for an account on the $gamename server, located at $gameurl.
|
||||
|
||||
This email is sent to verify your registration email. In order to begin using your account, you must verify your email address.
|
||||
Please visit the Verification Page ($verurl) and enter the code below to activate your account.
|
||||
Verification code: $vercode
|
||||
This email is sent to verify your registration email. In order to begin using your account, you must verify your email address.
|
||||
Please visit the Verification Page ($verurl) and enter the code below to activate your account.
|
||||
Verification code: $vercode
|
||||
|
||||
If you were not the person who signed up for the game, please disregard this message. You will not be emailed again.
|
||||
If you were not the person who signed up for the game, please disregard this message. You will not be emailed again.
|
||||
HTML;
|
||||
|
||||
$status = mymail($emailaddress, "$gamename Account Verification", $email);
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* thanks to arto dot PLEASE dot DO dot NOT dot SPAM at artoaaltonen dot fi.
|
||||
*/
|
||||
function mymail($to, $title, $body, $from = '')
|
||||
{
|
||||
global $controlrow;
|
||||
extract($controlrow);
|
||||
|
||||
$from = trim($from);
|
||||
|
||||
if (!$from) $from = '<'.$controlrow["adminemail"].'>';
|
||||
|
||||
$rp = $controlrow["adminemail"];
|
||||
$org = '$gameurl';
|
||||
$mailer = 'PHP';
|
||||
|
||||
$head = '';
|
||||
$head .= "Content-Type: text/plain \r\n";
|
||||
$head .= "Date: ". date('r'). " \r\n";
|
||||
$head .= "Return-Path: $rp \r\n";
|
||||
$head .= "From: $from \r\n";
|
||||
$head .= "Sender: $from \r\n";
|
||||
$head .= "Reply-To: $from \r\n";
|
||||
$head .= "Organization: $org \r\n";
|
||||
$head .= "X-Sender: $from \r\n";
|
||||
$head .= "X-Priority: 3 \r\n";
|
||||
$head .= "X-Mailer: $mailer \r\n";
|
||||
|
||||
$body = str_replace("\r\n", "\n", $body);
|
||||
$body = str_replace("\n", "\r\n", $body);
|
||||
|
||||
return mail($to, $title, $body, $head);
|
||||
return send_email($emailaddress, "$gamename Account Verification", $email);
|
||||
}
|
||||
|
|
104
src/auth.php
Normal file
104
src/auth.php
Normal 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();
|
||||
}
|
||||
}
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
require_once 'lib.php';
|
||||
require_once 'router.php';
|
||||
require_once 'explore.php';
|
||||
require_once 'heal.php';
|
||||
require_once 'auth.php';
|
||||
require_once 'mail.php';
|
||||
require_once 'actions/explore.php';
|
||||
require_once 'actions/heal.php';
|
||||
require_once 'actions/users.php';
|
||||
require_once 'actions/help.php';
|
||||
require_once 'actions/towns.php';
|
||||
|
@ -11,8 +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');
|
||||
|
@ -25,26 +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"] && (bool) $userrow["verify"] === false) {
|
||||
if ($controlrow['verifyemail'] && user()->verify !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
|
||||
redirect('/verify');
|
||||
header("Location: users.php?do=verify");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Ensure the user can't use the admin panel.
|
||||
if ($userrow['authlevel'] !== 1 && $uri[0] === 'admin') {
|
||||
if (user()->authlevel !== 1 && $uri[0] === 'admin') {
|
||||
redirect('/');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,12 +28,18 @@ class Database extends SQLite3
|
|||
public function query(string $query, array $params = []): SQLite3Result|false
|
||||
{
|
||||
$p = strpos($query, '?') !== false;
|
||||
$stmt = $this->prepare($query);
|
||||
foreach ($params ?? [] as $k => $v) $stmt->bindValue($p ? $k + 1 : $k, $v, $this->getSQLiteType($v));
|
||||
try {
|
||||
$stmt = $this->prepare($query);
|
||||
foreach ($params ?? [] as $k => $v) $stmt->bindValue($p ? $k + 1 : $k, $v, $this->getSQLiteType($v));
|
||||
} catch (Exception $e) {
|
||||
exit("Failed to prepare query ($query): ".$this->lastErrorMsg());
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
$r = $stmt->execute();
|
||||
$this->log($query, microtime(true) - $start);
|
||||
$error = '';
|
||||
$r = $stmt->execute();
|
||||
|
||||
$this->log($query, microtime(true) - $start, $error);
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
@ -68,11 +74,11 @@ class Database extends SQLite3
|
|||
/**
|
||||
* Log the query, including the time it took. Increment the query counter.
|
||||
*/
|
||||
private function log(string $query, float $time_taken): void
|
||||
private function log(string $query, float $time_taken, string $error = ''): void
|
||||
{
|
||||
$this->count++;
|
||||
$this->query_time += $time_taken;
|
||||
$this->log[] = [$query, $time_taken];
|
||||
$this->log[] = [$query, $time_taken, $error];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
// explore.php :: Handles all map exploring, chances to fight, etc.
|
||||
|
||||
function move()
|
||||
{
|
||||
global $userrow, $controlrow;
|
||||
|
||||
if ($userrow["currentaction"] == "Fighting") { redirect('/fight'); }
|
||||
|
||||
$latitude = $userrow["latitude"];
|
||||
$longitude = $userrow["longitude"];
|
||||
|
||||
$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'];
|
||||
|
||||
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); } }
|
||||
|
||||
$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',";
|
||||
|
||||
db()->query("UPDATE users SET $action latitude = ?, longitude = ?, dropcode = 0 WHERE id = ?;", [$latitude, $longitude, $userrow['id']]);
|
||||
redirect('/');
|
||||
}
|
202
src/lib.php
202
src/lib.php
|
@ -5,7 +5,6 @@ require_once __DIR__ . '/database.php';
|
|||
define('VERSION', '1.2.5');
|
||||
define('BUILD', 'Reawaken');
|
||||
define('START', microtime(true));
|
||||
define('DEBUG', false);
|
||||
|
||||
/**
|
||||
* Open or get SQLite database connection.
|
||||
|
@ -100,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>
|
||||
|
@ -119,101 +118,66 @@ 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") {
|
||||
$townquery = db()->query('SELECT * FROM towns WHERE latitude = ? AND longitude = ? LIMIT 1;', [$userrow["latitude"], $userrow["longitude"]]);
|
||||
$townrow = $townquery->fetchArray(SQLITE3_ASSOC);
|
||||
$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.
|
||||
$stathp = ceil($userrow["currenthp"] / $userrow["maxhp"] * 100);
|
||||
if ($userrow["maxmp"] != 0) { $statmp = ceil($userrow["currentmp"] / $userrow["maxmp"] * 100); } else { $statmp = 0; }
|
||||
$stattp = ceil($userrow["currenttp"] / $userrow["maxtp"] * 100);
|
||||
$stattable = "<table width=\"100\"><tr><td width=\"33%\">\n";
|
||||
$stattable .= "<table cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding:0px; width:15px; height:100px; border:solid 1px black; vertical-align:bottom;\">\n";
|
||||
if ($stathp >= 66) { $stattable .= "<div style=\"padding:0px; height:".$stathp."px; border-top:solid 1px black; background-image:url(/img/bars_green.gif);\"><img src=\"/img/bars_green.gif\" alt=\"\" /></div>"; }
|
||||
if ($stathp < 66 && $stathp >= 33) { $stattable .= "<div style=\"padding:0px; height:".$stathp."px; border-top:solid 1px black; background-image:url(/img/bars_yellow.gif);\"><img src=\"/img/bars_yellow.gif\" alt=\"\" /></div>"; }
|
||||
if ($stathp < 33) { $stattable .= "<div style=\"padding:0px; height:".$stathp."px; border-top:solid 1px black; background-image:url(/img/bars_red.gif);\"><img src=\"/img/bars_red.gif\" alt=\"\" /></div>"; }
|
||||
$stattable .= "</td></tr></table></td><td width=\"33%\">\n";
|
||||
$stattable .= "<table cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding:0px; width:15px; height:100px; border:solid 1px black; vertical-align:bottom;\">\n";
|
||||
if ($statmp >= 66) { $stattable .= "<div style=\"padding:0px; height:".$statmp."px; border-top:solid 1px black; background-image:url(/img/bars_green.gif);\"><img src=\"/img/bars_green.gif\" alt=\"\" /></div>"; }
|
||||
if ($statmp < 66 && $statmp >= 33) { $stattable .= "<div style=\"padding:0px; height:".$statmp."px; border-top:solid 1px black; background-image:url(/img/bars_yellow.gif);\"><img src=\"/img/bars_yellow.gif\" alt=\"\" /></div>"; }
|
||||
if ($statmp < 33) { $stattable .= "<div style=\"padding:0px; height:".$statmp."px; border-top:solid 1px black; background-image:url(/img/bars_red.gif);\"><img src=\"/img/bars_red.gif\" alt=\"\" /></div>"; }
|
||||
$stattable .= "</td></tr></table></td><td width=\"33%\">\n";
|
||||
$stattable .= "<table cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"padding:0px; width:15px; height:100px; border:solid 1px black; vertical-align:bottom;\">\n";
|
||||
if ($stattp >= 66) { $stattable .= "<div style=\"padding:0px; height:".$stattp."px; border-top:solid 1px black; background-image:url(/img/bars_green.gif);\"><img src=\"/img/bars_green.gif\" alt=\"\" /></div>"; }
|
||||
if ($stattp < 66 && $stattp >= 33) { $stattable .= "<div style=\"padding:0px; height:".$stattp."px; border-top:solid 1px black; background-image:url(/img/bars_yellow.gif);\"><img src=\"/img/bars_yellow.gif\" alt=\"\" /></div>"; }
|
||||
if ($stattp < 33) { $stattable .= "<div style=\"padding:0px; height:".$stattp."px; border-top:solid 1px black; background-image:url(/img/bars_red.gif);\"><img src=\"/img/bars_red.gif\" alt=\"\" /></div>"; }
|
||||
$stattable .= "</td></tr></table></td>\n";
|
||||
$stattable .= "</tr><tr><td>HP</td><td>MP</td><td>TP</td></tr></table>\n";
|
||||
$userrow["statbars"] = $stattable;
|
||||
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>"; }
|
||||
|
||||
$spellquery = db()->query('SELECT id, name, type FROM spells;');
|
||||
$userspells = explode(",",$userrow["spells"]);
|
||||
$userrow["magiclist"] = "";
|
||||
while ($spellrow = $spellquery->fetchArray(SQLITE3_ASSOC)) {
|
||||
$user_spells = explode(',', user()->spells);
|
||||
$spellquery = get_spells_from_list($user_spells);
|
||||
user()->magiclist = '';
|
||||
while ($spell = $spellquery->fetchArray(SQLITE3_ASSOC)) {
|
||||
$spell = false;
|
||||
foreach($userspells as $a => $b) {
|
||||
if ($b == $spellrow["id"] && $spellrow["type"] == 1) { $spell = true; }
|
||||
foreach($user_spells as $id) {
|
||||
if ($id === $spell['id'] && $spell['type'] == 1) $spell = true;
|
||||
}
|
||||
if ($spell == true) {
|
||||
$userrow["magiclist"] .= "<a href=\"/spell/{$spellrow["id"]}\">".$spellrow["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,
|
||||
'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,
|
||||
"version" => VERSION,
|
||||
"build" => BUILD,
|
||||
"querylog" => DEBUG ? db()->log : []
|
||||
"querylog" => env('debug', false) ? db()->log : []
|
||||
]);
|
||||
|
||||
exit;
|
||||
|
@ -270,9 +234,15 @@ function get_control_row(): array|false
|
|||
*/
|
||||
function get_town_by_xy(int $x, int $y): array|false
|
||||
{
|
||||
$query = db()->query('SELECT * FROM towns WHERE longitude = ? AND latitude = ? LIMIT 1;', [$x, $y]);
|
||||
if ($query === false) return false;
|
||||
return $query->fetchArray(SQLITE3_ASSOC);
|
||||
$cache_tag = "town-$x-$y";
|
||||
|
||||
if (!isset($GLOBALS['cache'][$cache_tag])) {
|
||||
$query = db()->query('SELECT * FROM towns WHERE longitude = ? AND latitude = ? LIMIT 1;', [$x, $y]);
|
||||
if ($query === false) return false;
|
||||
$GLOBALS['cache'][$cache_tag] = $query->fetchArray(SQLITE3_ASSOC);
|
||||
}
|
||||
|
||||
return $GLOBALS['cache'][$cache_tag];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,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);
|
||||
}
|
||||
|
@ -554,18 +527,91 @@ function uri(): array
|
|||
}
|
||||
|
||||
/**
|
||||
* Redirect to login if not authenticated.
|
||||
* Load the environment variables from the .env file.
|
||||
*/
|
||||
function auth_only(): void
|
||||
function env_load(string $filePath): void
|
||||
{
|
||||
if (!checkcookies()) redirect('/login');
|
||||
if (!file_exists($filePath)) throw new Exception("The .env file does not exist. (el)");
|
||||
|
||||
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
|
||||
// Skip lines that are empty after trimming or are comments
|
||||
if ($line === '' || str_starts_with($line, '#')) continue;
|
||||
|
||||
// Skip lines without an '=' character
|
||||
if (strpos($line, '=') === false) continue;
|
||||
|
||||
[$name, $value] = explode('=', $line, 2);
|
||||
|
||||
$name = trim($name);
|
||||
$value = trim($value, " \t\n\r\0\x0B\"'"); // Trim whitespace and quotes
|
||||
|
||||
if (!array_key_exists($name, $_SERVER) && !array_key_exists($name, $_ENV)) {
|
||||
putenv("$name=$value");
|
||||
$_ENV[$name] = $value;
|
||||
$_SERVER[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an environment variable.
|
||||
*/
|
||||
function env(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$v = $_ENV[$key] ?? $_SERVER[$key] ?? (getenv($key) ?: $default);
|
||||
return match(true) {
|
||||
$v === 'true' => true,
|
||||
$v === 'false' => false,
|
||||
is_numeric($v) => (int) $v,
|
||||
is_float($v) => (float) $v,
|
||||
default => $v
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to home if authenticated.
|
||||
* Get the data on spells from a given list of IDs.
|
||||
*/
|
||||
function guest_only(): void
|
||||
function get_spells_from_list(array|string $spell_ids): SQLite3Result|false
|
||||
{
|
||||
if (checkcookies()) redirect('/login');
|
||||
if (is_string($spell_ids)) $spell_ids = explode(',', $spell_ids);
|
||||
$placeholders = implode(',', array_fill(0, count($spell_ids), '?'));
|
||||
$query = db()->query("SELECT id, name, type FROM spells WHERE id IN($placeholders)", $spell_ids);
|
||||
if ($query === false) return false;
|
||||
return $query;
|
||||
}
|
||||
|
||||
function generate_stat_bar($current, $max)
|
||||
{
|
||||
$percent = ($max === 0) ? 0 : ceil($current / $max * 100);
|
||||
$color = $percent >= 66 ? 'green' : ($percent >= 33 ? 'yellow' : 'red');
|
||||
|
||||
return '<div class="stat-bar" style="width: 15px; height: 100px; border: solid 1px black;">' .
|
||||
'<div style="height: ' . $percent . 'px; background-image: url(/img/bars_' . $color . '.gif);"></div>' .
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function create_stat_table($userrow)
|
||||
{
|
||||
$stat_table = '<div class="stat-table">' .
|
||||
'<div class="stat-row">' .
|
||||
'<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'];
|
||||
}
|
||||
|
|
113
src/mail.php
Normal file
113
src/mail.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Send an email or log email details
|
||||
*
|
||||
* @param string $to Recipient email address
|
||||
* @param string $subject Email subject
|
||||
* @param string $message Email body
|
||||
* @param array $options Optional configuration options
|
||||
* @return bool Success status of email sending or logging
|
||||
*/
|
||||
function send_email(string $to, string $subject, string $message, array $options = []): bool
|
||||
{
|
||||
global $controlrow;
|
||||
|
||||
$from_addr = empty($controlrow['adminemail']) ? 'noreply@'.$_SERVER['SERVER_NAME'] : $controlrow['adminemail'];
|
||||
|
||||
// Default configuration
|
||||
$config = array_merge([
|
||||
'from' => $from_addr,
|
||||
'log_path' => '../logs/email.log',
|
||||
'method' => 'smtp', // 'smtp' or 'log'
|
||||
'smtp_host' => env('smtp_host', 'localhost'),
|
||||
'smtp_port' => env('smtp_port', 25),
|
||||
'smtp_username' => env('smtp_username', null),
|
||||
'smtp_password' => env('smtp_password', null),
|
||||
'smtp_encryption' => env('smtp_encryption', null)
|
||||
], $options);
|
||||
|
||||
// Always send to log during debug
|
||||
if (env('debug', false)) $config['method'] = 'log';
|
||||
|
||||
// Validate input
|
||||
if (empty($to) || empty($subject) || empty($message)) {
|
||||
error_log('Email sending failed: Missing required parameters');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare email headers
|
||||
$headers = [
|
||||
'From: ' . $config['from'],
|
||||
'X-Mailer: PHP/' . phpversion()
|
||||
];
|
||||
|
||||
// Choose sending method
|
||||
switch ($config['method']) {
|
||||
case 'log':
|
||||
// Log email details to file
|
||||
$logMessage = sprintf(
|
||||
"[%s] To: %s, Subject: %s, Message:\n\n %s\n\n\n\n",
|
||||
date('Y-m-d H:i:s'),
|
||||
$to,
|
||||
$subject,
|
||||
$message
|
||||
);
|
||||
|
||||
// Attempt to log to file
|
||||
if (file_put_contents($config['log_path'], $logMessage, FILE_APPEND) === false) {
|
||||
error_log('Failed to write to log file: ' . $config['log_path']);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case 'smtp':
|
||||
default:
|
||||
// Attempt to send via SMTP
|
||||
try {
|
||||
// Prepare SMTP connection
|
||||
$smtpConfig = [
|
||||
'host' => $config['smtp_host'],
|
||||
'port' => $config['smtp_port'],
|
||||
'username' => $config['smtp_username'],
|
||||
'password' => $config['smtp_password'],
|
||||
'encryption' => $config['smtp_encryption']
|
||||
];
|
||||
|
||||
// Send email using PHP's mail function (basic SMTP)
|
||||
$result = mail(
|
||||
$to,
|
||||
$subject,
|
||||
$message,
|
||||
implode("\r\n", $headers)
|
||||
);
|
||||
|
||||
if (!$result) {
|
||||
error_log('SMTP email sending failed');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log('Email sending error: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
// Send via SMTP
|
||||
// send_email('recipient@example.com', 'Test Subject', 'Email body text');
|
||||
|
||||
// Send via log
|
||||
// send_email('recipient@example.com', 'Test Subject', 'Email body text', ['method' => 'log']);
|
||||
|
||||
// Customize SMTP settings
|
||||
// send_email('recipient@example.com', 'Test Subject', 'Email body text', [
|
||||
// 'method' => 'smtp',
|
||||
// 'smtp_host' => 'smtp.yourserver.com',
|
||||
// 'smtp_port' => 587,
|
||||
// 'smtp_username' => 'your_username',
|
||||
// 'smtp_password' => 'your_password',
|
||||
// 'smtp_encryption' => 'tls'
|
||||
// ]);
|
42
src/models/model.php
Normal file
42
src/models/model.php
Normal 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
21
src/models/user.php
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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,17 +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>
|
||||
|
|
|
@ -1,63 +1,9 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= $title ?></title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
background-image: url('/img/background.jpg');
|
||||
color: black;
|
||||
font: 11px verdana;
|
||||
}
|
||||
table {
|
||||
border-style: none;
|
||||
padding: 0px;
|
||||
font: 11px verdana;
|
||||
}
|
||||
td {
|
||||
border-style: none;
|
||||
padding: 3px;
|
||||
vertical-align: top;
|
||||
}
|
||||
td.top {
|
||||
border-bottom: solid 2px black;
|
||||
}
|
||||
td.left {
|
||||
width: 150px;
|
||||
border-right: solid 2px black;
|
||||
}
|
||||
td.right {
|
||||
width: 150px;
|
||||
border-left: solid 2px black;
|
||||
}
|
||||
a {
|
||||
color: #663300;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
a:hover {
|
||||
color: #330000;
|
||||
}
|
||||
.small {
|
||||
font: 10px verdana;
|
||||
}
|
||||
.highlight {
|
||||
color: red;
|
||||
}
|
||||
.light {
|
||||
color: #999999;
|
||||
}
|
||||
.title {
|
||||
border: solid 1px black;
|
||||
background-color: #eeeeee;
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
margin: 3px;
|
||||
}
|
||||
.copyright {
|
||||
border: solid 1px black;
|
||||
background-color: #eeeeee;
|
||||
font: 10px verdana;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/css/dk.css">
|
||||
</head>
|
||||
<body>
|
||||
<?= $content ?>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<body class="skin-<?= $game_skin ?>">
|
||||
<div id="game-container">
|
||||
<header>
|
||||
<img id="logo" src="/img/logo.gif" alt="<?= $dkgamename ?>" title="<?= $dkgamename ?>">
|
||||
|
@ -42,7 +42,11 @@
|
|||
<?php
|
||||
if (!empty($querylog)) {
|
||||
echo '<pre>';
|
||||
foreach ($querylog as $record) echo '<div>['.round($record[1], 2)."s] {$record[0]}</div>";
|
||||
foreach ($querylog as $record) {
|
||||
$query_string = str_replace(["\r\n", "\n", "\r"], ' ', $record[0]);
|
||||
$error_string = !empty($record[2]) ? '// '.$record[2] : '';
|
||||
echo '<div>['.round($record[1], 2)."s] {$query_string}{$error_string}</div>";
|
||||
}
|
||||
echo '</pre>';
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -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>
|
||||
<?= $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>
|
||||
|
||||
|
|
12
templates/settings.php
Normal file
12
templates/settings.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<h1>Account Settings</h1>
|
||||
<p>Here you can change some basic settings for your account.</p>
|
||||
|
||||
<form action="/settings" method="post">
|
||||
<label for="game_skin">Game Skin</label>
|
||||
<select id="game_skin" name="game_skin">
|
||||
<option value="0">Default</option>
|
||||
<option value="1">Snowstorm</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
Loading…
Reference in New Issue
Block a user