functions.php
This commit is contained in:
parent
feba005335
commit
4d5c345528
@ -13,6 +13,10 @@
|
|||||||
"team-reflex/discord-php": "^10.18.45"
|
"team-reflex/discord-php": "^10.18.45"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/DragonKnight/functions.php",
|
||||||
|
"src/DragonKnight/DragonKnight.php"
|
||||||
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"DragonKnight\\": "src/DragonKnight"
|
"DragonKnight\\": "src/DragonKnight"
|
||||||
}
|
}
|
||||||
|
@ -21,20 +21,20 @@ use DragonKnight\Admin\Admin;
|
|||||||
|
|
||||||
// Do an early return with babblebox data if that's what's being requested
|
// Do an early return with babblebox data if that's what's being requested
|
||||||
if ($uri[0] === 'babblebox' && (isset($uri[1]) && $uri[1] === 'messages')) {
|
if ($uri[0] === 'babblebox' && (isset($uri[1]) && $uri[1] === 'messages')) {
|
||||||
echo Lib::babblebox_messages();
|
echo babblebox_messages();
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$r = new Router;
|
$r = new Router;
|
||||||
|
|
||||||
$r->get('/', 'DragonKnight\Lib::index');
|
$r->get('/', 'DragonKnight\index');
|
||||||
$r->post('/move', 'DragonKnight\Actions\Explore::move');
|
$r->post('/move', 'DragonKnight\Actions\Explore::move');
|
||||||
$r->get('/spell/:id', 'DragonKnight\Actions\Heal::healspells');
|
$r->get('/spell/:id', 'DragonKnight\Actions\Heal::healspells');
|
||||||
$r->get('/character', 'DragonKnight\Lib::show_character_info');
|
$r->get('/character', 'DragonKnight\show_character_info');
|
||||||
$r->get('/character/:id', 'DragonKnight\Lib::show_character_info');
|
$r->get('/character/:id', 'DragonKnight\show_character_info');
|
||||||
$r->get('/showmap', 'DragonKnight\Lib::show_map');
|
$r->get('/showmap', 'DragonKnight\show_map');
|
||||||
$r->form('/babblebox', 'DragonKnight\Lib::babblebox');
|
$r->form('/babblebox', 'DragonKnight\babblebox');
|
||||||
$r->get('/babblebox/messages', 'DragonKnight\Lib::babblebox_messages');
|
$r->get('/babblebox/messages', 'DragonKnight\babblebox_messages');
|
||||||
|
|
||||||
Towns::register_routes($r);
|
Towns::register_routes($r);
|
||||||
Fight::register_routes($r);
|
Fight::register_routes($r);
|
||||||
@ -57,4 +57,4 @@ $l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
|||||||
if (is_int($l)) {
|
if (is_int($l)) {
|
||||||
exit("Error: $l");
|
exit("Error: $l");
|
||||||
}
|
}
|
||||||
echo Lib::render_response($uri, $l['handler'](...$l['params'] ?? []));
|
echo render_response($uri, $l['handler'](...$l['params'] ?? []));
|
||||||
|
@ -13,15 +13,29 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Admin;
|
namespace DragonKnight\Admin;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
use DragonKnight\Router;
|
use DragonKnight\Router;
|
||||||
use SQLite3Result;
|
use SQLite3Result;
|
||||||
|
|
||||||
|
use function DragonKnight\db;
|
||||||
|
use function DragonKnight\env;
|
||||||
|
use function DragonKnight\get_drop;
|
||||||
|
use function DragonKnight\get_item;
|
||||||
|
use function DragonKnight\get_monster;
|
||||||
|
use function DragonKnight\get_spell;
|
||||||
|
use function DragonKnight\get_town_by_id;
|
||||||
|
use function DragonKnight\is_post;
|
||||||
|
use function DragonKnight\make_safe;
|
||||||
|
use function DragonKnight\page_title;
|
||||||
|
use function DragonKnight\render;
|
||||||
|
use function DragonKnight\ul_from_validate_errors;
|
||||||
|
use function DragonKnight\user;
|
||||||
|
use function DragonKnight\validate;
|
||||||
|
|
||||||
class Admin
|
class Admin
|
||||||
{
|
{
|
||||||
public static function register_routes(Router $r): Router
|
public static function register_routes(Router $r): Router
|
||||||
{
|
{
|
||||||
if (Lib::user() !== false && Lib::user()->authlevel === 1) {
|
if (user() !== false && user()->authlevel === 1) {
|
||||||
$r->get('/admin', 'Admin\donothing');
|
$r->get('/admin', 'Admin\donothing');
|
||||||
|
|
||||||
$r->form('/admin/main', 'Admin\primary');
|
$r->form('/admin/main', 'Admin\primary');
|
||||||
@ -58,7 +72,7 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function donothing(): string
|
public static function donothing(): string
|
||||||
{
|
{
|
||||||
Lib::page_title('Admin');
|
page_title('Admin');
|
||||||
|
|
||||||
return <<<HTML
|
return <<<HTML
|
||||||
Welcome to the administration section. Use the links on the left bar to control and edit various
|
Welcome to the administration section. Use the links on the left bar to control and edit various
|
||||||
@ -81,8 +95,8 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function primary(): string
|
public static function primary(): string
|
||||||
{
|
{
|
||||||
if (Lib::is_post()) {
|
if (is_post()) {
|
||||||
$form = Lib::validate($_POST, [
|
$form = validate($_POST, [
|
||||||
'gamename' => ['alphanum-spaces'],
|
'gamename' => ['alphanum-spaces'],
|
||||||
'gamesize' => ['int', 'min:5'],
|
'gamesize' => ['int', 'min:5'],
|
||||||
'class1name' => ['alpha-spaces'],
|
'class1name' => ['alpha-spaces'],
|
||||||
@ -106,7 +120,7 @@ class Admin
|
|||||||
|
|
||||||
$page = 'Main settings updated.';
|
$page = 'Main settings updated.';
|
||||||
} else {
|
} else {
|
||||||
$error_list = Lib::ul_from_validate_errors($form['errors']);
|
$error_list = ul_from_validate_errors($form['errors']);
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
<b>Errors:</b><br>
|
<b>Errors:</b><br>
|
||||||
<div style="color: red;">{$error_list}</div><br>
|
<div style="color: red;">{$error_list}</div><br>
|
||||||
@ -114,10 +128,10 @@ class Admin
|
|||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$page = Lib::render('admin/main_settings');
|
$page = render('admin/main_settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Admin: Main Settings');
|
page_title('Admin: Main Settings');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -127,11 +141,11 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function items(): string
|
public static function items(): string
|
||||||
{
|
{
|
||||||
$items = Lib::db()->query('SELECT * FROM items ORDER BY id;');
|
$items = db()->query('SELECT * FROM items ORDER BY id;');
|
||||||
$page = "<h2>Edit Items</h2>Click an item's name or ID to edit it.<br><br>\n";
|
$page = "<h2>Edit Items</h2>Click an item's name or ID to edit it.<br><br>\n";
|
||||||
$page .= self::build_bulk_table($items, 'name', '/admin/items');
|
$page .= self::build_bulk_table($items, 'name', '/admin/items');
|
||||||
|
|
||||||
Lib::page_title('Admin: Items');
|
page_title('Admin: Items');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -141,19 +155,19 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function edit_item(int $id): string
|
public static function edit_item(int $id): string
|
||||||
{
|
{
|
||||||
$item = Lib::get_item($id);
|
$item = get_item($id);
|
||||||
|
|
||||||
$page = Lib::is_post()
|
$page = is_post()
|
||||||
? self::handle_edit_form($id, 'items', Lib::validate($_POST, [
|
? self::handle_edit_form($id, 'items', validate($_POST, [
|
||||||
'name' => [],
|
'name' => [],
|
||||||
'type' => ['int', 'in:1,2,3'],
|
'type' => ['int', 'in:1,2,3'],
|
||||||
'buycost' => ['int', 'min:0'],
|
'buycost' => ['int', 'min:0'],
|
||||||
'attribute' => ['int', 'min:0'],
|
'attribute' => ['int', 'min:0'],
|
||||||
'special' => ['default:X'],
|
'special' => ['default:X'],
|
||||||
]))
|
]))
|
||||||
: Lib::render('admin/edit_item', ['item' => $item]);
|
: render('admin/edit_item', ['item' => $item]);
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing '.$item['name']);
|
page_title('Admin: Editing '.$item['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -163,11 +177,11 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function drops()
|
public static function drops()
|
||||||
{
|
{
|
||||||
$drops = Lib::db()->query('SELECT * FROM drops ORDER BY id;');
|
$drops = db()->query('SELECT * FROM drops ORDER BY id;');
|
||||||
$page = "<h2>Edit Drops</h2>Click an item's name to edit it.<br><br>\n";
|
$page = "<h2>Edit Drops</h2>Click an item's name to edit it.<br><br>\n";
|
||||||
$page .= self::build_bulk_table($drops, 'name', '/admin/drops');
|
$page .= self::build_bulk_table($drops, 'name', '/admin/drops');
|
||||||
|
|
||||||
Lib::page_title('Admin: Drops');
|
page_title('Admin: Drops');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -177,20 +191,20 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function edit_drop(int $id): string
|
public static function edit_drop(int $id): string
|
||||||
{
|
{
|
||||||
$drop = Lib::get_drop($id);
|
$drop = get_drop($id);
|
||||||
|
|
||||||
if (Lib::is_post()) {
|
if (is_post()) {
|
||||||
$page = self::handle_edit_form($id, 'drops', Lib::validate($_POST, [
|
$page = self::handle_edit_form($id, 'drops', validate($_POST, [
|
||||||
'name' => [],
|
'name' => [],
|
||||||
'mlevel' => ['int', 'min:1'],
|
'mlevel' => ['int', 'min:1'],
|
||||||
'attribute1' => [],
|
'attribute1' => [],
|
||||||
'attribute2' => ['default:X'],
|
'attribute2' => ['default:X'],
|
||||||
]));
|
]));
|
||||||
} else {
|
} else {
|
||||||
$page = Lib::render('admin/edit_drop', ['drop' => $drop]);
|
$page = render('admin/edit_drop', ['drop' => $drop]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing '.$drop['name']);
|
page_title('Admin: Editing '.$drop['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -200,11 +214,11 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function towns(): string
|
public static function towns(): string
|
||||||
{
|
{
|
||||||
$towns = Lib::db()->query('SELECT * FROM towns ORDER BY id;');
|
$towns = db()->query('SELECT * FROM towns ORDER BY id;');
|
||||||
$page = "<h2>Edit Towns</h2>Click an town's name or ID to edit it.<br><br>\n";
|
$page = "<h2>Edit Towns</h2>Click an town's name or ID to edit it.<br><br>\n";
|
||||||
$page .= self::build_bulk_table($towns, 'name', '/admin/towns');
|
$page .= self::build_bulk_table($towns, 'name', '/admin/towns');
|
||||||
|
|
||||||
Lib::page_title('Admin: Towns');
|
page_title('Admin: Towns');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -214,23 +228,23 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function edit_town(int $id): string
|
public static function edit_town(int $id): string
|
||||||
{
|
{
|
||||||
$town = Lib::get_town_by_id($id);
|
$town = get_town_by_id($id);
|
||||||
|
|
||||||
if (Lib::is_post()) {
|
if (is_post()) {
|
||||||
$page = self::handle_edit_form($id, 'towns', Lib::validate($_POST, [
|
$page = self::handle_edit_form($id, 'towns', validate($_POST, [
|
||||||
'name' => [],
|
'name' => [],
|
||||||
'latitude' => ['int', 'min:0', 'max:'.Lib::env('game_size')],
|
'latitude' => ['int', 'min:0', 'max:'.env('game_size')],
|
||||||
'longitude' => ['int', 'min:0', 'max:'.Lib::env('game_size')],
|
'longitude' => ['int', 'min:0', 'max:'.env('game_size')],
|
||||||
'innprice' => ['int', 'min:0'],
|
'innprice' => ['int', 'min:0'],
|
||||||
'mapprice' => ['int', 'min:0'],
|
'mapprice' => ['int', 'min:0'],
|
||||||
'travelpoints' => ['int', 'min:0'],
|
'travelpoints' => ['int', 'min:0'],
|
||||||
'itemslist' => ['optional'],
|
'itemslist' => ['optional'],
|
||||||
]));
|
]));
|
||||||
} else {
|
} else {
|
||||||
$page = Lib::render('admin/edit_town', ['town' => $town]);
|
$page = render('admin/edit_town', ['town' => $town]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing '.$town['name']);
|
page_title('Admin: Editing '.$town['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -240,19 +254,19 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function monsters()
|
public static function monsters()
|
||||||
{
|
{
|
||||||
$max_level = Lib::db()->query('SELECT level FROM monsters ORDER BY level DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC)['level'];
|
$max_level = db()->query('SELECT level FROM monsters ORDER BY level DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC)['level'];
|
||||||
$monsters = Lib::db()->query('SELECT * FROM monsters ORDER BY id;');
|
$monsters = db()->query('SELECT * FROM monsters ORDER BY id;');
|
||||||
|
|
||||||
$page = '<h2>Edit Monsters</h2>';
|
$page = '<h2>Edit Monsters</h2>';
|
||||||
|
|
||||||
$page .= ((Lib::env('game_size') / 5) !== $max_level)
|
$page .= ((env('game_size') / 5) !== $max_level)
|
||||||
? '<span class="highlight">Note:</span> Your highest monster level does not match with your entered map size. Highest monster level should be '.(Lib::env('game_size') / 5).", yours is $max_level. Please fix this before opening the game to the public.<br>"
|
? '<span class="highlight">Note:</span> Your highest monster level does not match with your entered map size. Highest monster level should be '.(env('game_size') / 5).", yours is $max_level. Please fix this before opening the game to the public.<br>"
|
||||||
: 'Monster level and map size match. No further actions are required for map compatibility.<br>';
|
: 'Monster level and map size match. No further actions are required for map compatibility.<br>';
|
||||||
|
|
||||||
$page .= "Click an monster's name or ID to edit it.<br><br>\n";
|
$page .= "Click an monster's name or ID to edit it.<br><br>\n";
|
||||||
$page .= self::build_bulk_table($monsters, 'name', '/admin/monsters');
|
$page .= self::build_bulk_table($monsters, 'name', '/admin/monsters');
|
||||||
|
|
||||||
Lib::page_title('Admin: Monsters');
|
page_title('Admin: Monsters');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -262,10 +276,10 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function edit_monster(int $id): string
|
public static function edit_monster(int $id): string
|
||||||
{
|
{
|
||||||
$monster = Lib::get_monster($id);
|
$monster = get_monster($id);
|
||||||
|
|
||||||
$page = (Lib::is_post())
|
$page = (is_post())
|
||||||
? self::handle_edit_form($id, 'monsters', Lib::validate($_POST, [
|
? self::handle_edit_form($id, 'monsters', validate($_POST, [
|
||||||
'name' => [],
|
'name' => [],
|
||||||
'maxhp' => ['int', 'min:1'],
|
'maxhp' => ['int', 'min:1'],
|
||||||
'maxdam' => ['int', 'min:0'],
|
'maxdam' => ['int', 'min:0'],
|
||||||
@ -275,9 +289,9 @@ class Admin
|
|||||||
'maxgold' => ['int', 'min:0'],
|
'maxgold' => ['int', 'min:0'],
|
||||||
'immune' => ['in:0,1,2'],
|
'immune' => ['in:0,1,2'],
|
||||||
]))
|
]))
|
||||||
: Lib::render('admin/edit_monster', ['monster' => $monster]);
|
: render('admin/edit_monster', ['monster' => $monster]);
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing '.$monster['name']);
|
page_title('Admin: Editing '.$monster['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -289,10 +303,10 @@ class Admin
|
|||||||
{
|
{
|
||||||
$page = "<h2>Edit Spells</h2>Click an spell's name to edit it.<br><br>\n";
|
$page = "<h2>Edit Spells</h2>Click an spell's name to edit it.<br><br>\n";
|
||||||
|
|
||||||
$spells = Lib::db()->query('SELECT * FROM spells ORDER BY id;');
|
$spells = db()->query('SELECT * FROM spells ORDER BY id;');
|
||||||
$page .= self::build_bulk_table($spells, 'name', '/admin/spells');
|
$page .= self::build_bulk_table($spells, 'name', '/admin/spells');
|
||||||
|
|
||||||
Lib::page_title('Admin: Spells');
|
page_title('Admin: Spells');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -302,18 +316,18 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function edit_spell(int $id): string
|
public static function edit_spell(int $id): string
|
||||||
{
|
{
|
||||||
$spell = Lib::get_spell($id);
|
$spell = get_spell($id);
|
||||||
|
|
||||||
$page = (Lib::is_post())
|
$page = (is_post())
|
||||||
? self::handle_edit_form($id, 'spells', Lib::validate($_POST, [
|
? self::handle_edit_form($id, 'spells', validate($_POST, [
|
||||||
'name' => [],
|
'name' => [],
|
||||||
'mp' => ['int', 'min:0'],
|
'mp' => ['int', 'min:0'],
|
||||||
'attribute' => ['int', 'min:0'],
|
'attribute' => ['int', 'min:0'],
|
||||||
'type' => ['in:1,2,3,4,5'],
|
'type' => ['in:1,2,3,4,5'],
|
||||||
]))
|
]))
|
||||||
: Lib::render('admin/edit_spell', ['spell' => $spell]);
|
: render('admin/edit_spell', ['spell' => $spell]);
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing '.$spell['name']);
|
page_title('Admin: Editing '.$spell['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -323,7 +337,7 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function levels(): string
|
public static function levels(): string
|
||||||
{
|
{
|
||||||
$max_level = Lib::db()->query('SELECT id FROM levels ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC)['id'];
|
$max_level = db()->query('SELECT id FROM levels ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC)['id'];
|
||||||
|
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
<h2>Edit Levels</h2>
|
<h2>Edit Levels</h2>
|
||||||
@ -340,7 +354,7 @@ class Admin
|
|||||||
</form>
|
</form>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
Lib::page_title('Admin: Levels');
|
page_title('Admin: Levels');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -354,13 +368,13 @@ class Admin
|
|||||||
return 'No level to edit.';
|
return 'No level to edit.';
|
||||||
}
|
}
|
||||||
$id = $_POST['level'];
|
$id = $_POST['level'];
|
||||||
$level = Lib::db()->query('SELECT * FROM levels WHERE id=? LIMIT 1;', [$id])->fetchArray(SQLITE3_ASSOC);
|
$level = db()->query('SELECT * FROM levels WHERE id=? LIMIT 1;', [$id])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
|
||||||
if (Lib::is_post() && isset($_POST['save'])) {
|
if (is_post() && isset($_POST['save'])) {
|
||||||
unset($_POST['save']);
|
unset($_POST['save']);
|
||||||
unset($_POST['level']);
|
unset($_POST['level']);
|
||||||
|
|
||||||
$page = self::handle_edit_form($id, 'levels', Lib::validate($_POST, [
|
$page = self::handle_edit_form($id, 'levels', validate($_POST, [
|
||||||
'1_exp' => ['int', 'min:0'],
|
'1_exp' => ['int', 'min:0'],
|
||||||
'1_hp' => ['int', 'min:0'],
|
'1_hp' => ['int', 'min:0'],
|
||||||
'1_mp' => ['int', 'min:0'],
|
'1_mp' => ['int', 'min:0'],
|
||||||
@ -384,21 +398,21 @@ class Admin
|
|||||||
'3_spells' => ['int', 'min:0'],
|
'3_spells' => ['int', 'min:0'],
|
||||||
]), 'Level <b>'.$id.'</b> updated.');
|
]), 'Level <b>'.$id.'</b> updated.');
|
||||||
} else {
|
} else {
|
||||||
$page = Lib::render('admin/edit_level', ['level' => $level]);
|
$page = render('admin/edit_level', ['level' => $level]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing Level '.$id);
|
page_title('Admin: Editing Level '.$id);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function users()
|
public static function users()
|
||||||
{
|
{
|
||||||
$users = Lib::db()->query('SELECT * FROM users ORDER BY id;');
|
$users = db()->query('SELECT * FROM users ORDER BY id;');
|
||||||
$page = '<h2>Edit Users</h2>Click a username or ID to edit the account.<br><br><div class="table-wrapper">';
|
$page = '<h2>Edit Users</h2>Click a username or ID to edit the account.<br><br><div class="table-wrapper">';
|
||||||
$page .= self::build_bulk_table($users, 'username', '/admin/users');
|
$page .= self::build_bulk_table($users, 'username', '/admin/users');
|
||||||
|
|
||||||
Lib::page_title('Admin: Users');
|
page_title('Admin: Users');
|
||||||
|
|
||||||
return $page.'</div>';
|
return $page.'</div>';
|
||||||
}
|
}
|
||||||
@ -408,17 +422,17 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function edit_user(int $id): string
|
public static function edit_user(int $id): string
|
||||||
{
|
{
|
||||||
$user = Lib::db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$id])->fetchArray(SQLITE3_ASSOC);
|
$user = db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$id])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
|
||||||
if (Lib::is_post()) {
|
if (is_post()) {
|
||||||
$form = Lib::validate($_POST, [
|
$form = validate($_POST, [
|
||||||
'username' => ['length:3-18', 'alpha-spaces', 'unique:users,username'],
|
'username' => ['length:3-18', 'alpha-spaces', 'unique:users,username'],
|
||||||
'verify' => [],
|
'verify' => [],
|
||||||
'authlevel' => ['int'],
|
'authlevel' => ['int'],
|
||||||
'email' => ['email', 'unique:users,email'],
|
'email' => ['email', 'unique:users,email'],
|
||||||
'charclass' => ['in:1,2,3'],
|
'charclass' => ['in:1,2,3'],
|
||||||
'latitude' => ['int', 'min:0', 'max:'.Lib::env('game_size')],
|
'latitude' => ['int', 'min:0', 'max:'.env('game_size')],
|
||||||
'longitude' => ['int', 'min:0', 'max:'.Lib::env('game_size')],
|
'longitude' => ['int', 'min:0', 'max:'.env('game_size')],
|
||||||
'currentaction' => [],
|
'currentaction' => [],
|
||||||
'currentfight' => ['int'],
|
'currentfight' => ['int'],
|
||||||
'currentmonster' => ['int'],
|
'currentmonster' => ['int'],
|
||||||
@ -463,7 +477,7 @@ class Admin
|
|||||||
self::save_data_row('users', $form['data'], $id);
|
self::save_data_row('users', $form['data'], $id);
|
||||||
$page = 'User <b>'.$user['username'].'</b> updated.';
|
$page = 'User <b>'.$user['username'].'</b> updated.';
|
||||||
} else {
|
} else {
|
||||||
$error_list = Lib::ul_from_validate_errors($form['errors']);
|
$error_list = ul_from_validate_errors($form['errors']);
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
<b>Errors:</b><br>
|
<b>Errors:</b><br>
|
||||||
<div style="color: red;">{$error_list}</div><br>
|
<div style="color: red;">{$error_list}</div><br>
|
||||||
@ -471,10 +485,10 @@ class Admin
|
|||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$page = Lib::render('admin/edit_user', ['user' => $user]);
|
$page = render('admin/edit_user', ['user' => $user]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Admin: Editing '.$user['username']);
|
page_title('Admin: Editing '.$user['username']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -484,7 +498,7 @@ class Admin
|
|||||||
*/
|
*/
|
||||||
public static function add_news()
|
public static function add_news()
|
||||||
{
|
{
|
||||||
if (Lib::is_post()) {
|
if (is_post()) {
|
||||||
$c = trim($_POST['content'] ?? '');
|
$c = trim($_POST['content'] ?? '');
|
||||||
|
|
||||||
$errors = [];
|
$errors = [];
|
||||||
@ -493,7 +507,7 @@ class Admin
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (count($errors) === 0) {
|
if (count($errors) === 0) {
|
||||||
Lib::db()->query('INSERT INTO news (author, content) VALUES (?, ?);', [Lib::user()->username, $c]);
|
db()->query('INSERT INTO news (author, content) VALUES (?, ?);', [user()->username, $c]);
|
||||||
$page = 'News post added.';
|
$page = 'News post added.';
|
||||||
} else {
|
} else {
|
||||||
$error_list = implode('<br>', $errors);
|
$error_list = implode('<br>', $errors);
|
||||||
@ -511,7 +525,7 @@ class Admin
|
|||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Admin: Add News');
|
page_title('Admin: Add News');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -541,7 +555,7 @@ class Admin
|
|||||||
|
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $column) {
|
||||||
$html_parts[] = '<th>'.
|
$html_parts[] = '<th>'.
|
||||||
Lib::make_safe($column === 'id' ? 'ID' : ucfirst($column)).
|
make_safe($column === 'id' ? 'ID' : ucfirst($column)).
|
||||||
'</th>';
|
'</th>';
|
||||||
}
|
}
|
||||||
$html_parts[] = '</tr></thead><tbody>';
|
$html_parts[] = '</tr></thead><tbody>';
|
||||||
@ -551,7 +565,7 @@ class Admin
|
|||||||
foreach ($data as $row) {
|
foreach ($data as $row) {
|
||||||
$html_parts[] = '<tr>';
|
$html_parts[] = '<tr>';
|
||||||
foreach ($columns as $column) {
|
foreach ($columns as $column) {
|
||||||
$name = Lib::make_safe($row[$column]);
|
$name = make_safe($row[$column]);
|
||||||
$html_parts[] = isset($is_edit_column[$column])
|
$html_parts[] = isset($is_edit_column[$column])
|
||||||
? "<td><a href=\"{$edit_link}/{$row['id']}\" hx-get=\"{$edit_link}/{$row['id']}\" hx-target=\"#main\">{$name}</a></td>"
|
? "<td><a href=\"{$edit_link}/{$row['id']}\" hx-get=\"{$edit_link}/{$row['id']}\" hx-target=\"#main\">{$name}</a></td>"
|
||||||
: "<td>{$name}</td>";
|
: "<td>{$name}</td>";
|
||||||
@ -578,7 +592,7 @@ class Admin
|
|||||||
$values = array_values($data);
|
$values = array_values($data);
|
||||||
$values[] = $id;
|
$values[] = $id;
|
||||||
|
|
||||||
return Lib::db()->query("UPDATE $table SET $fields WHERE id=?", $values);
|
return db()->query("UPDATE $table SET $fields WHERE id=?", $values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -590,7 +604,7 @@ class Admin
|
|||||||
self::save_data_row($table, $form['data'], $id);
|
self::save_data_row($table, $form['data'], $id);
|
||||||
$page = $updated_message ?: '<b>'.$form['data']['name'].'</b> updated.';
|
$page = $updated_message ?: '<b>'.$form['data']['name'].'</b> updated.';
|
||||||
} else {
|
} else {
|
||||||
$error_list = Lib::ul_from_validate_errors($form['errors']);
|
$error_list = ul_from_validate_errors($form['errors']);
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
<b>Errors:</b><br>
|
<b>Errors:</b><br>
|
||||||
<div style="color: red;">{$error_list}</div><br>
|
<div style="color: red;">{$error_list}</div><br>
|
||||||
|
@ -13,7 +13,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
use function DragonKnight\env;
|
||||||
|
use function DragonKnight\get_town_by_xy;
|
||||||
|
use function DragonKnight\index;
|
||||||
|
use function DragonKnight\page_title;
|
||||||
|
use function DragonKnight\redirect;
|
||||||
|
use function DragonKnight\ul_from_validate_errors;
|
||||||
|
use function DragonKnight\user;
|
||||||
|
use function DragonKnight\validate;
|
||||||
|
|
||||||
class Explore
|
class Explore
|
||||||
{
|
{
|
||||||
@ -23,7 +30,7 @@ class Explore
|
|||||||
*/
|
*/
|
||||||
public static function explore()
|
public static function explore()
|
||||||
{
|
{
|
||||||
Lib::page_title('Exploring');
|
page_title('Exploring');
|
||||||
|
|
||||||
return <<<HTML
|
return <<<HTML
|
||||||
<div class="title"><img src="/img/title_exploring.gif" alt="Exploring"></div>
|
<div class="title"><img src="/img/title_exploring.gif" alt="Exploring"></div>
|
||||||
@ -34,20 +41,20 @@ class Explore
|
|||||||
public static function move()
|
public static function move()
|
||||||
{
|
{
|
||||||
// Early exit if fighting
|
// Early exit if fighting
|
||||||
if (Lib::user()->currentaction == 'Fighting') {
|
if (user()->currentaction == 'Fighting') {
|
||||||
Lib::redirect('/fight');
|
redirect('/fight');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate direction
|
// Validate direction
|
||||||
$form = Lib::validate($_POST, ['direction' => ['in:north,west,east,south']]);
|
$form = validate($_POST, ['direction' => ['in:north,west,east,south']]);
|
||||||
if (! $form['valid']) {
|
if (! $form['valid']) {
|
||||||
return Lib::ul_from_validate_errors($form['errors']);
|
return ul_from_validate_errors($form['errors']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current game state
|
// Current game state
|
||||||
$game_size = Lib::env('game_size');
|
$game_size = env('game_size');
|
||||||
$latitude = Lib::user()->latitude;
|
$latitude = user()->latitude;
|
||||||
$longitude = Lib::user()->longitude;
|
$longitude = user()->longitude;
|
||||||
$direction = $form['data']['direction'];
|
$direction = $form['data']['direction'];
|
||||||
|
|
||||||
// Calculate new coordinates with boundary checks
|
// Calculate new coordinates with boundary checks
|
||||||
@ -67,23 +74,23 @@ class Explore
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for town
|
// Check for town
|
||||||
$town = Lib::get_town_by_xy($longitude, $latitude);
|
$town = get_town_by_xy($longitude, $latitude);
|
||||||
if ($town !== false) {
|
if ($town !== false) {
|
||||||
return Towns::travelto($town['id'], false);
|
return Towns::travelto($town['id'], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine action (1 in 5 chance of fighting)
|
// Determine action (1 in 5 chance of fighting)
|
||||||
if (rand(1, 5) === 1) {
|
if (rand(1, 5) === 1) {
|
||||||
Lib::user()->currentaction = 'Fighting';
|
user()->currentaction = 'Fighting';
|
||||||
Lib::user()->currentfight = 1;
|
user()->currentfight = 1;
|
||||||
} else {
|
} else {
|
||||||
Lib::user()->currentaction = 'Exploring';
|
user()->currentaction = 'Exploring';
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->latitude = $latitude;
|
user()->latitude = $latitude;
|
||||||
Lib::user()->longitude = $longitude;
|
user()->longitude = $longitude;
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
return Lib::index();
|
return index();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
use DragonKnight\Router;
|
use DragonKnight\Router;
|
||||||
|
|
||||||
class Fight
|
class Fight
|
||||||
@ -33,7 +32,7 @@ class Fight
|
|||||||
*/
|
*/
|
||||||
public static function fight()
|
public static function fight()
|
||||||
{
|
{
|
||||||
if (Lib::user()->currentaction !== 'Fighting') {
|
if (user()->currentaction !== 'Fighting') {
|
||||||
exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +40,7 @@ class Fight
|
|||||||
$playerisdead = 0;
|
$playerisdead = 0;
|
||||||
|
|
||||||
// Generate spell list
|
// Generate spell list
|
||||||
$user_spells = Lib::user()->spells();
|
$user_spells = user()->spells();
|
||||||
if (! empty($user_spells)) {
|
if (! empty($user_spells)) {
|
||||||
$page['magiclist'] = '<select name="userspell">';
|
$page['magiclist'] = '<select name="userspell">';
|
||||||
foreach ($user_spells as $spell) {
|
foreach ($user_spells as $spell) {
|
||||||
@ -51,52 +50,52 @@ class Fight
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine initial combat parameters
|
// Determine initial combat parameters
|
||||||
$chancetoswingfirst = rand(1, 10) + (int) ceil(sqrt(Lib::user()->dexterity));
|
$chancetoswingfirst = rand(1, 10) + (int) ceil(sqrt(user()->dexterity));
|
||||||
if (Lib::user()->currentfight === 1) {
|
if (user()->currentfight === 1) {
|
||||||
$maxlevel = (int) floor(max(abs(Lib::user()->latitude) + 5, abs(Lib::user()->longitude) + 5) / 5);
|
$maxlevel = (int) floor(max(abs(user()->latitude) + 5, abs(user()->longitude) + 5) / 5);
|
||||||
$minlevel = max(1, $maxlevel - 2);
|
$minlevel = max(1, $maxlevel - 2);
|
||||||
|
|
||||||
$monster = Lib::db()->query('SELECT * FROM monsters WHERE level >= ? AND level <= ? ORDER BY RANDOM() LIMIT 1;', [
|
$monster = db()->query('SELECT * FROM monsters WHERE level >= ? AND level <= ? ORDER BY RANDOM() LIMIT 1;', [
|
||||||
$minlevel, $maxlevel,
|
$minlevel, $maxlevel,
|
||||||
])->fetchArray(SQLITE3_ASSOC);
|
])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
|
||||||
Lib::user()->currentmonster = $monster['id'];
|
user()->currentmonster = $monster['id'];
|
||||||
Lib::user()->currentmonsterhp = rand((int) (($monster['maxhp'] / 5) * 4), $monster['maxhp']);
|
user()->currentmonsterhp = rand((int) (($monster['maxhp'] / 5) * 4), $monster['maxhp']);
|
||||||
Lib::user()->currentmonstersleep = 0;
|
user()->currentmonstersleep = 0;
|
||||||
Lib::user()->currentmonsterimmune = $monster['immune'];
|
user()->currentmonsterimmune = $monster['immune'];
|
||||||
|
|
||||||
$chancetoswingfirst = ($chancetoswingfirst > (rand(1, 7) + (int) ceil(sqrt($monster['maxdam'])))) ? 1 : 0;
|
$chancetoswingfirst = ($chancetoswingfirst > (rand(1, 7) + (int) ceil(sqrt($monster['maxdam'])))) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get monster statistics
|
// Get monster statistics
|
||||||
$monster = Lib::get_monster(Lib::user()->currentmonster);
|
$monster = get_monster(user()->currentmonster);
|
||||||
$page['monstername'] = $monster['name'];
|
$page['monstername'] = $monster['name'];
|
||||||
|
|
||||||
// Run action
|
// Run action
|
||||||
if (isset($_POST['run'])) {
|
if (isset($_POST['run'])) {
|
||||||
$chancetorun = rand(4, 10) + (int) ceil(sqrt(Lib::user()->dexterity));
|
$chancetorun = rand(4, 10) + (int) ceil(sqrt(user()->dexterity));
|
||||||
if ($chancetorun <= (rand(1, 5) + (int) ceil(sqrt($monster['maxdam'])))) {
|
if ($chancetorun <= (rand(1, 5) + (int) ceil(sqrt($monster['maxdam'])))) {
|
||||||
$page['yourturn'] = 'You tried to run away, but were blocked in front!<br><br>';
|
$page['yourturn'] = 'You tried to run away, but were blocked in front!<br><br>';
|
||||||
$page['monsterhp'] = "Monster's HP: ".Lib::user()->currentmonsterhp.'<br><br>';
|
$page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'<br><br>';
|
||||||
|
|
||||||
// Monster turn logic (similar to original public static function)
|
// Monster turn logic (similar to original public static function)
|
||||||
$page['monsterturn'] = self::handleMonsterTurn($userrow, $monster);
|
$page['monsterturn'] = self::handleMonsterTurn($userrow, $monster);
|
||||||
|
|
||||||
Lib::user()->currentaction = 'Exploring';
|
user()->currentaction = 'Exploring';
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
Lib::redirect('/');
|
redirect('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fight action
|
// Fight action
|
||||||
if (isset($_POST['fight'])) {
|
if (isset($_POST['fight'])) {
|
||||||
// Player's attack
|
// Player's attack
|
||||||
$min = (int) (Lib::user()->attackpower * 0.75);
|
$min = (int) (user()->attackpower * 0.75);
|
||||||
$max = (int) (Lib::user()->attackpower / 3);
|
$max = (int) (user()->attackpower / 3);
|
||||||
$tohit = (int) ceil(mt_rand(min($min, $max), max($min, $max)));
|
$tohit = (int) ceil(mt_rand(min($min, $max), max($min, $max)));
|
||||||
|
|
||||||
$toexcellent = rand(1, 150);
|
$toexcellent = rand(1, 150);
|
||||||
if ($toexcellent <= sqrt(Lib::user()->strength)) {
|
if ($toexcellent <= sqrt(user()->strength)) {
|
||||||
$tohit *= 2;
|
$tohit *= 2;
|
||||||
$page['yourturn'] .= 'Excellent hit!<br>';
|
$page['yourturn'] .= 'Excellent hit!<br>';
|
||||||
}
|
}
|
||||||
@ -113,19 +112,19 @@ class Fight
|
|||||||
$page['yourturn'] .= 'The monster is dodging. No damage has been scored.<br>';
|
$page['yourturn'] .= 'The monster is dodging. No damage has been scored.<br>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->currentuberdamage != 0) {
|
if (user()->currentuberdamage != 0) {
|
||||||
$monsterdamage += (int) ceil($monsterdamage * (Lib::user()->currentuberdamage / 100));
|
$monsterdamage += (int) ceil($monsterdamage * (user()->currentuberdamage / 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->currentmonsterhp -= $monsterdamage;
|
user()->currentmonsterhp -= $monsterdamage;
|
||||||
$page['yourturn'] .= "You attack the monster for $monsterdamage damage.<br><br>";
|
$page['yourturn'] .= "You attack the monster for $monsterdamage damage.<br><br>";
|
||||||
$page['monsterhp'] = "Monster's HP: ".Lib::user()->currentmonsterhp.'<br><br>';
|
$page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'<br><br>';
|
||||||
|
|
||||||
// Check for monster defeat
|
// Check for monster defeat
|
||||||
if (Lib::user()->currentmonsterhp <= 0) {
|
if (user()->currentmonsterhp <= 0) {
|
||||||
Lib::user()->currentmonsterhp = 0;
|
user()->currentmonsterhp = 0;
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
Lib::redirect('/victory');
|
redirect('/victory');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monster's turn
|
// Monster's turn
|
||||||
@ -139,26 +138,26 @@ class Fight
|
|||||||
return 'You must select a spell first. Please go back and try again.';
|
return 'You must select a spell first. Please go back and try again.';
|
||||||
}
|
}
|
||||||
|
|
||||||
$newspellrow = Lib::get_spell($pickedspell);
|
$newspellrow = get_spell($pickedspell);
|
||||||
$spell = in_array($pickedspell, explode(',', Lib::user()->spells));
|
$spell = in_array($pickedspell, explode(',', user()->spells));
|
||||||
|
|
||||||
if (! $spell) {
|
if (! $spell) {
|
||||||
return 'You have not yet learned this spell. Please go back and try again.';
|
return 'You have not yet learned this spell. Please go back and try again.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->currentmp < $newspellrow['mp']) {
|
if (user()->currentmp < $newspellrow['mp']) {
|
||||||
return 'You do not have enough Magic Points to cast this spell. Please go back and try again.';
|
return 'You do not have enough Magic Points to cast this spell. Please go back and try again.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spell type handling (similar to original public static function)
|
// Spell type handling (similar to original public static function)
|
||||||
$page['yourturn'] = self::handleSpellCast($userrow, $newspellrow);
|
$page['yourturn'] = self::handleSpellCast($userrow, $newspellrow);
|
||||||
$page['monsterhp'] = "Monster's HP: ".Lib::user()->currentmonsterhp.'<br><br>';
|
$page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'<br><br>';
|
||||||
|
|
||||||
// Check for monster defeat
|
// Check for monster defeat
|
||||||
if (Lib::user()->currentmonsterhp <= 0) {
|
if (user()->currentmonsterhp <= 0) {
|
||||||
Lib::user()->currentmonsterhp = 0;
|
user()->currentmonsterhp = 0;
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
Lib::redirect('/victory');
|
redirect('/victory');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monster's turn
|
// Monster's turn
|
||||||
@ -168,7 +167,7 @@ class Fight
|
|||||||
// Monster's turn if player lost first swing
|
// Monster's turn if player lost first swing
|
||||||
if (! isset($_POST['run']) && ! isset($_POST['fight']) && ! isset($_POST['spell']) && $chancetoswingfirst == 0) {
|
if (! isset($_POST['run']) && ! isset($_POST['fight']) && ! isset($_POST['spell']) && $chancetoswingfirst == 0) {
|
||||||
$page['yourturn'] = 'The monster attacks before you are ready!<br><br>';
|
$page['yourturn'] = 'The monster attacks before you are ready!<br><br>';
|
||||||
$page['monsterhp'] = "Monster's HP: ".Lib::user()->currentmonsterhp.'<br><br>';
|
$page['monsterhp'] = "Monster's HP: ".user()->currentmonsterhp.'<br><br>';
|
||||||
$page['monsterturn'] = self::handleMonsterTurn($userrow, $monster);
|
$page['monsterturn'] = self::handleMonsterTurn($userrow, $monster);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +182,7 @@ class Fight
|
|||||||
</form>
|
</form>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
Lib::user()->currentfight += 1;
|
user()->currentfight += 1;
|
||||||
} else {
|
} else {
|
||||||
$page['command'] = <<<HTML
|
$page['command'] = <<<HTML
|
||||||
<b>You have died.</b><br><br>
|
<b>You have died.</b><br><br>
|
||||||
@ -192,24 +191,24 @@ class Fight
|
|||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
// Finalize page and display it
|
// Finalize page and display it
|
||||||
$page = Lib::render('fight', ['page' => $page]);
|
$page = render('fight', ['page' => $page]);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function victory()
|
public static function victory()
|
||||||
{
|
{
|
||||||
if (Lib::user()->currentmonsterhp != 0) {
|
if (user()->currentmonsterhp != 0) {
|
||||||
Lib::redirect('/fight');
|
redirect('/fight');
|
||||||
}
|
}
|
||||||
if (Lib::user()->currentfight == 0) {
|
if (user()->currentfight == 0) {
|
||||||
Lib::redirect('/');
|
redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$monsterrow = Lib::get_monster(Lib::user()->currentmonster);
|
$monsterrow = get_monster(user()->currentmonster);
|
||||||
|
|
||||||
$min = (int) (($monsterrow['maxexp'] / 6) * 5);
|
$min = (int) (($monsterrow['maxexp'] / 6) * 5);
|
||||||
$max = (int) $monsterrow['maxexp'];
|
$max = (int) $monsterrow['maxexp'];
|
||||||
@ -218,8 +217,8 @@ class Fight
|
|||||||
$exp = 1;
|
$exp = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->expbonus != 0) {
|
if (user()->expbonus != 0) {
|
||||||
$exp += ceil((Lib::user()->expbonus / 100) * $exp);
|
$exp += ceil((user()->expbonus / 100) * $exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
$min = (int) (($monsterrow['maxgold'] / 6) * 5);
|
$min = (int) (($monsterrow['maxgold'] / 6) * 5);
|
||||||
@ -230,56 +229,56 @@ class Fight
|
|||||||
$gold = 1;
|
$gold = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->goldbonus != 0) {
|
if (user()->goldbonus != 0) {
|
||||||
$gold += ceil((Lib::user()->goldbonus / 100) * $exp);
|
$gold += ceil((user()->goldbonus / 100) * $exp);
|
||||||
}
|
}
|
||||||
if (Lib::user()->experience + $exp < 16777215) {
|
if (user()->experience + $exp < 16777215) {
|
||||||
$newexp = Lib::user()->experience += $exp;
|
$newexp = user()->experience += $exp;
|
||||||
$warnexp = '';
|
$warnexp = '';
|
||||||
} else {
|
} else {
|
||||||
$newexp = Lib::user()->experience;
|
$newexp = user()->experience;
|
||||||
$exp = 0;
|
$exp = 0;
|
||||||
$warnexp = 'You have maxed out your experience points.';
|
$warnexp = 'You have maxed out your experience points.';
|
||||||
}
|
}
|
||||||
if (Lib::user()->gold + $gold < 16777215) {
|
if (user()->gold + $gold < 16777215) {
|
||||||
$newgold = Lib::user()->gold += $gold;
|
$newgold = user()->gold += $gold;
|
||||||
$warngold = '';
|
$warngold = '';
|
||||||
} else {
|
} else {
|
||||||
$newgold = Lib::user()->gold;
|
$newgold = user()->gold;
|
||||||
$gold = 0;
|
$gold = 0;
|
||||||
$warngold = 'You have maxed out your gold.';
|
$warngold = 'You have maxed out your gold.';
|
||||||
}
|
}
|
||||||
|
|
||||||
$levelrow = Lib::db()->query('SELECT * FROM levels WHERE id=? LIMIT 1;', [Lib::user()->level + 1])->fetchArray(SQLITE3_ASSOC);
|
$levelrow = db()->query('SELECT * FROM levels WHERE id=? LIMIT 1;', [user()->level + 1])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
|
||||||
if (Lib::user()->level < 100) {
|
if (user()->level < 100) {
|
||||||
if ($newexp >= $levelrow[Lib::user()->charclass.'_exp']) {
|
if ($newexp >= $levelrow[user()->charclass.'_exp']) {
|
||||||
Lib::user()->maxhp += $levelrow[Lib::user()->charclass.'_hp'];
|
user()->maxhp += $levelrow[user()->charclass.'_hp'];
|
||||||
Lib::user()->maxmp += $levelrow[Lib::user()->charclass.'_mp'];
|
user()->maxmp += $levelrow[user()->charclass.'_mp'];
|
||||||
Lib::user()->maxtp += $levelrow[Lib::user()->charclass.'_tp'];
|
user()->maxtp += $levelrow[user()->charclass.'_tp'];
|
||||||
Lib::user()->strength += $levelrow[Lib::user()->charclass.'_strength'];
|
user()->strength += $levelrow[user()->charclass.'_strength'];
|
||||||
Lib::user()->dexterity += $levelrow[Lib::user()->charclass.'_dexterity'];
|
user()->dexterity += $levelrow[user()->charclass.'_dexterity'];
|
||||||
Lib::user()->attackpower += $levelrow[Lib::user()->charclass.'_strength'];
|
user()->attackpower += $levelrow[user()->charclass.'_strength'];
|
||||||
Lib::user()->defensepower += $levelrow[Lib::user()->charclass.'_dexterity'];
|
user()->defensepower += $levelrow[user()->charclass.'_dexterity'];
|
||||||
Lib::user()->level += 1;
|
user()->level += 1;
|
||||||
$newlevel = $levelrow['id'];
|
$newlevel = $levelrow['id'];
|
||||||
|
|
||||||
if ($levelrow[Lib::user()->charclass.'_spells'] != 0) {
|
if ($levelrow[user()->charclass.'_spells'] != 0) {
|
||||||
Lib::user()->spells .= ','.$levelrow[Lib::user()->charclass.'_spells'];
|
user()->spells .= ','.$levelrow[user()->charclass.'_spells'];
|
||||||
$spelltext = 'You have learned a new spell.<br>';
|
$spelltext = 'You have learned a new spell.<br>';
|
||||||
} else {
|
} else {
|
||||||
$spelltext = '';
|
$spelltext = '';
|
||||||
$newspell = '';
|
$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[Lib::user()->charclass.'_hp'].' hit points.<br>You gain '.$levelrow[Lib::user()->charclass.'_mp'].' magic points.<br>You gain '.$levelrow[Lib::user()->charclass.'_tp'].' travel points.<br>You gain '.$levelrow[Lib::user()->charclass.'_strength'].' strength.<br>You gain '.$levelrow[Lib::user()->charclass.'_dexterity']." dexterity.<br>$spelltext<br>You can now continue <a href=\"/\" hx-get=\"/\" hx-target=\"#middle\">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!';
|
$title = 'Courage and Wit have served thee well!';
|
||||||
$dropcode = '';
|
$dropcode = '';
|
||||||
} else {
|
} else {
|
||||||
$page = 'Congratulations. You have defeated the '.$monsterrow['name'].".<br>You gain $exp experience. $warnexp <br>You gain $gold gold. $warngold <br><br>";
|
$page = 'Congratulations. You have defeated the '.$monsterrow['name'].".<br>You gain $exp experience. $warnexp <br>You gain $gold gold. $warngold <br><br>";
|
||||||
|
|
||||||
if (rand(1, 30) === 1) {
|
if (rand(1, 30) === 1) {
|
||||||
$droprow = Lib::db()->query('SELECT * FROM drops WHERE mlevel <= ? ORDER BY RANDOM() LIMIT 1;', [$monsterrow['level']])->fetchArray(SQLITE3_ASSOC);
|
$droprow = db()->query('SELECT * FROM drops WHERE mlevel <= ? ORDER BY RANDOM() LIMIT 1;', [$monsterrow['level']])->fetchArray(SQLITE3_ASSOC);
|
||||||
$dropcode = "dropcode='".$droprow['id']."',";
|
$dropcode = "dropcode='".$droprow['id']."',";
|
||||||
$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>.';
|
$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 {
|
} else {
|
||||||
@ -291,26 +290,26 @@ class Fight
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->currentaction = 'Exploring';
|
user()->currentaction = 'Exploring';
|
||||||
Lib::user()->currentfight = 0;
|
user()->currentfight = 0;
|
||||||
Lib::user()->currentuberdamage = 0;
|
user()->currentuberdamage = 0;
|
||||||
Lib::user()->currentuberdefense = 0;
|
user()->currentuberdefense = 0;
|
||||||
Lib::user()->currentmonstersleep = 0;
|
user()->currentmonstersleep = 0;
|
||||||
Lib::user()->currentmonsterimmune = 0;
|
user()->currentmonsterimmune = 0;
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
Lib::page_title($title);
|
page_title($title);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function drop()
|
public static function drop()
|
||||||
{
|
{
|
||||||
if (Lib::user()->dropcode == 0) {
|
if (user()->dropcode == 0) {
|
||||||
Lib::redirect('/');
|
redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$droprow = Lib::get_drop(Lib::user()->dropcode);
|
$droprow = get_drop(user()->dropcode);
|
||||||
|
|
||||||
if (isset($_POST['submit'])) {
|
if (isset($_POST['submit'])) {
|
||||||
$slot = $_POST['slot'];
|
$slot = $_POST['slot'];
|
||||||
@ -320,8 +319,8 @@ class Fight
|
|||||||
}
|
}
|
||||||
|
|
||||||
$slotstr = 'slot'.$slot.'id';
|
$slotstr = 'slot'.$slot.'id';
|
||||||
if (Lib::user()->$slotstr != 0) {
|
if (user()->$slotstr != 0) {
|
||||||
$slotrow = Lib::get_drop(Lib::user()->$slotstr);
|
$slotrow = get_drop(user()->$slotstr);
|
||||||
|
|
||||||
$old1 = explode(',', $slotrow['attribute1']);
|
$old1 = explode(',', $slotrow['attribute1']);
|
||||||
if ($slotrow['attribute2'] != 'X') {
|
if ($slotrow['attribute2'] != 'X') {
|
||||||
@ -336,52 +335,52 @@ class Fight
|
|||||||
$new2 = [0 => 'maxhp',1 => 0];
|
$new2 = [0 => 'maxhp',1 => 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->$old1[0] -= $old1[1];
|
user()->$old1[0] -= $old1[1];
|
||||||
Lib::user()->$old2[0] -= $old2[1];
|
user()->$old2[0] -= $old2[1];
|
||||||
if ($old1[0] == 'strength') {
|
if ($old1[0] == 'strength') {
|
||||||
Lib::user()->attackpower -= $old1[1];
|
user()->attackpower -= $old1[1];
|
||||||
}
|
}
|
||||||
if ($old1[0] == 'dexterity') {
|
if ($old1[0] == 'dexterity') {
|
||||||
Lib::user()->defensepower -= $old1[1];
|
user()->defensepower -= $old1[1];
|
||||||
}
|
}
|
||||||
if ($old2[0] == 'strength') {
|
if ($old2[0] == 'strength') {
|
||||||
Lib::user()->attackpower -= $old2[1];
|
user()->attackpower -= $old2[1];
|
||||||
}
|
}
|
||||||
if ($old2[0] == 'dexterity') {
|
if ($old2[0] == 'dexterity') {
|
||||||
Lib::user()->defensepower -= $old2[1];
|
user()->defensepower -= $old2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->$new1[0] += $new1[1];
|
user()->$new1[0] += $new1[1];
|
||||||
Lib::user()->$new2[0] += $new2[1];
|
user()->$new2[0] += $new2[1];
|
||||||
if ($new1[0] == 'strength') {
|
if ($new1[0] == 'strength') {
|
||||||
Lib::user()->attackpower += $new1[1];
|
user()->attackpower += $new1[1];
|
||||||
}
|
}
|
||||||
if ($new1[0] == 'dexterity') {
|
if ($new1[0] == 'dexterity') {
|
||||||
Lib::user()->defensepower += $new1[1];
|
user()->defensepower += $new1[1];
|
||||||
}
|
}
|
||||||
if ($new2[0] == 'strength') {
|
if ($new2[0] == 'strength') {
|
||||||
Lib::user()->attackpower += $new2[1];
|
user()->attackpower += $new2[1];
|
||||||
}
|
}
|
||||||
if ($new2[0] == 'dexterity') {
|
if ($new2[0] == 'dexterity') {
|
||||||
Lib::user()->defensepower += $new2[1];
|
user()->defensepower += $new2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->currenthp > Lib::user()->maxhp) {
|
if (user()->currenthp > user()->maxhp) {
|
||||||
Lib::user()->currenthp = Lib::user()->maxhp;
|
user()->currenthp = user()->maxhp;
|
||||||
}
|
}
|
||||||
if (Lib::user()->currentmp > Lib::user()->maxmp) {
|
if (user()->currentmp > user()->maxmp) {
|
||||||
Lib::user()->currentmp = Lib::user()->maxmp;
|
user()->currentmp = user()->maxmp;
|
||||||
}
|
}
|
||||||
if (Lib::user()->currenttp > Lib::user()->maxtp) {
|
if (user()->currenttp > user()->maxtp) {
|
||||||
Lib::user()->currenttp = Lib::user()->maxtp;
|
user()->currenttp = user()->maxtp;
|
||||||
}
|
}
|
||||||
|
|
||||||
$slot_s = 'slot'.$_POST['slot'];
|
$slot_s = 'slot'.$_POST['slot'];
|
||||||
$slot_name = "{$slot_s}name";
|
$slot_name = "{$slot_s}name";
|
||||||
$slot_id = "{$slot_s}id";
|
$slot_id = "{$slot_s}id";
|
||||||
|
|
||||||
Lib::user()->$slot_name = $droprow['name'];
|
user()->$slot_name = $droprow['name'];
|
||||||
Lib::user()->$slot_id = $droprow['id'];
|
user()->$slot_id = $droprow['id'];
|
||||||
} else {
|
} else {
|
||||||
$new1 = explode(',', $droprow['attribute1']);
|
$new1 = explode(',', $droprow['attribute1']);
|
||||||
if ($droprow['attribute2'] != 'X') {
|
if ($droprow['attribute2'] != 'X') {
|
||||||
@ -390,30 +389,30 @@ class Fight
|
|||||||
$new2 = [0 => 'maxhp',1 => 0];
|
$new2 = [0 => 'maxhp',1 => 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->$new1[0] += $new1[1];
|
user()->$new1[0] += $new1[1];
|
||||||
Lib::user()->$new2[0] += $new2[1];
|
user()->$new2[0] += $new2[1];
|
||||||
if ($new1[0] == 'strength') {
|
if ($new1[0] == 'strength') {
|
||||||
Lib::user()->attackpower += $new1[1];
|
user()->attackpower += $new1[1];
|
||||||
}
|
}
|
||||||
if ($new1[0] == 'dexterity') {
|
if ($new1[0] == 'dexterity') {
|
||||||
Lib::user()->defensepower += $new1[1];
|
user()->defensepower += $new1[1];
|
||||||
}
|
}
|
||||||
if ($new2[0] == 'strength') {
|
if ($new2[0] == 'strength') {
|
||||||
Lib::user()->attackpower += $new2[1];
|
user()->attackpower += $new2[1];
|
||||||
}
|
}
|
||||||
if ($new2[0] == 'dexterity') {
|
if ($new2[0] == 'dexterity') {
|
||||||
Lib::user()->defensepower += $new2[1];
|
user()->defensepower += $new2[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
$slot_s = 'slot'.$_POST['slot'];
|
$slot_s = 'slot'.$_POST['slot'];
|
||||||
$slot_name = "{$slot_s}name";
|
$slot_name = "{$slot_s}name";
|
||||||
$slot_id = "{$slot_s}id";
|
$slot_id = "{$slot_s}id";
|
||||||
|
|
||||||
Lib::user()->$slot_name = $droprow['name'];
|
user()->$slot_name = $droprow['name'];
|
||||||
Lib::user()->$slot_id = $droprow['id'];
|
user()->$slot_id = $droprow['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
return 'The item has been equipped. You can now continue <a href="/" hx-get="/" hx-target="#middle">exploring</a>.';
|
return 'The item has been equipped. You can now continue <a href="/" hx-get="/" hx-target="#middle">exploring</a>.';
|
||||||
}
|
}
|
||||||
@ -450,7 +449,7 @@ class Fight
|
|||||||
}
|
}
|
||||||
|
|
||||||
$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 .= '<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: '.Lib::user()->slot1name.'</option><option value="2">Slot 2: '.Lib::user()->slot2name.'</option><option value="3">Slot 3: '.Lib::user()->slot3name.'</option></select> <input type="submit" name="submit" value="Submit" /></form>';
|
$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="/" hx-get="/" hx-target="#middle">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 $page;
|
return $page;
|
||||||
@ -469,40 +468,40 @@ class Fight
|
|||||||
public static function handleMonsterTurn(&$userrow, $monsterrow)
|
public static function handleMonsterTurn(&$userrow, $monsterrow)
|
||||||
{
|
{
|
||||||
$pagearray = '';
|
$pagearray = '';
|
||||||
if (Lib::user()->currentmonstersleep != 0) {
|
if (user()->currentmonstersleep != 0) {
|
||||||
$chancetowake = rand(1, 15);
|
$chancetowake = rand(1, 15);
|
||||||
if ($chancetowake > Lib::user()->currentmonstersleep) {
|
if ($chancetowake > user()->currentmonstersleep) {
|
||||||
Lib::user()->currentmonstersleep = 0;
|
user()->currentmonstersleep = 0;
|
||||||
$pagearray .= 'The monster has woken up.<br>';
|
$pagearray .= 'The monster has woken up.<br>';
|
||||||
} else {
|
} else {
|
||||||
$pagearray .= 'The monster is still asleep.<br>';
|
$pagearray .= 'The monster is still asleep.<br>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->currentmonstersleep == 0) {
|
if (user()->currentmonstersleep == 0) {
|
||||||
$tohit = (int) ceil(mt_rand((int) ($monsterrow['maxdam'] * 0.5), (int) $monsterrow['maxdam']));
|
$tohit = (int) ceil(mt_rand((int) ($monsterrow['maxdam'] * 0.5), (int) $monsterrow['maxdam']));
|
||||||
$toblock = (int) ceil(mt_rand((int) (Lib::user()->defensepower * 0.75), (int) Lib::user()->defensepower) / 4);
|
$toblock = (int) ceil(mt_rand((int) (user()->defensepower * 0.75), (int) user()->defensepower) / 4);
|
||||||
$tododge = rand(1, 150);
|
$tododge = rand(1, 150);
|
||||||
|
|
||||||
if ($tododge <= sqrt(Lib::user()->dexterity)) {
|
if ($tododge <= sqrt(user()->dexterity)) {
|
||||||
$tohit = 0;
|
$tohit = 0;
|
||||||
$pagearray .= "You dodge the monster's attack. No damage has been scored.<br>";
|
$pagearray .= "You dodge the monster's attack. No damage has been scored.<br>";
|
||||||
$persondamage = 0;
|
$persondamage = 0;
|
||||||
} else {
|
} else {
|
||||||
$persondamage = max(1, $tohit - $toblock);
|
$persondamage = max(1, $tohit - $toblock);
|
||||||
if (Lib::user()->currentuberdefense != 0) {
|
if (user()->currentuberdefense != 0) {
|
||||||
$persondamage -= (int) ceil($persondamage * (Lib::user()->currentuberdefense / 100));
|
$persondamage -= (int) ceil($persondamage * (user()->currentuberdefense / 100));
|
||||||
}
|
}
|
||||||
$persondamage = max(1, $persondamage);
|
$persondamage = max(1, $persondamage);
|
||||||
}
|
}
|
||||||
|
|
||||||
$pagearray .= "The monster attacks you for $persondamage damage.<br><br>";
|
$pagearray .= "The monster attacks you for $persondamage damage.<br><br>";
|
||||||
Lib::user()->currenthp -= $persondamage;
|
user()->currenthp -= $persondamage;
|
||||||
|
|
||||||
if (Lib::user()->currenthp <= 0) {
|
if (user()->currenthp <= 0) {
|
||||||
$newgold = (int) ceil(Lib::user()->gold / 2);
|
$newgold = (int) ceil(user()->gold / 2);
|
||||||
$newhp = (int) ceil(Lib::user()->maxhp / 4);
|
$newhp = (int) ceil(user()->maxhp / 4);
|
||||||
Lib::db()->query("UPDATE users SET currenthp=?, currentaction='In Town', currentmonster=0, currentmonsterhp=0, currentmonstersleep=0, currentmonsterimmune=0, currentfight=0, latitude=0, longitude=0, gold=? WHERE id=?;", [
|
db()->query("UPDATE users SET currenthp=?, currentaction='In Town', currentmonster=0, currentmonsterhp=0, currentmonstersleep=0, currentmonsterimmune=0, currentfight=0, latitude=0, longitude=0, gold=? WHERE id=?;", [
|
||||||
$newhp, $newgold, $userrow['id'],
|
$newhp, $newgold, $userrow['id'],
|
||||||
]);
|
]);
|
||||||
self::dead();
|
self::dead();
|
||||||
@ -517,38 +516,38 @@ class Fight
|
|||||||
$pagearray = '';
|
$pagearray = '';
|
||||||
switch ($newspellrow['type']) {
|
switch ($newspellrow['type']) {
|
||||||
case 1: // Heal spell
|
case 1: // Heal spell
|
||||||
$newhp = min(Lib::user()->currenthp + $newspellrow['attribute'], Lib::user()->maxhp);
|
$newhp = min(user()->currenthp + $newspellrow['attribute'], user()->maxhp);
|
||||||
Lib::user()->currenthp = $newhp;
|
user()->currenthp = $newhp;
|
||||||
Lib::user()->currentmp -= $newspellrow['mp'];
|
user()->currentmp -= $newspellrow['mp'];
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell, and gained {$newspellrow['attribute']} Hit Points.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell, and gained {$newspellrow['attribute']} Hit Points.<br><br>";
|
||||||
break;
|
break;
|
||||||
case 2: // Hurt spell
|
case 2: // Hurt spell
|
||||||
if (Lib::user()->currentmonsterimmune == 0) {
|
if (user()->currentmonsterimmune == 0) {
|
||||||
$monsterdamage = mt_rand((int) (($newspellrow['attribute'] / 6) * 5), $newspellrow['attribute']);
|
$monsterdamage = mt_rand((int) (($newspellrow['attribute'] / 6) * 5), $newspellrow['attribute']);
|
||||||
Lib::user()->currentmonsterhp -= $monsterdamage;
|
user()->currentmonsterhp -= $monsterdamage;
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell for $monsterdamage damage.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell for $monsterdamage damage.<br><br>";
|
||||||
} else {
|
} else {
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell, but the monster is immune to it.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell, but the monster is immune to it.<br><br>";
|
||||||
}
|
}
|
||||||
Lib::user()->currentmp -= $newspellrow['mp'];
|
user()->currentmp -= $newspellrow['mp'];
|
||||||
break;
|
break;
|
||||||
case 3: // Sleep spell
|
case 3: // Sleep spell
|
||||||
if (Lib::user()->currentmonsterimmune != 2) {
|
if (user()->currentmonsterimmune != 2) {
|
||||||
Lib::user()->currentmonstersleep = $newspellrow['attribute'];
|
user()->currentmonstersleep = $newspellrow['attribute'];
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell. The monster is asleep.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell. The monster is asleep.<br><br>";
|
||||||
} else {
|
} else {
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell, but the monster is immune to it.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell, but the monster is immune to it.<br><br>";
|
||||||
}
|
}
|
||||||
Lib::user()->currentmp -= $newspellrow['mp'];
|
user()->currentmp -= $newspellrow['mp'];
|
||||||
break;
|
break;
|
||||||
case 4: // +Damage spell
|
case 4: // +Damage spell
|
||||||
Lib::user()->currentuberdamage = $newspellrow['attribute'];
|
user()->currentuberdamage = $newspellrow['attribute'];
|
||||||
Lib::user()->currentmp -= $newspellrow['mp'];
|
user()->currentmp -= $newspellrow['mp'];
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell, and will gain {$newspellrow['attribute']}% damage until the end of this fight.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell, and will gain {$newspellrow['attribute']}% damage until the end of this fight.<br><br>";
|
||||||
break;
|
break;
|
||||||
case 5: // +Defense spell
|
case 5: // +Defense spell
|
||||||
Lib::user()->currentuberdefense = $newspellrow['attribute'];
|
user()->currentuberdefense = $newspellrow['attribute'];
|
||||||
Lib::user()->currentmp -= $newspellrow['mp'];
|
user()->currentmp -= $newspellrow['mp'];
|
||||||
$pagearray = "You have cast the {$newspellrow['name']} spell, and will gain {$newspellrow['attribute']}% defense until the end of this fight.<br><br>";
|
$pagearray = "You have cast the {$newspellrow['name']} spell, and will gain {$newspellrow['attribute']}% defense until the end of this fight.<br><br>";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
use DragonKnight\Router;
|
use DragonKnight\Router;
|
||||||
|
|
||||||
class Forum
|
class Forum
|
||||||
@ -31,7 +30,7 @@ class Forum
|
|||||||
|
|
||||||
public static function donothing($start = 0)
|
public static function donothing($start = 0)
|
||||||
{
|
{
|
||||||
$query = Lib::db()->query('SELECT * FROM forum WHERE parent=0 ORDER BY newpostdate DESC LIMIT 20 OFFSET ?;', [20 * $start]);
|
$query = db()->query('SELECT * FROM forum WHERE parent=0 ORDER BY newpostdate DESC LIMIT 20 OFFSET ?;', [20 * $start]);
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
@ -68,45 +67,45 @@ class Forum
|
|||||||
|
|
||||||
$page .= '</table></td></tr></table>';
|
$page .= '</table></td></tr></table>';
|
||||||
|
|
||||||
Lib::page_title('Forum');
|
page_title('Forum');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function showthread($id, $start)
|
public static function showthread($id, $start)
|
||||||
{
|
{
|
||||||
$posts = Lib::db()->query('SELECT * FROM forum WHERE id=? OR parent=? ORDER BY id LIMIT 15 OFFSET ?;', [$id, $id, $start * 15]);
|
$posts = db()->query('SELECT * FROM forum WHERE id=? OR parent=? ORDER BY id LIMIT 15 OFFSET ?;', [$id, $id, $start * 15]);
|
||||||
$title = Lib::db()->query('SELECT title FROM forum WHERE id=? LIMIT 1;', [$id])->fetchArray(SQLITE3_ASSOC);
|
$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" hx-get="/forum" hx-target="#middle">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)) {
|
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>'.Lib::pretty_date($row['postdate']).'</td><td style="background-color:#ffffff; vertical-align:top;">'.nl2br($row['content'])."</td></tr>\n";
|
$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></td></tr></table><br>';
|
||||||
$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>';
|
$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>';
|
||||||
|
|
||||||
Lib::page_title('Forum: '.$title['title']);
|
page_title('Forum: '.$title['title']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function reply()
|
public static function reply()
|
||||||
{
|
{
|
||||||
$form = Lib::validate($_POST, [
|
$form = validate($_POST, [
|
||||||
'title' => [],
|
'title' => [],
|
||||||
'content' => [],
|
'content' => [],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $form['valid']) {
|
if (! $form['valid']) {
|
||||||
exit(Lib::ul_from_validate_errors($form['errors']));
|
exit(ul_from_validate_errors($form['errors']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $form['data'];
|
$form = $form['data'];
|
||||||
|
|
||||||
Lib::db()->query('INSERT INTO forum (author, title, content, parent) VALUES (?, ?, ?, ?);', [
|
db()->query('INSERT INTO forum (author, title, content, parent) VALUES (?, ?, ?, ?);', [
|
||||||
Lib::user()->username, $form['title'], $form['content'], $form['parent'],
|
user()->username, $form['title'], $form['content'], $form['parent'],
|
||||||
]);
|
]);
|
||||||
Lib::db()->query('UPDATE forum SET newpostdate=CURRENT_TIMESTAMP, replies=replies + 1 WHERE id=?;', [$form['parent']]);
|
db()->query('UPDATE forum SET newpostdate=CURRENT_TIMESTAMP, replies=replies + 1 WHERE id=?;', [$form['parent']]);
|
||||||
|
|
||||||
return self::showthread($form['parent'], 0);
|
return self::showthread($form['parent'], 0);
|
||||||
}
|
}
|
||||||
@ -114,23 +113,23 @@ class Forum
|
|||||||
public static function newthread()
|
public static function newthread()
|
||||||
{
|
{
|
||||||
if (isset($_POST['submit'])) {
|
if (isset($_POST['submit'])) {
|
||||||
$form = Lib::validate($_POST, [
|
$form = validate($_POST, [
|
||||||
'title' => ['length:2-30'],
|
'title' => ['length:2-30'],
|
||||||
'content' => [],
|
'content' => [],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $form['valid']) {
|
if (! $form['valid']) {
|
||||||
exit(Lib::ul_from_validate_errors($form['errors']));
|
exit(ul_from_validate_errors($form['errors']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $form['data'];
|
$form = $form['data'];
|
||||||
Lib::db()->query('INSERT INTO forum (author, title, content) VALUES (?, ?, ?);', [
|
db()->query('INSERT INTO forum (author, title, content) VALUES (?, ?, ?);', [
|
||||||
Lib::user()->username, $form['title'], $form['content'],
|
user()->username, $form['title'], $form['content'],
|
||||||
]);
|
]);
|
||||||
Lib::redirect('/forum/thread/'.Lib::db()->lastInsertRowID().'/0');
|
redirect('/forum/thread/'.db()->lastInsertRowID().'/0');
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Form: New Thread');
|
page_title('Form: New Thread');
|
||||||
|
|
||||||
return '<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>';
|
return '<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>';
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
|
|
||||||
class Heal
|
class Heal
|
||||||
{
|
{
|
||||||
public static function healspells(int $id): string
|
public static function healspells(int $id): string
|
||||||
{
|
{
|
||||||
$user_spells = Lib::user()->spells();
|
$user_spells = user()->spells();
|
||||||
$spell = Lib::get_spell($id);
|
$spell = get_spell($id);
|
||||||
$has_spell = false;
|
$has_spell = false;
|
||||||
foreach ($user_spells as $us) {
|
foreach ($user_spells as $us) {
|
||||||
if ($us['id'] === $id) {
|
if ($us['id'] === $id) {
|
||||||
@ -32,23 +30,23 @@ class Heal
|
|||||||
$page = 'You have not yet learned this spell. Please go back and try again.';
|
$page = 'You have not yet learned this spell. Please go back and try again.';
|
||||||
} elseif ($spell['type'] !== 1) {
|
} elseif ($spell['type'] !== 1) {
|
||||||
$page = 'This is not a healing spell. Please go back and try again.';
|
$page = 'This is not a healing spell. Please go back and try again.';
|
||||||
} elseif (Lib::user()->currentmp < $spell['mp']) {
|
} elseif (user()->currentmp < $spell['mp']) {
|
||||||
$page = 'You do not have enough Magic Points to cast this spell. Please go back and try again.';
|
$page = 'You do not have enough Magic Points to cast this spell. Please go back and try again.';
|
||||||
} elseif (Lib::user()->currentaction === 'Fighting') {
|
} 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.';
|
$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 (Lib::user()->currenthp == Lib::user()->maxhp) {
|
} elseif (user()->currenthp == user()->maxhp) {
|
||||||
$page = 'Your HP is already full. You don\'t need to use a Healing spell now.';
|
$page = 'Your HP is already full. You don\'t need to use a Healing spell now.';
|
||||||
} else {
|
} else {
|
||||||
$restored = Lib::user()->restore_hp($spell['attribute']);
|
$restored = user()->restore_hp($spell['attribute']);
|
||||||
Lib::user()->currentmp -= $spell['mp'];
|
user()->currentmp -= $spell['mp'];
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
$page = <<<HTML
|
$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>.
|
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;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Casting '.$spell['name']);
|
page_title('Casting '.$spell['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
use DragonKnight\Router;
|
use DragonKnight\Router;
|
||||||
|
|
||||||
class Help
|
class Help
|
||||||
@ -270,7 +269,7 @@ class Help
|
|||||||
<tr><td><b>Type</b></td><td><b>Name</b></td><td><b>Cost</b></td><td><b>Attribute</b></td><td><b>Special</b></td></tr>
|
<tr><td><b>Type</b></td><td><b>Name</b></td><td><b>Cost</b></td><td><b>Attribute</b></td><td><b>Special</b></td></tr>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
$items = Lib::db()->query('SELECT * FROM items ORDER BY id;');
|
$items = db()->query('SELECT * FROM items ORDER BY id;');
|
||||||
$item_types = [1 => ['weapon', 'Attack'], 2 => ['armor', 'Defense'], 3 => ['shield', 'Defense']];
|
$item_types = [1 => ['weapon', 'Attack'], 2 => ['armor', 'Defense'], 3 => ['shield', 'Defense']];
|
||||||
|
|
||||||
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
||||||
@ -279,7 +278,7 @@ class Help
|
|||||||
|
|
||||||
if ($item['special'] !== 'X') {
|
if ($item['special'] !== 'X') {
|
||||||
$special = explode(',', $item['special']);
|
$special = explode(',', $item['special']);
|
||||||
$attr = Lib::special_to_string($special[0]);
|
$attr = special_to_string($special[0]);
|
||||||
$stat = (($special[1] > 0) ? '+' : '').$special[1];
|
$stat = (($special[1] > 0) ? '+' : '').$special[1];
|
||||||
$bigspecial = "$attr $stat";
|
$bigspecial = "$attr $stat";
|
||||||
} else {
|
} else {
|
||||||
@ -299,12 +298,12 @@ class Help
|
|||||||
<tr><td><b>Name</b></td><td><b>Monster Level</b></td><td><b>Attribute 1</b></td><td><b>Attribute 2</b></td></tr>
|
<tr><td><b>Name</b></td><td><b>Monster Level</b></td><td><b>Attribute 1</b></td><td><b>Attribute 2</b></td></tr>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
$drops = Lib::db()->query('SELECT * FROM drops ORDER BY id;');
|
$drops = db()->query('SELECT * FROM drops ORDER BY id;');
|
||||||
|
|
||||||
while ($drop = $drops->fetchArray(SQLITE3_ASSOC)) {
|
while ($drop = $drops->fetchArray(SQLITE3_ASSOC)) {
|
||||||
if ($drop['attribute1'] !== 'X') {
|
if ($drop['attribute1'] !== 'X') {
|
||||||
$special = explode(',', $drop['attribute1']);
|
$special = explode(',', $drop['attribute1']);
|
||||||
$attr = Lib::special_to_string($special[0]);
|
$attr = special_to_string($special[0]);
|
||||||
$stat = (($special[1] > 0) ? '+' : '').$special[1];
|
$stat = (($special[1] > 0) ? '+' : '').$special[1];
|
||||||
$bigspecial1 = "$attr $stat";
|
$bigspecial1 = "$attr $stat";
|
||||||
} else {
|
} else {
|
||||||
@ -313,7 +312,7 @@ class Help
|
|||||||
|
|
||||||
if ($drop['attribute2'] !== 'X') {
|
if ($drop['attribute2'] !== 'X') {
|
||||||
$special = explode(',', $drop['attribute2']);
|
$special = explode(',', $drop['attribute2']);
|
||||||
$attr = Lib::special_to_string($special[0]);
|
$attr = special_to_string($special[0]);
|
||||||
$stat = (($special[1] > 0) ? '+' : '').$special[1];
|
$stat = (($special[1] > 0) ? '+' : '').$special[1];
|
||||||
$bigspecial2 = "$attr $stat";
|
$bigspecial2 = "$attr $stat";
|
||||||
} else {
|
} else {
|
||||||
@ -335,7 +334,7 @@ class Help
|
|||||||
<tr><td><b>Name</b></td><td><b>Cost</b></td><td><b>Type</b></td><td><b>Attribute</b></td></tr>
|
<tr><td><b>Name</b></td><td><b>Cost</b></td><td><b>Type</b></td><td><b>Attribute</b></td></tr>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
$spells = Lib::db()->query('SELECT * FROM spells ORDER BY id;');
|
$spells = db()->query('SELECT * FROM spells ORDER BY id;');
|
||||||
$spell_types = ['None', 'Heal', 'Hurt', 'Sleep', '+Damage (%)', '+Defense (%)'];
|
$spell_types = ['None', 'Heal', 'Hurt', 'Sleep', '+Damage (%)', '+Defense (%)'];
|
||||||
while ($spell = $spells->fetchArray(SQLITE3_ASSOC)) {
|
while ($spell = $spells->fetchArray(SQLITE3_ASSOC)) {
|
||||||
$page .= <<<HTML
|
$page .= <<<HTML
|
||||||
@ -368,7 +367,7 @@ class Help
|
|||||||
<tr><td><b>Name</b></td><td><b>Max HP</b></td><td><b>Max Damage</b></td><td><b>Armor</b></td><td><b>Level</b></td><td><b>Max Exp.</b></td><td><b>Max Gold</b></td><td><b>Immunity</b></td></tr>
|
<tr><td><b>Name</b></td><td><b>Max HP</b></td><td><b>Max Damage</b></td><td><b>Armor</b></td><td><b>Level</b></td><td><b>Max Exp.</b></td><td><b>Max Gold</b></td><td><b>Immunity</b></td></tr>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
$monsters = Lib::db()->query('SELECT * FROM monsters ORDER BY id;');
|
$monsters = db()->query('SELECT * FROM monsters ORDER BY id;');
|
||||||
$immunities = ['<span class="light">None</span>', 'Hurt', 'Hurt & Sleep'];
|
$immunities = ['<span class="light">None</span>', 'Hurt', 'Hurt & Sleep'];
|
||||||
|
|
||||||
while ($m = $monsters->fetchArray(SQLITE3_ASSOC)) {
|
while ($m = $monsters->fetchArray(SQLITE3_ASSOC)) {
|
||||||
@ -383,7 +382,7 @@ class Help
|
|||||||
{
|
{
|
||||||
$rows = [];
|
$rows = [];
|
||||||
|
|
||||||
$levels = Lib::db()->query('SELECT * FROM levels ORDER BY id;');
|
$levels = db()->query('SELECT * FROM levels ORDER BY id;');
|
||||||
while ($level = $levels->fetchArray(SQLITE3_ASSOC)) {
|
while ($level = $levels->fetchArray(SQLITE3_ASSOC)) {
|
||||||
$class_data = [1 => [], 2 => [], 3 => []];
|
$class_data = [1 => [], 2 => [], 3 => []];
|
||||||
|
|
||||||
@ -405,7 +404,7 @@ class Help
|
|||||||
}
|
}
|
||||||
|
|
||||||
$spells = [];
|
$spells = [];
|
||||||
$spells_query = Lib::db()->query('SELECT * FROM spells ORDER BY id;');
|
$spells_query = db()->query('SELECT * FROM spells ORDER BY id;');
|
||||||
while ($spell = $spells_query->fetchArray(SQLITE3_ASSOC)) {
|
while ($spell = $spells_query->fetchArray(SQLITE3_ASSOC)) {
|
||||||
$spells[$spell['id']] = $spell;
|
$spells[$spell['id']] = $spell;
|
||||||
}
|
}
|
||||||
@ -508,7 +507,7 @@ class Help
|
|||||||
|
|
||||||
public static function display_help(string $content)
|
public static function display_help(string $content)
|
||||||
{
|
{
|
||||||
return Lib::render('layouts/help', [
|
return render('layouts/help', [
|
||||||
'content' => $content,
|
'content' => $content,
|
||||||
'version' => VERSION,
|
'version' => VERSION,
|
||||||
'build' => BUILD,
|
'build' => BUILD,
|
||||||
|
@ -13,9 +13,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
use DragonKnight\Router;
|
use DragonKnight\Router;
|
||||||
|
|
||||||
|
use function DragonKnight\db;
|
||||||
|
use function DragonKnight\ul_from_validate_errors;
|
||||||
|
use function DragonKnight\user;
|
||||||
|
use function DragonKnight\validate;
|
||||||
|
|
||||||
class Install
|
class Install
|
||||||
{
|
{
|
||||||
public static function register_routes(Router $r): Router
|
public static function register_routes(Router $r): Router
|
||||||
@ -56,20 +60,20 @@ class Install
|
|||||||
*/
|
*/
|
||||||
public static function second()
|
public static function second()
|
||||||
{
|
{
|
||||||
if (! is_dir($path = getcwd().'/db')) {
|
if (! is_dir($path = getcwd().'/db')) {
|
||||||
if (mkdir($path, 0777, true) === false) {
|
if (mkdir($path, 0777, true) === false) {
|
||||||
throw new \Exception('Failed to create database directory at '.$path.'. Please check permissions.');
|
throw new \Exception('Failed to create database directory at '.$path.'. Please check permissions.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (file_exists($path = getcwd().'/db/database.db')) {
|
if (file_exists($path = getcwd().'/db/database.db')) {
|
||||||
if (unlink($path) === false) {
|
if (unlink($path) === false) {
|
||||||
throw new \Exception('Failed to delete existing database file at '.$path.'. Please check permissions.');
|
throw new \Exception('Failed to delete existing database file at '.$path.'. Please check permissions.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$page = '<html><head><title>Dragon Knight Installation</title></head><body><b>Dragon Knight Installation: Page Two</b><br><br>';
|
$page = '<html><head><title>Dragon Knight Installation</title></head><body><b>Dragon Knight Installation: Page Two</b><br><br>';
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE babble (
|
CREATE TABLE babble (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`posttime` TEXT NOT NULL DEFAULT '00:00:00',
|
`posttime` TEXT NOT NULL DEFAULT '00:00:00',
|
||||||
@ -80,7 +84,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Babble', 'create');
|
$page .= self::table_status_msg($query === true, 'Babble', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE drops (
|
CREATE TABLE drops (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`name` TEXT NOT NULL DEFAULT '',
|
`name` TEXT NOT NULL DEFAULT '',
|
||||||
@ -93,7 +97,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Drops', 'create');
|
$page .= self::table_status_msg($query === true, 'Drops', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO drops VALUES
|
INSERT INTO drops VALUES
|
||||||
(1, 'Life Pebble', 1, 1, 'maxhp,10', 'X'),
|
(1, 'Life Pebble', 1, 1, 'maxhp,10', 'X'),
|
||||||
(2, 'Life Stone', 10, 1, 'maxhp,25', 'X'),
|
(2, 'Life Stone', 10, 1, 'maxhp,25', 'X'),
|
||||||
@ -131,7 +135,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Drops', 'populate');
|
$page .= self::table_status_msg($query === true, 'Drops', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE forum (
|
CREATE TABLE forum (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`postdate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`postdate` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
@ -146,7 +150,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Forum', 'create');
|
$page .= self::table_status_msg($query === true, 'Forum', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE items (
|
CREATE TABLE items (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`type` INTEGER NOT NULL DEFAULT 0,
|
`type` INTEGER NOT NULL DEFAULT 0,
|
||||||
@ -159,7 +163,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Items', 'create');
|
$page .= self::table_status_msg($query === true, 'Items', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO items VALUES
|
INSERT INTO items VALUES
|
||||||
(1, 1, 'Stick', 10, 2, 'X'),
|
(1, 1, 'Stick', 10, 2, 'X'),
|
||||||
(2, 1, 'Branch', 30, 4, 'X'),
|
(2, 1, 'Branch', 30, 4, 'X'),
|
||||||
@ -198,7 +202,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Drops', 'populate');
|
$page .= self::table_status_msg($query === true, 'Drops', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE classes (
|
CREATE TABLE classes (
|
||||||
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
|
'id' INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
'name' TEXT NOT NULL,
|
'name' TEXT NOT NULL,
|
||||||
@ -217,7 +221,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Classes', 'create');
|
$page .= self::table_status_msg($query === true, 'Classes', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO classes VALUES
|
INSERT INTO classes VALUES
|
||||||
(0, 'Adventurer', '', 3, 15, 10, 4, 4, 2, 2, 2, 2),
|
(0, 'Adventurer', '', 3, 15, 10, 4, 4, 2, 2, 2, 2),
|
||||||
(1, 'Mage', '', 1, 10, 15, 1, 7, 1, 3, 1, 2),
|
(1, 'Mage', '', 1, 10, 15, 1, 7, 1, 3, 1, 2),
|
||||||
@ -227,7 +231,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Classes', 'populate');
|
$page .= self::table_status_msg($query === true, 'Classes', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE levels (
|
CREATE TABLE levels (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`1_exp` INTEGER NOT NULL DEFAULT 0,
|
`1_exp` INTEGER NOT NULL DEFAULT 0,
|
||||||
@ -256,7 +260,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Levels', 'create');
|
$page .= self::table_status_msg($query === true, 'Levels', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO levels VALUES
|
INSERT INTO levels VALUES
|
||||||
(1, 0, 15, 0, 5, 5, 5, 0, 0, 15, 0, 5, 5, 5, 0, 0, 15, 0, 5, 5, 5, 0),
|
(1, 0, 15, 0, 5, 5, 5, 0, 0, 15, 0, 5, 5, 5, 0, 0, 15, 0, 5, 5, 5, 0),
|
||||||
(2, 15, 2, 5, 1, 0, 1, 1, 18, 2, 4, 1, 2, 1, 1, 20, 2, 5, 1, 0, 2, 1),
|
(2, 15, 2, 5, 1, 0, 1, 1, 18, 2, 4, 1, 2, 1, 1, 20, 2, 5, 1, 0, 2, 1),
|
||||||
@ -362,7 +366,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Levels', 'populate');
|
$page .= self::table_status_msg($query === true, 'Levels', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE monsters (
|
CREATE TABLE monsters (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`name` TEXT NOT NULL DEFAULT '',
|
`name` TEXT NOT NULL DEFAULT '',
|
||||||
@ -378,7 +382,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Monsters', 'create');
|
$page .= self::table_status_msg($query === true, 'Monsters', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO monsters VALUES
|
INSERT INTO monsters VALUES
|
||||||
(1, 'Blue Slime', 4, 3, 1, 1, 1, 1, 0),
|
(1, 'Blue Slime', 4, 3, 1, 1, 1, 1, 0),
|
||||||
(2, 'Red Slime', 6, 5, 1, 1, 2, 1, 0),
|
(2, 'Red Slime', 6, 5, 1, 1, 2, 1, 0),
|
||||||
@ -535,7 +539,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Monsters', 'populate');
|
$page .= self::table_status_msg($query === true, 'Monsters', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE news (
|
CREATE TABLE news (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`author` TEXT NOT NULL DEFAULT 'Guild Master',
|
`author` TEXT NOT NULL DEFAULT 'Guild Master',
|
||||||
@ -546,11 +550,11 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'News', 'create');
|
$page .= self::table_status_msg($query === true, 'News', 'create');
|
||||||
|
|
||||||
$query = Lib::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.');");
|
$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.');");
|
||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'News', 'populate');
|
$page .= self::table_status_msg($query === true, 'News', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE spells (
|
CREATE TABLE spells (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`name` TEXT NOT NULL,
|
`name` TEXT NOT NULL,
|
||||||
@ -562,7 +566,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Spells', 'create');
|
$page .= self::table_status_msg($query === true, 'Spells', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO spells VALUES
|
INSERT INTO spells VALUES
|
||||||
(1, 'Heal', 5, 10, 1),
|
(1, 'Heal', 5, 10, 1),
|
||||||
(2, 'Revive', 10, 25, 1),
|
(2, 'Revive', 10, 25, 1),
|
||||||
@ -587,7 +591,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Spells', 'populate');
|
$page .= self::table_status_msg($query === true, 'Spells', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE towns (
|
CREATE TABLE towns (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`name` TEXT NOT NULL,
|
`name` TEXT NOT NULL,
|
||||||
@ -602,7 +606,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Towns', 'create');
|
$page .= self::table_status_msg($query === true, 'Towns', 'create');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
INSERT INTO towns VALUES
|
INSERT INTO towns VALUES
|
||||||
(1, 'Midworld', 0, 0, 5, 0, 0, '1,2,3,17,18,19,28,29'),
|
(1, 'Midworld', 0, 0, 5, 0, 0, '1,2,3,17,18,19,28,29'),
|
||||||
(2, 'Roma', 30, 30, 10, 25, 5, '2,3,4,18,19,29'),
|
(2, 'Roma', 30, 30, 10, 25, 5, '2,3,4,18,19,29'),
|
||||||
@ -616,7 +620,7 @@ class Install
|
|||||||
|
|
||||||
$page .= self::table_status_msg($query === true, 'Towns', 'populate');
|
$page .= self::table_status_msg($query === true, 'Towns', 'populate');
|
||||||
|
|
||||||
$query = Lib::db()->exec(<<<SQL
|
$query = db()->exec(<<<SQL
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`username` TEXT NOT NULL,
|
`username` TEXT NOT NULL,
|
||||||
@ -714,7 +718,7 @@ class Install
|
|||||||
public static function fourth(?array $post = null)
|
public static function fourth(?array $post = null)
|
||||||
{
|
{
|
||||||
$post ??= $_POST;
|
$post ??= $_POST;
|
||||||
$form = Lib::validate($post, [
|
$form = validate($post, [
|
||||||
'username' => ['length:3-18', 'alpha-spaces'],
|
'username' => ['length:3-18', 'alpha-spaces'],
|
||||||
'email' => ['email'],
|
'email' => ['email'],
|
||||||
'confirm_email' => ['confirm'],
|
'confirm_email' => ['confirm'],
|
||||||
@ -723,11 +727,11 @@ class Install
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $form['valid']) {
|
if (! $form['valid']) {
|
||||||
exit(Lib::ul_from_validate_errors($form['errors']));
|
exit(ul_from_validate_errors($form['errors']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $form['data'];
|
$form = $form['data'];
|
||||||
if (Lib::db()->query(
|
if (db()->query(
|
||||||
"INSERT INTO users (username, password, email, verify, charclass, authlevel) VALUES (?, ?, ?, 'g2g', ?, 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'] ?? null]
|
[$form['username'], password_hash($form['password'], PASSWORD_ARGON2ID), $form['email'], $form['charclass'] ?? null]
|
||||||
) === false) {
|
) === false) {
|
||||||
@ -788,7 +792,7 @@ class Install
|
|||||||
};
|
};
|
||||||
|
|
||||||
if ($condition === false) {
|
if ($condition === false) {
|
||||||
return "Error {$verb[1]} $table_name table. (".Lib::db()->lastErrorMsg().')<br>';
|
return "Error {$verb[1]} $table_name table. (".db()->lastErrorMsg().')<br>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return "$table_name table {$verb[0]}.<br>";
|
return "$table_name table {$verb[0]}.<br>";
|
||||||
|
@ -13,9 +13,19 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Actions;
|
namespace DragonKnight\Actions;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
use DragonKnight\Router;
|
use DragonKnight\Router;
|
||||||
|
|
||||||
|
use function DragonKnight\db;
|
||||||
|
use function DragonKnight\env;
|
||||||
|
use function DragonKnight\get_town_by_xy;
|
||||||
|
use function DragonKnight\get_item;
|
||||||
|
use function DragonKnight\get_town_by_id;
|
||||||
|
use function DragonKnight\is_post;
|
||||||
|
use function DragonKnight\page_title;
|
||||||
|
use function DragonKnight\redirect;
|
||||||
|
use function DragonKnight\render;
|
||||||
|
use function DragonKnight\user;
|
||||||
|
|
||||||
class Towns
|
class Towns
|
||||||
{
|
{
|
||||||
public static function register_routes(Router $r): Router
|
public static function register_routes(Router $r): Router
|
||||||
@ -36,7 +46,7 @@ class Towns
|
|||||||
*/
|
*/
|
||||||
public static function town()
|
public static function town()
|
||||||
{
|
{
|
||||||
$town = Lib::get_town_by_xy(Lib::user()->longitude, Lib::user()->latitude);
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
||||||
if ($town === false) {
|
if ($town === false) {
|
||||||
exit('There is an error with your user account, or with the town data. Please try again.');
|
exit('There is an error with your user account, or with the town data. Please try again.');
|
||||||
}
|
}
|
||||||
@ -44,9 +54,9 @@ class Towns
|
|||||||
$page = ['news' => '', 'whos_online' => ''];
|
$page = ['news' => '', 'whos_online' => ''];
|
||||||
|
|
||||||
// News box. Grab latest news entry and display it. Something a little more graceful coming soon maybe.
|
// News box. Grab latest news entry and display it. Something a little more graceful coming soon maybe.
|
||||||
if (Lib::env('show_news')) {
|
if (env('show_news')) {
|
||||||
$news = Lib::db()->query('SELECT * FROM news ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC);
|
$news = db()->query('SELECT * FROM news ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC);
|
||||||
$news_date = Lib::pretty_date($news['postdate']);
|
$news_date = pretty_date($news['postdate']);
|
||||||
$news_content = nl2br($news['content']);
|
$news_content = nl2br($news['content']);
|
||||||
$page['news'] = <<<HTML
|
$page['news'] = <<<HTML
|
||||||
<div class="title">Latest News</div>
|
<div class="title">Latest News</div>
|
||||||
@ -56,8 +66,8 @@ class Towns
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Who's Online. Currently just members. Guests maybe later.
|
// Who's Online. Currently just members. Guests maybe later.
|
||||||
if (Lib::env('show_online')) {
|
if (env('show_online')) {
|
||||||
$onlinequery = Lib::db()->query(<<<SQL
|
$onlinequery = db()->query(<<<SQL
|
||||||
SELECT id, username
|
SELECT id, username
|
||||||
FROM users
|
FROM users
|
||||||
WHERE onlinetime >= datetime('now', '-600 seconds')
|
WHERE onlinetime >= datetime('now', '-600 seconds')
|
||||||
@ -75,13 +85,13 @@ class Towns
|
|||||||
$online_rows = implode(', ', $online_rows);
|
$online_rows = implode(', ', $online_rows);
|
||||||
$page['whos_online'] = <<<HTML
|
$page['whos_online'] = <<<HTML
|
||||||
<div class="title">Who's Online</div>
|
<div class="title">Who's Online</div>
|
||||||
There are <b>$online_count</b> Lib::user(s) online within the last 10 minutes: $online_rows
|
There are <b>$online_count</b> user(s) online within the last 10 minutes: $online_rows
|
||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title($town['name']);
|
page_title($town['name']);
|
||||||
|
|
||||||
return Lib::render('towns', ['town' => $town, 'news' => $page['news'], 'whos_online' => $page['whos_online']]);
|
return render('towns', ['town' => $town, 'news' => $page['news'], 'whos_online' => $page['whos_online']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,25 +100,25 @@ class Towns
|
|||||||
*/
|
*/
|
||||||
public static function inn()
|
public static function inn()
|
||||||
{
|
{
|
||||||
$town = Lib::get_town_by_xy(Lib::user()->longitude, Lib::user()->latitude);
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
||||||
if ($town === false) {
|
if ($town === false) {
|
||||||
exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->gold < $town['innprice']) {
|
if (user()->gold < $town['innprice']) {
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
You do not have enough gold to stay at this Inn tonight. <br><br>
|
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.
|
You may return to <a hx-get="/" hx-target="#middle">town</a>, or use the direction buttons on the left to start exploring.
|
||||||
HTML;
|
HTML;
|
||||||
} elseif (Lib::is_post() && $_POST['rest']) {
|
} elseif (is_post() && $_POST['rest']) {
|
||||||
Lib::user()->gold -= $town['innprice'];
|
user()->gold -= $town['innprice'];
|
||||||
Lib::user()->restore_points()->save();
|
user()->restore_points()->save();
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
You wake up feeling refreshed and ready for action. <br><br>
|
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.
|
You may return to <a hx-get="/" hx-target="#middle">town</a>, or use the direction buttons on the left to start exploring.
|
||||||
HTML;
|
HTML;
|
||||||
} elseif (Lib::is_post() && ! $_POST['rest']) {
|
} elseif (is_post() && ! $_POST['rest']) {
|
||||||
Lib::redirect('/');
|
redirect('/');
|
||||||
} else {
|
} else {
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
Resting at the inn will refill your current HP, MP, and TP to their maximum levels.<br><br>
|
Resting at the inn will refill your current HP, MP, and TP to their maximum levels.<br><br>
|
||||||
@ -120,7 +130,7 @@ class Towns
|
|||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title($town['name'].' Inn');
|
page_title($town['name'].' Inn');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -132,7 +142,7 @@ class Towns
|
|||||||
*/
|
*/
|
||||||
public static function shop()
|
public static function shop()
|
||||||
{
|
{
|
||||||
$town = Lib::get_town_by_xy(Lib::user()->longitude, Lib::user()->latitude);
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
||||||
if ($town === false) {
|
if ($town === false) {
|
||||||
exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
||||||
}
|
}
|
||||||
@ -144,7 +154,7 @@ class Towns
|
|||||||
<table>
|
<table>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
$items = Lib::db()->query('SELECT * FROM items WHERE id IN ('.$town['itemslist'].');');
|
$items = db()->query('SELECT * FROM items WHERE id IN ('.$town['itemslist'].');');
|
||||||
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
||||||
$attrib = ($item['type'] == 1) ? 'Attack Power:' : 'Defense Power:';
|
$attrib = ($item['type'] == 1) ? 'Attack Power:' : 'Defense Power:';
|
||||||
$page .= '<tr><td width="4%">';
|
$page .= '<tr><td width="4%">';
|
||||||
@ -154,7 +164,7 @@ class Towns
|
|||||||
3 => '<img src="/img/icon_shield.gif" alt="shield">'
|
3 => '<img src="/img/icon_shield.gif" alt="shield">'
|
||||||
};
|
};
|
||||||
$page .= '</td>';
|
$page .= '</td>';
|
||||||
if (Lib::user()->weaponid === $item['id'] || Lib::user()->armorid === $item['id'] || Lib::user()->shieldid === $item['id']) {
|
if (user()->weaponid === $item['id'] || user()->armorid === $item['id'] || user()->shieldid === $item['id']) {
|
||||||
$page .= <<<HTML
|
$page .= <<<HTML
|
||||||
<td width="32%"><span class="light">{$item['name']}</span></td>
|
<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">$attrib {$item['attribute']}</span></td>
|
||||||
@ -175,7 +185,7 @@ class Towns
|
|||||||
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
Lib::page_title($town['name'].' Shop');
|
page_title($town['name'].' Shop');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -185,15 +195,15 @@ class Towns
|
|||||||
*/
|
*/
|
||||||
public static function buy(int $id)
|
public static function buy(int $id)
|
||||||
{
|
{
|
||||||
$town = Lib::get_town_by_xy(Lib::user()->longitude, Lib::user()->latitude);
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
||||||
if ($town === false) {
|
if ($town === false) {
|
||||||
Lib::redirect('/');
|
redirect('/');
|
||||||
}
|
}
|
||||||
if (! in_array($id, explode(',', $town['itemslist']))) {
|
if (! in_array($id, explode(',', $town['itemslist']))) {
|
||||||
Lib::redirect('/shop');
|
redirect('/shop');
|
||||||
}
|
}
|
||||||
$item = Lib::get_item($id);
|
$item = get_item($id);
|
||||||
$can_afford = Lib::user()->gold >= $item['buycost'];
|
$can_afford = user()->gold >= $item['buycost'];
|
||||||
|
|
||||||
if (! $can_afford) {
|
if (! $can_afford) {
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
@ -201,9 +211,9 @@ class Towns
|
|||||||
You may return to <a hx-get="/" hx-target="#middle">town</a>, <a hx-get="/shop" hx-target="#middle">shop</a>,
|
You may return to <a hx-get="/" hx-target="#middle">town</a>, <a hx-get="/shop" hx-target="#middle">shop</a>,
|
||||||
or use the direction buttons on the left to start exploring.
|
or use the direction buttons on the left to start exploring.
|
||||||
HTML;
|
HTML;
|
||||||
} elseif (Lib::is_post() && ! $_POST['buy']) {
|
} elseif (is_post() && ! $_POST['buy']) {
|
||||||
Lib::redirect('/shop');
|
redirect('/shop');
|
||||||
} elseif (Lib::is_post() && $_POST['buy']) {
|
} elseif (is_post() && $_POST['buy']) {
|
||||||
$type_mapping = [
|
$type_mapping = [
|
||||||
1 => ['id' => 'weaponid', 'name' => 'weaponname', 'power' => 'attackpower'],
|
1 => ['id' => 'weaponid', 'name' => 'weaponname', 'power' => 'attackpower'],
|
||||||
2 => ['id' => 'armorid', 'name' => 'armorname', 'power' => 'defensepower'],
|
2 => ['id' => 'armorid', 'name' => 'armorname', 'power' => 'defensepower'],
|
||||||
@ -215,9 +225,9 @@ class Towns
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve current equipped item or create a default
|
// Retrieve current equipped item or create a default
|
||||||
$current_equip_id = Lib::user()->{$type_mapping[$item['type']]['id']};
|
$current_equip_id = user()->{$type_mapping[$item['type']]['id']};
|
||||||
if ($current_equip_id != 0) {
|
if ($current_equip_id != 0) {
|
||||||
$item2 = Lib::get_item($current_equip_id);
|
$item2 = get_item($current_equip_id);
|
||||||
} else {
|
} else {
|
||||||
$item2 = ['attribute' => 0, 'buycost' => 0, 'special' => 'X'];
|
$item2 = ['attribute' => 0, 'buycost' => 0, 'special' => 'X'];
|
||||||
}
|
}
|
||||||
@ -233,9 +243,9 @@ class Towns
|
|||||||
$toChange = $special[0];
|
$toChange = $special[0];
|
||||||
$changeAmount = $index === 0 ? $special[1] : -$special[1];
|
$changeAmount = $index === 0 ? $special[1] : -$special[1];
|
||||||
|
|
||||||
Lib::user()->$toChange += $changeAmount;
|
user()->$toChange += $changeAmount;
|
||||||
$specialFields[] = "$toChange = ?";
|
$specialFields[] = "$toChange = ?";
|
||||||
$specialValues[] = Lib::user()->$toChange;
|
$specialValues[] = user()->$toChange;
|
||||||
|
|
||||||
// Adjust attack or defense power
|
// Adjust attack or defense power
|
||||||
if ($toChange == 'strength' || $toChange == 'dexterity') {
|
if ($toChange == 'strength' || $toChange == 'dexterity') {
|
||||||
@ -248,21 +258,21 @@ class Towns
|
|||||||
// Determine power and type-specific updates
|
// Determine power and type-specific updates
|
||||||
$currentType = $type_mapping[$item['type']];
|
$currentType = $type_mapping[$item['type']];
|
||||||
$powerField = $currentType['power'];
|
$powerField = $currentType['power'];
|
||||||
Lib::user()->$powerField += $item['attribute'] - $item2['attribute'];
|
user()->$powerField += $item['attribute'] - $item2['attribute'];
|
||||||
|
|
||||||
// Calculate new gold with trade-in value
|
// Calculate new gold with trade-in value
|
||||||
Lib::user()->gold += ceil($item2['buycost'] / 2) - $item['buycost'];
|
user()->gold += ceil($item2['buycost'] / 2) - $item['buycost'];
|
||||||
|
|
||||||
// Ensure current HP/MP/TP don't exceed max values
|
// Ensure current HP/MP/TP don't exceed max values
|
||||||
Lib::user()->currenthp = min(Lib::user()->currenthp, Lib::user()->maxhp);
|
user()->currenthp = min(user()->currenthp, user()->maxhp);
|
||||||
Lib::user()->currentmp = min(Lib::user()->currentmp, Lib::user()->maxmp);
|
user()->currentmp = min(user()->currentmp, user()->maxmp);
|
||||||
Lib::user()->currenttp = min(Lib::user()->currenttp, Lib::user()->maxtp);
|
user()->currenttp = min(user()->currenttp, user()->maxtp);
|
||||||
|
|
||||||
// Update item info in user
|
// Update item info in user
|
||||||
Lib::user()->{$type_mapping[$item['type']]['id']} = $item['id'];
|
user()->{$type_mapping[$item['type']]['id']} = $item['id'];
|
||||||
Lib::user()->{$type_mapping[$item['type']]['name']} = $item['name'];
|
user()->{$type_mapping[$item['type']]['name']} = $item['name'];
|
||||||
|
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
Thank you for purchasing <b>{$item['name']}</b>.<br><br>
|
Thank you for purchasing <b>{$item['name']}</b>.<br><br>
|
||||||
@ -271,10 +281,10 @@ class Towns
|
|||||||
HTML;
|
HTML;
|
||||||
} else {
|
} else {
|
||||||
$type_to_row_mapping = [1 => 'weaponid', 2 => 'armorid', 3 => 'shieldid'];
|
$type_to_row_mapping = [1 => 'weaponid', 2 => 'armorid', 3 => 'shieldid'];
|
||||||
$current_equipped_id = Lib::user()->{$type_to_row_mapping[$item['type']]} ?? 0;
|
$current_equipped_id = user()->{$type_to_row_mapping[$item['type']]} ?? 0;
|
||||||
|
|
||||||
if ($current_equipped_id != 0) {
|
if ($current_equipped_id != 0) {
|
||||||
$item2 = Lib::get_item($current_equipped_id);
|
$item2 = get_item($current_equipped_id);
|
||||||
$sell_price = ceil($item2['buycost'] / 2);
|
$sell_price = ceil($item2['buycost'] / 2);
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
If you are buying the {$item['name']}, then I will buy your {$item2['name']} for $sell_price gold. Is that ok?<br><br>
|
If you are buying the {$item['name']}, then I will buy your {$item2['name']} for $sell_price gold. Is that ok?<br><br>
|
||||||
@ -294,7 +304,7 @@ class Towns
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Buying '.$item['name']);
|
page_title('Buying '.$item['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -310,8 +320,8 @@ class Towns
|
|||||||
<table>
|
<table>
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
$mapped = explode(',', Lib::user()->towns);
|
$mapped = explode(',', user()->towns);
|
||||||
$towns = Lib::db()->query('SELECT * FROM towns ORDER BY id;');
|
$towns = db()->query('SELECT * FROM towns ORDER BY id;');
|
||||||
while ($town = $towns->fetchArray(SQLITE3_ASSOC)) {
|
while ($town = $towns->fetchArray(SQLITE3_ASSOC)) {
|
||||||
$latitude = ($town['latitude'] >= 0) ? $town['latitude'].'N,' : ($town['latitude'] * -1).'S,';
|
$latitude = ($town['latitude'] >= 0) ? $town['latitude'].'N,' : ($town['latitude'] * -1).'S,';
|
||||||
$longitude = ($town['longitude'] >= 0) ? $town['longitude'].'E' : ($town['longitude'] * -1).'W';
|
$longitude = ($town['longitude'] >= 0) ? $town['longitude'].'E' : ($town['longitude'] * -1).'W';
|
||||||
@ -341,34 +351,34 @@ class Towns
|
|||||||
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
||||||
HTML;
|
HTML;
|
||||||
|
|
||||||
Lib::page_title('Maps');
|
page_title('Maps');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function buy_map(int $id): string
|
public static function buy_map(int $id): string
|
||||||
{
|
{
|
||||||
$town = Lib::get_town_by_id($id);
|
$town = get_town_by_id($id);
|
||||||
if ($town === false) {
|
if ($town === false) {
|
||||||
Lib::redirect('/maps');
|
redirect('/maps');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Lib::user()->gold < $town['mapprice']) {
|
if (user()->gold < $town['mapprice']) {
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
You do not have enough gold to buy this map.<br><br>
|
You do not have enough gold to buy 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">store</a>, or use the direction buttons on the left to start exploring.
|
||||||
HTML;
|
HTML;
|
||||||
} elseif (Lib::is_post() && $_POST['buy']) {
|
} elseif (is_post() && $_POST['buy']) {
|
||||||
Lib::user()->towns .= ",$id";
|
user()->towns .= ",$id";
|
||||||
Lib::user()->gold -= $town['mapprice'];
|
user()->gold -= $town['mapprice'];
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
|
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
Thank you for purchasing this map.<br><br>
|
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">map shop</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;
|
HTML;
|
||||||
} elseif (Lib::is_post() && ! $_POST['buy']) {
|
} elseif (is_post() && ! $_POST['buy']) {
|
||||||
Lib::redirect('/maps');
|
redirect('/maps');
|
||||||
} else {
|
} else {
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
You are buying the <b>{$town['name']}</b> map for {$town['mapprice']} gold. Is that ok?<br><br>
|
You are buying the <b>{$town['name']}</b> map for {$town['mapprice']} gold. Is that ok?<br><br>
|
||||||
@ -379,7 +389,7 @@ class Towns
|
|||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Buying '.$town['name'].' Map');
|
page_title('Buying '.$town['name'].' Map');
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
@ -389,24 +399,24 @@ class Towns
|
|||||||
*/
|
*/
|
||||||
public static function travelto(int $id, bool $use_points = true): string
|
public static function travelto(int $id, bool $use_points = true): string
|
||||||
{
|
{
|
||||||
if (Lib::user()->currentaction == 'Fighting') {
|
if (user()->currentaction == 'Fighting') {
|
||||||
Lib::redirect('/fight');
|
redirect('/fight');
|
||||||
}
|
}
|
||||||
|
|
||||||
$town = Lib::get_town_by_id($id);
|
$town = get_town_by_id($id);
|
||||||
$cost = $use_points ? $town['travelpoints'] : 0;
|
$cost = $use_points ? $town['travelpoints'] : 0;
|
||||||
$mapped = explode(',', Lib::user()->towns);
|
$mapped = explode(',', user()->towns);
|
||||||
$travelled = false;
|
$travelled = false;
|
||||||
|
|
||||||
if ($use_points && ! in_array($id, $mapped)) {
|
if ($use_points && ! in_array($id, $mapped)) {
|
||||||
// trying to teleport to this town when it is not mapped
|
// trying to teleport to this town when it is not mapped
|
||||||
Lib::redirect('/');
|
redirect('/');
|
||||||
} elseif (Lib::user()->currenttp < $cost) {
|
} 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.';
|
$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 ((Lib::user()->latitude == $town['latitude']) && (Lib::user()->longitude == $town['longitude'])) {
|
} elseif ((user()->latitude == $town['latitude']) && (user()->longitude == $town['longitude'])) {
|
||||||
if (! in_array($id, $mapped)) {
|
if (! in_array($id, $mapped)) {
|
||||||
// add town to user's mapped if they travelled here
|
// add town to user's mapped if they travelled here
|
||||||
Lib::user()->towns .= ",$id";
|
user()->towns .= ",$id";
|
||||||
$travelled = true;
|
$travelled = true;
|
||||||
$page = <<<HTML
|
$page = <<<HTML
|
||||||
You have discovered <b>{$town['name']}</b>! It has been added to your mapped towns.<br><br>
|
You have discovered <b>{$town['name']}</b>! It has been added to your mapped towns.<br><br>
|
||||||
@ -416,19 +426,19 @@ class Towns
|
|||||||
$page = 'You are already in this town. <a href="/" hx-get="/" hx-target="#middle">Click here</a> to return.';
|
$page = 'You are already in this town. <a href="/" hx-get="/" hx-target="#middle">Click here</a> to return.';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Lib::user()->latitude = $town['latitude'];
|
user()->latitude = $town['latitude'];
|
||||||
Lib::user()->longitude = $town['longitude'];
|
user()->longitude = $town['longitude'];
|
||||||
Lib::user()->currenttp -= $cost;
|
user()->currenttp -= $cost;
|
||||||
$travelled = true;
|
$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>.';
|
$page = 'You have travelled to <b>'.$town['name'].'</b>. You may now <a href="/" hx-get="/" hx-target="#middle">enter this town</a>.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($travelled) {
|
if ($travelled) {
|
||||||
Lib::user()->currentaction = 'In Town';
|
user()->currentaction = 'In Town';
|
||||||
Lib::user()->save();
|
user()->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
Lib::page_title('Travelling to '.$town['name']);
|
page_title('Travelling to '.$town['name']);
|
||||||
|
|
||||||
return $page;
|
return $page;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ class Auth
|
|||||||
|
|
||||||
public function login(string $username, string $password): bool
|
public function login(string $username, string $password): bool
|
||||||
{
|
{
|
||||||
$user = Lib::get_user($username);
|
$user = get_user($username);
|
||||||
if ($user === false) {
|
if ($user === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
18
src/DragonKnight/DragonKnight.php
Normal file
18
src/DragonKnight/DragonKnight.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is a part of the Dragon-Knight project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024-present Sharkk
|
||||||
|
*
|
||||||
|
* This file is subject to the MIT license that is bundled
|
||||||
|
* with this source code in the LICENSE.md file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace DragonKnight;
|
||||||
|
|
||||||
|
define('VERSION', '1.2.5');
|
||||||
|
define('BUILD', 'Reawaken');
|
||||||
|
define('START', microtime(true));
|
@ -1,731 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is a part of the Dragon-Knight project.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024-present Sharkk
|
|
||||||
*
|
|
||||||
* This file is subject to the MIT license that is bundled
|
|
||||||
* with this source code in the LICENSE.md file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace DragonKnight;
|
|
||||||
|
|
||||||
use DragonKnight\Actions\Explore;
|
|
||||||
use DragonKnight\Actions\Towns;
|
|
||||||
use DragonKnight\Models\User;
|
|
||||||
|
|
||||||
define('VERSION', '1.2.5');
|
|
||||||
define('BUILD', 'Reawaken');
|
|
||||||
define('START', microtime(true));
|
|
||||||
|
|
||||||
class Lib
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return a page for a couple generic actions.
|
|
||||||
*/
|
|
||||||
public static function index(): string
|
|
||||||
{
|
|
||||||
if (self::user()->currentaction === 'In Town') {
|
|
||||||
$page = Towns::town();
|
|
||||||
} elseif (self::user()->currentaction === 'Exploring') {
|
|
||||||
$page = Explore::explore();
|
|
||||||
} elseif (self::user()->currentaction === 'Fighting') {
|
|
||||||
self::redirect('/fight');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $page;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the user their position on the current world map. Only works with a game size of 250 and the default towns 😅.
|
|
||||||
*/
|
|
||||||
public static function show_map()
|
|
||||||
{
|
|
||||||
$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 + Lib::user()->longitude * (500 / 500) - 3),
|
|
||||||
round(258 - Lib::user()->latitude * (500 / 500) - 3)
|
|
||||||
);
|
|
||||||
|
|
||||||
echo Lib::render('layouts/minimal', [
|
|
||||||
'content' => '<img src="/img/map.gif" alt="Map">'.$pos,
|
|
||||||
'title' => 'Map',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show a character's info. Defaults to the currently logged in user.
|
|
||||||
*/
|
|
||||||
public static function show_character_info(int $id = 0): string
|
|
||||||
{
|
|
||||||
$user = $id !== 0 ? User::find($id) : Lib::user();
|
|
||||||
if ($user === false) {
|
|
||||||
exit('Failed to show info for user ID '.$id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$level = Lib::db()->query("SELECT `{$user->charclass}_exp` FROM levels WHERE id=? LIMIT 1;", [$user->level + 1])->fetchArray(SQLITE3_ASSOC);
|
|
||||||
|
|
||||||
$spells = $user->spells();
|
|
||||||
$magic_list = 'None';
|
|
||||||
if (! empty($spells)) {
|
|
||||||
$magic_list = '';
|
|
||||||
foreach ($spells as $spell) {
|
|
||||||
$magic_list .= $spell['name'].'<br>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$showchar = Lib::render('show_char', [
|
|
||||||
'char' => $user,
|
|
||||||
'level' => $level,
|
|
||||||
'magic_list' => $magic_list,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return Lib::render('layouts/minimal', ['content' => $showchar, 'title' => $user->username.' Information']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a POST request to send a new babblebox message.
|
|
||||||
*/
|
|
||||||
public static function babblebox()
|
|
||||||
{
|
|
||||||
if (Lib::is_post()) {
|
|
||||||
$content = trim($_POST['babble']);
|
|
||||||
if (! empty($content)) {
|
|
||||||
Lib::db()->query(
|
|
||||||
'INSERT INTO babble (posttime, author, babble) VALUES (CURRENT_TIMESTAMP, ?, ?);',
|
|
||||||
[Lib::user()->username, $content]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::babblebox_messages();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The handler that is polled by HTMX for new babblebox messages.
|
|
||||||
*/
|
|
||||||
public static function babblebox_messages(): string
|
|
||||||
{
|
|
||||||
if (Lib::user() === false) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = Lib::db()->query('SELECT * FROM babble ORDER BY id ASC LIMIT 40;');
|
|
||||||
$has_chats = false;
|
|
||||||
$messages = '';
|
|
||||||
while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
$has_chats = true;
|
|
||||||
$messages .= '<div class="message">[<b>'.$row['author'].'</b>] '.Lib::make_safe($row['babble']).'</div>';
|
|
||||||
}
|
|
||||||
if (! $has_chats) {
|
|
||||||
$messages = 'There are no messages. :(';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open or get SQLite database connection.
|
|
||||||
*/
|
|
||||||
public static function db(): Database
|
|
||||||
{
|
|
||||||
if (! is_dir($path = getcwd().'/db')) {
|
|
||||||
error_log('Database folder not found at '.$path.'. Please run the installer first.');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
return $GLOBALS['database'] ??= new Database(getcwd().'/db/database.db');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect to a different URL, exit.
|
|
||||||
*/
|
|
||||||
public static function redirect(string $location): void
|
|
||||||
{
|
|
||||||
if (self::is_htmx()) {
|
|
||||||
$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");
|
|
||||||
}
|
|
||||||
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a view with the given data. Can be used redundantly within the template.
|
|
||||||
*/
|
|
||||||
public static function render(string $path_to_base_view, array $data = []): string|false
|
|
||||||
{
|
|
||||||
ob_start();
|
|
||||||
extract($data);
|
|
||||||
require __DIR__."/../templates/$path_to_base_view.php";
|
|
||||||
|
|
||||||
return ob_get_clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace tags with given content.
|
|
||||||
*/
|
|
||||||
public static function parse(string $template, array $array): string
|
|
||||||
{
|
|
||||||
return strtr($template, array_combine(
|
|
||||||
array_map(fn ($key) => "{{{$key}}}", array_keys($array)),
|
|
||||||
array_values($array)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the SQLite3 datetime format (YYYY-MM-DD HH:MM:SS) into something friendlier.
|
|
||||||
*/
|
|
||||||
public static function pretty_date(string $uglydate): string
|
|
||||||
{
|
|
||||||
return date('l, F j, Y', mktime(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
(int) substr($uglydate, 5, 2), // Month
|
|
||||||
(int) substr($uglydate, 8, 2), // Day
|
|
||||||
(int) substr($uglydate, 0, 4) // Year
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use htmlentities with UTF-8 encoding to ensure we're only outputting healthy, safe and effective HTML.
|
|
||||||
*/
|
|
||||||
public static function make_safe(string $content): string
|
|
||||||
{
|
|
||||||
return htmlentities($content, ENT_QUOTES, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finalize admin page and output to browser.
|
|
||||||
*/
|
|
||||||
public static function display_admin($content, $title)
|
|
||||||
{
|
|
||||||
echo self::render('layouts/admin', [
|
|
||||||
'title' => $title,
|
|
||||||
'content' => $content,
|
|
||||||
]);
|
|
||||||
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine what game skin to use. If a user is logged in then it uses their setting, otherwise defaults to 0 (retro).
|
|
||||||
*/
|
|
||||||
public static function game_skin(): int
|
|
||||||
{
|
|
||||||
return self::user() !== false ? self::user()->game_skin : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a town's data by it's coordinates.
|
|
||||||
*/
|
|
||||||
public static function get_town_by_xy(int $x, int $y): array|false
|
|
||||||
{
|
|
||||||
$cache_tag = "town-$x-$y";
|
|
||||||
|
|
||||||
if (! isset($GLOBALS['cache'][$cache_tag])) {
|
|
||||||
$query = self::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];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a town's data by it's ID.
|
|
||||||
*/
|
|
||||||
public static function get_town_by_id(int $id): array|false
|
|
||||||
{
|
|
||||||
$query = self::db()->query('SELECT * FROM towns WHERE id = ? LIMIT 1;', [$id]);
|
|
||||||
if ($query === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->fetchArray(SQLITE3_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a user's data by their ID, username or email.
|
|
||||||
*/
|
|
||||||
public static function get_user(int|string $id, string $data = '*'): array|false
|
|
||||||
{
|
|
||||||
$query = self::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an item by it's ID.
|
|
||||||
*/
|
|
||||||
public static function get_item(int $id): array|false
|
|
||||||
{
|
|
||||||
$query = self::db()->query('SELECT * FROM items WHERE id=? LIMIT 1;', [$id]);
|
|
||||||
if ($query === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->fetchArray(SQLITE3_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a drop by it's ID.
|
|
||||||
*/
|
|
||||||
public static function get_drop(int $id): array|false
|
|
||||||
{
|
|
||||||
$query = self::db()->query('SELECT * FROM drops WHERE id=? LIMIT 1;', [$id]);
|
|
||||||
if ($query === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->fetchArray(SQLITE3_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a spell by it's ID.
|
|
||||||
*/
|
|
||||||
public static function get_spell(int $id): array|false
|
|
||||||
{
|
|
||||||
$query = self::db()->query('SELECT * FROM spells WHERE id=? LIMIT 1;', [$id]);
|
|
||||||
if ($query === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->fetchArray(SQLITE3_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a monster by it's ID.
|
|
||||||
*/
|
|
||||||
public static function get_monster(int $id): array|false
|
|
||||||
{
|
|
||||||
$query = self::db()->query('SELECT * FROM monsters WHERE id=? LIMIT 1;', [$id]);
|
|
||||||
if ($query === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->fetchArray(SQLITE3_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a Specials keyword to it's string.
|
|
||||||
*/
|
|
||||||
public static function special_to_string(string $special): string
|
|
||||||
{
|
|
||||||
return match ($special) {
|
|
||||||
'maxhp' => 'Max HP',
|
|
||||||
'maxmp' => 'Max MP',
|
|
||||||
'maxtp' => 'Max TP',
|
|
||||||
'goldbonus' => 'Gold Bonus (%)',
|
|
||||||
'expbonus' => 'Experience Bonus (%)',
|
|
||||||
'strength' => 'Strength',
|
|
||||||
'dexterity' => 'Dexterity',
|
|
||||||
'attackpower' => 'Attack Power',
|
|
||||||
'defensepower' => 'Defense Power',
|
|
||||||
default => $special
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a pretty dope token.
|
|
||||||
*/
|
|
||||||
public static function token($length = 32): string
|
|
||||||
{
|
|
||||||
return bin2hex(random_bytes($length));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate any given array of data against rules. Returns [valid, data, error]. Data contains the trimmed
|
|
||||||
* values from the input array. Note: all fields with rules are assumed to be required, unless the optional
|
|
||||||
* rule is used.
|
|
||||||
*
|
|
||||||
* Example: ['required', 'no-trim', 'length:5-20', 'alphanum-spaces']
|
|
||||||
*/
|
|
||||||
public static function validate(array $input_data, array $rules): array
|
|
||||||
{
|
|
||||||
$data = [];
|
|
||||||
$errors = [];
|
|
||||||
|
|
||||||
foreach ($rules as $field => $field_rules) {
|
|
||||||
$value = $input_data[$field] ?? null;
|
|
||||||
$field_name = ucfirst(str_replace('_', ' ', $field));
|
|
||||||
$is_required = true;
|
|
||||||
$default_value = null;
|
|
||||||
|
|
||||||
if (in_array('optional', $field_rules)) {
|
|
||||||
$is_required = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($field_rules as $rule) {
|
|
||||||
if (strpos($rule, 'default:') === 0) {
|
|
||||||
$default_value = substr($rule, 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($value === null || $value === '') && $default_value !== null) {
|
|
||||||
$value = $default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($value === null || $value === '') && ! $is_required) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($is_required && ($value === null || $value === '')) {
|
|
||||||
$errors[$field][] = "{$field_name} is required.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! in_array('no-trim', $field_rules)) {
|
|
||||||
$value = trim($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$data[$field] = $value;
|
|
||||||
|
|
||||||
foreach ($field_rules as $rule) {
|
|
||||||
// Parse rule and arguments
|
|
||||||
if (strpos($rule, ':') !== false) {
|
|
||||||
list($rule_name, $rule_args) = explode(':', $rule, 2);
|
|
||||||
} else {
|
|
||||||
$rule_name = $rule;
|
|
||||||
$rule_args = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($rule_name === 'optional') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($rule_name) {
|
|
||||||
case 'bool':
|
|
||||||
if (! isset($input_data[$field]) || empty($value)) {
|
|
||||||
$value = false;
|
|
||||||
} else {
|
|
||||||
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
||||||
|
|
||||||
if ($value === null) {
|
|
||||||
$errors[$field][] = "{$field_name} must be a valid boolean value.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'length':
|
|
||||||
list($min, $max) = explode('-', $rule_args);
|
|
||||||
$len = strlen((string) $value);
|
|
||||||
if ($len < $min || $len > $max) {
|
|
||||||
$errors[$field][] = "{$field_name} must be between {$min} and {$max} characters.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'alphanum':
|
|
||||||
if (! preg_match('/^[a-zA-Z0-9]+$/', $value)) {
|
|
||||||
$errors[$field][] = "{$field_name} must contain only letters and numbers.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'alpha':
|
|
||||||
if (! preg_match('/^[a-zA-Z]+$/', $value)) {
|
|
||||||
$errors[$field][] = "{$field_name} must contain only letters and numbers.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'alphanum-spaces':
|
|
||||||
if (! preg_match('/^[a-zA-Z0-9\s_]+$/', $value)) {
|
|
||||||
$errors[$field][] = "{$field_name} must contain only letters, numbers, spaces, and underscores.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'alpha-spaces':
|
|
||||||
if (! preg_match('/^[a-zA-Z\s_]+$/', $value)) {
|
|
||||||
$errors[$field][] = "{$field_name} must contain only letters, numbers, spaces, and underscores.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'email':
|
|
||||||
if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
||||||
$errors[$field][] = "{$field_name} must be a valid email address.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
if (filter_var($value, FILTER_VALIDATE_INT) === false) {
|
|
||||||
$errors[$field][] = "{$field_name} must be an integer.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'min':
|
|
||||||
if ($value < $rule_args) {
|
|
||||||
$errors[$field][] = "{$field_name} must be at least {$rule_args}.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'max':
|
|
||||||
if ($value > $rule_args) {
|
|
||||||
$errors[$field][] = "{$field_name} must be no more than {$rule_args}.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'regex':
|
|
||||||
if (! preg_match($rule_args, $value)) {
|
|
||||||
$errors[$field][] = "{$field_name} does not match the required pattern.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'in':
|
|
||||||
$options = explode(',', $rule_args);
|
|
||||||
if (! in_array($value, $options)) {
|
|
||||||
$errors[$field][] = "{$field_name} must be one of: ".implode(', ', $options);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'confirm':
|
|
||||||
$field_to_confirm = substr($field, 8);
|
|
||||||
$confirm_value = $data[$field_to_confirm] ?? '';
|
|
||||||
$confirm_field_name = ucfirst(str_replace('_', ' ', $field_to_confirm));
|
|
||||||
if ($value !== $confirm_value) {
|
|
||||||
$errors[$field][] = "{$field_name} must match {$confirm_field_name}.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'unique':
|
|
||||||
list($table, $column) = explode(',', $rule_args, 2);
|
|
||||||
if (self::db()->exists($table, $column, $value)) {
|
|
||||||
$errors[$field][] = "{$field_name} must be unique.";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($input_data as $field => $value) {
|
|
||||||
if (! isset($data[$field])) {
|
|
||||||
$data[$field] = trim($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'valid' => empty($errors),
|
|
||||||
'data' => $data,
|
|
||||||
'errors' => $errors,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a ul list from `validate()`'s errors.
|
|
||||||
*/
|
|
||||||
public static function ul_from_validate_errors(array $errors): string
|
|
||||||
{
|
|
||||||
$string = '<ul>';
|
|
||||||
foreach ($errors as $field => $errors) {
|
|
||||||
$string .= '<li>';
|
|
||||||
foreach ($errors as $error) {
|
|
||||||
$string .= $error;
|
|
||||||
}
|
|
||||||
$string .= '</li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string.'</ul>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the environment variables from the .env file.
|
|
||||||
*/
|
|
||||||
public static function env_load(string $filePath): void
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
public static 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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data on spells from a given list of IDs.
|
|
||||||
*/
|
|
||||||
public static 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 = self::db()->query("SELECT id, name, type FROM spells WHERE id IN($placeholders)", $spell_ids);
|
|
||||||
if ($query === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$rows = [];
|
|
||||||
while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
$rows[] = $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ! empty($rows) ? $rows : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function generate_stat_bar(int $current, int $max): string
|
|
||||||
{
|
|
||||||
$percent = $max > 0 ? round(max(0, $current) / $max * 100, 4) : 0;
|
|
||||||
if ($percent < 0) {
|
|
||||||
$percent = 0;
|
|
||||||
}
|
|
||||||
if ($percent > 100) {
|
|
||||||
$percent = 100;
|
|
||||||
}
|
|
||||||
$color = $percent >= 66 ? 'green' : ($percent >= 33 ? 'yellow' : 'red');
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function create_stat_table(): string
|
|
||||||
{
|
|
||||||
$stat_table = '<div class="stat-table">'.
|
|
||||||
'<div class="stat-row">'.
|
|
||||||
'<div class="stat-col">'.self::generate_stat_bar((int) self::user()->currenthp, (int) self::user()->maxhp).'<div>HP</div></div>'.
|
|
||||||
'<div class="stat-col">'.self::generate_stat_bar((int) self::user()->currentmp, (int) self::user()->maxmp).'<div>MP</div></div>'.
|
|
||||||
'<div class="stat-col">'.self::generate_stat_bar((int) self::user()->currenttp, (int) self::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.
|
|
||||||
*/
|
|
||||||
public static function user(): User|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.
|
|
||||||
*/
|
|
||||||
public static 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';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether the request is POST.
|
|
||||||
*/
|
|
||||||
public static function is_post(): bool
|
|
||||||
{
|
|
||||||
return $_SERVER['REQUEST_METHOD'] === 'POST';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current page title per updates. Optionally set a new title.
|
|
||||||
*/
|
|
||||||
public static function page_title(string $new_title = ''): string
|
|
||||||
{
|
|
||||||
if ($new_title) {
|
|
||||||
return $GLOBALS['state']['new-page-title'] = $new_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $GLOBALS['state']['new-page-title'] ?? self::env('game_name');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the response for the browser based on the request context. The main point is to seperate the handling
|
|
||||||
* of HTMX responses from normal responses.
|
|
||||||
*/
|
|
||||||
public static function render_response(array $uri, string $content): string
|
|
||||||
{
|
|
||||||
if ($uri[0] === 'babblebox') {
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self::is_htmx()) {
|
|
||||||
header('HX-Push-Url: '.$_SERVER['REQUEST_URI']);
|
|
||||||
|
|
||||||
$content .= '<title>'.self::page_title().'</title>';
|
|
||||||
|
|
||||||
$content .= Render::debug_db_info();
|
|
||||||
|
|
||||||
if (self::env('debug', false)) {
|
|
||||||
$content .= Render::debug_query_log();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($GLOBALS['state']['user-state-changed'] ?? false) {
|
|
||||||
$content .= Render::right_nav();
|
|
||||||
$content .= Render::left_nav();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Render::content($content, self::page_layout());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get/set page layout through GLOBALS state.
|
|
||||||
*/
|
|
||||||
public static function page_layout(string $layout = ''): string
|
|
||||||
{
|
|
||||||
if ($layout === '') {
|
|
||||||
return $GLOBALS['state']['page-layout'] ?? 'layouts/primary';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $GLOBALS['state']['page-layout'] = $layout;
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,8 +13,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Models;
|
namespace DragonKnight\Models;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
|
|
||||||
class Model
|
class Model
|
||||||
{
|
{
|
||||||
protected string $table_name = '';
|
protected string $table_name = '';
|
||||||
@ -59,7 +57,7 @@ class Model
|
|||||||
$values[] = $this->id;
|
$values[] = $this->id;
|
||||||
$query = 'UPDATE '.$this->table_name.' SET '.implode(', ', $placeholders).' WHERE id = ?;';
|
$query = 'UPDATE '.$this->table_name.' SET '.implode(', ', $placeholders).' WHERE id = ?;';
|
||||||
|
|
||||||
$result = Lib::db()->query($query, $values);
|
$result = db()->query($query, $values);
|
||||||
|
|
||||||
return $result === false ? false : true;
|
return $result === false ? false : true;
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace DragonKnight\Models;
|
namespace DragonKnight\Models;
|
||||||
|
|
||||||
use DragonKnight\Lib;
|
|
||||||
|
|
||||||
class User extends Model
|
class User extends Model
|
||||||
{
|
{
|
||||||
protected string $table_name = 'users';
|
protected string $table_name = 'users';
|
||||||
@ -24,7 +22,7 @@ class User extends Model
|
|||||||
*/
|
*/
|
||||||
public static function find(int|string $id): User|false
|
public static function find(int|string $id): User|false
|
||||||
{
|
{
|
||||||
$query = Lib::db()->query(
|
$query = db()->query(
|
||||||
'SELECT * FROM users WHERE id=? OR username=? COLLATE NOCASE OR email=? COLLATE NOCASE LIMIT 1;',
|
'SELECT * FROM users WHERE id=? OR username=? COLLATE NOCASE OR email=? COLLATE NOCASE LIMIT 1;',
|
||||||
[$id, $id, $id]
|
[$id, $id, $id]
|
||||||
);
|
);
|
||||||
@ -44,7 +42,7 @@ class User extends Model
|
|||||||
*/
|
*/
|
||||||
public function spells(): array|false
|
public function spells(): array|false
|
||||||
{
|
{
|
||||||
return Lib::get_spells_from_list($this->spells);
|
return get_spells_from_list($this->spells);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,7 +65,7 @@ class User extends Model
|
|||||||
if ($this->onlinetime && strtotime($this->onlinetime) > strtotime('-9 minutes')) {
|
if ($this->onlinetime && strtotime($this->onlinetime) > strtotime('-9 minutes')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Lib::db()->query('UPDATE users SET onlinetime=CURRENT_TIMESTAMP WHERE id=?;', [$this->id]);
|
db()->query('UPDATE users SET onlinetime=CURRENT_TIMESTAMP WHERE id=?;', [$this->id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,7 +103,7 @@ class User extends Model
|
|||||||
$values[] = $this->id;
|
$values[] = $this->id;
|
||||||
$query = 'UPDATE '.$this->table_name.' SET '.implode(', ', $placeholders).' WHERE id = ?;';
|
$query = 'UPDATE '.$this->table_name.' SET '.implode(', ', $placeholders).' WHERE id = ?;';
|
||||||
|
|
||||||
$result = Lib::db()->query($query, $values);
|
$result = db()->query($query, $values);
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -21,37 +21,37 @@ class Render
|
|||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Prepare content for final render. If the request is HTMX-based, will return just the content passed to it. Otherwise
|
* Prepare content for final render. If the request is HTMX-based, will return just the content passed to it. Otherwise
|
||||||
* it will Lib::render() onto $layout with some additional bits.
|
* it will render() onto $layout with some additional bits.
|
||||||
*/
|
*/
|
||||||
public static function content(string $content, string $layout = 'layouts/primary'): string
|
public static function content(string $content, string $layout = 'layouts/primary'): string
|
||||||
{
|
{
|
||||||
if (Lib::is_htmx()) {
|
if (is_htmx()) {
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Lib::render($layout, ['content' => $content]);
|
return render($layout, ['content' => $content]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function debug_db_info(): string
|
public static function debug_db_info(): string
|
||||||
{
|
{
|
||||||
$total_time = round(microtime(true) - START, 4);
|
$total_time = round(microtime(true) - START, 4);
|
||||||
$htmx = Lib::is_htmx() ? ' (htmx)' : '';
|
$htmx = is_htmx() ? ' (htmx)' : '';
|
||||||
|
|
||||||
return '<div id="debug-db-info" hx-swap-oob="true">'.$total_time.' Seconds, '.Lib::db()->count.' Queries'.$htmx.'</div>';
|
return '<div id="debug-db-info" hx-swap-oob="true">'.$total_time.' Seconds, '.db()->count.' Queries'.$htmx.'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function right_nav(): string
|
public static function right_nav(): string
|
||||||
{
|
{
|
||||||
if (Lib::user() === false) {
|
if (user() === false) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flashy numbers if they're low
|
// Flashy numbers if they're low
|
||||||
$hp = (Lib::user()->currenthp <= (Lib::user()->maxhp / 5)) ? '<blink><span class="highlight"><b>*'.Lib::user()->currenthp.'*</b></span></blink>' : Lib::user()->currenthp;
|
$hp = (user()->currenthp <= (user()->maxhp / 5)) ? '<blink><span class="highlight"><b>*'.user()->currenthp.'*</b></span></blink>' : user()->currenthp;
|
||||||
$mp = (Lib::user()->currentmp <= (Lib::user()->maxmp / 5)) ? '<blink><span class="highlight"><b>*'.Lib::user()->currentmp.'*</b></span></blink>' : Lib::user()->currentmp;
|
$mp = (user()->currentmp <= (user()->maxmp / 5)) ? '<blink><span class="highlight"><b>*'.user()->currentmp.'*</b></span></blink>' : user()->currentmp;
|
||||||
|
|
||||||
$template = Lib::render('right_nav', ['hp' => $hp, 'mp' => $mp]);
|
$template = render('right_nav', ['hp' => $hp, 'mp' => $mp]);
|
||||||
if (Lib::is_htmx()) {
|
if (is_htmx()) {
|
||||||
$template = '<section id="right" hx-swap-oob="true">'.$template.'</section>';
|
$template = '<section id="right" hx-swap-oob="true">'.$template.'</section>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,12 +60,12 @@ class Render
|
|||||||
|
|
||||||
public static function left_nav(): string
|
public static function left_nav(): string
|
||||||
{
|
{
|
||||||
if (Lib::user() === false) {
|
if (user() === false) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$template = Lib::render('left_nav');
|
$template = render('left_nav');
|
||||||
if (Lib::is_htmx()) {
|
if (is_htmx()) {
|
||||||
$template = '<section id="left" hx-swap-oob="true">'.$template.'</section>';
|
$template = '<section id="left" hx-swap-oob="true">'.$template.'</section>';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,13 +74,13 @@ class Render
|
|||||||
|
|
||||||
public static function babblebox(): string
|
public static function babblebox(): string
|
||||||
{
|
{
|
||||||
return Lib::render('babblebox', ['messages' => babblebox_messages()]);
|
return render('babblebox', ['messages' => babblebox_messages()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function debug_query_log(): string
|
public static function debug_query_log(): string
|
||||||
{
|
{
|
||||||
$html = '<pre id="debug-query-log" hx-swap-oob="true">';
|
$html = '<pre id="debug-query-log" hx-swap-oob="true">';
|
||||||
foreach (Lib::db()->log as $record) {
|
foreach (db()->log as $record) {
|
||||||
$query_string = str_replace(["\r\n", "\n", "\r"], ' ', $record[0]);
|
$query_string = str_replace(["\r\n", "\n", "\r"], ' ', $record[0]);
|
||||||
$error_string = ! empty($record[2]) ? '// '.$record[2] : '';
|
$error_string = ! empty($record[2]) ? '// '.$record[2] : '';
|
||||||
$html .= '<div>['.round($record[1], 2)."s] {$query_string}{$error_string}</div>";
|
$html .= '<div>['.round($record[1], 2)."s] {$query_string}{$error_string}</div>";
|
||||||
|
724
src/DragonKnight/functions.php
Normal file
724
src/DragonKnight/functions.php
Normal file
@ -0,0 +1,724 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is a part of the Dragon-Knight project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024-present Sharkk
|
||||||
|
*
|
||||||
|
* This file is subject to the MIT license that is bundled
|
||||||
|
* with this source code in the LICENSE.md file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace DragonKnight;
|
||||||
|
|
||||||
|
use DragonKnight\Actions\Explore;
|
||||||
|
use DragonKnight\Actions\Towns;
|
||||||
|
use DragonKnight\Models\User;
|
||||||
|
|
||||||
|
function index(): string|false
|
||||||
|
{
|
||||||
|
$page = false;
|
||||||
|
|
||||||
|
if (user()->currentaction === 'In Town') {
|
||||||
|
$page = Towns::town();
|
||||||
|
} elseif (user()->currentaction === 'Exploring') {
|
||||||
|
$page = Explore::explore();
|
||||||
|
} elseif (user()->currentaction === 'Fighting') {
|
||||||
|
redirect('/fight');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the user their position on the current world map. Only works with a game size of 250 and the default towns 😅.
|
||||||
|
*/
|
||||||
|
function show_map()
|
||||||
|
{
|
||||||
|
$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 + user()->longitude * (500 / 500) - 3),
|
||||||
|
round(258 - user()->latitude * (500 / 500) - 3)
|
||||||
|
);
|
||||||
|
|
||||||
|
echo render('layouts/minimal', [
|
||||||
|
'content' => '<img src="/img/map.gif" alt="Map">'.$pos,
|
||||||
|
'title' => 'Map',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a character's info. Defaults to the currently logged in user.
|
||||||
|
*/
|
||||||
|
function show_character_info(int $id = 0): string
|
||||||
|
{
|
||||||
|
$user = $id !== 0 ? User::find($id) : user();
|
||||||
|
if ($user === false) {
|
||||||
|
exit('Failed to show info for user ID '.$id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$level = db()->query("SELECT `{$user->charclass}_exp` FROM levels WHERE id=? LIMIT 1;", [$user->level + 1])->fetchArray(SQLITE3_ASSOC);
|
||||||
|
|
||||||
|
$spells = $user->spells();
|
||||||
|
$magic_list = 'None';
|
||||||
|
if (! empty($spells)) {
|
||||||
|
$magic_list = '';
|
||||||
|
foreach ($spells as $spell) {
|
||||||
|
$magic_list .= $spell['name'].'<br>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$showchar = render('show_char', [
|
||||||
|
'char' => $user,
|
||||||
|
'level' => $level,
|
||||||
|
'magic_list' => $magic_list,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return render('layouts/minimal', ['content' => $showchar, 'title' => $user->username.' Information']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a POST request to send a new babblebox message.
|
||||||
|
*/
|
||||||
|
function babblebox()
|
||||||
|
{
|
||||||
|
if (is_post()) {
|
||||||
|
$content = trim($_POST['babble']);
|
||||||
|
if (! empty($content)) {
|
||||||
|
db()->query(
|
||||||
|
'INSERT INTO babble (posttime, author, babble) VALUES (CURRENT_TIMESTAMP, ?, ?);',
|
||||||
|
[user()->username, $content]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return babblebox_messages();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The handler that is polled by HTMX for new babblebox messages.
|
||||||
|
*/
|
||||||
|
function babblebox_messages(): string
|
||||||
|
{
|
||||||
|
if (user() === false) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = db()->query('SELECT * FROM babble ORDER BY id ASC LIMIT 40;');
|
||||||
|
$has_chats = false;
|
||||||
|
$messages = '';
|
||||||
|
while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
|
||||||
|
$has_chats = true;
|
||||||
|
$messages .= '<div class="message">[<b>'.$row['author'].'</b>] '.make_safe($row['babble']).'</div>';
|
||||||
|
}
|
||||||
|
if (! $has_chats) {
|
||||||
|
$messages = 'There are no messages. :(';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open or get SQLite database connection.
|
||||||
|
*/
|
||||||
|
function db(): Database
|
||||||
|
{
|
||||||
|
if (! is_dir($path = getcwd().'/db')) {
|
||||||
|
error_log('Database folder not found at '.$path.'. Please run the installer first.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $GLOBALS['database'] ??= new Database(getcwd().'/db/database.db');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to a different URL, exit.
|
||||||
|
*/
|
||||||
|
function redirect(string $location): void
|
||||||
|
{
|
||||||
|
if (is_htmx()) {
|
||||||
|
$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");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 __DIR__."/../templates/$path_to_base_view.php";
|
||||||
|
|
||||||
|
return ob_get_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace tags with given content.
|
||||||
|
*/
|
||||||
|
function parse(string $template, array $array): string
|
||||||
|
{
|
||||||
|
return strtr($template, array_combine(
|
||||||
|
array_map(fn ($key) => "{{{$key}}}", array_keys($array)),
|
||||||
|
array_values($array)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the SQLite3 datetime format (YYYY-MM-DD HH:MM:SS) into something friendlier.
|
||||||
|
*/
|
||||||
|
function pretty_date(string $uglydate): string
|
||||||
|
{
|
||||||
|
return date('l, F j, Y', mktime(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(int) substr($uglydate, 5, 2), // Month
|
||||||
|
(int) substr($uglydate, 8, 2), // Day
|
||||||
|
(int) substr($uglydate, 0, 4) // Year
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use htmlentities with UTF-8 encoding to ensure we're only outputting healthy, safe and effective HTML.
|
||||||
|
*/
|
||||||
|
function make_safe(string $content): string
|
||||||
|
{
|
||||||
|
return htmlentities($content, ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize admin page and output to browser.
|
||||||
|
*/
|
||||||
|
function display_admin($content, $title)
|
||||||
|
{
|
||||||
|
echo render('layouts/admin', [
|
||||||
|
'title' => $title,
|
||||||
|
'content' => $content,
|
||||||
|
]);
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine what game skin to use. If a user is logged in then it uses their setting, otherwise defaults to 0 (retro).
|
||||||
|
*/
|
||||||
|
function game_skin(): int
|
||||||
|
{
|
||||||
|
return user() !== false ? user()->game_skin : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a town's data by it's coordinates.
|
||||||
|
*/
|
||||||
|
function get_town_by_xy(int $x, int $y): array|false
|
||||||
|
{
|
||||||
|
$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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a town's data by it's ID.
|
||||||
|
*/
|
||||||
|
function get_town_by_id(int $id): array|false
|
||||||
|
{
|
||||||
|
$query = db()->query('SELECT * FROM towns WHERE id = ? LIMIT 1;', [$id]);
|
||||||
|
if ($query === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->fetchArray(SQLITE3_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a user's data by their ID, username or email.
|
||||||
|
*/
|
||||||
|
function get_user(int|string $id, string $data = '*'): array|false
|
||||||
|
{
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an item by it's ID.
|
||||||
|
*/
|
||||||
|
function get_item(int $id): array|false
|
||||||
|
{
|
||||||
|
$query = db()->query('SELECT * FROM items WHERE id=? LIMIT 1;', [$id]);
|
||||||
|
if ($query === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->fetchArray(SQLITE3_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a drop by it's ID.
|
||||||
|
*/
|
||||||
|
function get_drop(int $id): array|false
|
||||||
|
{
|
||||||
|
$query = db()->query('SELECT * FROM drops WHERE id=? LIMIT 1;', [$id]);
|
||||||
|
if ($query === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->fetchArray(SQLITE3_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a spell by it's ID.
|
||||||
|
*/
|
||||||
|
function get_spell(int $id): array|false
|
||||||
|
{
|
||||||
|
$query = db()->query('SELECT * FROM spells WHERE id=? LIMIT 1;', [$id]);
|
||||||
|
if ($query === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->fetchArray(SQLITE3_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a monster by it's ID.
|
||||||
|
*/
|
||||||
|
function get_monster(int $id): array|false
|
||||||
|
{
|
||||||
|
$query = db()->query('SELECT * FROM monsters WHERE id=? LIMIT 1;', [$id]);
|
||||||
|
if ($query === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->fetchArray(SQLITE3_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate a Specials keyword to it's string.
|
||||||
|
*/
|
||||||
|
function special_to_string(string $special): string
|
||||||
|
{
|
||||||
|
return match ($special) {
|
||||||
|
'maxhp' => 'Max HP',
|
||||||
|
'maxmp' => 'Max MP',
|
||||||
|
'maxtp' => 'Max TP',
|
||||||
|
'goldbonus' => 'Gold Bonus (%)',
|
||||||
|
'expbonus' => 'Experience Bonus (%)',
|
||||||
|
'strength' => 'Strength',
|
||||||
|
'dexterity' => 'Dexterity',
|
||||||
|
'attackpower' => 'Attack Power',
|
||||||
|
'defensepower' => 'Defense Power',
|
||||||
|
default => $special
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a pretty dope token.
|
||||||
|
*/
|
||||||
|
function token($length = 32): string
|
||||||
|
{
|
||||||
|
return bin2hex(random_bytes($length));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate any given array of data against rules. Returns [valid, data, error]. Data contains the trimmed
|
||||||
|
* values from the input array. Note: all fields with rules are assumed to be required, unless the optional
|
||||||
|
* rule is used.
|
||||||
|
*
|
||||||
|
* Example: ['required', 'no-trim', 'length:5-20', 'alphanum-spaces']
|
||||||
|
*/
|
||||||
|
function validate(array $input_data, array $rules): array
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
foreach ($rules as $field => $field_rules) {
|
||||||
|
$value = $input_data[$field] ?? null;
|
||||||
|
$field_name = ucfirst(str_replace('_', ' ', $field));
|
||||||
|
$is_required = true;
|
||||||
|
$default_value = null;
|
||||||
|
|
||||||
|
if (in_array('optional', $field_rules)) {
|
||||||
|
$is_required = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($field_rules as $rule) {
|
||||||
|
if (strpos($rule, 'default:') === 0) {
|
||||||
|
$default_value = substr($rule, 8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($value === null || $value === '') && $default_value !== null) {
|
||||||
|
$value = $default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($value === null || $value === '') && ! $is_required) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_required && ($value === null || $value === '')) {
|
||||||
|
$errors[$field][] = "{$field_name} is required.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! in_array('no-trim', $field_rules)) {
|
||||||
|
$value = trim($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[$field] = $value;
|
||||||
|
|
||||||
|
foreach ($field_rules as $rule) {
|
||||||
|
// Parse rule and arguments
|
||||||
|
if (strpos($rule, ':') !== false) {
|
||||||
|
list($rule_name, $rule_args) = explode(':', $rule, 2);
|
||||||
|
} else {
|
||||||
|
$rule_name = $rule;
|
||||||
|
$rule_args = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rule_name === 'optional') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($rule_name) {
|
||||||
|
case 'bool':
|
||||||
|
if (! isset($input_data[$field]) || empty($value)) {
|
||||||
|
$value = false;
|
||||||
|
} else {
|
||||||
|
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
|
||||||
|
if ($value === null) {
|
||||||
|
$errors[$field][] = "{$field_name} must be a valid boolean value.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'length':
|
||||||
|
list($min, $max) = explode('-', $rule_args);
|
||||||
|
$len = strlen((string) $value);
|
||||||
|
if ($len < $min || $len > $max) {
|
||||||
|
$errors[$field][] = "{$field_name} must be between {$min} and {$max} characters.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'alphanum':
|
||||||
|
if (! preg_match('/^[a-zA-Z0-9]+$/', $value)) {
|
||||||
|
$errors[$field][] = "{$field_name} must contain only letters and numbers.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'alpha':
|
||||||
|
if (! preg_match('/^[a-zA-Z]+$/', $value)) {
|
||||||
|
$errors[$field][] = "{$field_name} must contain only letters and numbers.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'alphanum-spaces':
|
||||||
|
if (! preg_match('/^[a-zA-Z0-9\s_]+$/', $value)) {
|
||||||
|
$errors[$field][] = "{$field_name} must contain only letters, numbers, spaces, and underscores.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'alpha-spaces':
|
||||||
|
if (! preg_match('/^[a-zA-Z\s_]+$/', $value)) {
|
||||||
|
$errors[$field][] = "{$field_name} must contain only letters, numbers, spaces, and underscores.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'email':
|
||||||
|
if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$errors[$field][] = "{$field_name} must be a valid email address.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'int':
|
||||||
|
if (filter_var($value, FILTER_VALIDATE_INT) === false) {
|
||||||
|
$errors[$field][] = "{$field_name} must be an integer.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'min':
|
||||||
|
if ($value < $rule_args) {
|
||||||
|
$errors[$field][] = "{$field_name} must be at least {$rule_args}.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'max':
|
||||||
|
if ($value > $rule_args) {
|
||||||
|
$errors[$field][] = "{$field_name} must be no more than {$rule_args}.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'regex':
|
||||||
|
if (! preg_match($rule_args, $value)) {
|
||||||
|
$errors[$field][] = "{$field_name} does not match the required pattern.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'in':
|
||||||
|
$options = explode(',', $rule_args);
|
||||||
|
if (! in_array($value, $options)) {
|
||||||
|
$errors[$field][] = "{$field_name} must be one of: ".implode(', ', $options);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'confirm':
|
||||||
|
$field_to_confirm = substr($field, 8);
|
||||||
|
$confirm_value = $data[$field_to_confirm] ?? '';
|
||||||
|
$confirm_field_name = ucfirst(str_replace('_', ' ', $field_to_confirm));
|
||||||
|
if ($value !== $confirm_value) {
|
||||||
|
$errors[$field][] = "{$field_name} must match {$confirm_field_name}.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'unique':
|
||||||
|
list($table, $column) = explode(',', $rule_args, 2);
|
||||||
|
if (db()->exists($table, $column, $value)) {
|
||||||
|
$errors[$field][] = "{$field_name} must be unique.";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($input_data as $field => $value) {
|
||||||
|
if (! isset($data[$field])) {
|
||||||
|
$data[$field] = trim($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'valid' => empty($errors),
|
||||||
|
'data' => $data,
|
||||||
|
'errors' => $errors,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a ul list from `validate()`'s errors.
|
||||||
|
*/
|
||||||
|
function ul_from_validate_errors(array $errors): string
|
||||||
|
{
|
||||||
|
$string = '<ul>';
|
||||||
|
foreach ($errors as $field => $errors) {
|
||||||
|
$string .= '<li>';
|
||||||
|
foreach ($errors as $error) {
|
||||||
|
$string .= $error;
|
||||||
|
}
|
||||||
|
$string .= '</li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string.'</ul>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the environment variables from the .env file.
|
||||||
|
*/
|
||||||
|
function env_load(string $filePath): void
|
||||||
|
{
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the data on spells from a given list of IDs.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
$rows = [];
|
||||||
|
while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ! empty($rows) ? $rows : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generate_stat_bar(int $current, int $max): string
|
||||||
|
{
|
||||||
|
$percent = $max > 0 ? round(max(0, $current) / $max * 100, 4) : 0;
|
||||||
|
if ($percent < 0) {
|
||||||
|
$percent = 0;
|
||||||
|
}
|
||||||
|
if ($percent > 100) {
|
||||||
|
$percent = 100;
|
||||||
|
}
|
||||||
|
$color = $percent >= 66 ? 'green' : ($percent >= 33 ? 'yellow' : 'red');
|
||||||
|
|
||||||
|
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(): string
|
||||||
|
{
|
||||||
|
$stat_table = '<div class="stat-table">'.
|
||||||
|
'<div class="stat-row">'.
|
||||||
|
'<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>';
|
||||||
|
|
||||||
|
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'] ??= (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';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the request is POST.
|
||||||
|
*/
|
||||||
|
function is_post(): bool
|
||||||
|
{
|
||||||
|
return $_SERVER['REQUEST_METHOD'] === 'POST';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current page title per updates. Optionally set a new title.
|
||||||
|
*/
|
||||||
|
function page_title(string $new_title = ''): string
|
||||||
|
{
|
||||||
|
if ($new_title) {
|
||||||
|
return $GLOBALS['state']['new-page-title'] = $new_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $GLOBALS['state']['new-page-title'] ?? env('game_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the response for the browser based on the request context. The main point is to seperate the handling
|
||||||
|
* of HTMX responses from normal responses.
|
||||||
|
*/
|
||||||
|
function render_response(array $uri, string $content): string
|
||||||
|
{
|
||||||
|
if ($uri[0] === 'babblebox') {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_htmx()) {
|
||||||
|
header('HX-Push-Url: '.$_SERVER['REQUEST_URI']);
|
||||||
|
|
||||||
|
$content .= '<title>'.page_title().'</title>';
|
||||||
|
|
||||||
|
$content .= Render::debug_db_info();
|
||||||
|
|
||||||
|
if (env('debug', false)) {
|
||||||
|
$content .= Render::debug_query_log();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($GLOBALS['state']['user-state-changed'] ?? false) {
|
||||||
|
$content .= Render::right_nav();
|
||||||
|
$content .= Render::left_nav();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Render::content($content, page_layout());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get/set page layout through GLOBALS state.
|
||||||
|
*/
|
||||||
|
function page_layout(string $layout = ''): string
|
||||||
|
{
|
||||||
|
if ($layout === '') {
|
||||||
|
return $GLOBALS['state']['page-layout'] ?? 'layouts/primary';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $GLOBALS['state']['page-layout'] = $layout;
|
||||||
|
}
|
@ -15,7 +15,7 @@ Experience values for each level should be the cumulative total amount of experi
|
|||||||
<tr><td colspan="2"></td></tr>
|
<tr><td colspan="2"></td></tr>
|
||||||
|
|
||||||
<?php foreach ([1, 2, 3] as $n): ?>
|
<?php foreach ([1, 2, 3] as $n): ?>
|
||||||
<?php $class_name = DragonKnight\Lib::env("class_{$n}_name"); ?>
|
<?php $class_name = DragonKnight\env("class_{$n}_name"); ?>
|
||||||
<tr><td><?php echo $class_name ?> EXP</td> <td><input type="number" name="<?php echo $n ?>_exp" value="<?php echo $level["{$n}_exp"] ?>"></td></tr>
|
<tr><td><?php echo $class_name ?> EXP</td> <td><input type="number" name="<?php echo $n ?>_exp" value="<?php echo $level["{$n}_exp"] ?>"></td></tr>
|
||||||
<tr><td><?php echo $class_name ?> HP</td> <td><input type="number" name="<?php echo $n ?>_hp" value="<?php echo $level["{$n}_hp"] ?>"></td></tr>
|
<tr><td><?php echo $class_name ?> HP</td> <td><input type="number" name="<?php echo $n ?>_hp" value="<?php echo $level["{$n}_hp"] ?>"></td></tr>
|
||||||
<tr><td><?php echo $class_name ?> MP</td> <td><input type="number" name="<?php echo $n ?>_mp" value="<?php echo $level["{$n}_mp"] ?>"></td></tr>
|
<tr><td><?php echo $class_name ?> MP</td> <td><input type="number" name="<?php echo $n ?>_mp" value="<?php echo $level["{$n}_mp"] ?>"></td></tr>
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
<tr><td>Longitude</td><td><input type="number" name="longitude" value="<?php echo $user['longitude'] ?>" /></td></tr>
|
<tr><td>Longitude</td><td><input type="number" name="longitude" value="<?php echo $user['longitude'] ?>" /></td></tr>
|
||||||
<tr><td>Character Class</td><td>
|
<tr><td>Character Class</td><td>
|
||||||
<select name="charclass">
|
<select name="charclass">
|
||||||
<option value="1" <?php echo $user['charclass'] == 1 ? 'selected' : '' ?>><?php echo DragonKnight\Lib::env('class_1_name') ?></option>
|
<option value="1" <?php echo $user['charclass'] == 1 ? 'selected' : '' ?>><?php echo DragonKnight\env('class_1_name') ?></option>
|
||||||
<option value="2" <?php echo $user['charclass'] == 2 ? 'selected' : '' ?>><?php echo DragonKnight\Lib::env('class_2_name') ?></option>
|
<option value="2" <?php echo $user['charclass'] == 2 ? 'selected' : '' ?>><?php echo DragonKnight\env('class_2_name') ?></option>
|
||||||
<option value="3" <?php echo $user['charclass'] == 3 ? 'selected' : '' ?>><?php echo DragonKnight\Lib::env('class_3_name') ?></option>
|
<option value="3" <?php echo $user['charclass'] == 3 ? 'selected' : '' ?>><?php echo DragonKnight\env('class_3_name') ?></option>
|
||||||
</select>
|
</select>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
<td width="20%"><span class="highlight">Game Open:</span></td>
|
<td width="20%"><span class="highlight">Game Open:</span></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="gameopen">
|
<select name="gameopen">
|
||||||
<option value="1" <?php echo DragonKnight\Lib::env('game_open') ? 'selected' : '' ?>>Open</option>
|
<option value="1" <?php echo DragonKnight\env('game_open') ? 'selected' : '' ?>>Open</option>
|
||||||
<option value="0" <?php echo ! DragonKnight\Lib::env('game_open') ? 'selected' : '' ?>>Closed</option>
|
<option value="0" <?php echo ! DragonKnight\env('game_open') ? 'selected' : '' ?>>Closed</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<span class="small">Close the game if you are upgrading or working on settings and don't want to
|
<span class="small">Close the game if you are upgrading or working on settings and don't want to
|
||||||
cause odd errors for end-users. Closing the game will completely halt all activity.</span>
|
cause odd errors for end-users. Closing the game will completely halt all activity.</span>
|
||||||
@ -18,14 +18,14 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Game Name:</td>
|
<td width="20%">Game Name:</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="gamename" value="<?php echo DragonKnight\Lib::env('game_name') ?>"><br>
|
<input type="text" name="gamename" value="<?php echo DragonKnight\env('game_name') ?>"><br>
|
||||||
<span class="small">Change this if you want to change to call your game something different.</span>
|
<span class="small">Change this if you want to change to call your game something different.</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Game URL:</td>
|
<td width="20%">Game URL:</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="gameurl" value="<?php echo DragonKnight\Lib::env('game_url') ?>"><br>
|
<input type="text" name="gameurl" value="<?php echo DragonKnight\env('game_url') ?>"><br>
|
||||||
<span class="small">Please specify the full URL to your game installation
|
<span class="small">Please specify the full URL to your game installation
|
||||||
("https://www.dragonknight.com/"). This gets used in the registration email sent to users. If
|
("https://www.dragonknight.com/"). This gets used in the registration email sent to users. If
|
||||||
you leave this field blank or incorrect, users may not be able to register correctly.</span>
|
you leave this field blank or incorrect, users may not be able to register correctly.</span>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Admin Email:</td>
|
<td width="20%">Admin Email:</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="adminemail" value="<?php echo DragonKnight\Lib::env('admin_email') ?>"><br>
|
<input type="text" name="adminemail" value="<?php echo DragonKnight\env('admin_email') ?>"><br>
|
||||||
<span class="small">Please specify your email address. This gets used when the game has to send an
|
<span class="small">Please specify your email address. This gets used when the game has to send an
|
||||||
email to users.</span>
|
email to users.</span>
|
||||||
</td>
|
</td>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Map Size:</td>
|
<td width="20%">Map Size:</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="number" name="gamesize" value="<?php echo DragonKnight\Lib::env('game_size') ?>"><br>
|
<input type="number" name="gamesize" value="<?php echo DragonKnight\env('game_size') ?>"><br>
|
||||||
<span class="small">
|
<span class="small">
|
||||||
Default is 250. This is the size of each map quadrant. Note that monster
|
Default is 250. This is the size of each map quadrant. Note that monster
|
||||||
levels increase every 5 spaces, so you should ensure that you have at least (map size / 5)
|
levels increase every 5 spaces, so you should ensure that you have at least (map size / 5)
|
||||||
@ -55,8 +55,8 @@
|
|||||||
<td width="20%">Email Verification:</td>
|
<td width="20%">Email Verification:</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="verifyemail">
|
<select name="verifyemail">
|
||||||
<option value="0" <?php echo ! DragonKnight\Lib::env('verify_email') ? 'selected' : '' ?>>Disabled</option>
|
<option value="0" <?php echo ! DragonKnight\env('verify_email') ? 'selected' : '' ?>>Disabled</option>
|
||||||
<option value="1" <?php echo DragonKnight\Lib::env('verify_email') ? 'selected' : '' ?>>Enabled</option>
|
<option value="1" <?php echo DragonKnight\env('verify_email') ? 'selected' : '' ?>>Enabled</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<span class="small">Make users verify their email address for added security.</span>
|
<span class="small">Make users verify their email address for added security.</span>
|
||||||
</td>
|
</td>
|
||||||
@ -65,8 +65,8 @@
|
|||||||
<td width="20%">Show News:</td>
|
<td width="20%">Show News:</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="shownews">
|
<select name="shownews">
|
||||||
<option value="0" <?php echo ! DragonKnight\Lib::env('show_news') ? 'selected' : '' ?>>No</option>
|
<option value="0" <?php echo ! DragonKnight\env('show_news') ? 'selected' : '' ?>>No</option>
|
||||||
<option value="1" <?php echo DragonKnight\Lib::env('show_news') ? 'selected' : '' ?>>Yes</option>
|
<option value="1" <?php echo DragonKnight\env('show_news') ? 'selected' : '' ?>>Yes</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<span class="small">Toggle display of the Latest News box in towns.
|
<span class="small">Toggle display of the Latest News box in towns.
|
||||||
</td>
|
</td>
|
||||||
@ -75,8 +75,8 @@
|
|||||||
<td width="20%">Show Who's Online:</td>
|
<td width="20%">Show Who's Online:</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="showonline">
|
<select name="showonline">
|
||||||
<option value="0" <?php echo ! DragonKnight\Lib::env('show_online') ? 'selected' : '' ?>>No</option>
|
<option value="0" <?php echo ! DragonKnight\env('show_online') ? 'selected' : '' ?>>No</option>
|
||||||
<option value="1" <?php echo DragonKnight\Lib::env('show_online') ? 'selected' : '' ?>>Yes</option>
|
<option value="1" <?php echo DragonKnight\env('show_online') ? 'selected' : '' ?>>Yes</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<span class="small">Toggle display of the Who's Online box in towns.</span>
|
<span class="small">Toggle display of the Who's Online box in towns.</span>
|
||||||
</td>
|
</td>
|
||||||
@ -85,23 +85,23 @@
|
|||||||
<td width="20%">Show Babblebox:</td>
|
<td width="20%">Show Babblebox:</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="showbabble">
|
<select name="showbabble">
|
||||||
<option value="0" <?php echo ! DragonKnight\Lib::env('show_babble') ? 'selected' : '' ?>>No</option>
|
<option value="0" <?php echo ! DragonKnight\env('show_babble') ? 'selected' : '' ?>>No</option>
|
||||||
<option value="1" <?php echo DragonKnight\Lib::env('show_babble') ? 'selected' : '' ?>>Yes</option>
|
<option value="1" <?php echo DragonKnight\env('show_babble') ? 'selected' : '' ?>>Yes</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
<span class="small">Toggle display of the Babble Box in towns.</span>
|
<span class="small">Toggle display of the Babble Box in towns.</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Class 1 Name:</td>
|
<td width="20%">Class 1 Name:</td>
|
||||||
<td><input type="text" name="class1name" value="<?php echo DragonKnight\Lib::env('class_1_name') ?>"><br></td>
|
<td><input type="text" name="class1name" value="<?php echo DragonKnight\env('class_1_name') ?>"><br></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Class 2 Name:</td>
|
<td width="20%">Class 2 Name:</td>
|
||||||
<td><input type="text" name="class2name" value="<?php echo DragonKnight\Lib::env('class_2_name') ?>"><br></td>
|
<td><input type="text" name="class2name" value="<?php echo DragonKnight\env('class_2_name') ?>"><br></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="20%">Class 3 Name:</td>
|
<td width="20%">Class 3 Name:</td>
|
||||||
<td><input type="text" name="class3name" value="<?php echo DragonKnight\Lib::env('class_3_name') ?>"><br></td>
|
<td><input type="text" name="class3name" value="<?php echo DragonKnight\env('class_3_name') ?>"><br></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title><?php echo DragonKnight\Lib::page_title() ?></title>
|
<title><?php echo DragonKnight\page_title() ?></title>
|
||||||
<link rel="stylesheet" href="/css/admin.css">
|
<link rel="stylesheet" href="/css/admin.css">
|
||||||
<script src="/js/htmx.js"></script>
|
<script src="/js/htmx.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="admin-container">
|
<div id="admin-container">
|
||||||
<header>
|
<header>
|
||||||
<h1><?php echo DragonKnight\Lib::env('game_name') ?></h1>
|
<h1><?php echo DragonKnight\env('game_name') ?></h1>
|
||||||
<h3>Admin</h3>
|
<h3>Admin</h3>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<div>Version <?php echo VERSION ?> <?php echo BUILD ?></div>
|
<div>Version <?php echo VERSION ?> <?php echo BUILD ?></div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<?php if (DragonKnight\Lib::env('debug', false)) {
|
<?php if (DragonKnight\env('debug', false)) {
|
||||||
echo DragonKnight\Render::debug_query_log();
|
echo DragonKnight\Render::debug_query_log();
|
||||||
} ?>
|
} ?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title><?php echo DragonKnight\Lib::env('game_name', 'Dragon Knight') ?> Help</title>
|
<title><?php echo DragonKnight\env('game_name', 'Dragon Knight') ?> Help</title>
|
||||||
<link rel="stylesheet" href="/css/help.css">
|
<link rel="stylesheet" href="/css/help.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<a name="top"></a>
|
<a name="top"></a>
|
||||||
<h1><?php echo DragonKnight\Lib::env('game_name', 'Dragon Knight') ?> Help</h1>
|
<h1><?php echo DragonKnight\env('game_name', 'Dragon Knight') ?> Help</h1>
|
||||||
[ <a href="/help">Back to Help</a> ]<br>
|
[ <a href="/help">Back to Help</a> ]<br>
|
||||||
[ <a href="/">Return to Game</a> ]
|
[ <a href="/">Return to Game</a> ]
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title><?php echo DragonKnight\Lib::page_title() ?></title>
|
<title><?php echo DragonKnight\page_title() ?></title>
|
||||||
<link rel="stylesheet" href="/css/dk.css">
|
<link rel="stylesheet" href="/css/dk.css">
|
||||||
<script src="/js/htmx.js"></script>
|
<script src="/js/htmx.js"></script>
|
||||||
|
|
||||||
@ -20,12 +20,12 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="skin-<?php echo DragonKnight\Lib::game_skin() ?>">
|
<body class="skin-<?php echo DragonKnight\game_skin() ?>">
|
||||||
<div id="game-container">
|
<div id="game-container">
|
||||||
<header>
|
<header>
|
||||||
<a href="/"><img id="logo" src="/img/logo.gif" alt="<?php echo DragonKnight\Lib::env('game_name', 'Dragon Knight') ?>" title="<?php echo DragonKnight\Lib::env('game_name', 'Dragon Knight') ?>"></a>
|
<a href="/"><img id="logo" src="/img/logo.gif" alt="<?php echo DragonKnight\env('game_name', 'Dragon Knight') ?>" title="<?php echo DragonKnight\env('game_name', 'Dragon Knight') ?>"></a>
|
||||||
<nav>
|
<nav>
|
||||||
<?php if (DragonKnight\Lib::user() !== false): ?>
|
<?php if (DragonKnight\user() !== false): ?>
|
||||||
<a href='/logout'><img src='/img/button_logout.gif' alt='Log Out' title='Log Out'></a>
|
<a href='/logout'><img src='/img/button_logout.gif' alt='Log Out' title='Log Out'></a>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href='/login'><img src='/img/button_login.gif' alt='Log In' title='Log In'></a>
|
<a href='/login'><img src='/img/button_login.gif' alt='Log In' title='Log In'></a>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<div>Version <?php echo VERSION ?> <?php echo BUILD ?></div>
|
<div>Version <?php echo VERSION ?> <?php echo BUILD ?></div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<?php if (DragonKnight\Lib::env('debug', false)) {
|
<?php if (DragonKnight\env('debug', false)) {
|
||||||
echo DragonKnight\Render::debug_query_log();
|
echo DragonKnight\Render::debug_query_log();
|
||||||
} ?>
|
} ?>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<section>
|
<section>
|
||||||
<div class="title"><img src="/img/button_location.gif" alt="Location" title="Location"></div>
|
<div class="title"><img src="/img/button_location.gif" alt="Location" title="Location"></div>
|
||||||
Currently: <?php echo DragonKnight\Lib::user()->currentaction ?><br>
|
Currently: <?php echo DragonKnight\user()->currentaction ?><br>
|
||||||
<?php
|
<?php
|
||||||
$lat = DragonKnight\Lib::user()->latitude;
|
$lat = DragonKnight\user()->latitude;
|
||||||
$lon = DragonKnight\Lib::user()->longitude;
|
$lon = DragonKnight\user()->longitude;
|
||||||
if ($lat < 0) {
|
if ($lat < 0) {
|
||||||
$lat = ($lat * -1).'S';
|
$lat = ($lat * -1).'S';
|
||||||
} else {
|
} else {
|
||||||
@ -31,15 +31,15 @@
|
|||||||
<section>
|
<section>
|
||||||
<div class="title"><img src="/img/button_towns.gif" alt="Towns" title="Towns"></div>
|
<div class="title"><img src="/img/button_towns.gif" alt="Towns" title="Towns"></div>
|
||||||
<?php
|
<?php
|
||||||
if (DragonKnight\Lib::user()->currentaction == 'In Town') {
|
if (DragonKnight\user()->currentaction == 'In Town') {
|
||||||
$town = DragonKnight\Lib::get_town_by_xy((int) DragonKnight\Lib::user()->latitude, (int) DragonKnight\Lib::user()->longitude);
|
$town = DragonKnight\get_town_by_xy((int) DragonKnight\user()->latitude, (int) DragonKnight\user()->longitude);
|
||||||
echo "Welcome to <b>{$town['name']}</b>.<br><br>";
|
echo "Welcome to <b>{$town['name']}</b>.<br><br>";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
Travel To:<br>
|
Travel To:<br>
|
||||||
<?php
|
<?php
|
||||||
$town_list = explode(',', DragonKnight\Lib::user()->towns);
|
$town_list = explode(',', DragonKnight\user()->towns);
|
||||||
$towns = DragonKnight\Lib::db()->query('SELECT * FROM towns ORDER BY id;');
|
$towns = DragonKnight\db()->query('SELECT * FROM towns ORDER BY id;');
|
||||||
$mapped = false;
|
$mapped = false;
|
||||||
while ($row = $towns->fetchArray(SQLITE3_ASSOC)) {
|
while ($row = $towns->fetchArray(SQLITE3_ASSOC)) {
|
||||||
$mapped = true;
|
$mapped = true;
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<a href="/" hx-get="/" hx-target="#middle">Home</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="/forum" hx-get="/forum" hx-target="#middle">Forum</a><br>
|
||||||
<a href="/settings">Settings</a><br>
|
<a href="/settings">Settings</a><br>
|
||||||
<?php if (DragonKnight\Lib::user()->authlevel === 1): ?>
|
<?php if (DragonKnight\user()->authlevel === 1): ?>
|
||||||
<a href="/admin">Admin</a><br>
|
<a href="/admin">Admin</a><br>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<a href="/help">Help</a><br>
|
<a href="/help">Help</a><br>
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<td>Character Class:</td>
|
<td>Character Class:</td>
|
||||||
<td>
|
<td>
|
||||||
<select name="charclass">
|
<select name="charclass">
|
||||||
<option value="1"><?php echo DragonKnight\Lib::env('class_1_name') ?></option>
|
<option value="1"><?php echo DragonKnight\env('class_1_name') ?></option>
|
||||||
<option value="2"><?php echo DragonKnight\Lib::env('class_2_name') ?></option>
|
<option value="2"><?php echo DragonKnight\env('class_2_name') ?></option>
|
||||||
<option value="3"><?php echo DragonKnight\Lib::env('class_3_name') ?></option>
|
<option value="3"><?php echo DragonKnight\env('class_3_name') ?></option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
<section>
|
<section>
|
||||||
<div class="title"><img src="/img/button_character.gif" alt="Character" title="Character"></div>
|
<div class="title"><img src="/img/button_character.gif" alt="Character" title="Character"></div>
|
||||||
<b><?php echo DragonKnight\Lib::user()->username ?></b><br>
|
<b><?php echo DragonKnight\user()->username ?></b><br>
|
||||||
Level: <?php echo DragonKnight\Lib::user()->level ?><br>
|
Level: <?php echo DragonKnight\user()->level ?><br>
|
||||||
Exp: <?php echo number_format(DragonKnight\Lib::user()->experience) ?><br>
|
Exp: <?php echo number_format(DragonKnight\user()->experience) ?><br>
|
||||||
Gold: <?php echo number_format(DragonKnight\Lib::user()->gold) ?><br>
|
Gold: <?php echo number_format(DragonKnight\user()->gold) ?><br>
|
||||||
HP: <?php echo $hp ?><br>
|
HP: <?php echo $hp ?><br>
|
||||||
MP: <?php echo $mp ?><br>
|
MP: <?php echo $mp ?><br>
|
||||||
TP: <?php echo DragonKnight\Lib::user()->currenttp ?><br><br>
|
TP: <?php echo DragonKnight\user()->currenttp ?><br><br>
|
||||||
<?php echo DragonKnight\Lib::create_stat_table() ?><br>
|
<?php echo DragonKnight\create_stat_table() ?><br>
|
||||||
<a href="javascript:opencharpopup()">Extended Stats</a>
|
<a href="javascript:opencharpopup()">Extended Stats</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="title"><img src="/img/button_inventory.gif" alt="Inventory" title="Inventory"></div>
|
<div class="title"><img src="/img/button_inventory.gif" alt="Inventory" title="Inventory"></div>
|
||||||
<img src="/img/icon_weapon.gif" alt="Weapon" title="Weapon"> <?php echo DragonKnight\Lib::user()->weaponname ?><br>
|
<img src="/img/icon_weapon.gif" alt="Weapon" title="Weapon"> <?php echo DragonKnight\user()->weaponname ?><br>
|
||||||
<img src="/img/icon_armor.gif" alt="Armor" title="Armor"> <?php echo DragonKnight\Lib::user()->armorname ?><br>
|
<img src="/img/icon_armor.gif" alt="Armor" title="Armor"> <?php echo DragonKnight\user()->armorname ?><br>
|
||||||
<img src="/img/icon_shield.gif" alt="Shield" title="Shield"> <?php echo DragonKnight\Lib::user()->shieldname ?><br>
|
<img src="/img/icon_shield.gif" alt="Shield" title="Shield"> <?php echo DragonKnight\user()->shieldname ?><br>
|
||||||
Slot 1: <?php echo DragonKnight\Lib::user()->slot1name ?><br>
|
Slot 1: <?php echo DragonKnight\user()->slot1name ?><br>
|
||||||
Slot 2: <?php echo DragonKnight\Lib::user()->slot2name ?><br>
|
Slot 2: <?php echo DragonKnight\user()->slot2name ?><br>
|
||||||
Slot 3: <?php echo DragonKnight\Lib::user()->slot3name ?>
|
Slot 3: <?php echo DragonKnight\user()->slot3name ?>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<div class="title"><img src="/img/button_fastspells.gif" alt="Fast Spells" title="Fast Spells"></div>
|
<div class="title"><img src="/img/button_fastspells.gif" alt="Fast Spells" title="Fast Spells"></div>
|
||||||
<?php
|
<?php
|
||||||
$user_spells = DragonKnight\Lib::user()->spells();
|
$user_spells = DragonKnight\user()->spells();
|
||||||
if ($user_spells !== false) {
|
if ($user_spells !== false) {
|
||||||
foreach ($user_spells as $spell) {
|
foreach ($user_spells as $spell) {
|
||||||
// list only healing spells for now
|
// list only healing spells for now
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
<b><?php echo $char->username ?></b><br><br>
|
<b><?php echo $char->username ?></b><br><br>
|
||||||
|
|
||||||
Class: <?php echo match ($char->charclass) {
|
Class: <?php echo match ($char->charclass) {
|
||||||
1 => DragonKnight\Lib::env('class_1_name'),
|
1 => DragonKnight\env('class_1_name'),
|
||||||
2 => DragonKnight\Lib::env('class_2_name'),
|
2 => DragonKnight\env('class_2_name'),
|
||||||
3 => DragonKnight\Lib::env('class_3_name')
|
3 => DragonKnight\env('class_3_name')
|
||||||
}; ?><br><br>
|
}; ?><br><br>
|
||||||
|
|
||||||
Level: <?php echo $char->level ?><br>
|
Level: <?php echo $char->level ?><br>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user