ava borders, controllers, item boxes
|
@ -276,6 +276,7 @@ span.badge {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
|
position: absolute;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
color: white;
|
color: white;
|
||||||
border: 1px solid #666;
|
border: 1px solid #666;
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
section.profile {
|
section.profile {
|
||||||
header {
|
header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 3rem;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
color: rgba(0, 0, 0, 0.3);
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h5 {
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +21,7 @@ section.profile {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
|
||||||
& > div:not(:last-child) {
|
& > div:not(:last-child) {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +30,17 @@ section.profile {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: 250px;
|
height: 185px;
|
||||||
|
width: 185px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border {
|
||||||
|
width: 250px;
|
||||||
|
height: 250px;
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,4 +75,58 @@ section.profile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#equipped-gear {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
div.item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&.i-1x1 {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background-image: url('/assets/img/ui/1x1.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.i-2x2 {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background-image: url('/assets/img/ui/2x2.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.i-2x3 {
|
||||||
|
width: 60px;
|
||||||
|
height: 90px;
|
||||||
|
background-image: url('/assets/img/ui/2x3.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 60px;
|
||||||
|
|
||||||
|
&.top, &.bot {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mid {
|
||||||
|
width: 60px;
|
||||||
|
height: 90px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
public/assets/img/ui/1x1.png
Normal file
After Width: | Height: | Size: 155 B |
BIN
public/assets/img/ui/2x2.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
public/assets/img/ui/2x3.png
Normal file
After Width: | Height: | Size: 186 B |
BIN
public/assets/img/ui/borders/alchemist.webp
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
public/assets/img/ui/borders/divine.webp
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
public/assets/img/ui/borders/dragon_slaying.webp
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
public/assets/img/ui/borders/dwarven_smiths.webp
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
public/assets/img/ui/borders/earth.webp
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
public/assets/img/ui/borders/egyptian.webp
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
public/assets/img/ui/borders/elven_archer.webp
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
public/assets/img/ui/borders/fire.webp
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
public/assets/img/ui/borders/gladiator.webp
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
public/assets/img/ui/borders/gold_mine.webp
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
public/assets/img/ui/borders/golden.webp
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
public/assets/img/ui/borders/ice.webp
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
public/assets/img/ui/borders/knight.webp
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
public/assets/img/ui/borders/mage.webp
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
public/assets/img/ui/borders/metal.webp
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
public/assets/img/ui/borders/necromancer.webp
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
public/assets/img/ui/borders/orcs.webp
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
public/assets/img/ui/borders/rock.webp
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
public/assets/img/ui/borders/royal.webp
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
public/assets/img/ui/borders/rune.webp
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
public/assets/img/ui/borders/tavern.webp
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
public/assets/img/ui/borders/vikings.webp
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
public/assets/img/ui/borders/water.webp
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
public/assets/img/ui/borders/wind.webp
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
public/assets/img/ui/borders/wooden.webp
Normal file
After Width: | Height: | Size: 10 KiB |
|
@ -6,12 +6,12 @@
|
||||||
define('SRC', __DIR__ . '/../src');
|
define('SRC', __DIR__ . '/../src');
|
||||||
require_once SRC . '/bootstrap.php';
|
require_once SRC . '/bootstrap.php';
|
||||||
|
|
||||||
$r = [];
|
$r = new Router;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Home
|
Home
|
||||||
*/
|
*/
|
||||||
router_get($r, '/', function () {
|
$r->get('/', function () {
|
||||||
if (user()) must_have_character();
|
if (user()) must_have_character();
|
||||||
$GLOBALS['active_nav_tab'] = 'home';
|
$GLOBALS['active_nav_tab'] = 'home';
|
||||||
echo render('layouts/basic', ['view' => 'pages/home']);
|
echo render('layouts/basic', ['view' => 'pages/home']);
|
||||||
|
@ -20,54 +20,54 @@ router_get($r, '/', function () {
|
||||||
/*
|
/*
|
||||||
Auth
|
Auth
|
||||||
*/
|
*/
|
||||||
router_get($r, '/auth/register', 'auth_controller_register_get');
|
$r->get('/auth/register', 'auth_controller_register_get');
|
||||||
router_post($r, '/auth/register', 'auth_controller_register_post');
|
$r->post('/auth/register', 'auth_controller_register_post');
|
||||||
router_get($r, '/auth/login', 'auth_controller_login_get');
|
$r->get('/auth/login', 'auth_controller_login_get');
|
||||||
router_post($r, '/auth/login', 'auth_controller_login_post');
|
$r->post('/auth/login', 'auth_controller_login_post');
|
||||||
router_post($r, '/auth/logout', 'auth_controller_logout_post');
|
$r->post('/auth/logout', 'auth_controller_logout_post');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Characters
|
Characters
|
||||||
*/
|
*/
|
||||||
router_get($r, '/characters', 'char_controller_list_get');
|
$r->get('/characters', 'char_controller_list_get');
|
||||||
router_post($r, '/characters', 'char_controller_list_post');
|
$r->post('/characters', 'char_controller_list_post');
|
||||||
router_get($r, '/character/create-first', 'char_controller_create_first_get');
|
$r->get('/character/create-first', 'char_controller_create_first_get');
|
||||||
router_post($r, '/character/create', 'char_controller_create_post');
|
$r->post('/character/create', 'char_controller_create_post');
|
||||||
router_post($r, '/character/delete', 'char_controller_delete_post');
|
$r->post('/character/delete', 'char_controller_delete_post');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
World
|
World
|
||||||
*/
|
*/
|
||||||
router_get($r, '/world', 'world_controller_get');
|
$r->get('/world', 'world_controller_get');
|
||||||
router_post($r, '/move', 'world_controller_move_post');
|
$r->post('/move', 'world_controller_move_post');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Profile
|
Profile
|
||||||
*/
|
*/
|
||||||
router_get($r, '/profile', 'profile_controller_get');
|
$r->get('/profile', 'profile_controller_get');
|
||||||
router_get($r, '/profile/:id', 'profile_controller_show_get');
|
$r->get('/profile/:id', 'profile_controller_show_get');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Settings
|
Settings
|
||||||
*/
|
*/
|
||||||
router_get($r, '/settings', 'settings_controller_get');
|
$r->get('/settings', 'settings_controller_get');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Auctions
|
Auctions
|
||||||
*/
|
*/
|
||||||
router_get($r, '/auctions', 'auctions_controller_get');
|
$r->get('/auctions', 'auctions_controller_get');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Testing
|
Testing
|
||||||
*/
|
*/
|
||||||
if (env('debug')) {
|
if (env('debug')) {
|
||||||
router_get($r, '/give_silver/:x', function (int $amt) {
|
$r->get('/give_silver/:x', function (int $amt) {
|
||||||
auth_only_and_must_have_character();
|
auth_only_and_must_have_character();
|
||||||
wallet()->give(Currency::Silver, $amt);
|
wallet()->give(Currency::Silver, $amt);
|
||||||
redirect('/');
|
redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
router_get($r, '/take_silver/:x', function (int $amt) {
|
$r->get('/take_silver/:x', function (int $amt) {
|
||||||
auth_only_and_must_have_character();
|
auth_only_and_must_have_character();
|
||||||
wallet()->take(Currency::Silver, $amt);
|
wallet()->take(Currency::Silver, $amt);
|
||||||
redirect('/');
|
redirect('/');
|
||||||
|
@ -79,11 +79,11 @@ if (env('debug')) {
|
||||||
*/
|
*/
|
||||||
// [code, handler, params]
|
// [code, handler, params]
|
||||||
stopwatch_start('router');
|
stopwatch_start('router');
|
||||||
$l = router_lookup($r, $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
||||||
stopwatch_stop('router');
|
stopwatch_stop('router');
|
||||||
|
|
||||||
stopwatch_start('handler');
|
stopwatch_start('handler');
|
||||||
if ($l['code'] !== 200) router_error($l['code']);
|
if ($l['code'] !== 200) error_response($l['code']);
|
||||||
$l['handler'](...$l['params'] ?? []);
|
$l['handler'](...$l['params'] ?? []);
|
||||||
stopwatch_stop('handler');
|
stopwatch_stop('handler');
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,12 @@ require_once SRC . '/models/session.php';
|
||||||
require_once SRC . '/models/token.php';
|
require_once SRC . '/models/token.php';
|
||||||
|
|
||||||
// Controllers
|
// Controllers
|
||||||
require_once SRC . '/controller/char.php';
|
require_once SRC . '/controllers/char.php';
|
||||||
require_once SRC . '/controller/auth.php';
|
require_once SRC . '/controllers/auth.php';
|
||||||
require_once SRC . '/controller/world.php';
|
require_once SRC . '/controllers/world.php';
|
||||||
require_once SRC . '/controller/settings.php';
|
require_once SRC . '/controllers/settings.php';
|
||||||
require_once SRC . '/controller/auctions.php';
|
require_once SRC . '/controllers/auctions.php';
|
||||||
require_once SRC . '/controller/profile.php';
|
require_once SRC . '/controllers/profile.php';
|
||||||
|
|
||||||
spl_autoload_register(function (string $class) {
|
spl_autoload_register(function (string $class) {
|
||||||
if (array_key_exists($class, CLASS_MAP)) require_once SRC . CLASS_MAP[$class];
|
if (array_key_exists($class, CLASS_MAP)) require_once SRC . CLASS_MAP[$class];
|
||||||
|
|
|
@ -71,7 +71,7 @@ function auth_controller_register_post()
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (User::create($u, $e, $p) === false) router_error(400);
|
if (User::create($u, $e, $p) === false) error_response(400);
|
||||||
|
|
||||||
$_SESSION['user'] = serialize(User::find($u));
|
$_SESSION['user'] = serialize(User::find($u));
|
||||||
Wallet::create(user()->id);
|
Wallet::create(user()->id);
|
||||||
|
@ -128,7 +128,7 @@ function auth_controller_login_post()
|
||||||
"INSERT INTO sessions (token, user_id, expires) VALUES (:t, :u, :e)",
|
"INSERT INTO sessions (token, user_id, expires) VALUES (:t, :u, :e)",
|
||||||
[':t' => $token, ':u' => user()->id, ':e' => $expires]
|
[':t' => $token, ':u' => user()->id, ':e' => $expires]
|
||||||
);
|
);
|
||||||
if (!$result) router_error(400);
|
if (!$result) error_response(400);
|
||||||
set_cookie('remember_me', $token, $expires);
|
set_cookie('remember_me', $token, $expires);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ function auth_controller_login_post()
|
||||||
redirect('/character/create-first');
|
redirect('/character/create-first');
|
||||||
} elseif (!change_user_character(user()->char_id)) {
|
} elseif (!change_user_character(user()->char_id)) {
|
||||||
echo "failed to change user character (aclp)";
|
echo "failed to change user character (aclp)";
|
||||||
router_error(999);
|
error_response(999);
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect('/');
|
redirect('/');
|
|
@ -24,7 +24,7 @@ function char_controller_list_post()
|
||||||
$action = $_POST['action'] ?? '';
|
$action = $_POST['action'] ?? '';
|
||||||
|
|
||||||
// If the character ID is not a number, or the action is not a string, return a 400.
|
// If the character ID is not a number, or the action is not a string, return a 400.
|
||||||
if (!is_numeric($char_id) || !is_string($action)) router_error(400);
|
if (!is_numeric($char_id) || !is_string($action)) error_response(400);
|
||||||
|
|
||||||
// If the character ID is 0, return to the list.
|
// If the character ID is 0, return to the list.
|
||||||
if ($char_id === 0) {
|
if ($char_id === 0) {
|
||||||
|
@ -33,7 +33,7 @@ function char_controller_list_post()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the action is not one of the allowed actions, return a 400.
|
// If the action is not one of the allowed actions, return a 400.
|
||||||
if (!in_array($action, ['select', 'delete'])) router_error(400);
|
if (!in_array($action, ['select', 'delete'])) error_response(400);
|
||||||
|
|
||||||
// If the action is to select a character, change the user's selected character.
|
// If the action is to select a character, change the user's selected character.
|
||||||
if ($action === 'select') {
|
if ($action === 'select') {
|
||||||
|
@ -43,7 +43,7 @@ function char_controller_list_post()
|
||||||
redirect('/characters');
|
redirect('/characters');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Character::belongs_to($char_id, user()->id)) router_error(999);
|
if (!Character::belongs_to($char_id, user()->id)) error_response(999);
|
||||||
|
|
||||||
change_user_character($char_id);
|
change_user_character($char_id);
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ function char_controller_list_post()
|
||||||
|
|
||||||
// If the action is to delete a character, move to the confirmation page.
|
// If the action is to delete a character, move to the confirmation page.
|
||||||
if ($action === 'delete') {
|
if ($action === 'delete') {
|
||||||
if (!Character::belongs_to($char_id, user()->id)) router_error(999);
|
if (!Character::belongs_to($char_id, user()->id)) error_response(999);
|
||||||
|
|
||||||
echo page('chars/delete', ['char' => Character::find($char_id)]);
|
echo page('chars/delete', ['char' => Character::find($char_id)]);
|
||||||
exit;
|
exit;
|
||||||
|
@ -71,10 +71,10 @@ function char_controller_delete_post()
|
||||||
$char_id = (int) ($_POST['char_id'] ?? 0);
|
$char_id = (int) ($_POST['char_id'] ?? 0);
|
||||||
|
|
||||||
// If the character ID is not a number, return a 400.
|
// If the character ID is not a number, return a 400.
|
||||||
if (!is_numeric($char_id)) router_error(400);
|
if (!is_numeric($char_id)) error_response(400);
|
||||||
|
|
||||||
// Ensure the character ID is valid and belongs to the user.
|
// Ensure the character ID is valid and belongs to the user.
|
||||||
if (!Character::belongs_to($char_id, user()->id)) router_error(999);
|
if (!Character::belongs_to($char_id, user()->id)) error_response(999);
|
||||||
|
|
||||||
$char = Character::find($char_id);
|
$char = Character::find($char_id);
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ function char_controller_create_post()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($char = Character::create(user()->id, $name)) === false) router_error(400);
|
if (($char = Character::create(user()->id, $name)) === false) error_response(400);
|
||||||
|
|
||||||
// Create the auxiliary tables
|
// Create the auxiliary tables
|
||||||
$char->create_location();
|
$char->create_location();
|
|
@ -18,7 +18,7 @@ function profile_controller_show_get($id)
|
||||||
{
|
{
|
||||||
auth_only_and_must_have_character();
|
auth_only_and_must_have_character();
|
||||||
|
|
||||||
if (($char = Character::find($id)) == false) router_error(999);
|
if (($char = Character::find($id)) == false) error_response(999);
|
||||||
if (user()->char_id == $id) redirect('/profile');
|
if (user()->char_id == $id) redirect('/profile');
|
||||||
echo page('profile/show', ['c' => $char]);
|
echo page('profile/show', ['c' => $char]);
|
||||||
}
|
}
|
|
@ -45,7 +45,7 @@ function world_controller_move_post()
|
||||||
$x += directions[$d][0];
|
$x += directions[$d][0];
|
||||||
$y += directions[$d][1];
|
$y += directions[$d][1];
|
||||||
} else {
|
} else {
|
||||||
router_error(999);
|
error_response(999);
|
||||||
}
|
}
|
||||||
|
|
||||||
$r = db_query(db_live(), 'UPDATE char_locations SET x = :x, y = :y WHERE char_id = :c', [
|
$r = db_query(db_live(), 'UPDATE char_locations SET x = :x, y = :y WHERE char_id = :c', [
|
|
@ -75,7 +75,7 @@ function csrf_field()
|
||||||
*/
|
*/
|
||||||
function csrf_ensure()
|
function csrf_ensure()
|
||||||
{
|
{
|
||||||
if (!csrf_verify($_POST['csrf'] ?? '')) router_error(418);
|
if (!csrf_verify($_POST['csrf'] ?? '')) error_response(418);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,8 +121,8 @@ function modify_user_session(string $field, mixed $value): bool
|
||||||
function char(): Character|false
|
function char(): Character|false
|
||||||
{
|
{
|
||||||
if (empty($_SESSION['user'])) return false;
|
if (empty($_SESSION['user'])) return false;
|
||||||
if (empty($GLOBALS['char'])) $GLOBALS['char'] = serialize(user()->current_char());
|
if (empty($GLOBALS['char'])) $GLOBALS['char'] = user()->current_char();
|
||||||
return unserialize($GLOBALS['char']);
|
return $GLOBALS['char'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,7 +133,7 @@ function change_user_character(int $char_id): bool
|
||||||
{
|
{
|
||||||
// If the character does not exist, return false
|
// If the character does not exist, return false
|
||||||
if (($char = Character::find($char_id)) === false) return false;
|
if (($char = Character::find($char_id)) === false) return false;
|
||||||
$GLOBALS['char'] = serialize($char);
|
$GLOBALS['char'] = $char;
|
||||||
|
|
||||||
// If the character ID is different, update the session and database
|
// If the character ID is different, update the session and database
|
||||||
if (user()->char_id !== $char_id) {
|
if (user()->char_id !== $char_id) {
|
||||||
|
@ -218,17 +218,17 @@ function stopwatch_stop($key)
|
||||||
/**
|
/**
|
||||||
* Get the stopwatch value and format it to within 10 digits.
|
* Get the stopwatch value and format it to within 10 digits.
|
||||||
*/
|
*/
|
||||||
function stopwatch_get($key)
|
function stopwatch_get(string $key): string
|
||||||
{
|
{
|
||||||
if (!env('debug', false)) return;
|
if (!env('debug', false)) return '';
|
||||||
if (empty($GLOBALS['stopwatch'][$key])) return 0;
|
if (empty($GLOBALS['stopwatch'][$key])) return '';
|
||||||
return number_format($GLOBALS['stopwatch'][$key], 10);
|
return number_format($GLOBALS['stopwatch'][$key], 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conditional Echo; if the condition is true, echo the value. If the condition is false, echo the $or value.
|
* Conditional Echo; if the condition is true, echo the value. If the condition is false, echo the $or value.
|
||||||
*/
|
*/
|
||||||
function ce($condition, $value, $or = '')
|
function ce(bool $condition, mixed $value, mixed $or = ''): void
|
||||||
{
|
{
|
||||||
echo $condition ? $value : $or;
|
echo $condition ? $value : $or;
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ function ce($condition, $value, $or = '')
|
||||||
/**
|
/**
|
||||||
* Get whether the request is an HTMX request.
|
* Get whether the request is an HTMX request.
|
||||||
*/
|
*/
|
||||||
function is_htmx()
|
function is_htmx(): bool
|
||||||
{
|
{
|
||||||
return isset($_SERVER['HTTP_HX_REQUEST']);
|
return isset($_SERVER['HTTP_HX_REQUEST']);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ function is_htmx()
|
||||||
/**
|
/**
|
||||||
* Get whether the request is an AJAX (fetch) request.
|
* Get whether the request is an AJAX (fetch) request.
|
||||||
*/
|
*/
|
||||||
function is_ajax()
|
function is_ajax(): bool
|
||||||
{
|
{
|
||||||
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
|
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
|
||||||
}
|
}
|
||||||
|
@ -252,33 +252,50 @@ function is_ajax()
|
||||||
/**
|
/**
|
||||||
* Limit a request to AJAX only.
|
* Limit a request to AJAX only.
|
||||||
*/
|
*/
|
||||||
function ajax_only()
|
function ajax_only(): void
|
||||||
{
|
{
|
||||||
if (!is_ajax()) router_error(418);
|
if (!is_ajax()) error_response(418);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a JSON response with the given data.
|
* Return a JSON response with the given data.
|
||||||
*/
|
*/
|
||||||
function json_response($data)
|
function json_response(mixed $data): void
|
||||||
{
|
{
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
echo json_encode($data);
|
echo json_encode($data);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an error by setting the response code and echoing an error message
|
||||||
|
*/
|
||||||
|
function error_response(int $code): void
|
||||||
|
{
|
||||||
|
http_response_code($code);
|
||||||
|
echo match ($code) {
|
||||||
|
403 => 'Forbidden',
|
||||||
|
404 => 'Not Found',
|
||||||
|
405 => 'Method Not Allowed',
|
||||||
|
418 => 'I\'m a teapot',
|
||||||
|
999 => 'Cheating attempt detected',
|
||||||
|
default => 'Unknown Error',
|
||||||
|
};
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a title's [name, lore].
|
* Return a title's [name, lore].
|
||||||
*/
|
*/
|
||||||
function title($title_id)
|
function title(int $title_id): array|false
|
||||||
{
|
{
|
||||||
return db_query(db_live(), 'SELECT * FROM titles WHERE id = :i', [':i' => $title_id])->fetchArray();
|
return db_query(db_live(), 'SELECT * FROM titles WHERE id = ?', [$title_id])->fetchArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abbreviate a number in text notation.
|
* Abbreviate a number in text notation.
|
||||||
*/
|
*/
|
||||||
function abb_num($num)
|
function abb_num(int $num): string
|
||||||
{
|
{
|
||||||
$d = $num % 100 === 0 ? 0 : 1;
|
$d = $num % 100 === 0 ? 0 : 1;
|
||||||
return match(true) {
|
return match(true) {
|
||||||
|
|
|
@ -36,7 +36,15 @@ class Character
|
||||||
public int $pre; // Precision
|
public int $pre; // Precision
|
||||||
public int $fer; // Ferocity
|
public int $fer; // Ferocity
|
||||||
public int $luck; // Luck
|
public int $luck; // Luck
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max number of slots this Character has in their inventory.
|
||||||
|
*/
|
||||||
public int $inv_slots;
|
public int $inv_slots;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of points available to spend on attributes.
|
||||||
|
*/
|
||||||
public int $att_points;
|
public int $att_points;
|
||||||
public string $bio;
|
public string $bio;
|
||||||
|
|
||||||
|
@ -45,6 +53,11 @@ class Character
|
||||||
*/
|
*/
|
||||||
private User $user;
|
private User $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current title of the Character.
|
||||||
|
*/
|
||||||
|
private array $title;
|
||||||
|
|
||||||
public function __construct(array $data)
|
public function __construct(array $data)
|
||||||
{
|
{
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
|
@ -52,7 +65,10 @@ class Character
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function find(int $id): Character|false
|
/**
|
||||||
|
* Find a Character by their name or ID.
|
||||||
|
*/
|
||||||
|
public static function find(int|string $id): Character|false
|
||||||
{
|
{
|
||||||
$q = db_query(
|
$q = db_query(
|
||||||
db_live(),
|
db_live(),
|
||||||
|
@ -63,6 +79,10 @@ class Character
|
||||||
return ($c = $q->fetchArray(SQLITE3_ASSOC)) === false ? false : new Character($c);
|
return ($c = $q->fetchArray(SQLITE3_ASSOC)) === false ? false : new Character($c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Character in the database using a User ID and a name. Pass optional overrides to adjust the
|
||||||
|
* defaults for other fields.
|
||||||
|
*/
|
||||||
public static function create(int $user_id, string $name, array $overrides = []): Character|false
|
public static function create(int $user_id, string $name, array $overrides = []): Character|false
|
||||||
{
|
{
|
||||||
// Prep the data and merge in any overrides
|
// Prep the data and merge in any overrides
|
||||||
|
@ -254,12 +274,14 @@ class Character
|
||||||
*/
|
*/
|
||||||
public function title(): array|false
|
public function title(): array|false
|
||||||
{
|
{
|
||||||
|
if (isset($this->title)) return $this->title;
|
||||||
|
|
||||||
$t = title($this->title_id);
|
$t = title($this->title_id);
|
||||||
|
|
||||||
$q = db_query(
|
$q = db_query(
|
||||||
db_live(),
|
db_live(),
|
||||||
'SELECT awarded FROM owned_titles WHERE char_id = :c AND title_id = :t LIMIT 1',
|
'SELECT awarded FROM owned_titles WHERE char_id = ? AND title_id = ? LIMIT 1',
|
||||||
[':c' => $this->id, ':t' => $this->title_id]
|
[$this->id, $this->title_id]
|
||||||
);
|
);
|
||||||
if ($q === false) throw new Exception('Failed to query title. (C::t)');
|
if ($q === false) throw new Exception('Failed to query title. (C::t)');
|
||||||
|
|
||||||
|
@ -267,6 +289,6 @@ class Character
|
||||||
if ($a === false) return false;
|
if ($a === false) return false;
|
||||||
|
|
||||||
$t['awarded'] = $a['awarded']; // add the awarded date to the title info
|
$t['awarded'] = $a['awarded']; // add the awarded date to the title info
|
||||||
return $t;
|
return $this->title = $t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Render the logout button's form.
|
* Render the logout button's form.
|
||||||
*/
|
*/
|
||||||
function c_logout_button()
|
function c_logout_button(): string
|
||||||
{
|
{
|
||||||
return render('components/logout_button');
|
return render('components/logout_button');
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ function c_logout_button()
|
||||||
* Render the character bar. Relies on there being a character in the session. Without one, this will return an empty
|
* Render the character bar. Relies on there being a character in the session. Without one, this will return an empty
|
||||||
* string.
|
* string.
|
||||||
*/
|
*/
|
||||||
function c_char_bar()
|
function c_char_bar(): string
|
||||||
{
|
{
|
||||||
if (char() === false) return '';
|
if (char() === false) return '';
|
||||||
return render('components/char_bar', ['char' => char()]);
|
return render('components/char_bar', ['char' => char()]);
|
||||||
|
@ -22,7 +22,7 @@ function c_char_bar()
|
||||||
* Render the left sidebar navigation menu. Provide the active tab to highlight it. Will retrieve the current
|
* Render the left sidebar navigation menu. Provide the active tab to highlight it. Will retrieve the current
|
||||||
* tab from the GLOBALS.
|
* tab from the GLOBALS.
|
||||||
*/
|
*/
|
||||||
function c_left_nav()
|
function c_left_nav(): string
|
||||||
{
|
{
|
||||||
return render('components/left_nav');
|
return render('components/left_nav');
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ function c_left_nav()
|
||||||
/**
|
/**
|
||||||
* Render the right sidebar menu.
|
* Render the right sidebar menu.
|
||||||
*/
|
*/
|
||||||
function c_right_nav()
|
function c_right_nav(): string
|
||||||
{
|
{
|
||||||
return render('components/right_nav', ['c' => char()]);
|
return render('components/right_nav', ['c' => char()]);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ function c_right_nav()
|
||||||
/**
|
/**
|
||||||
* Render the debug query log.
|
* Render the debug query log.
|
||||||
*/
|
*/
|
||||||
function c_debug_query_log()
|
function c_debug_query_log(): string
|
||||||
{
|
{
|
||||||
return render('components/debug_query_log');
|
return render('components/debug_query_log');
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,15 @@ function c_debug_query_log()
|
||||||
/**
|
/**
|
||||||
* Render the character select radio buttons.
|
* Render the character select radio buttons.
|
||||||
*/
|
*/
|
||||||
function c_char_select_box($id, $char)
|
function c_char_select_box(int $id, array $info): string
|
||||||
{
|
{
|
||||||
return render('components/char_select_box', ['id' => $id, 'char' => $char]);
|
return render('components/char_select_box', ['id' => $id, 'c' => $info]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render an alert with a given type and message.
|
* Render an alert with a given type and message.
|
||||||
*/
|
*/
|
||||||
function c_alert($type, $message)
|
function c_alert(string $type, string $message): string
|
||||||
{
|
{
|
||||||
$a = $type !== 'danger' ? ' auto-close="5000"' : '';
|
$a = $type !== 'danger' ? ' auto-close="5000"' : '';
|
||||||
return "<div class=\"alert $type\"$a><div>$message</div> <a alert-close>×</a></div>";
|
return "<div class=\"alert $type\"$a><div>$message</div> <a alert-close>×</a></div>";
|
||||||
|
@ -63,7 +63,7 @@ function c_alert($type, $message)
|
||||||
/**
|
/**
|
||||||
* Renders a danger alert with form errors, if there are any. Add an optional placement id.
|
* Renders a danger alert with form errors, if there are any. Add an optional placement id.
|
||||||
*/
|
*/
|
||||||
function c_form_errors($placement = '')
|
function c_form_errors(string $placement = ''): string
|
||||||
{
|
{
|
||||||
$errors = $GLOBALS[($placement !== '' ? "form-errors-$placement" : 'form-errors')] ?? false;
|
$errors = $GLOBALS[($placement !== '' ? "form-errors-$placement" : 'form-errors')] ?? false;
|
||||||
if ($errors === false) return '';
|
if ($errors === false) return '';
|
||||||
|
@ -78,8 +78,14 @@ function c_form_errors($placement = '')
|
||||||
* Generate a text form field. This component will automatically add the error class if there are errors for this field,
|
* Generate a text form field. This component will automatically add the error class if there are errors for this field,
|
||||||
* depending on the form-errors GLOBAL. Pass an optional form ID to target a specific form GLOBAL.
|
* depending on the form-errors GLOBAL. Pass an optional form ID to target a specific form GLOBAL.
|
||||||
*/
|
*/
|
||||||
function c_form_field($type, $name, $placeholder, $required = false, $autocomplete = "off", $formId = '')
|
function c_form_field(
|
||||||
{
|
string $type,
|
||||||
|
string $name,
|
||||||
|
string $placeholder,
|
||||||
|
bool $required = false,
|
||||||
|
string $autocomplete = "off",
|
||||||
|
string $formId = ''
|
||||||
|
) {
|
||||||
$errors = $GLOBALS[($formId !== '' ? "form-errors-$formId" : 'form-errors')] ?? false;
|
$errors = $GLOBALS[($formId !== '' ? "form-errors-$formId" : 'form-errors')] ?? false;
|
||||||
$html = "<input type=\"$type\" name=\"$name\" id=\"$name\" placeholder=\"$placeholder\"";
|
$html = "<input type=\"$type\" name=\"$name\" id=\"$name\" placeholder=\"$placeholder\"";
|
||||||
if ($required) $html .= ' required';
|
if ($required) $html .= ' required';
|
||||||
|
@ -99,7 +105,15 @@ function c_debug_stopwatch()
|
||||||
/**
|
/**
|
||||||
* Render a profile's stat grid using a character array.
|
* Render a profile's stat grid using a character array.
|
||||||
*/
|
*/
|
||||||
function c_profile_stats($char)
|
function c_profile_stats(Character $char): string
|
||||||
{
|
{
|
||||||
return render('components/profile_stats', ['char' => $char]);
|
return render('components/profile_stats', ['char' => $char]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a character's equipped gear for their profile.
|
||||||
|
*/
|
||||||
|
function c_equipped_gear(Character $char): string
|
||||||
|
{
|
||||||
|
return render('components/equipped_gear', ['char' => $char]);
|
||||||
|
}
|
||||||
|
|
|
@ -1,131 +1,91 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
class Router
|
||||||
* Add a route to the route tree. The route must be a URI path, and contain dynamic segments
|
|
||||||
* using a colon prefix. (:id, :slug, etc)
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* `router_add($routes, 'GET', '/posts/:id', function($id) { echo "Viewing post $id"; });`
|
|
||||||
*/
|
|
||||||
function router_add(&$routes, $method, $route, $handler)
|
|
||||||
{
|
{
|
||||||
// Expand the route into segments and make dynamic segments into a common placeholder
|
private array $routes = [];
|
||||||
$segments = array_map(function($segment) {
|
|
||||||
return str_starts_with($segment, ':') ? ':x' : $segment;
|
|
||||||
}, explode('/', trim($route, '/')));
|
|
||||||
|
|
||||||
// Push each segment into the routes array as a node, except if this is the root node
|
/**
|
||||||
$node = &$routes;
|
* Add a route to the route tree. The route must be a URI path, and contain dynamic segments
|
||||||
foreach ($segments as $segment) {
|
* using a colon prefix. (:id, :slug, etc)
|
||||||
// skip an empty segment, which allows us to register handlers for the root node
|
*
|
||||||
if ($segment === '') continue;
|
* Example:
|
||||||
$node = &$node[$segment]; // build the node tree as we go
|
* `$r->add($routes, 'GET', '/posts/:id', function($id) { echo "Viewing post $id"; });`
|
||||||
|
*/
|
||||||
|
public function add(string $method, string $route, callable $handler): Router
|
||||||
|
{
|
||||||
|
// Expand the route into segments and make dynamic segments into a common placeholder
|
||||||
|
$segments = array_map(function($segment) {
|
||||||
|
return str_starts_with($segment, ':') ? ':x' : $segment;
|
||||||
|
}, explode('/', trim($route, '/')));
|
||||||
|
|
||||||
|
// Push each segment into the routes array as a node, except if this is the root node
|
||||||
|
$node = &$this->routes;
|
||||||
|
foreach ($segments as $segment) {
|
||||||
|
// skip an empty segment, which allows us to register handlers for the root node
|
||||||
|
if ($segment === '') continue;
|
||||||
|
$node = &$node[$segment]; // build the node tree as we go
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the handler to the last node
|
||||||
|
$node[$method] = $handler;
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the handler to the last node
|
/**
|
||||||
$node[$method] = $handler;
|
* Perform a lookup in the route tree for a given method and URI. Returns an array with a result code,
|
||||||
}
|
* a handler if found, and any dynamic parameters. Codes are 200 for success, 404 for not found, and
|
||||||
|
* 405 for method not allowed.
|
||||||
|
*
|
||||||
|
* @return array ['code', 'handler', 'params']
|
||||||
|
*/
|
||||||
|
public function lookup(string $method, string $uri): array
|
||||||
|
{
|
||||||
|
// node is a reference to our current location in the node tree
|
||||||
|
$node = $this->routes;
|
||||||
|
|
||||||
/**
|
// params will hold any dynamic segments we find
|
||||||
* Perform a lookup in the route tree for a given method and URI. Returns an array with a result code,
|
$params = [];
|
||||||
* a handler if found, and any dynamic parameters. Codes are 200 for success, 404 for not found, and
|
|
||||||
* 405 for method not allowed.
|
|
||||||
*
|
|
||||||
* @return array ['code', 'handler', 'params']
|
|
||||||
*/
|
|
||||||
function router_lookup($routes, $method, $uri)
|
|
||||||
{
|
|
||||||
// node is a reference to our current location in the node tree
|
|
||||||
$node = $routes;
|
|
||||||
|
|
||||||
// params will hold any dynamic segments we find
|
// if the URI is just a slash, we can return the handler for the root node
|
||||||
$params = [];
|
if ($uri === '/') {
|
||||||
|
return isset($node[$method])
|
||||||
|
? ['code' => 200, 'handler' => $node[$method], 'params' => null]
|
||||||
|
: ['code' => 405, 'handler' => null, 'params' => null];
|
||||||
|
}
|
||||||
|
|
||||||
// if the URI is just a slash, we can return the handler for the root node
|
// We'll split up the URI into segments and traverse the node tree
|
||||||
if ($uri === '/') {
|
foreach (explode('/', trim($uri, '/')) as $segment) {
|
||||||
|
// if there is a node for this segment, move to it
|
||||||
|
if (isset($node[$segment])) {
|
||||||
|
$node = $node[$segment];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a dynamic segment, move to it and store the value
|
||||||
|
if (isset($node[':x'])) {
|
||||||
|
$params[] = $segment;
|
||||||
|
$node = $node[':x'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we can't find a node for this segment, return 404
|
||||||
|
return ['code' => 404, 'handler' => null, 'params' => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we found a handler for the method, return it and any params. if not, return a 405
|
||||||
return isset($node[$method])
|
return isset($node[$method])
|
||||||
? ['code' => 200, 'handler' => $node[$method], 'params' => null]
|
? ['code' => 200, 'handler' => $node[$method], 'params' => $params ?? []]
|
||||||
: ['code' => 405, 'handler' => null, 'params' => null];
|
: ['code' => 405, 'handler' => null, 'params' => []];
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll split up the URI into segments and traverse the node tree
|
public function get(string $route, callable $handler): Router
|
||||||
foreach (explode('/', trim($uri, '/')) as $segment) {
|
{
|
||||||
// if there is a node for this segment, move to it
|
return $this->add('GET', $route, $handler);
|
||||||
if (isset($node[$segment])) {
|
|
||||||
$node = $node[$segment];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is a dynamic segment, move to it and store the value
|
|
||||||
if (isset($node[':x'])) {
|
|
||||||
$params[] = $segment;
|
|
||||||
$node = $node[':x'];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we can't find a node for this segment, return 404
|
|
||||||
return ['code' => 404, 'handler' => null, 'params' => []];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we found a handler for the method, return it and any params. if not, return a 405
|
public function post(string $route, callable $handler): Router
|
||||||
return isset($node[$method])
|
{
|
||||||
? ['code' => 200, 'handler' => $node[$method], 'params' => $params ?? []]
|
return $this->add('POST', $route, $handler);
|
||||||
: ['code' => 405, 'handler' => null, 'params' => []];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a GET route
|
|
||||||
*/
|
|
||||||
function router_get(array &$routes, $route, callable $handler)
|
|
||||||
{
|
|
||||||
router_add($routes, 'GET', $route, $handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a POST route
|
|
||||||
*/
|
|
||||||
function router_post(array &$routes, $route, callable $handler)
|
|
||||||
{
|
|
||||||
router_add($routes, 'POST', $route, $handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a PUT route
|
|
||||||
*/
|
|
||||||
function router_put(array &$routes, $route, callable $handler)
|
|
||||||
{
|
|
||||||
router_add($routes, 'PUT', $route, $handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a DELETE route
|
|
||||||
*/
|
|
||||||
function router_delete(array &$routes, $route, callable $handler)
|
|
||||||
{
|
|
||||||
router_add($routes, 'DELETE', $route, $handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a PATCH route
|
|
||||||
*/
|
|
||||||
function router_patch(array &$routes, $route, callable $handler)
|
|
||||||
{
|
|
||||||
router_add($routes, 'PATCH', $route, $handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a router error by setting the response code and echoing an error message
|
|
||||||
*/
|
|
||||||
function router_error($code)
|
|
||||||
{
|
|
||||||
http_response_code($code);
|
|
||||||
echo match ($code) {
|
|
||||||
403 => 'Forbidden',
|
|
||||||
404 => 'Not Found',
|
|
||||||
405 => 'Method Not Allowed',
|
|
||||||
418 => 'I\'m a teapot',
|
|
||||||
999 => 'Cheating attempt detected',
|
|
||||||
default => 'Unknown Error',
|
|
||||||
};
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div class="radio-block <?= $id === user()->char_id ? 'active' : '' ?>">
|
<div class="radio-block <?= $id === user()->char_id ? 'active' : '' ?>">
|
||||||
<input type="radio" name="char_id" value="<?= $id ?>" id="char_<?= $id ?>"<?= $id === user()->char_id ? 'disabled' : '' ?>>
|
<input type="radio" name="char_id" value="<?= $id ?>" id="char_<?= $id ?>"<?= $id === user()->char_id ? 'disabled' : '' ?>>
|
||||||
<label for="char_<?= $id ?>">
|
<label for="char_<?= $id ?>">
|
||||||
<?= $char['name'] ?>
|
<?= $c['name'] ?>
|
||||||
<span class="badge"><?= $char['level'] ?></span>
|
<span class="badge"><?= $c['level'] ?></span>
|
||||||
<span class="badge green selected">Active</span>
|
<span class="badge green selected">Active</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
22
templates/components/equipped_gear.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<div id="equipped-gear">
|
||||||
|
<!-- Top tow; gloves, head, amulet -->
|
||||||
|
<div class="top">
|
||||||
|
<div><div class="item i-2x2"></div></div>
|
||||||
|
<div><div class="item i-2x2"></div></div>
|
||||||
|
<div><div class="item i-1x1"></div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mid row; main hand, chest, off hand -->
|
||||||
|
<div class="mid">
|
||||||
|
<div><div class="item i-2x3"></div></div>
|
||||||
|
<div><div class="item i-2x3"></div></div>
|
||||||
|
<div><div class="item i-2x3"></div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bot row; ring, boots, relic -->
|
||||||
|
<div class="bot">
|
||||||
|
<div><div class="item i-1x1"></div></div>
|
||||||
|
<div><div class="item i-2x2"></div></div>
|
||||||
|
<div><div class="item i-1x1"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -54,7 +54,9 @@
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import Tooltip from '/assets/scripts/tooltip.js';
|
import Tooltip from '/assets/scripts/tooltip.js';
|
||||||
Tooltip.init();
|
Tooltip.init({
|
||||||
|
removalDelay: 0
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
<input type="hidden" name="csrf" value="<?= csrf() ?>">
|
||||||
|
|
||||||
<div class="my-2 character-select">
|
<div class="my-2 character-select">
|
||||||
<?php foreach ($chars as $id => $char) echo c_char_select_box($id, $char); ?>
|
<?php foreach ($chars as $i => $c) echo c_char_select_box($i, $c); ?>
|
||||||
|
|
||||||
<div class="mt-4 buttons">
|
<div class="mt-4 buttons">
|
||||||
<button type="submit" class="ui button primary" name="action" value="select">Select</button>
|
<button type="submit" class="ui button primary" name="action" value="select">Select</button>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<section class="left">
|
<section class="left">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<img src="/assets/img/rathalos.webp">
|
<img src="/assets/img/rathalos.webp">
|
||||||
|
<img class="border" src="/assets/img/ui/borders/water.webp">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= c_profile_stats(char()) ?>
|
<?= c_profile_stats(char()) ?>
|
||||||
|
@ -32,12 +33,16 @@
|
||||||
|
|
||||||
<div class="gear">
|
<div class="gear">
|
||||||
<h4>Equipped Gear</h4>
|
<h4>Equipped Gear</h4>
|
||||||
@TODO
|
<?= c_equipped_gear(char()) ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inv">
|
<div class="inv">
|
||||||
<h4>Inventory</h4>
|
<h4>Inventory</h4>
|
||||||
@TODO
|
<?php
|
||||||
|
for ($i = 0; $i < char()->inv_slots; $i++) {
|
||||||
|
echo '<img class="mr-1" src="/assets/img/ui/2x3.png">';
|
||||||
|
}
|
||||||
|
?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<section class="left">
|
<section class="left">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<img src="/assets/img/rathalos.webp">
|
<img src="/assets/img/rathalos.webp">
|
||||||
|
<img class="border" src="/assets/img/ui/borders/water.webp">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= c_profile_stats($c) ?>
|
<?= c_profile_stats($c) ?>
|
||||||
|
@ -32,12 +33,16 @@
|
||||||
|
|
||||||
<div class="gear">
|
<div class="gear">
|
||||||
<h4>Equipped Gear</h4>
|
<h4>Equipped Gear</h4>
|
||||||
@TODO
|
<?= c_equipped_gear($c) ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inv">
|
<div class="inv">
|
||||||
<h4>Inventory</h4>
|
<h4>Inventory</h4>
|
||||||
@TODO
|
<?php
|
||||||
|
for ($i = 0; $i < $c->inv_slots; $i++) {
|
||||||
|
echo '<img class="mr-1" src="/assets/img/ui/2x3.png">';
|
||||||
|
}
|
||||||
|
?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|