So many changes... sheesh. Adds HTMX, reworks rendering, etc
This commit is contained in:
parent
169e617989
commit
1b9106fadb
|
@ -96,6 +96,7 @@ a {
|
|||
color: #663300;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
|
|
|
@ -8,7 +8,7 @@ html {
|
|||
}
|
||||
|
||||
body {
|
||||
background-image: url('/img/background.jpg');
|
||||
background-image: url('/img/backgrounds/background.jpg');
|
||||
padding: 2rem;
|
||||
}
|
||||
table {
|
||||
|
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
100
public/index.php
100
public/index.php
|
@ -8,7 +8,7 @@ $r = new Router;
|
|||
|
||||
$r->get('/', function() {
|
||||
if (user()->currentaction === "In Town") {
|
||||
$page = dotown();
|
||||
$page = Towns\town();
|
||||
$title = "In Town";
|
||||
} elseif (user()->currentaction === "Exploring") {
|
||||
$page = doexplore();
|
||||
|
@ -17,7 +17,7 @@ $r->get('/', function() {
|
|||
redirect('/fight');
|
||||
}
|
||||
|
||||
display($page, $title);
|
||||
return is_htmx() ? $page : display($page, $title);
|
||||
});
|
||||
|
||||
$r->get('/ninja', function() {
|
||||
|
@ -45,83 +45,15 @@ $l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
|||
|
||||
if (is_int($l)) exit("Error: $l");
|
||||
if (!empty($l['middleware'])) foreach ($l['middleware'] as $middleware) $middleware();
|
||||
$l['handler'](...$l['params'] ?? []);
|
||||
|
||||
function donothing()
|
||||
{
|
||||
if (user()->currentaction == "In Town") {
|
||||
$page = dotown();
|
||||
$title = "In Town";
|
||||
} elseif (user()->currentaction == "Exploring") {
|
||||
$page = doexplore();
|
||||
$title = "Exploring";
|
||||
} elseif (user()->currentaction == "Fighting") {
|
||||
redirect('/fight');
|
||||
}
|
||||
|
||||
display($page, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spit out the main town page.
|
||||
*/
|
||||
function dotown()
|
||||
{
|
||||
global $controlrow;
|
||||
|
||||
$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"] = "";
|
||||
$townrow["whosonline"] = "";
|
||||
$townrow["babblebox"] = "";
|
||||
|
||||
// News box. Grab latest news entry and display it. Something a little more graceful coming soon maybe.
|
||||
if ($controlrow["shownews"] == 1) {
|
||||
$newsrow = db()->query('SELECT * FROM news ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC);
|
||||
$townrow["news"] = '<div class="title">Latest News</div>';
|
||||
$townrow["news"] .= "<span class=\"light\">[".pretty_date($newsrow["postdate"])."]</span><br>".nl2br($newsrow["content"]);
|
||||
}
|
||||
|
||||
// Who's Online. Currently just members. Guests maybe later.
|
||||
if ($controlrow["showonline"] == 1) {
|
||||
$onlinequery = db()->query(<<<SQL
|
||||
SELECT id, username
|
||||
FROM users
|
||||
WHERE onlinetime >= datetime('now', '-600 seconds')
|
||||
ORDER BY username;
|
||||
SQL);
|
||||
|
||||
$online_count = 0;
|
||||
$online_rows = [];
|
||||
|
||||
while ($onlinerow = $onlinequery->fetchArray(SQLITE3_ASSOC)) {
|
||||
$online_count++;
|
||||
$online_rows[] = "<a href=\"javascript:opencharpopup({$onlinerow['id']})\">".$onlinerow["username"]."</a>";
|
||||
}
|
||||
|
||||
$townrow["whosonline"] = '<div class="title">Who\'s Online</div>';
|
||||
$townrow["whosonline"] .= "There are <b>$online_count</b> user(s) online within the last 10 minutes: ";
|
||||
$townrow["whosonline"] .= rtrim(implode(', ', $online_rows), ', ');
|
||||
}
|
||||
|
||||
if ($controlrow["showbabble"] == 1) {
|
||||
$townrow["babblebox"] = <<<HTML
|
||||
<div class="title">Babble Box</div>
|
||||
<iframe src="/babblebox" name="sbox" width="100%" height="250" frameborder="0" id="bbox">
|
||||
Your browser does not support inline frames! The Babble Box will not be available until you upgrade to
|
||||
a newer <a href="http://www.mozilla.org" target="_new">browser</a>.
|
||||
</iframe>
|
||||
HTML;
|
||||
}
|
||||
|
||||
$u = User::find(1);
|
||||
$u->gold += 100;
|
||||
$u->save();
|
||||
var_dump($u->gold);
|
||||
|
||||
return render('towns', ['town' => $townrow]);
|
||||
$content = $l['handler'](...$l['params'] ?? []);
|
||||
if (is_htmx()) {
|
||||
$content .= Render\debug_db_info();
|
||||
if ($GLOBALS['state']['user-state-changed'] ?? false) {
|
||||
$content .= Render\right_nav();
|
||||
}
|
||||
}
|
||||
echo $content;
|
||||
exit;
|
||||
|
||||
/**
|
||||
* Just spit out a blank exploring page. Exploring without a GET string is normally when they first log in, or when
|
||||
|
@ -130,12 +62,8 @@ function dotown()
|
|||
function doexplore()
|
||||
{
|
||||
return <<<HTML
|
||||
<table width="100%">
|
||||
<tr><td class="title"><img src="/img/title_exploring.gif" alt="Exploring" /></td></tr>
|
||||
<tr><td>
|
||||
You are exploring the map, and nothing has happened. Continue exploring using the direction buttons or the Travel To menus.
|
||||
</td></tr>
|
||||
</table>
|
||||
<div class="title"><img src="/img/title_exploring.gif" alt="Exploring"></div>
|
||||
You are exploring the map, and nothing has happened. Continue exploring using the direction buttons or the Travel To menus.
|
||||
HTML;
|
||||
}
|
||||
|
||||
|
@ -167,7 +95,7 @@ function show_character_info(int $id = 0): void
|
|||
'magic_list' => $magic_list,
|
||||
'controlrow' => $controlrow
|
||||
]);
|
||||
echo render('minimal', ['content' => $showchar, 'title' => $userrow['username'].' Information']);
|
||||
echo render('layouts/minimal', ['content' => $showchar, 'title' => $userrow['username'].' Information']);
|
||||
}
|
||||
|
||||
function showmap()
|
||||
|
@ -178,7 +106,7 @@ function showmap()
|
|||
round(258 - user()->latitude * (500 / 500) - 3)
|
||||
);
|
||||
|
||||
echo render('minimal', [
|
||||
echo render('layouts/minimal', [
|
||||
'content' => '<img src="/img/map.gif" alt="Map">'.$pos,
|
||||
'title' => 'Map'
|
||||
]);
|
||||
|
|
1
public/js/htmx.js
Normal file
1
public/js/htmx.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -495,7 +495,7 @@ function levels()
|
|||
function display_help(string $content)
|
||||
{
|
||||
global $controlrow;
|
||||
echo render('help', [
|
||||
echo render('layouts/help', [
|
||||
'control' => $controlrow,
|
||||
'content' => $content,
|
||||
'version' => VERSION,
|
||||
|
|
|
@ -20,40 +20,99 @@ function register_routes(Router $r): Router
|
|||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spit out the main town page.
|
||||
*/
|
||||
function town()
|
||||
{
|
||||
global $controlrow;
|
||||
|
||||
$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"] = "";
|
||||
$townrow["whosonline"] = "";
|
||||
$townrow["babblebox"] = "";
|
||||
|
||||
// News box. Grab latest news entry and display it. Something a little more graceful coming soon maybe.
|
||||
if ($controlrow["shownews"] == 1) {
|
||||
$newsrow = db()->query('SELECT * FROM news ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC);
|
||||
$townrow["news"] = '<div class="title">Latest News</div>';
|
||||
$townrow["news"] .= "<span class=\"light\">[".pretty_date($newsrow["postdate"])."]</span><br>".nl2br($newsrow["content"]);
|
||||
}
|
||||
|
||||
// Who's Online. Currently just members. Guests maybe later.
|
||||
if ($controlrow["showonline"] == 1) {
|
||||
$onlinequery = db()->query(<<<SQL
|
||||
SELECT id, username
|
||||
FROM users
|
||||
WHERE onlinetime >= datetime('now', '-600 seconds')
|
||||
ORDER BY username;
|
||||
SQL);
|
||||
|
||||
$online_count = 0;
|
||||
$online_rows = [];
|
||||
|
||||
while ($onlinerow = $onlinequery->fetchArray(SQLITE3_ASSOC)) {
|
||||
$online_count++;
|
||||
$online_rows[] = "<a href=\"javascript:opencharpopup({$onlinerow['id']})\">".$onlinerow["username"]."</a>";
|
||||
}
|
||||
|
||||
$townrow["whosonline"] = '<div class="title">Who\'s Online</div>';
|
||||
$townrow["whosonline"] .= "There are <b>$online_count</b> user(s) online within the last 10 minutes: ";
|
||||
$townrow["whosonline"] .= rtrim(implode(', ', $online_rows), ', ');
|
||||
}
|
||||
|
||||
if ($controlrow["showbabble"] == 1) {
|
||||
$townrow["babblebox"] = <<<HTML
|
||||
<div class="title">Babble Box</div>
|
||||
<iframe src="/babblebox" name="sbox" width="100%" height="250" frameborder="0" id="bbox">
|
||||
Your browser does not support inline frames! The Babble Box will not be available until you upgrade to
|
||||
a newer <a href="http://www.mozilla.org" target="_new">browser</a>.
|
||||
</iframe>
|
||||
HTML;
|
||||
}
|
||||
|
||||
if (is_htmx()) htmx_update_page_title($townrow['name']);
|
||||
return render('towns', ['town' => $townrow]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Staying at the inn resets all expendable stats to their max values.
|
||||
*/
|
||||
function inn()
|
||||
{
|
||||
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
|
||||
if ($townrow === false) { display("Cheat attempt detected.<br><br>Get a life, loser.", "Error"); }
|
||||
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
||||
if ($town === false) { exit('Cheat attempt detected.<br><br>Get a life, loser.'); }
|
||||
|
||||
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");
|
||||
}
|
||||
$htmx = is_htmx();
|
||||
if ($htmx) htmx_update_page_title($town['name'] . ' Inn');
|
||||
|
||||
if (isset($_POST["submit"])) {
|
||||
$newgold = user()->gold - $townrow["innprice"];
|
||||
db()->query(
|
||||
'UPDATE users SET gold=?, currenthp=?, currentmp=?, currenttp=? WHERE 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.";
|
||||
} elseif (isset($_POST["cancel"])) {
|
||||
if (user()->gold < $town['innprice']) {
|
||||
$page = <<<HTML
|
||||
You do not have enough gold to stay at this Inn tonight. <br><br>
|
||||
You may return to <a hx-get="/" hx-target="#middle">town</a>, or use the direction buttons on the left to start exploring.
|
||||
HTML;
|
||||
} elseif (isset($_POST['submit'])) {
|
||||
user()->gold -= $town['innprice'];
|
||||
user()->restore_points()->save();
|
||||
$page = <<<HTML
|
||||
You wake up feeling refreshed and ready for action. <br><br>
|
||||
You may return to <a hx-get="/" hx-target="#middle">town</a>, or use the direction buttons on the left to start exploring.
|
||||
HTML;
|
||||
} elseif (isset($_POST['cancel'])) {
|
||||
redirect('/');
|
||||
} else {
|
||||
$title = "Inn";
|
||||
$page = <<<HTML
|
||||
Resting at the inn will refill your current HP, MP, and TP to their maximum levels.<br><br>
|
||||
A night's sleep at this Inn will cost you <b>{$townrow["innprice"]} gold</b>. Is that ok?<br><br>
|
||||
<form action="/inn" method="post">
|
||||
<input type="submit" name="submit" value="Yes"> <input type="submit" name="cancel" value="No">
|
||||
</form>
|
||||
Resting at the inn will refill your current HP, MP, and TP to their maximum levels.<br><br>
|
||||
A night's sleep at this Inn will cost you <b>{$town['innprice']} gold</b>. Is that ok?<br><br>
|
||||
<form hx-post="/inn" hx-target="#middle">
|
||||
<input type="submit" name="submit" value="Yes"> <input type="submit" name="cancel" value="No">
|
||||
</form>
|
||||
HTML;
|
||||
}
|
||||
|
||||
display($page, $title);
|
||||
return $htmx ? $page : display($page, $town['name'] . ' Inn');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,32 +120,51 @@ function inn()
|
|||
*/
|
||||
function buy()
|
||||
{
|
||||
$townrow = get_town_by_xy(user()->longitude, user()->latitude);
|
||||
if ($townrow === false) display("Cheat attempt detected.<br><br>Get a life, loser.", "Error");
|
||||
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
||||
if ($town === false) { exit('Cheat attempt detected.<br><br>Get a life, loser.'); }
|
||||
|
||||
$items = db()->query("SELECT * FROM items WHERE id IN ({$townrow["itemslist"]});");
|
||||
$page = "Buying weapons will increase your Attack Power. Buying armor and shields will increase your Defense Power.<br><br>Click an item name to purchase it.<br><br>The following items are available at this town:<br><br>\n";
|
||||
$page .= "<table width=\"80%\">\n";
|
||||
while ($itemsrow = $items->fetchArray(SQLITE3_ASSOC)) {
|
||||
$attrib = ($itemsrow["type"] == 1) ? "Attack Power:" : "Defense Power:";
|
||||
$page .= "<tr><td width=\"4%\">";
|
||||
$page .= match ($itemsrow["type"]) {
|
||||
1 => '<img src="/img/icon_weapon.gif" alt="weapon" /></td>',
|
||||
2 => '<img src="/img/icon_armor.gif" alt="armor" /></td>',
|
||||
3 => '<img src="/img/icon_shield.gif" alt="shield" /></td>'
|
||||
$htmx = is_htmx();
|
||||
if ($htmx) htmx_update_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>
|
||||
Click an item name to purchase it.<br><br>
|
||||
The following items are available at this town:<br><br>
|
||||
<table>
|
||||
HTML;
|
||||
|
||||
$items = db()->query('SELECT * FROM items WHERE id IN (' . $town["itemslist"] . ');');
|
||||
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
||||
$attrib = ($item["type"] == 1) ? "Attack Power:" : "Defense Power:";
|
||||
$page .= '<tr><td width="4%">';
|
||||
$page .= match ($item["type"]) {
|
||||
1 => '<img src="/img/icon_weapon.gif" alt="weapon">',
|
||||
2 => '<img src="/img/icon_armor.gif" alt="armor">',
|
||||
3 => '<img src="/img/icon_shield.gif" alt="shield">'
|
||||
};
|
||||
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";
|
||||
$page .= '</td>';
|
||||
if (user()->weaponid === $item["id"] || user()->armorid === $item["id"] || user()->shieldid === $item["id"]) {
|
||||
$page .= <<<HTML
|
||||
<td width="32%"><span class="light">{$item["name"]}</span></td>
|
||||
<td width="32%"><span class="light">$attrib {$item['attribute']}</span></td>
|
||||
<td width="32%"><span class="light">Already purchased</span></td>
|
||||
HTML;
|
||||
} else {
|
||||
if ($itemsrow["special"] != "X") { $specialdot = "<span class=\"highlight\">*</span>"; } else { $specialdot = ""; }
|
||||
$page .= "<td width=\"32%\"><b><a href=\"/buy2/{$itemsrow["id"]}\">".$itemsrow["name"]."</a>$specialdot</b></td><td width=\"32%\">$attrib <b>".$itemsrow["attribute"]."</b></td><td width=\"32%\">Price: <b>".$itemsrow["buycost"]." gold</b></td></tr>\n";
|
||||
$specialdot = $item['special'] !== 'X' ? '<span class="highlight">*</span>' : '';
|
||||
$page .= <<<HTML
|
||||
<td width="32%"><b><a href="/buy2/{$item['id']}">{$item['name']}</a>$specialdot</b></td>
|
||||
<td width="32%">$attrib <b>{$item['attribute']}</b></td>
|
||||
<td width="32%">Price: <b>{$item['buycost']} gold</b></td>
|
||||
HTML;
|
||||
}
|
||||
$page .= '</tr>';
|
||||
}
|
||||
$page .= "</table><br>\n";
|
||||
$page .= "If you've changed your mind, you may also return back to <a href=\"/\">town</a>.\n";
|
||||
$title = "Buy Items";
|
||||
$page .= <<<HTML
|
||||
</table><br>
|
||||
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
||||
HTML;
|
||||
|
||||
display($page, $title);
|
||||
return $htmx ? $page : display($page, $town['name'] . ' Shop');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,7 @@ require_once 'lib.php';
|
|||
require_once 'router.php';
|
||||
require_once 'auth.php';
|
||||
require_once 'mail.php';
|
||||
require_once 'render.php';
|
||||
require_once 'actions/explore.php';
|
||||
require_once 'actions/heal.php';
|
||||
require_once 'actions/users.php';
|
||||
|
|
110
src/lib.php
110
src/lib.php
|
@ -19,7 +19,13 @@ function db(): Database
|
|||
*/
|
||||
function redirect(string $location): void
|
||||
{
|
||||
header("Location: $location");
|
||||
if (is_htmx()) {
|
||||
header("HX-Redirect: $location");
|
||||
header("HX-Replace-Url: $location");
|
||||
} else {
|
||||
header("Location: $location");
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
|
@ -82,7 +88,7 @@ function make_safe(string $content): string
|
|||
*/
|
||||
function display_admin($content, $title)
|
||||
{
|
||||
echo render('admin', [
|
||||
echo render('layouts/admin', [
|
||||
"title" => $title,
|
||||
"content" => $content,
|
||||
"totaltime" => round(microtime(true) - START, 4),
|
||||
|
@ -97,28 +103,17 @@ function display_admin($content, $title)
|
|||
/**
|
||||
* Finalize page and output to browser.
|
||||
*/
|
||||
function display($content, $title, bool $topnav = true, bool $leftnav = true, bool $rightnav = true): void
|
||||
function display($content, $title, bool $topnav = true, bool $leftnav = true, bool $rightnav = true): string
|
||||
{
|
||||
global $controlrow;
|
||||
|
||||
if ($topnav == true) {
|
||||
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>
|
||||
HTML;
|
||||
} else {
|
||||
$topnav = <<<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>
|
||||
<a href='/help'><img src='/img/button_help.gif' alt='Help' title='Help'></a>
|
||||
HTML;
|
||||
}
|
||||
} else {
|
||||
$topnav = '';
|
||||
}
|
||||
$game_skin = 0;
|
||||
|
||||
$topnav = $topnav ? Render\header_links() : '';
|
||||
|
||||
if (user() !== false) {
|
||||
$game_skin = user()->game_skin;
|
||||
|
||||
if (user()->currentaction == 'In Town') {
|
||||
$town = get_town_by_xy(user()->latitude, user()->longitude);
|
||||
$current_town = "Welcome to <b>{$town['name']}</b>.<br><br>";
|
||||
|
@ -129,26 +124,6 @@ function display($content, $title, bool $topnav = true, bool $leftnav = true, bo
|
|||
// Format various userrow stuffs...
|
||||
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 (user()->currenthp <= (user()->maxhp/5)) { user()->currenthp = "<blink><span class=\"highlight\"><b>*".user()->currenthp."*</b></span></blink>"; }
|
||||
if (user()->currentmp <= (user()->maxmp/5)) { user()->currentmp = "<blink><span class=\"highlight\"><b>*".user()->currentmp."*</b></span></blink>"; }
|
||||
|
||||
$user_spells = explode(',', user()->spells);
|
||||
$spellquery = get_spells_from_list($user_spells);
|
||||
user()->magiclist = '';
|
||||
while ($spell = $spellquery->fetchArray(SQLITE3_ASSOC)) {
|
||||
$spell = false;
|
||||
foreach($user_spells as $id) {
|
||||
if ($id === $spell['id'] && $spell['type'] == 1) $spell = true;
|
||||
}
|
||||
if ($spell == true) {
|
||||
user()->magiclist .= "<a href=\"/spell/{$spell['id']}\">".$spell['name']."</a><br>";
|
||||
}
|
||||
}
|
||||
if (user()->magiclist == "") { user()->magiclist = "None"; }
|
||||
|
||||
// Travel To list.
|
||||
$townslist = explode(",",user()->towns);
|
||||
|
@ -165,22 +140,14 @@ function display($content, $title, bool $topnav = true, bool $leftnav = true, bo
|
|||
}
|
||||
}
|
||||
|
||||
echo render('primary', [
|
||||
return render('layouts/primary', [
|
||||
"dkgamename" => $controlrow["gamename"],
|
||||
"title" => $title,
|
||||
"content" => $content,
|
||||
"game_skin" => user()->game_skin ??= '0',
|
||||
'rightnav' => $rightnav ? render('rightnav', ['statbars' => create_stat_table(user())]) : '',
|
||||
"game_skin" => $game_skin,
|
||||
"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" => env('debug', false) ? db()->log : []
|
||||
]);
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
function checkcookies()
|
||||
|
@ -575,32 +542,36 @@ function env(string $key, mixed $default = null): mixed
|
|||
/**
|
||||
* Get the data on spells from a given list of IDs.
|
||||
*/
|
||||
function get_spells_from_list(array|string $spell_ids): SQLite3Result|false
|
||||
function get_spells_from_list(array|string $spell_ids): array|false
|
||||
{
|
||||
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;
|
||||
$rows = [];
|
||||
while ($row = $query->fetchArray(SQLITE3_ASSOC)) $rows[] = $row;
|
||||
return !empty($rows) ? $rows : false;
|
||||
}
|
||||
|
||||
function generate_stat_bar($current, $max)
|
||||
function generate_stat_bar(int $current, int $max): string
|
||||
{
|
||||
$percent = ($max === 0) ? 0 : ceil($current / $max * 100);
|
||||
$percent = $max > 0 ? round(max(0, $current) / $max * 100, 4) : 0;
|
||||
$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>';
|
||||
return <<<HTML
|
||||
<div class="stat-bar" style="width: 15px; height: 100px; border: solid 1px black;">
|
||||
<div style="height: $percent%; background-image: url(/img/bars_$color.gif);"></div>
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
|
||||
function create_stat_table($userrow)
|
||||
function create_stat_table(): string
|
||||
{
|
||||
$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 class="stat-col">' . generate_stat_bar((int)user()->currenthp, (int)user()->maxhp) . '<div>HP</div></div>' .
|
||||
'<div class="stat-col">' . generate_stat_bar((int)user()->currentmp, (int)user()->maxmp) . '<div>MP</div></div>' .
|
||||
'<div class="stat-col">' . generate_stat_bar((int)user()->currenttp, (int)user()->maxtp) . '<div>TP</div></div>' .
|
||||
'</div>' .
|
||||
'</div>';
|
||||
|
||||
|
@ -612,6 +583,23 @@ function create_stat_table($userrow)
|
|||
*/
|
||||
function user(): User|false
|
||||
{
|
||||
$GLOBALS['state']['user'] ??= ($_SESSION['user_id'] ? User::find($_SESSION['user_id']) : false);
|
||||
$GLOBALS['state']['user'] ??= (isset($_SESSION['user_id']) ? User::find($_SESSION['user_id']) : false);
|
||||
return $GLOBALS['state']['user'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a request is from HTMX. If HTMX is trying to restore history, we will say no in order to render
|
||||
* full pages.
|
||||
*/
|
||||
function is_htmx(): bool
|
||||
{
|
||||
if (isset($_SERVER['HTTP_HX_HISTORY_RESTORE_REQUEST']) && $_SERVER['HTTP_HX_HISTORY_RESTORE_REQUEST'] === 'true') return false;
|
||||
return isset($_SERVER['HTTP_HX_REQUEST']) && $_SERVER['HTTP_HX_REQUEST'] === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the page title using HTMX.
|
||||
*/
|
||||
function htmx_update_page_title(string $new_title) {
|
||||
header('HX-Trigger: ' . json_encode(['updateTitle' => ['title' => $new_title]]));
|
||||
}
|
||||
|
|
|
@ -19,7 +19,11 @@ class Model
|
|||
|
||||
public function __set(string $key, mixed $value): void
|
||||
{
|
||||
if (array_key_exists($key, $this->original_data)) $this->changes[$key] = $value;
|
||||
if (array_key_exists($key, $this->original_data)) {
|
||||
$this->changes[$key] = $value;
|
||||
} else {
|
||||
throw new InvalidArgumentException("Attempted to write to $key, which doesn't exist in the data for this model.");
|
||||
}
|
||||
}
|
||||
|
||||
public function save(): bool
|
||||
|
|
|
@ -18,4 +18,48 @@ class User extends Model
|
|||
if ($data === false) return false;
|
||||
return new User($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of spells from this user's spell list.
|
||||
*/
|
||||
public function spells(): array|false
|
||||
{
|
||||
return get_spells_from_list($this->spells);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore all HP, MP, and TP values to their max.
|
||||
*/
|
||||
public function restore_points(): User
|
||||
{
|
||||
$this->currenthp = $this->maxhp;
|
||||
$this->currentmp = $this->maxmp;
|
||||
$this->currenttp = $this->maxtp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* we set a flag in GLOBALS state to signify this.
|
||||
*/
|
||||
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);
|
||||
if ($result === false) return false;
|
||||
$GLOBALS['state']['user-state-changed'] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
40
src/render.php
Normal file
40
src/render.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Render;
|
||||
|
||||
/*
|
||||
This file contains functions to render various UI elements. The goal is to begin shifting elements in the game
|
||||
to HTMX/AJAX for more fluid gameplay.
|
||||
*/
|
||||
|
||||
function header_links(): 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>";
|
||||
}
|
||||
|
||||
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>';
|
||||
}
|
||||
|
||||
function right_nav(): string
|
||||
{
|
||||
if (user() === false) return '';
|
||||
|
||||
// Flashy numbers if they're low
|
||||
$hp = (user()->currenthp <= (user()->maxhp / 5)) ? "<blink><span class=\"highlight\"><b>*" . user()->currenthp . "*</b></span></blink>" : user()->currenthp;
|
||||
$mp = (user()->currentmp <= (user()->maxmp / 5)) ? "<blink><span class=\"highlight\"><b>*" . user()->currentmp . "*</b></span></blink>" : user()->currentmp;
|
||||
|
||||
$template = render('right_nav', ['hp' => $hp, 'mp' => $mp]);
|
||||
if (is_htmx()) $template = '<section id="right" hx-swap-oob="true">'.$template."</section>";
|
||||
return $template;
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= $title ?></title>
|
||||
<link rel="stylesheet" href="/css/dk.css">
|
||||
<script src="/js/htmx.js"></script>
|
||||
|
||||
<script>
|
||||
function opencharpopup(id = 0)
|
||||
|
@ -29,20 +30,20 @@
|
|||
<main>
|
||||
<section id="left"><?= $leftnav ?></section>
|
||||
<section id="middle"><?= $content ?></section>
|
||||
<section id="right"><?= $rightnav ?></section>
|
||||
<section id="right"><?= Render\right_nav() ?></section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div>Powered by <a href="/" target="_new">Dragon Knight</a></div>
|
||||
<div>© 2024 Sharkk</div>
|
||||
<div><?= $totaltime ?> Seconds, <?= $numqueries ?> Queries</div>
|
||||
<div>Version <?= $version ?> <?= $build ?></div>
|
||||
<?= Render\debug_db_info(); ?>
|
||||
<div>Version <?= VERSION ?> <?= BUILD ?></div>
|
||||
</footer>
|
||||
|
||||
<?php
|
||||
if (!empty($querylog)) {
|
||||
if (env('debug', false)) {
|
||||
echo '<pre>';
|
||||
foreach ($querylog as $record) {
|
||||
foreach (db()->log 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>";
|
||||
|
@ -51,5 +52,15 @@
|
|||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("updateTitle", (event) => {
|
||||
const title = event.detail?.title;
|
||||
if (title) {
|
||||
console.log('New title:', title);
|
||||
document.title = title;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -2,26 +2,36 @@
|
|||
<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>
|
||||
Exp: <?= number_format(user()->experience) ?><br>
|
||||
Gold: <?= number_format(user()->gold) ?><br>
|
||||
HP: <?= $hp ?><br>
|
||||
MP: <?= $mp ?><br>
|
||||
TP: <?= user()->currenttp ?><br><br>
|
||||
<?= $statbars ?><br>
|
||||
<?= create_stat_table() ?><br>
|
||||
<a href="javascript:opencharpopup()">Extended Stats</a>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="title"><img src="/img/button_inventory.gif" alt="Inventory" title="Inventory"></div>
|
||||
<img src="/img/icon_weapon.gif" alt="Weapon" title="Weapon"> Weapon: <?= $user['weaponname'] ?><br>
|
||||
<img src="/img/icon_armor.gif" alt="Armor" title="Armor"> Armor: <?= $user['armorname'] ?><br>
|
||||
<img src="/img/icon_shield.gif" alt="Shield" title="Shield"> Shield: <?= $user['shieldname'] ?><br>
|
||||
Slot 1: <?= $user['slot1name'] ?><br>
|
||||
Slot 2: <?= $user['slot2name'] ?><br>
|
||||
Slot 3: <?= $user['slot3name'] ?>
|
||||
<img src="/img/icon_weapon.gif" alt="Weapon" title="Weapon"> Weapon: <?= user()->weaponname ?><br>
|
||||
<img src="/img/icon_armor.gif" alt="Armor" title="Armor"> Armor: <?= user()->armorname ?><br>
|
||||
<img src="/img/icon_shield.gif" alt="Shield" title="Shield"> Shield: <?= user()->shieldname ?><br>
|
||||
Slot 1: <?= user()->slot1name ?><br>
|
||||
Slot 2: <?= user()->slot2name ?><br>
|
||||
Slot 3: <?= user()->slot3name ?>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="title"><img src="/img/button_fastspells.gif" alt="Fast Spells" title="Fast Spells"></div>
|
||||
<?= $user['magiclist'] ?>
|
||||
<?php
|
||||
$user_spells = user()->spells();
|
||||
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>";
|
||||
}
|
||||
} else {
|
||||
echo 'None';
|
||||
}
|
||||
?>
|
||||
</section>
|
|
@ -3,8 +3,8 @@
|
|||
<div class="title"><img src="/img/town_<?= $town['id'] ?>.gif" alt="Welcome to <?= $town['name'] ?>" title="Welcome to <?= $town['name'] ?>"></div>
|
||||
<b>Town Options:</b><br>
|
||||
<ul>
|
||||
<li><a href="/inn">Rest at the Inn</a></li>
|
||||
<li><a href="/buy">Buy Weapons/Armor</a></li>
|
||||
<li><a hx-get="/inn" hx-target="#middle">Rest at the Inn</a></li>
|
||||
<li><a hx-get="/buy" hx-target="#middle">Buy Weapons/Armor</a></li>
|
||||
<li><a href="/maps">Buy Maps</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue
Block a user