Compare commits

...

10 Commits

26 changed files with 342 additions and 387 deletions

View File

@ -1,4 +1,21 @@
# Game
game_name = 'Dragon Knight'
game_size = 250
game_open = true
game_url = 'localhost:8080'
admin_email = 'noreply@localhost'
class_1_name = 'Mage'
class_2_name = 'Warrior'
class_3_name = 'Paladin'
verify_email = false
show_news = true
show_babble = true
show_online = true
# Environment
debug = true
# Email
smtp_host = smtp.foobar.com
smtp_port = 546
smtp_encryption = tls

View File

@ -13,6 +13,7 @@ html {
body {
background-image: url('/img/backgrounds/classic.jpg');
scrollbar-gutter: stable both-edges;
&.skin-1 {
background-image: url('/img/backgrounds/snowstorm.jpg');

View File

@ -12,24 +12,14 @@ if ($uri[0] === 'babblebox' && (isset($uri[1]) && $uri[1] === 'messages')) {
$r = new Router;
$r->get('/', function() {
if (user()->currentaction === "In Town") {
$page = Towns\town();
} elseif (user()->currentaction === "Exploring") {
$page = Explore\explore();
} elseif (user()->currentaction === "Fighting") {
redirect('/fight');
}
return is_htmx() ? $page : display($page, '');
});
/*
NINJA! 🥷
*/
$r->get('/ninja', function() {
exit('NINJA! 🥷');
});
$r->get('/', 'index');
$r->post('/move', 'Explore\move');
$r->get('/spell/:id', 'healspells');
$r->get('/character', 'show_character_info');
$r->get('/character/:id', 'show_character_info');
$r->get('/showmap', 'showmap');
$r->form('/babblebox', 'babblebox');
$r->get('/babblebox/messages', 'babblebox_messages');
Towns\register_routes($r);
Fights\register_routes($r);
@ -39,14 +29,12 @@ Forum\register_routes($r);
Install\register_routes($r);
Admin\register_routes($r);
$r->post('/move', 'Explore\move');
$r->get('/spell/:id', 'healspells');
$r->get('/character', 'show_character_info');
$r->get('/character/:id', 'show_character_info');
$r->get('/showmap', 'showmap');
$r->form('/babblebox', 'babblebox');
$r->get('/babblebox/messages', 'babblebox_messages');
/*
NINJA! 🥷
*/
$r->get('/ninja', function() {
exit('NINJA! 🥷');
});
// [code, handler, params, middleware]
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
@ -67,13 +55,27 @@ if (is_htmx() && $uri[0] !== 'babblebox') {
echo $content;
exit;
/**
* Return a page for a couple generic actions.
*/
function index(): string
{
if (user()->currentaction === "In Town") {
$page = Towns\town();
} elseif (user()->currentaction === "Exploring") {
$page = Explore\explore();
} elseif (user()->currentaction === "Fighting") {
redirect('/fight');
}
return Render\content($page);
}
/**
* Show a character's info. Defaults to the currently logged in user.
*/
function show_character_info(int $id = 0): string
{
global $controlrow;
$user = $id !== 0 ? User::find($id) : user();
if ($user === false) exit('Failed to show info for user ID '.$id);
@ -86,11 +88,10 @@ function show_character_info(int $id = 0): string
foreach ($spells as $spell) $magic_list .= $spell['name'].'<br>';
}
$showchar = render('showchar', [
$showchar = render('show_char', [
'char' => $user,
'level' => $level,
'magic_list' => $magic_list,
'controlrow' => $controlrow
'magic_list' => $magic_list
]);
return render('layouts/minimal', ['content' => $showchar, 'title' => $user->username.' Information']);
}

View File

@ -18,17 +18,18 @@ function explore()
}
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']) return display(ul_from_validate_errors($form['errors']), 'Move Error');
if (!$form['valid']) {
$errors = ul_from_validate_errors($form['errors']);
return \Render\content($errors);
}
// Current game state
$game_size = $controlrow['gamesize'];
$game_size = env('game_size');
$latitude = user()->latitude;
$longitude = user()->longitude;
$direction = $form['data']['direction'];
@ -67,5 +68,5 @@ function move() {
user()->longitude = $longitude;
user()->save();
redirect('/');
return index();
}

View File

@ -120,22 +120,15 @@ function fight()
// Spell action
if (isset($_POST["spell"])) {
$pickedspell = $_POST["userspell"];
if ($pickedspell == 0) {
return display("You must select a spell first. Please go back and try again.", "Error");
die();
}
if ($pickedspell == 0) return \Render\content('You must select a spell first. Please go back and try again.');
$newspellrow = get_spell($pickedspell);
$spell = in_array($pickedspell, explode(',', user()->spells));
if (!$spell) {
return display("You have not yet learned this spell. Please go back and try again.", "Error");
die();
}
if (!$spell) return \Render\content('You have not yet learned this spell. Please go back and try again.');
if (user()->currentmp < $newspellrow["mp"]) {
return display("You do not have enough Magic Points to cast this spell. Please go back and try again.", "Error");
die();
return \Render\content('You do not have enough Magic Points to cast this spell. Please go back and try again.');
}
// Spell type handling (similar to original function)
@ -164,7 +157,7 @@ function fight()
if ($playerisdead != 1) {
$page["command"] = <<<HTML
Command?<br><br>
<form action="/fight" method="post">
<form action="/fight" method="post" hx-post="/fight" hx-target="#middle">
<input type="submit" name="fight" value="Fight"><br><br>
{$page['magiclist']}
<input type="submit" name="run" value="Run"><br><br>
@ -173,13 +166,18 @@ function fight()
user()->currentfight += 1;
} else {
$pagearray["command"] = "<b>You have died.</b><br><br>As a consequence, you've lost half of your gold. However, you have been given back a portion of your hit points to continue your journey.<br><br>You may now continue back to <a href=\"/\">town</a>, and we hope you fair better next time.";
$page["command"] = <<<HTML
<b>You have died.</b><br><br>
As a consequence, you've lost half of your gold. However, you have been given back a portion of your hit points to continue your journey.<br><br>
You may now continue back to <a href="/" hx-get="/" hx-target="#middle">town</a>, and we hope you fair better next time.
HTML;
}
user()->save();
// Finalize page and display it
return display(render('fight', ['page' => $page]), "Fighting");
$page = render('fight', ['page' => $page]);
return \Render\content($page);
}
function victory()
@ -225,7 +223,7 @@ function victory()
$spelltext = "You have learned a new spell.<br>";
} else { $spelltext = ""; $newspell=""; }
$page = "Congratulations. You have defeated the ".$monsterrow["name"].".<br>You gain $exp experience. $warnexp <br>You gain $gold gold. $warngold <br><br><b>You have gained a level!</b><br><br>You gain ".$levelrow[user()->charclass."_hp"]." hit points.<br>You gain ".$levelrow[user()->charclass."_mp"]." magic points.<br>You gain ".$levelrow[user()->charclass."_tp"]." travel points.<br>You gain ".$levelrow[user()->charclass."_strength"]." strength.<br>You gain ".$levelrow[user()->charclass."_dexterity"]." dexterity.<br>$spelltext<br>You can now continue <a href=\"/\">exploring</a>.";
$page = "Congratulations. You have defeated the ".$monsterrow["name"].".<br>You gain $exp experience. $warnexp <br>You gain $gold gold. $warngold <br><br><b>You have gained a level!</b><br><br>You gain ".$levelrow[user()->charclass."_hp"]." hit points.<br>You gain ".$levelrow[user()->charclass."_mp"]." magic points.<br>You gain ".$levelrow[user()->charclass."_tp"]." travel points.<br>You gain ".$levelrow[user()->charclass."_strength"]." strength.<br>You gain ".$levelrow[user()->charclass."_dexterity"]." dexterity.<br>$spelltext<br>You can now continue <a href=\"/\" hx-get=\"/\" hx-target=\"#middle\">exploring</a>.";
$title = "Courage and Wit have served thee well!";
$dropcode = "";
} else {
@ -234,10 +232,10 @@ function victory()
if (rand(1, 30) === 1) {
$droprow = db()->query('SELECT * FROM drops WHERE mlevel <= ? ORDER BY RANDOM() LIMIT 1;', [$monsterrow['level']])->fetchArray(SQLITE3_ASSOC);
$dropcode = "dropcode='".$droprow["id"]."',";
$page .= "This monster has dropped an item. <a href=\"/drop\">Click here</a> to reveal and equip the item, or you may also move on and continue <a href=\"/\">exploring</a>.";
$page .= "This monster has dropped an item. <a href=\"/drop\" hx-get=\"/drop\" hx-target=\"#middle\">Click here</a> to reveal and equip the item, or you may also move on and continue <a href=\"/\" hx-get=\"/\" hx-target=\"#middle\">exploring</a>.";
} else {
$dropcode = "";
$page .= "You can now continue <a href=\"/\">exploring</a>.";
$page .= 'You can now continue <a href="/" hx-get="/" hx-target="#middle">exploring</a>.';
}
$title = "Victory!";
@ -252,7 +250,8 @@ function victory()
user()->currentmonsterimmune = 0;
user()->save();
return display($page, $title);
page_title($title);
return \Render\content($page);
}
function drop()
@ -264,7 +263,10 @@ function drop()
if (isset($_POST["submit"])) {
$slot = $_POST["slot"];
if ($slot == 0) { return display("Please go back and select an inventory slot to continue.","Error"); }
if ($slot == 0) {
$page = 'Please go back and select an inventory slot to continue.';
return \Render\content($page);
}
$slotstr = 'slot'.$slot.'id';
if (user()->$slotstr != 0) {
@ -319,7 +321,8 @@ function drop()
}
user()->save();
return display("The item has been equipped. You can now continue <a href=\"/\">exploring</a>.", "Item Drop");
$page = 'The item has been equipped. You can now continue <a href="/" hx-get="/" hx-target="#middle">exploring</a>.';
return \Render\content($page);
}
$attributearray = array("maxhp"=>"Max HP",
@ -347,9 +350,9 @@ function drop()
$page .= "<br>Select an inventory slot from the list below to equip this item. If the inventory slot is already full, the old item will be discarded.";
$page .= "<form action=\"/drop\" method=\"post\"><select name=\"slot\"><option value=\"0\">Choose One</option><option value=\"1\">Slot 1: ".user()->slot1name."</option><option value=\"2\">Slot 2: ".user()->slot2name."</option><option value=\"3\">Slot 3: ".user()->slot3name."</option></select> <input type=\"submit\" name=\"submit\" value=\"Submit\" /></form>";
$page .= "You may also choose to just continue <a href=\"/\">exploring</a> and give up this item.";
$page .= "You may also choose to just continue <a href=\"/\" hx-get=\"/\" hx-target=\"#middle\">exploring</a> and give up this item.";
return display($page, "Item Drop");
return \Render\content($page);
}
@ -359,9 +362,9 @@ function dead()
<b>You have died.</b><br><br>
As a consequence, you've lost half of your gold. However, you have been given back a portion of your hit points
to continue your journey.<br><br>
You may now continue back to <a href="/">town</a>, and we hope you fair better next time.
You may now continue back to <a href="/" hx-get="/" hx-target="#middle">town</a>, and we hope you fair better next time.
HTML;
return display($page, 'You Died');
return \Render\content($page);
}
function handleMonsterTurn(&$userrow, $monsterrow)

View File

@ -19,22 +19,44 @@ function register_routes(Router $r): Router
function donothing($start = 0)
{
$query = db()->query('SELECT * FROM forum WHERE parent=0 ORDER BY newpostdate DESC LIMIT 20 OFFSET ?;', [20 * $start]);
$page = "<table width=\"100%\"><tr><td style=\"padding:1px; background-color:black;\"><table width=\"100%\" style=\"margins:0px;\" cellspacing=\"1\" cellpadding=\"3\"><tr><th colspan=\"3\" style=\"background-color:#dddddd;\"><center><a href=\"/forum/new\">New Thread</a></center></th></tr><tr><th width=\"50%\" style=\"background-color:#dddddd;\">Thread</th><th width=\"10%\" style=\"background-color:#dddddd;\">Replies</th><th style=\"background-color:#dddddd;\">Last Post</th></tr>\n";
$page = <<<HTML
<table width="100%">
<tr>
<td style="padding: 1px; background-color: black;">
<table width="100%" style="margins: 0px;" cellspacing="1" cellpadding="3">
<tr>
<th colspan="3" style="background-color: #ddd;">
<center><a href="/forum/new" hx-get="/forum/new" hx-target="#middle">New Thread</a></center>
</th>
</tr>
<tr>
<th width="50%" style="background-color:#dddddd;">Thread</th>
<th width="10%" style="background-color:#dddddd;">Replies</th>
<th style="background-color:#dddddd;">Last Post</th>
</tr>
HTML;
$hasRows = false;
while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
$hasRows = true;
$page .= "<tr><td style=\"background-color:#ffffff;\"><a href=\"/forum/thread/".$row["id"]."/0\">".$row["title"]."</a></td><td style=\"background-color:#ffffff;\">".$row["replies"]."</td><td style=\"background-color:#ffffff;\">".$row["newpostdate"]."</td></tr>\n";
$page .= <<<HTML
<tr>
<td style="background-color: white;"><a href="/forum/thread/{$row['id']}/0" hx-get="/forum/thread/{$row['id']}/0" hx-target="#middle">{$row['title']}</a></td>
<td style="background-color: white;">{$row['replies']}</td>
<td style="background-color: white;">{$row['newpostdate']}</td>
</tr>
HTML;
}
if (!$hasRows) {
$page .= "<tr><td style=\"background-color:#ffffff;\" colspan=\"3\"><b>No threads in forum.</b></td></tr>\n";
$page .= '<tr><td style="background-color:#ffffff;" colspan="3"><b>No threads in forum.</b></td></tr>';
}
$page .= "</table></td></tr></table>";
$page .= '</table></td></tr></table>';
return display($page, "Forum");
page_title('Forum');
return \Render\content($page);
}
function showthread($id, $start)
@ -42,28 +64,25 @@ function showthread($id, $start)
$posts = db()->query('SELECT * FROM forum WHERE id=? OR parent=? ORDER BY id LIMIT 15 OFFSET ?;', [$id, $id, $start * 15]);
$title = db()->query('SELECT title FROM forum WHERE id=? LIMIT 1;', [$id])->fetchArray(SQLITE3_ASSOC);
$page = "<table width=\"100%\"><tr><td style=\"padding:1px; background-color:black;\"><table width=\"100%\" style=\"margins:0px;\" cellspacing=\"1\" cellpadding=\"3\"><tr><td colspan=\"2\" style=\"background-color:#dddddd;\"><b><a href=\"/forum\">Forum</a> :: ".$title['title']."</b></td></tr>\n";
$page = "<table width=\"100%\"><tr><td style=\"padding:1px; background-color:black;\"><table width=\"100%\" style=\"margins:0px;\" cellspacing=\"1\" cellpadding=\"3\"><tr><td colspan=\"2\" style=\"background-color:#dddddd;\"><b><a href=\"/forum\" hx-get=\"/forum\" hx-target=\"#middle\">Forum</a> :: ".$title['title']."</b></td></tr>\n";
while ($row = $posts->fetchArray(SQLITE3_ASSOC)) {
$page .= "<tr><td width=\"25%\" style=\"background-color:#ffffff; vertical-align:top;\"><span class=\"small\"><b>".$row["author"]."</b><br><br>".pretty_date($row["postdate"])."</td><td style=\"background-color:#ffffff; vertical-align:top;\">".nl2br($row["content"])."</td></tr>\n";
}
$page .= "</table></td></tr></table><br>";
$page .= "<table width=\"100%\"><tr><td><b>Reply To This Thread:</b><br><form action=\"/forum/reply\" method=\"post\"><input type=\"hidden\" name=\"parent\" value=\"$id\" /><input type=\"hidden\" name=\"title\" value=\"Re: ".$title["title"]."\" /><textarea name=\"content\" rows=\"7\" cols=\"40\"></textarea><br><input type=\"submit\" name=\"submit\" value=\"Submit\" /> <input type=\"reset\" name=\"reset\" value=\"Reset\" /></form></td></tr></table>";
$page .= "<table width=\"100%\"><tr><td><b>Reply To This Thread:</b><br><form action=\"/forum/reply\" method=\"post\" hx-post=\"/forum/reply\" hx-target=\"#middle\"><input type=\"hidden\" name=\"parent\" value=\"$id\" /><input type=\"hidden\" name=\"title\" value=\"Re: ".$title["title"]."\" /><textarea name=\"content\" rows=\"7\" cols=\"40\"></textarea><br><input type=\"submit\" name=\"submit\" value=\"Submit\" /> <input type=\"reset\" name=\"reset\" value=\"Reset\" /></form></td></tr></table>";
return display($page, "Forum");
page_title('Forum: '.$title['title']);
return \Render\content($page);
}
function reply()
{
global $userrow;
$form = validate($_POST, [
'title' => [],
'content' => []
]);
if (!$form['valid']) {
exit(ul_from_validate_errors($form['errors']));
}
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
$form = $form['data'];
@ -71,7 +90,7 @@ function reply()
user()->username, $form['title'], $form['content'], $form['parent']
]);
db()->query('UPDATE forum SET newpostdate=CURRENT_TIMESTAMP, replies=replies + 1 WHERE id=?;', [$form['parent']]);
redirect("/forum/thread/{$form['parent']}/0");
return showthread($form['parent'], 0);
}
function newthread()
@ -82,17 +101,16 @@ function newthread()
'content' => []
]);
if (!$form['valid']) {
exit(ul_from_validate_errors($form['errors']));
}
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
$form = $form['data'];
db()->query('INSERT INTO forum (author, title, content) VALUES (?, ?, ?);', [
user()->username, $form['title'], $form['content']
]);
redirect('/forum');
redirect('/forum/thread/'.db()->lastInsertRowID().'/0');
}
$page = "<table width=\"100%\"><tr><td><b>Make A New Post:</b><br><br/ ><form action=\"/forum/new\" method=\"post\">Title:<br><input type=\"text\" name=\"title\" size=\"50\" maxlength=\"50\" /><br><br>Message:<br><textarea name=\"content\" rows=\"7\" cols=\"40\"></textarea><br><br><input type=\"submit\" name=\"submit\" value=\"Submit\" /> <input type=\"reset\" name=\"reset\" value=\"Reset\" /></form></td></tr></table>";
return display($page, "Forum");
$page = "<table width=\"100%\"><tr><td><b>Make A New Post:</b><br><br/ ><form action=\"/forum/new\" method=\"post\" hx-post=\"/forum/new\" hx-target=\"#middle\">Title:<br><input type=\"text\" name=\"title\" size=\"50\" maxlength=\"50\" /><br><br>Message:<br><textarea name=\"content\" rows=\"7\" cols=\"40\"></textarea><br><br><input type=\"submit\" name=\"submit\" value=\"Submit\" /> <input type=\"reset\" name=\"reset\" value=\"Reset\" /></form></td></tr></table>";
page_title('Form: New Thread');
return \Render\content($page);
}

View File

@ -2,27 +2,33 @@
// heal.php :: Handles stuff from the Quick Spells menu. (Healing spells only... other spells are handled in fight.php.)
function healspells($id)
function healspells(int $id): string
{
global $userrow;
$user_spells = user()->spells();
$spell = get_spell($id);
$has_spell = false;
foreach ($user_spells as $us) if ($us['id'] === $id) $has_spell = true;
$userspells = explode(",", $userrow["spells"]);
$spellrow = get_spell($id);
if ($has_spell !== true) {
$page = 'You have not yet learned this spell. Please go back and try again.';
} elseif ($spell['type'] !== 1) {
$page = 'This is not a healing spell. Please go back and try again.';
} elseif (user()->currentmp < $spell['mp']) {
$page = 'You do not have enough Magic Points to cast this spell. Please go back and try again.';
} elseif (user()->currentaction === 'Fighting') {
$page = 'You cannot use the Quick Spells list during a fight. Please go back and select the Healing Spell you wish to use from the Spells box on the main fighting screen to continue.';
} elseif (user()->currenthp == user()->maxhp) {
$page = 'Your HP is already full. You don\'t need to use a Healing spell now.';
} else {
$restored = user()->restore_hp($spell['attribute']);
user()->currentmp -= $spell['mp'];
user()->save();
// All the various ways to error out.
$spell = false;
foreach ($userspells as $b) if ($b == $id) $spell = true;
if ($spell !== true) return display("You have not yet learned this spell. Please go back and try again.", "Error");
if ($spellrow["type"] != 1) return display("This is not a healing spell. Please go back and try again.", "Error");
if ($userrow["currentmp"] < $spellrow["mp"]) return display("You do not have enough Magic Points to cast this spell. Please go back and try again.", "Error");
if ($userrow["currentaction"] == "Fighting") return display("You cannot use the Quick Spells list during a fight. Please go back and select the Healing Spell you wish to use from the Spells box on the main fighting screen to continue.", "Error");
if ($userrow["currenthp"] == $userrow["maxhp"]) return display("Your Hit Points are already full. You don't need to use a Healing spell now.", "Error");
$page = <<<HTML
You have cast the {$spell['name']} spell, and gained {$restored} HP. You can now continue <a href="/" hx-get="/" hx-target="#middle">exploring</a>.
HTML;
}
$newhp = $userrow["currenthp"] + $spellrow["attribute"];
if ($userrow["maxhp"] < $newhp) { $spellrow["attribute"] = $userrow["maxhp"] - $userrow["currenthp"]; $newhp = $userrow["currenthp"] + $spellrow["attribute"]; }
$newmp = $userrow["currentmp"] - $spellrow["mp"];
db()->query('UPDATE users SET currenthp=?, currentmp=? WHERE id=?;', [$newhp, $newmp, $userrow['id']]);
return display("You have cast the ".$spellrow["name"]." spell, and gained ".$spellrow["attribute"]." Hit Points. You can now continue <a href=\"/\">exploring</a>.", "Healing Spell");
page_title('Casting '.$spell['name']);
return \Render\content($page);
}

View File

@ -16,8 +16,6 @@ function register_routes(Router $r): Router
function main()
{
global $controlrow;
$page = <<<HTML
<h3>Table of Contents</h3>
<ul>
@ -63,7 +61,7 @@ function main()
is a basic outline of each of the character classes. For more detailed information about the characters, please
view the Levels table at the bottom of this page. Also, note that the outline below refers to the stock class setup
for the game. If your administrator has used his/her own class setup, this information may not be accurate.<br><br>
<b>{{class1name}}</b>
<b>{env('class_1_name')}</b>
<ul>
<li>Fast level-ups</li>
<li>High hit points</li>
@ -76,7 +74,7 @@ function main()
<li>3 +defense spells</li>
<li>0 +attack spells</li>
</ul>
<b>{{class2name}}</b>
<b>{env('class_2_name')}</b>
<ul>
<li>Medium level-ups</li>
<li>Medium hit points</li>
@ -89,7 +87,7 @@ function main()
<li>3 +defense spells</li>
<li>3 +attack spells</li>
</ul>
<b>{{class3name}}</b>
<b>{env('class_3_name')}</b>
<ul>
<li>Slow level-ups</li>
<li>Medium hit points</li>
@ -246,13 +244,11 @@ function main()
[ <a href="#top">Top</a> ]
HTML;
return display_help(parse($page, $controlrow));
return display_help($page);
}
function items()
{
global $controlrow;
$page = <<<HTML
<table width="60%" style="border: solid 1px black" cellspacing="0" cellpadding="0">
<tr><td colspan="5" bgcolor="#ffffff"><center><b>Items</b></center></td></tr>
@ -319,8 +315,6 @@ function items()
function spells()
{
global $controlrow;
$page = <<<HTML
<table width="50%" style="border: solid 1px black" cellspacing="0" cellpadding="0">
<tr><td colspan="8" bgcolor="#ffffff"><center><b>Spells</b></center></td></tr>
@ -373,8 +367,6 @@ function monsters()
function levels()
{
global $controlrow;
$rows = [];
$levels = db()->query('SELECT * FROM levels ORDER BY id;');
@ -489,14 +481,12 @@ function levels()
Experience points listed are total values up until that point. All other values are just the new amount that you gain for each level.
HTML;
return display_help(parse($page, $controlrow));
return display_help($page);
}
function display_help(string $content)
{
global $controlrow;
return render('layouts/help', [
'control' => $controlrow,
'content' => $content,
'version' => VERSION,
'build' => BUILD

View File

@ -56,33 +56,6 @@ function second()
echo table_status_msg($query === true, 'Babble', 'create');
$query = db()->exec(<<<SQL
CREATE TABLE control (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`gamename` TEXT NOT NULL DEFAULT 'Dragon Knight',
`gamesize` INTEGER NOT NULL DEFAULT 250,
`gameopen` INTEGER NOT NULL DEFAULT 1,
`gameurl` TEXT NOT NULL DEFAULT '',
`adminemail` TEXT NOT NULL DEFAULT '',
`class1name` TEXT NOT NULL DEFAULT '',
`class2name` TEXT NOT NULL DEFAULT '',
`class3name` TEXT NOT NULL DEFAULT '',
`verifyemail` INTEGER NOT NULL DEFAULT 0,
`shownews` INTEGER NOT NULL DEFAULT 0,
`showbabble` INTEGER NOT NULL DEFAULT 0,
`showonline` INTEGER NOT NULL DEFAULT 0
);
SQL);
echo table_status_msg($query === true, 'Control', 'create');
$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 table_status_msg($query !== false, 'Control', 'populate');
$query = db()->exec(<<<SQL
CREATE TABLE drops (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,

View File

@ -23,15 +23,13 @@ function register_routes(Router $r): Router
*/
function town()
{
global $controlrow;
$town = get_town_by_xy(user()->longitude, user()->latitude);
$town = get_town_by_xy(user()->longitude, user()->latitude);
if ($town === false) exit('There is an error with your user account, or with the town data. Please try again.');
$page = ['news' => '', 'whos_online' => ''];
// News box. Grab latest news entry and display it. Something a little more graceful coming soon maybe.
if ($controlrow['shownews'] === 1) {
if (env('show_news')) {
$news = db()->query('SELECT * FROM news ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC);
$news_date = pretty_date($news["postdate"]);
$news_content = nl2br($news["content"]);
@ -43,7 +41,7 @@ function town()
}
// Who's Online. Currently just members. Guests maybe later.
if ($controlrow['showonline'] === 1) {
if (env('show_online')) {
$onlinequery = db()->query(<<<SQL
SELECT id, username
FROM users
@ -79,9 +77,6 @@ function inn()
$town = get_town_by_xy(user()->longitude, user()->latitude);
if ($town === false) { exit('Cheat attempt detected.<br><br>Get a life, loser.'); }
$htmx = is_htmx();
page_title($town['name'] . ' Inn');
if (user()->gold < $town['innprice']) {
$page = <<<HTML
You do not have enough gold to stay at this Inn tonight. <br><br>
@ -107,7 +102,8 @@ function inn()
HTML;
}
return $htmx ? $page : display($page, $town['name'] . ' Inn');
page_title($town['name'] . ' Inn');
return \Render\content($page);
}
/**
@ -120,8 +116,6 @@ function shop()
$town = get_town_by_xy(user()->longitude, user()->latitude);
if ($town === false) exit('Cheat attempt detected.<br><br>Get a life, loser.');
$htmx = is_htmx();
page_title($town['name'] . ' Shop');
$page = <<<HTML
Buying weapons will increase your Attack Power. Buying armor and shields will increase your Defense Power.<br><br>
@ -161,7 +155,8 @@ function shop()
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
HTML;
return $htmx ? $page : display($page, $town['name'] . ' Shop');
page_title($town['name'] . ' Shop');
return \Render\content($page);
}
/**
@ -192,7 +187,7 @@ function buy(int $id)
if (!isset($type_mapping[$item["type"]])) { // should never happen
$page = 'Error! Invalid item type...<br>'.var_dump($item);
return is_htmx() ? $page : display($page, '');
return \Render\content($page, '');
}
// Retrieve current equipped item or create a default
@ -214,9 +209,9 @@ function buy(int $id)
$toChange = $special[0];
$changeAmount = $index === 0 ? $special[1] : -$special[1];
user()[$toChange] += $changeAmount;
user()->$toChange += $changeAmount;
$specialFields[] = "$toChange = ?";
$specialValues[] = user()[$toChange];
$specialValues[] = user()->$toChange;
// Adjust attack or defense power
if ($toChange == "strength" || $toChange == "dexterity") {
@ -276,7 +271,7 @@ function buy(int $id)
}
page_title('Buying '.$item['name']);
return is_htmx() ? $page : display($page, 'Buying '.$item['name']);
return \Render\content($page);
}
/**
@ -322,7 +317,7 @@ function maps()
HTML;
page_title('Maps');
return is_htmx() ? $page : display($page, '');
return \Render\content($page);
}
function buy_map(int $id): string
@ -342,7 +337,7 @@ function buy_map(int $id): string
$page = <<<HTML
Thank you for purchasing this map.<br><br>
You may return to <a hx-get="/" hx-target="#middle">town</a>, <a hx-get="/maps" hx-target="#middle">store</a>, or use the direction buttons on the left to start exploring.
You may return to <a hx-get="/" hx-target="#middle">town</a>, <a hx-get="/maps" hx-target="#middle">map shop</a>, or use the direction buttons on the left to start exploring.
HTML;
} elseif (is_post() && !$_POST['buy']) {
redirect('/maps');
@ -357,49 +352,51 @@ function buy_map(int $id): string
}
page_title('Buying '.$town['name'].' Map');
return is_htmx() ? $page : display($page, '');
return \Render\content($page);
}
/**
* Send a user to a town from the Travel To menu.
*/
function travelto($id, bool $usepoints = true)
function travelto(int $id, bool $use_points = true): string
{
if (user()->currentaction == "Fighting") redirect('/fight');
$townrow = get_town_by_id($id);
$town = get_town_by_id($id);
$cost = $use_points ? $town['travelpoints'] : 0;
$mapped = explode(',', user()->towns);
$travelled = false;
if ($usepoints) {
if (user()->currenttp < $townrow["travelpoints"]) {
return 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(",",user()->towns);
if (!in_array($id, $mapped)) { display("Cheat attempt detected.<br><br>Get a life, loser.", "Error"); }
}
if ((user()->latitude == $townrow["latitude"]) && (user()->longitude == $townrow["longitude"])) {
return display("You are already in this town. <a href=\"/\">Click here</a> to return to the main town screen.", "Travel To");
if ($use_points && !in_array($id, $mapped)) {
// trying to teleport to this town when it is not mapped
redirect('/');
} elseif (user()->currenttp < $cost) {
$page = 'You do not have enough TP to travel here. Please <a href="/" hx-get="/" hx-target="#middle">go back</a> and try again when you get more TP.';
} elseif ((user()->latitude == $town['latitude']) && (user()->longitude == $town['longitude'])) {
if (!in_array($id, $mapped)) {
// add town to user's mapped if they travelled here
user()->towns .= ",$id";
$travelled = true;
$page = <<<HTML
You have discovered <b>{$town['name']}</b>! It has been added to your mapped towns.<br><br>
You may now <a href="/" hx-get="/" hx-target="#middle">enter this town</a>.
HTML;
} else {
$page = 'You are already in this town. <a href="/" hx-get="/" hx-target="#middle">Click here</a> to return.';
}
} else {
user()->latitude = $town['latitude'];
user()->longitude = $town['longitude'];
user()->currenttp -= $cost;
$travelled = true;
$page = 'You have travelled to <b>'.$town['name'].'</b>. You may now <a href="/" hx-get="/" hx-target="#middle">enter this town</a>.';
}
$newtp = ($usepoints) ? user()->currenttp - $townrow["travelpoints"] : user()->currenttp;
if ($travelled) {
user()->currentaction = 'In Town';
user()->save();
}
$newlat = $townrow["latitude"];
$newlon = $townrow["longitude"];
// If they got here by exploring, add this town to their map.
$mapped = explode(",",user()->towns);
$town = false;
foreach($mapped as $b) if ($b == $id) $town = true;
$mapped = implode(",", $mapped);
if ($town == false) $mapped .= ",$id";
user()->currentaction = 'In Town';
user()->towns = $mapped;
user()->currenttp = $newtp;
user()->longitude = $newlon;
user()->latitude = $newlat;
user()->save();
$page = "You have travelled to ".$townrow["name"].". You may now <a href=\"/\">enter this town</a>.";
return display($page, "Travel To");
page_title('Travelling to '.$town['name']);
return \Render\content($page);
}

View File

@ -10,7 +10,7 @@ function register_routes(Router $r): Router
$r->get('/logout', 'Users\logout');
$r->form('/register', 'Users\register');
$r->form('/lostpassword', 'Users\lostpassword');
$r->form('/changepassword', 'Users\changepassword');
$r->post('/changepassword', 'Users\changepassword');
$r->form('/verify', 'Users\verify');
$r->form('/settings', 'Users\settings');
return $r;
@ -30,24 +30,16 @@ function login()
'remember' => ['bool']
]);
if (!$form['valid']) {
exit(ul_from_validate_errors($form['errors']));
}
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
$form = $form['data'];
$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.");
$good = $auth->login($form['data']['username'], $form['data']['password']);
if (!$good) exit('Invalid username or password. Please go back and try again.');
$expiretime = $form['remember'] ? time() + 31536000 : 0;
$rememberme = $form['remember'] ? 1 : 0;
$cookie = implode(' ', [$row['id'], $row['username'], $row['password'], $rememberme]);
set_cookie("dkgame", $cookie, $expiretime);
redirect('/');
}
return display(render('login'), 'Log In', true, false, false);
page_title('Login');
return \Render\content(render('login'));
}
/**
@ -57,7 +49,6 @@ function logout()
{
global $auth;
$auth->logout();
set_cookie("dkgame", "", -3600);
redirect('/login');
}
@ -66,8 +57,6 @@ function logout()
*/
function register()
{
global $controlrow;
if (isset($_POST["submit"])) {
$form = validate($_POST, [
'username' => ['length:3-18', 'alpha-spaces', 'unique:users,username'],
@ -84,32 +73,33 @@ function register()
} else {
$form = $form['data'];
$password = password_hash($form['password'], PASSWORD_ARGON2ID);
$token = ($controlrow['verifyemail'] == true) ? token(8) : 'g2g';
$token = env('verify_email') ? token(8) : 'g2g';
db()->query('INSERT INTO users (verify, username, password, email, charclass) VALUES (?, ?, ?, ?, ?)', [
$token, $form['username'], $password, $form['email'], $form['charclass']
]);
if ($controlrow['verifyemail'] == true) {
if (env('verify_email')) {
if (sendregmail($form['email'], $token)) {
$page = "Your account was created successfully.<br><br>You should receive an Account Verification email shortly. You will need the verification code contained in that email before you are allowed to log in. Once you have received the email, please visit the <a href=\"users.php?do=verify\">Verification Page</a> to enter your code and start playing.";
} else {
$page = "Your account was created successfully.<br><br>However, there was a problem sending your verification email. Please check with the game administrator to help resolve this problem.";
}
} else {
$page = "Your account was created succesfully.<br><br>You may now continue to the <a href=\"/login\">Login Page</a> and continue playing ".$controlrow["gamename"]."!";
$page = "Your account was created succesfully.<br><br>You may now continue to the <a href=\"/login\">Login Page</a> and continue playing ".env('game_name')."!";
}
}
} else {
if ($controlrow["verifyemail"] == true) {
$controlrow["verifytext"] = "<br><span class=\"small\">A verification code will be sent to the address above, and you will not be able to log in without first entering the code. Please be sure to enter your correct email address.</span>";
if (env('verify_email')) {
$verify_text = "<br><span class=\"small\">A verification code will be sent to the address above, and you will not be able to log in without first entering the code. Please be sure to enter your correct email address.</span>";
} else {
$controlrow["verifytext"] = "";
$verify_text = "";
}
$page = render('register', ['controlrow' => $controlrow]);
$page = render('register', ['verify_text' => $verify_text]);
}
return display($page, 'Register', true, false, false);
page_title('Register');
return \Render\content($page);
}
function verify()
@ -124,10 +114,10 @@ function verify()
db()->query("UPDATE users SET verify='g2g' WHERE username=?;", [$u]);
return display("Your account was verified successfully.<br><br>You may now continue to the <a href=\"/login\">Login Page</a> and start playing the game.<br><br>Thanks for playing!","Verify Email",false,false,false);
return \Render\content("Your account was verified successfully.<br><br>You may now continue to the <a href=\"/login\">Login Page</a> and start playing the game.<br><br>Thanks for playing!");
}
return display(render('verify'), "Verify Email", true, false, false);
return \Render\content(render('verify'));
}
function lostpassword()
@ -143,17 +133,19 @@ function lostpassword()
db()->query('UPDATE users SET password=? WHERE email=?;', [$hashed, $e]);
if (sendpassemail($e, $newpass)) {
return display("Your new password was emailed to the address you provided.<br><br>Once you receive it, you may <a href=\"/login\">Log In</a> and continue playing.<br><br>Thank you.","Lost Password",false,false,false);
return \Render\content("Your new password was emailed to the address you provided.<br><br>Once you receive it, you may <a href=\"/login\">Log In</a> and continue playing.<br><br>Thank you.");
} else {
return display("There was an error sending your new password.<br><br>Please check with the game administrator for more information.<br><br>We apologize for the inconvience.","Lost Password",false,false,false);
return \Render\content("There was an error sending your new password.<br><br>Please check with the game administrator for more information.<br><br>We apologize for the inconvience.");
}
}
return display(render('lostpassword'), "Lost Password", true, false, false);
return \Render\content(render('lostpassword'));
}
function changepassword()
{
global $auth;
if (isset($_POST["submit"])) {
$u = trim($_POST['username'] ?? '');
$p = $_POST['password'] ?? '';
@ -177,12 +169,10 @@ function changepassword()
$realnewpass = password_hash($np, PASSWORD_ARGON2ID);
db()->query('UPDATE users SET password=? WHERE username=?;', [$realnewpass, $u]);
set_cookie('dkgame', '', -3600);
$auth->logout();
return display("Your password was changed successfully.<br><br>You have been logged out of the game to avoid errors.<br><br>Please <a href=\"/login\">log back in</a> to continue playing.","Change Password",false,false,false);
return \Render\content("Your password was changed successfully.<br><br>You have been logged out of the game to avoid errors.<br><br>Please <a href=\"/login\">log back in</a> to continue playing.");
}
return display(render('changepassword'), "Change Password", true, false, false);
}
function settings()
@ -198,19 +188,16 @@ function settings()
user()->save();
$alert = '<div class="alert">Settings updated</div>';
return display($alert . render('settings'), "Account Settings");
return \Render\content($alert . render('settings'));
}
return display(render('settings'), "Account Settings");
return \Render\content(render('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 {env('game_name')} server, located at {env('game_url')}.
We have issued you a new password so you can log back into the game.
@ -219,17 +206,15 @@ function sendpassemail($emailaddress, $password)
Thanks for playing.
HTML;
return send_email($emailaddress, "$gamename Lost Password", $email);
return send_email($emailaddress, env('game_name')." Lost Password", $email);
}
function sendregmail($emailaddress, $vercode)
{
global $controlrow;
extract($controlrow);
$verurl = $gameurl . "/verify";
$verurl = env('game_url') . "/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 {env('game_name')} server, located at {env('game_url')}.
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.
@ -238,5 +223,5 @@ function sendregmail($emailaddress, $vercode)
If you were not the person who signed up for the game, please disregard this message. You will not be emailed again.
HTML;
return send_email($emailaddress, "$gamename Account Verification", $email);
return send_email($emailaddress, env('game_name')." Account Verification", $email);
}

View File

@ -28,10 +28,9 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
} elseif (file_exists(('../.installed')) && $uri[0] === 'install') {
redirect('/');
} elseif (file_exists(('../.installed')) && $uri[0] !== 'install') {
$controlrow = get_control_row();
if (!$controlrow["gameopen"]) {
display("The game is currently closed for maintanence. Please check back later.", "Game Closed");
if (!env('game_open')) {
echo Render\content('The game is currently closed for maintanence. Please check back later.');
exit;
}
$auth = new Auth;
@ -41,14 +40,14 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
if (!in_array($uri[0], ['login', 'register', 'verify', 'lostpassword', 'help'])) {
redirect('/login');
}
} else {
} elseif ($auth->good()) {
// Block user if he/she has been banned.
if (user()->authlevel === 2) {
exit("Your account has been banned.");
}
// Force verify if the user isn't verified yet.
if ($controlrow['verifyemail'] && user()->verify !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
if (env('verify_email') && user()->verify !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
redirect('/verify');
}
@ -56,5 +55,10 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
if (user()->authlevel !== 1 && $uri[0] === 'admin') {
redirect('/');
}
user()->update_online_time();
} else {
$auth->logout();
redirect('/login');
}
}

View File

@ -20,7 +20,8 @@ function db(): Database
function redirect(string $location): void
{
if (is_htmx()) {
$json = json_encode(['path' => $location, 'target' => '#'.$_SERVER['HTTP_HX_TARGET'] ?? '#middle']);
$target = isset($_SERVER['HTTP_HX_TARGET']) ? '#'.$_SERVER['HTTP_HX_TARGET'] : '#middle';
$json = json_encode(['path' => $location, 'target' => $target]);
header("HX-Location: $json");
} else {
header("Location: $location");
@ -30,22 +31,13 @@ function redirect(string $location): void
}
/**
* Return the path to a view file.
*/
function template(string $name): string
{
return "../templates/$name.php";
}
/**
* Render a view with the given data. Looks for `$path_to_base_view` through `template()`. Can be used redundantly
* within the template.
* Render a view with the given data. Can be used redundantly within the template.
*/
function render(string $path_to_base_view, array $data = []): string|false
{
ob_start();
extract($data);
require template($path_to_base_view);
require "../templates/$path_to_base_view.php";
return ob_get_clean();
}
@ -101,66 +93,11 @@ function display_admin($content, $title)
}
/**
* Finalize page and output to browser.
* Determine what game skin to use. If a user is logged in then it uses their setting, otherwise defaults to 0 (retro).
*/
function display($content, $title, bool $topnav = true, bool $leftnav = true, bool $rightnav = true): string
function game_skin(): int
{
global $controlrow;
$game_skin = user() !== false ? user()->game_skin : 0;
return render('layouts/primary', [
"dkgamename" => $controlrow["gamename"],
"content" => $content,
"game_skin" => $game_skin,
"topnav" => $topnav ? Render\header_links() : ''
]);
}
function checkcookies()
{
$row = false;
if (isset($_COOKIE["dkgame"])) {
// COOKIE FORMAT:
// {ID} {USERNAME} {PASSWORDHASH} {REMEMBERME}
$theuser = explode(" ",$_COOKIE["dkgame"]);
$query = db()->query('SELECT * FROM users WHERE id = ? AND username = ? AND password = ? LIMIT 1;', [$theuser[0], $theuser[1], $theuser[2]]);
if ($query === false) {
set_cookie('dkgame', '', -3600);
die("Invalid cookie data. Please log in again.");
}
$row = $query->fetchArray(SQLITE3_ASSOC);
set_cookie('dkgame', implode(" ", $theuser), (int) $theuser[3] === 1 ? time() + 31536000 : 0);
db()->query('UPDATE users SET onlinetime = CURRENT_TIMESTAMP WHERE id = ?;', [$theuser[0]]);
}
return $row;
}
/**
* Set a cookie with secure and HTTP-only flags.
*/
function set_cookie($name, $value, $expires)
{
setcookie($name, $value, [
'expires' => $expires,
'path' => '/',
'domain' => '', // Defaults to the current domain
'secure' => true, // Ensure the cookie is only sent over HTTPS
'httponly' => true, // Prevent access to cookie via JavaScript
'samesite' => 'Strict' // Enforce SameSite=Strict
]);
}
/**
* Get the current control row from the database.
*/
function get_control_row(): array|false
{
$query = db()->query('SELECT * FROM control WHERE id = 1 LIMIT 1;');
if ($query === false) return false;
return $query->fetchArray(SQLITE3_ASSOC);
return user() !== false ? user()->game_skin : 0;
}
/**
@ -563,7 +500,7 @@ function is_htmx(): bool
*/
function is_post(): bool
{
return is_post();
return $_SERVER['REQUEST_METHOD'] === 'POST';
}
/**
@ -571,7 +508,6 @@ function is_post(): bool
*/
function page_title(string $new_title = ''): string
{
global $controlrow;
if ($new_title) return $GLOBALS['state']['new-page-title'] = $new_title;
return $GLOBALS['state']['new-page-title'] ?? $controlrow['gamename'];
return $GLOBALS['state']['new-page-title'] ?? env('game_name');
}

View File

@ -11,13 +11,9 @@
*/
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
// Default configuration
$config = array_merge([
'from' => $from_addr,
'from' => env('admin_email', 'noreply@'.$_SERVER['SERVER_NAME']),
'log_path' => '../logs/email.log',
'method' => 'smtp', // 'smtp' or 'log'
'smtp_host' => env('smtp_host', 'localhost'),

View File

@ -20,7 +20,7 @@ class Model
public function __set(string $key, mixed $value): void
{
if (array_key_exists($key, $this->original_data)) {
$this->changes[$key] = $value;
if ($value !== $this->original_data[$key]) $this->changes[$key] = $value;
} else {
throw new InvalidArgumentException("Attempted to write to $key, which doesn't exist in the data for this model.");
}

View File

@ -38,6 +38,25 @@ class User extends Model
return $this;
}
/**
* Sends a manual update to online time for this user.
*/
public function update_online_time(): void
{
db()->query('UPDATE users SET onlinetime=CURRENT_TIMESTAMP WHERE id=?;', [$this->id]);
}
/**
* Heal HP by a given amount. Caps to max HP. Returns number of points restored.
*/
function restore_hp(int $amount): int
{
$initial_hp = $this->currenthp;
$this->currenthp += $amount;
if ($this->currenthp > $this->maxhp) $this->currenthp = $this->maxhp;
return $this->currenthp - $initial_hp;
}
/**
* Save works just as it does on the Model class. In our case, though, user state changing may necessitate
* OOB swaps for parts of the UI that have user data displayed. Left and right nav, for example. In these cases,

View File

@ -7,23 +7,20 @@ namespace Render;
to HTMX/AJAX for more fluid gameplay.
*/
function header_links(): string
/**
* Prepare content for final render. If the request is HTMX-based, will return just the content passed to it. Otherwise
* it will render() onto layouts/primary with some additional bits.
*/
function content(string $content): string
{
if (user() !== false) {
$links = "<a href='/logout'><img src='/img/button_logout.gif' alt='Log Out' title='Log Out'></a>";
} else {
$links = <<<HTML
<a href='/login'><img src='/img/button_login.gif' alt='Log In' title='Log In'></a>
<a href='/register'><img src='/img/button_register.gif' alt='Register' title='Register'></a>
HTML;
}
return $links .= "<a href='/help'><img src='/img/button_help.gif' alt='Help' title='Help'></a>";
if (is_htmx()) return $content;
return render('layouts/primary', ['content' => $content]);
}
function debug_db_info(): string {
$total_time = round(microtime(true) - START, 4);
return '<div id="debug-db-info" hx-swap-oob="true">'. $total_time . ' Seconds, ' . db()->count . ' Queries</div>';
$htmx = is_htmx() ? ' (htmx)' : '';
return '<div id="debug-db-info" hx-swap-oob="true">'. $total_time . ' Seconds, ' . db()->count . ' Queries'.$htmx.'</div>';
}
function right_nav(): string

View File

@ -1,10 +0,0 @@
<form action="/changepassword" method="post">
<table width="100%">
<tr><td colspan="2">Use the form below to change your password. All fields are required. New passwords must be 10 alphanumeric characters or less.</td></tr>
<tr><td width="20%">Username:</td><td><input type="text" name="username" size="30" maxlength="30" /></td></tr>
<tr><td>Old Password:</td><td><input type="password" name="password" /></td></tr>
<tr><td>New Password:</td><td><input type="password" name="new_password" /></td></tr>
<tr><td>Verify New Password:</td><td><input type="password" name="new_password2" /><br><br><br></td></tr>
<tr><td colspan="2"><input type="submit" name="submit" value="Submit"> <input type="reset" name="reset" value="Reset"></td></tr>
</table>
</form>

View File

@ -3,12 +3,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $control['gamename'] ?> Help</title>
<title><?= env('game_name', 'Dragon Knight') ?> Help</title>
<link rel="stylesheet" href="/css/help.css">
</head>
<body>
<a name="top"></a>
<h1><?= $control['gamename'] ?> Help</h1>
<h1><?= env('game_name', 'Dragon Knight') ?> Help</h1>
[ <a href="/help">Back to Help</a> ]<br>
[ <a href="/">Return to Game</a> ]

View File

@ -20,11 +20,19 @@
}
</script>
</head>
<body class="skin-<?= $game_skin ?>">
<body class="skin-<?= game_skin() ?>">
<div id="game-container">
<header>
<a href="/"><img id="logo" src="/img/logo.gif" alt="<?= $dkgamename ?>" title="<?= $dkgamename ?>"></a>
<nav><?= $topnav ?></nav>
<a href="/"><img id="logo" src="/img/logo.gif" alt="<?= env('game_name', 'Dragon Knight') ?>" title="<?= env('game_name', 'Dragon Knight') ?>"></a>
<nav>
<?php if (user() !== false): ?>
<a href='/logout'><img src='/img/button_logout.gif' alt='Log Out' title='Log Out'></a>
<?php else: ?>
<a href='/login'><img src='/img/button_login.gif' alt='Log In' title='Log In'></a>
<a href='/register'><img src='/img/button_register.gif' alt='Register' title='Register'></a>
<?php endif; ?>
<a href="/help" hx-boost='/help'><img src='/img/button_help.gif' alt='Help' title='Help'></a>
</nav>
</header>
<main>

View File

@ -10,13 +10,13 @@
Latitude: <?= $lat ?><br>
Longitude: <?= $lon ?><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>
<form action="/move" method="post" hx-post="/move" hx-target="#middle" class="move-compass">
<button name="direction" value="north" class="north">North</button>
<div class="mid">
<button type="submit" name="direction" value="west" class="west">West</button>
<button type="submit" name="direction" value="east" class="east">East</button>
<button name="direction" value="west" class="west">West</button>
<button name="direction" value="east" class="east">East</button>
</div>
<button type="submit" name="direction" value="south" class="south">South</button>
<button name="direction" value="south" class="south">South</button>
</form>
</section>
@ -36,7 +36,9 @@
while ($row = $towns->fetchArray(SQLITE3_ASSOC)) {
$mapped = true;
if (in_array($row['id'], $town_list)) {
echo "<a href=\"/gotown/{$row["id"]}\">".$row["name"]."</a><br>";
echo <<<HTML
<a href="/gotown/{$row['id']}" hx-get="/gotown/{$row['id']}" hx-target="#middle">{$row['name']}</a><br>
HTML;
}
}
if (!$mapped) echo 'You have no towns mapped.';
@ -45,13 +47,12 @@
<section>
<div class="title"><img src="/img/button_functions.gif" alt="Functions" title="Functions"></div>
<a href="/">Home</a><br>
<a href="/forum">Forum</a><br>
<a href="/" hx-get="/" hx-target="#middle">Home</a><br>
<a href="/forum" hx-get="/forum" hx-target="#middle">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>
<a href="/help">Help</a><br>
<a href="/logout">Log Out</a>
</section>

View File

@ -8,13 +8,6 @@
<td>Password:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>Remember me?</td>
<td>
<input type="hidden" name="remember" value="0">
<input type="checkbox" name="remember" value="1">
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" name="submit" value="Log In"></td>
</tr>
@ -22,9 +15,9 @@
<td colspan="2">
Checking the "Remember Me" option will store your login information in a cookie so you don't have
to enter it next time you get online.<br><br>Want to play? You gotta
<a href="users.php?do=register">register your own character.</a><br><br>You may also
<a href="users.php?do=changepassword">change your password</a>, or
<a href="users.php?do=lostpassword">request a new one</a> if you've lost yours.
<a href="/register">register your own character.</a><br><br>You may also
<a href="/changepassword">change your password</a>, or
<a href="/lostpassword">request a new one</a> if you've lost yours.
</td>
</tr>
</table>

View File

@ -4,14 +4,14 @@
<tr><td>Password:</td><td><input type="password" name="password"></td></tr>
<tr><td>Verify Password:</td><td><input type="password" name="confirm_password"><br>Passwords must be 10 alphanumeric characters or less.<br><br><br></td></tr>
<tr><td>Email Address:</td><td><input type="email" name="email"></td></tr>
<tr><td>Verify Email:</td><td><input type="email" name="confirm_email"><?= $controlrow['verifytext'] ?><br><br><br></td></tr>
<tr><td>Verify Email:</td><td><input type="email" name="confirm_email"><?= $verify_text ?><br><br><br></td></tr>
<tr>
<td>Character Class:</td>
<td>
<select name="charclass">
<option value="1"><?= $controlrow['class1name'] ?></option>
<option value="2"><?= $controlrow['class2name'] ?></option>
<option value="3"><?= $controlrow['class3name'] ?></option>
<option value="1"><?= env('class_1_name') ?></option>
<option value="2"><?= env('class_2_name') ?></option>
<option value="3"><?= env('class_3_name') ?></option>
</select>
</td>
</tr>

View File

@ -28,7 +28,9 @@
if ($user_spells !== false) {
foreach ($user_spells as $spell) {
// list only healing spells for now
if ($spell['type'] === 1) echo "<a href=\"/spell/{$spell['id']}\">".$spell['name']."</a><br>";
if ($spell['type'] === 1) echo <<<HTML
<a href="/spell/{$spell['id']}" hx-get="/spell/{$spell['id']}" hx-target="#middle">{$spell['name']}</a><br>
HTML;
}
} else {
echo 'None';

View File

@ -1,12 +1,29 @@
<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>
<section>
<h2>Game Skin</h2>
<form action="/settings" method="post">
<select name="game_skin">
<option value="0">Default</option>
<option value="1">Snowstorm</option>
</select>
<button type="submit">Save</button>
</form>
</section>
<section>
<h2>Change Password</h2>
<form action="/changepassword" method="post">
<table width="100%">
<tr><td colspan="2">Use the form below to change your password. All fields are required. New passwords must be 10 alphanumeric characters or less.</td></tr>
<tr><td>Old Password:</td><td><input type="password" name="password"></td></tr>
<tr><td>New Password:</td><td><input type="password" name="new_password"></td></tr>
<tr><td>Verify New Password:</td><td><input type="password" name="confirm_new_password"><br><br><br></td></tr>
<tr><td colspan="2"><input type="submit" name="submit" value="Submit"></td></tr>
</table>
</form>
</section>
<button type="submit">Save</button>
</form>

View File

@ -2,9 +2,9 @@
<b><?= $char->username ?></b><br><br>
Class: <?= match ($char->charclass) {
1 => $controlrow["class1name"],
2 => $controlrow["class2name"],
3 => $controlrow["class3name"]
1 => env('class_1_name'),
2 => env('class_2_name'),
3 => env('class_3_name')
}; ?><br><br>
Level: <?= $char->level ?><br>