2024-09-27 18:45:33 -05:00
|
|
|
<?php
|
|
|
|
|
2024-12-05 18:34:12 -06:00
|
|
|
use Models\Character;
|
|
|
|
|
2024-09-28 18:33:17 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
|
|
|
Bootstrapping
|
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
*/
|
2024-09-27 18:45:33 -05:00
|
|
|
define('SRC', __DIR__ . '/../src');
|
2024-12-02 21:33:47 -06:00
|
|
|
define('DATABASE_PATH', __DIR__ . '/../database');
|
2024-09-27 18:45:33 -05:00
|
|
|
require_once SRC . '/bootstrap.php';
|
|
|
|
|
2024-10-24 18:23:55 -05:00
|
|
|
$r = new Router;
|
2024-09-27 18:45:33 -05:00
|
|
|
|
2024-09-28 18:33:17 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
Home
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
*/
|
2024-11-13 20:53:05 -06:00
|
|
|
$r->get('/', function() {
|
2024-12-02 21:33:47 -06:00
|
|
|
if (user()) redirect('/world');
|
|
|
|
echo render('layouts/basic', ['view' => 'pages/hello']);
|
2024-09-27 18:45:33 -05:00
|
|
|
});
|
|
|
|
|
2024-09-28 18:33:17 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
Auth
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
*/
|
2024-12-03 21:00:07 -06:00
|
|
|
$r->get('/register', 'Actions\Auth::register_get')->middleware('guest_only');
|
|
|
|
$r->post('/register', 'Actions\Auth::register_post')->middleware('guest_only');
|
2024-11-13 20:53:05 -06:00
|
|
|
|
2024-12-05 18:34:12 -06:00
|
|
|
$r->get('/login', 'Actions\Auth::login_get')->middleware('guest_only');
|
|
|
|
$r->post('/login', 'Actions\Auth::login_post')->middleware('guest_only');
|
2024-11-13 20:53:05 -06:00
|
|
|
|
2024-12-05 18:34:12 -06:00
|
|
|
$r->post('/logout', 'Actions\Auth::logout')->middleware('auth_only');
|
|
|
|
if (env('debug', false)) $r->get('/debug/logout', 'Actions\Auth::logout');
|
2024-09-27 18:45:33 -05:00
|
|
|
|
2024-09-28 18:33:17 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
Characters
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
*/
|
2024-11-13 20:53:05 -06:00
|
|
|
$r->get('/characters', function() {
|
2024-12-02 21:33:47 -06:00
|
|
|
//echo page('chars/list', ['chars' => user()->char_list()]);
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('must_have_character');
|
2024-11-13 20:53:05 -06:00
|
|
|
|
|
|
|
$r->post('/characters', function() {
|
|
|
|
$char_id = (int) ($_POST['char_id'] ?? 0);
|
|
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
|
|
|
|
// 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)) error_response(400);
|
|
|
|
|
|
|
|
// If the character ID is 0, return to the list.
|
|
|
|
if ($char_id === 0) {
|
|
|
|
flash('alert_character_list_1', ['', 'No character selected.']);
|
|
|
|
redirect('/characters');
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the action is not one of the allowed actions, return a 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 ($action === 'select') {
|
|
|
|
// If the character ID is the current character, do nothing.
|
|
|
|
if ($char_id === user()->char_id || $char_id === 0) {
|
|
|
|
flash('alert_character_list_1', ['info', 'You are already using <b>' . char()->name . '</b>.']);
|
|
|
|
redirect('/characters');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Character::belongs_to($char_id, user()->id)) error_response(999);
|
|
|
|
|
|
|
|
change_user_character($char_id);
|
|
|
|
|
|
|
|
flash('alert_character_list_1', ['success', 'Switched to <b>' . char()->name . '</b>!']);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the action is to delete a character, move to the confirmation page.
|
|
|
|
if ($action === 'delete') {
|
|
|
|
if (!Character::belongs_to($char_id, user()->id)) error_response(999);
|
|
|
|
|
2024-12-02 21:33:47 -06:00
|
|
|
//echo page('chars/delete', ['char' => Character::find($char_id)]);
|
2024-11-13 20:53:05 -06:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
redirect('/characters');
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('must_have_character');
|
2024-11-13 20:53:05 -06:00
|
|
|
|
|
|
|
$r->get('/character/create-first', function() {
|
|
|
|
// If the user already has a character, redirect them to the main page.
|
|
|
|
if (user()->char_count() > 0) redirect('/');
|
|
|
|
|
2024-12-02 21:33:47 -06:00
|
|
|
//echo page('chars/first');
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('auth_only');
|
2024-11-13 20:53:05 -06:00
|
|
|
|
|
|
|
$r->post('/character/create', function() {
|
|
|
|
$errors = [];
|
|
|
|
|
|
|
|
$name = trim($_POST['n'] ?? '');
|
|
|
|
|
|
|
|
/*
|
|
|
|
A name is required.
|
|
|
|
A name must be between 3 and 18 characters.
|
|
|
|
A name must contain only alphanumeric characters and spaces.
|
|
|
|
*/
|
|
|
|
if (empty($name) || strlen($name) < 3 || strlen($name) > 18 || !ctype_alnum(str_replace(' ', '', $name))) {
|
|
|
|
$errors['n'][] = 'Name is required and must be between 3 and 18 characters long and contain only alphanumeric characters and spaces.';
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
A character's name must be unique.
|
|
|
|
*/
|
|
|
|
if (Character::name_exists($name)) $errors['n'][] = 'Name is already taken.';
|
|
|
|
|
|
|
|
// If there are errors at this point, send them to the page with errors flashed.
|
|
|
|
if (!empty($errors)) {
|
|
|
|
$GLOBALS['form-errors-create-character'] = $errors;
|
|
|
|
|
|
|
|
if (isset($_POST['first']) && $_POST['first'] === 'true') {
|
|
|
|
// If this is the first character, return to the first character creation page.
|
2024-12-02 21:33:47 -06:00
|
|
|
//echo page('chars/first');
|
2024-11-13 20:53:05 -06:00
|
|
|
exit;
|
|
|
|
} else {
|
|
|
|
// If this is not the first character, return to the character list page.
|
2024-12-02 21:33:47 -06:00
|
|
|
//echo page('chars/list', ['chars' => user()->char_list()]);
|
2024-11-13 20:53:05 -06:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (($char = Character::create(user()->id, $name)) === false) error_response(400);
|
|
|
|
|
|
|
|
// Create the auxiliary tables
|
|
|
|
$char->create_location();
|
|
|
|
$char->create_gear();
|
|
|
|
|
|
|
|
// Award the Adventurer title.
|
|
|
|
$char->award_title(1);
|
|
|
|
|
|
|
|
// Set the character as the user's selected character
|
|
|
|
change_user_character($char->id);
|
|
|
|
|
|
|
|
flash('alert_character_list_1', ['success', 'Character <b>' . $name . '</b> created!']);
|
|
|
|
redirect('/characters');
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('auth_only');
|
2024-11-13 20:53:05 -06:00
|
|
|
|
|
|
|
$r->post('/character/delete', function() {
|
|
|
|
$char_id = (int) ($_POST['char_id'] ?? 0);
|
|
|
|
|
|
|
|
// If the character ID is not a number, return a 400.
|
|
|
|
if (!is_numeric($char_id)) error_response(400);
|
|
|
|
|
|
|
|
// Ensure the character ID is valid and belongs to the user.
|
|
|
|
if (!Character::belongs_to($char_id, user()->id)) error_response(999);
|
|
|
|
|
|
|
|
$char = Character::find($char_id);
|
|
|
|
|
|
|
|
// Confirm the name matches the name of the character. CASE SENSITIVE.
|
|
|
|
if ($char['name'] !== trim($_POST['n'] ?? '')) {
|
|
|
|
flash('alert_character_list_1', ['danger', 'Failed to delete <b>' . $char['name'] . '</b>. Name confirmation did not match.']);
|
|
|
|
redirect('/characters');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the character
|
|
|
|
Character::delete($char_id);
|
|
|
|
|
|
|
|
// If the character being deleted is the currently selected character, select the first character.
|
|
|
|
if (user()->char_id === $char_id) {
|
|
|
|
$chars = user()->char_list();
|
|
|
|
if (count($chars) > 0) change_user_character($chars[0]['id']);
|
|
|
|
}
|
|
|
|
|
|
|
|
flash('alert_character_list_1', ['danger', 'Character <b>' . $char['name'] . '</b> deleted.']);
|
|
|
|
redirect('/characters');
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('must_have_character');
|
2024-09-28 18:33:17 -05:00
|
|
|
|
2024-10-10 13:14:14 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-10-10 13:14:14 -05:00
|
|
|
World
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-10-10 13:14:14 -05:00
|
|
|
*/
|
2024-11-13 20:53:05 -06:00
|
|
|
$r->get('/world', function() {
|
|
|
|
echo render('layouts/game');
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('must_have_character');
|
2024-10-10 13:14:14 -05:00
|
|
|
|
2024-11-13 20:53:05 -06:00
|
|
|
$r->post('/move', function() {
|
|
|
|
/*
|
|
|
|
This endpoint is used to move the character around the world. The client sends a POST request with the direction
|
|
|
|
they want to move the character. The server will update the character's position in the database and return the
|
|
|
|
new position to the client.
|
2024-10-16 22:55:47 -05:00
|
|
|
|
2024-11-13 20:53:05 -06:00
|
|
|
We should only be using this endpoint as an AJAX request from the world page. Since we don't need all the character's
|
|
|
|
data to move them, we can just get and update their lcoation using the user's currently selected character ID.
|
|
|
|
*/
|
2024-10-12 10:46:03 -05:00
|
|
|
|
2024-11-13 20:53:05 -06:00
|
|
|
define('directions', [
|
|
|
|
[0, -1], // Up
|
|
|
|
[0, 1], // Down
|
|
|
|
[-1, 0], // Left
|
|
|
|
[1, 0] // Right
|
|
|
|
]);
|
|
|
|
|
|
|
|
// direction must exist
|
|
|
|
$d = (int) $_POST['direction'] ?? -1;
|
|
|
|
|
|
|
|
// Update the character's position
|
|
|
|
// 0 = up, 1 = down, 2 = left, 3 = right
|
|
|
|
$x = location('x');
|
|
|
|
$y = location('y');
|
|
|
|
|
|
|
|
if (isset(directions[$d])) {
|
|
|
|
$x += directions[$d][0];
|
|
|
|
$y += directions[$d][1];
|
|
|
|
} else {
|
|
|
|
error_response(999);
|
|
|
|
}
|
|
|
|
|
2024-12-02 21:33:47 -06:00
|
|
|
$r = live_db()->query('UPDATE char_locations SET x = :x, y = :y WHERE char_id = :c', [
|
2024-11-13 20:53:05 -06:00
|
|
|
':x' => $x,
|
|
|
|
':y' => $y,
|
|
|
|
':c' => user()->char_id
|
|
|
|
]);
|
|
|
|
|
|
|
|
if ($r === false) throw new Exception('Failed to move character. (wcmp)');
|
|
|
|
|
|
|
|
json_response(['x' => $x, 'y' => $y]);
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('ajax_only')->middleware('must_have_character');
|
2024-11-07 11:19:33 -06:00
|
|
|
|
2024-10-23 17:39:48 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
|
|
|
UI Components
|
|
|
|
============================================================
|
2024-10-23 17:39:48 -05:00
|
|
|
*/
|
2024-12-02 21:33:47 -06:00
|
|
|
$r->get('/ui/stats', function() {
|
2024-11-13 20:53:05 -06:00
|
|
|
echo c_profile_stats(char());
|
2024-12-03 21:00:07 -06:00
|
|
|
})->middleware('ajax_only')->middleware('must_have_character');
|
2024-10-23 17:39:48 -05:00
|
|
|
|
2024-09-28 18:33:17 -05:00
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
Router
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
*/
|
2024-12-03 21:00:07 -06:00
|
|
|
// [code, handler, params, middleware]
|
2024-10-24 18:23:55 -05:00
|
|
|
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
2024-10-05 18:28:04 -05:00
|
|
|
|
2024-10-24 18:23:55 -05:00
|
|
|
if ($l['code'] !== 200) error_response($l['code']);
|
2024-12-03 21:00:07 -06:00
|
|
|
if (!empty($l['middleware'])) foreach ($l['middleware'] as $middleware) $middleware();
|
2024-09-27 18:45:33 -05:00
|
|
|
$l['handler'](...$l['params'] ?? []);
|
2024-09-28 18:33:17 -05:00
|
|
|
|
|
|
|
/*
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
Cleanup
|
2024-12-05 18:34:12 -06:00
|
|
|
============================================================
|
2024-09-28 18:33:17 -05:00
|
|
|
*/
|
2024-09-27 18:45:33 -05:00
|
|
|
clear_flashes();
|