406 lines
14 KiB
PHP
406 lines
14 KiB
PHP
<?php
|
|
|
|
// towns.php :: Handles all actions you can do in town.
|
|
|
|
namespace Towns;
|
|
|
|
use Router;
|
|
|
|
function register_routes(Router $r): Router
|
|
{
|
|
$r->form('/inn', 'Towns\inn');
|
|
$r->get('/shop', 'Towns\shop');
|
|
$r->form('/buy/:id', 'Towns\buy');
|
|
// $r->get('/sell', 'Towns\sell');
|
|
$r->get('/maps', 'Towns\maps');
|
|
$r->form('/maps/:id', 'Towns\buy_map');
|
|
$r->get('/gotown/:id', 'Towns\travelto');
|
|
return $r;
|
|
}
|
|
|
|
/**
|
|
* Spit out the main town page.
|
|
*/
|
|
function town()
|
|
{
|
|
global $controlrow;
|
|
|
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
|
if ($town === false) exit('There is an error with your user account, or with the town data. Please try again.');
|
|
|
|
$page = ['news' => '', 'whos_online' => ''];
|
|
|
|
// News box. Grab latest news entry and display it. Something a little more graceful coming soon maybe.
|
|
if ($controlrow['shownews'] === 1) {
|
|
$news = db()->query('SELECT * FROM news ORDER BY id DESC LIMIT 1;')->fetchArray(SQLITE3_ASSOC);
|
|
$news_date = pretty_date($news["postdate"]);
|
|
$news_content = nl2br($news["content"]);
|
|
$page['news'] = <<<HTML
|
|
<div class="title">Latest News</div>
|
|
<span class="light">$news_date</span><br>
|
|
$news_content
|
|
HTML;
|
|
}
|
|
|
|
// Who's Online. Currently just members. Guests maybe later.
|
|
if ($controlrow['showonline'] === 1) {
|
|
$onlinequery = db()->query(<<<SQL
|
|
SELECT id, username
|
|
FROM users
|
|
WHERE onlinetime >= datetime('now', '-600 seconds')
|
|
ORDER BY username;
|
|
SQL);
|
|
|
|
$online_count = 0;
|
|
$online_rows = [];
|
|
|
|
while ($onlinerow = $onlinequery->fetchArray(SQLITE3_ASSOC)) {
|
|
$online_count++;
|
|
$online_rows[] = "<a href=\"javascript:opencharpopup({$onlinerow['id']})\">".$onlinerow["username"]."</a>";
|
|
}
|
|
|
|
$online_rows = implode(', ', $online_rows);
|
|
$page['whos_online'] = <<<HTML
|
|
<div class="title">Who's Online</div>
|
|
There are <b>$online_count</b> user(s) online within the last 10 minutes: $online_rows
|
|
HTML;
|
|
}
|
|
|
|
page_title($town['name']);
|
|
return render('towns', ['town' => $town, 'news' => $page['news'], 'whos_online' => $page['whos_online']]);
|
|
}
|
|
|
|
/**
|
|
* Staying at the inn resets all expendable stats to their max values.
|
|
* GET/POST /inn
|
|
*/
|
|
function inn()
|
|
{
|
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
|
if ($town === false) { exit('Cheat attempt detected.<br><br>Get a life, loser.'); }
|
|
|
|
$htmx = is_htmx();
|
|
page_title($town['name'] . ' Inn');
|
|
|
|
if (user()->gold < $town['innprice']) {
|
|
$page = <<<HTML
|
|
You do not have enough gold to stay at this Inn tonight. <br><br>
|
|
You may return to <a hx-get="/" hx-target="#middle">town</a>, or use the direction buttons on the left to start exploring.
|
|
HTML;
|
|
} elseif (is_post() && $_POST['rest']) {
|
|
user()->gold -= $town['innprice'];
|
|
user()->restore_points()->save();
|
|
$page = <<<HTML
|
|
You wake up feeling refreshed and ready for action. <br><br>
|
|
You may return to <a hx-get="/" hx-target="#middle">town</a>, or use the direction buttons on the left to start exploring.
|
|
HTML;
|
|
} elseif (is_post() && !$_POST['rest']) {
|
|
redirect('/');
|
|
} else {
|
|
$page = <<<HTML
|
|
Resting at the inn will refill your current HP, MP, and TP to their maximum levels.<br><br>
|
|
A night's sleep at this Inn will cost you <b>{$town['innprice']} gold</b>. Is that ok?<br><br>
|
|
<form hx-post="/inn" hx-target="#middle">
|
|
<button name="rest" value="1">Yes</button>
|
|
<button name="rest" value="0">No</button>
|
|
</form>
|
|
HTML;
|
|
}
|
|
|
|
return $htmx ? $page : display($page, $town['name'] . ' Inn');
|
|
}
|
|
|
|
/**
|
|
* Displays a list of available items for purchase from the town the user is currently in. If the user is not in a town,
|
|
* redirects to home.
|
|
* GET /shop
|
|
*/
|
|
function shop()
|
|
{
|
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
|
if ($town === false) exit('Cheat attempt detected.<br><br>Get a life, loser.');
|
|
|
|
$htmx = is_htmx();
|
|
page_title($town['name'] . ' Shop');
|
|
|
|
$page = <<<HTML
|
|
Buying weapons will increase your Attack Power. Buying armor and shields will increase your Defense Power.<br><br>
|
|
Click an item name to purchase it.<br><br>
|
|
The following items are available at this town:<br><br>
|
|
<table>
|
|
HTML;
|
|
|
|
$items = db()->query('SELECT * FROM items WHERE id IN (' . $town["itemslist"] . ');');
|
|
while ($item = $items->fetchArray(SQLITE3_ASSOC)) {
|
|
$attrib = ($item["type"] == 1) ? "Attack Power:" : "Defense Power:";
|
|
$page .= '<tr><td width="4%">';
|
|
$page .= match ($item["type"]) {
|
|
1 => '<img src="/img/icon_weapon.gif" alt="weapon">',
|
|
2 => '<img src="/img/icon_armor.gif" alt="armor">',
|
|
3 => '<img src="/img/icon_shield.gif" alt="shield">'
|
|
};
|
|
$page .= '</td>';
|
|
if (user()->weaponid === $item["id"] || user()->armorid === $item["id"] || user()->shieldid === $item["id"]) {
|
|
$page .= <<<HTML
|
|
<td width="32%"><span class="light">{$item["name"]}</span></td>
|
|
<td width="32%"><span class="light">$attrib {$item['attribute']}</span></td>
|
|
<td width="32%"><span class="light">Already purchased</span></td>
|
|
HTML;
|
|
} else {
|
|
$specialdot = $item['special'] !== 'X' ? '<span class="highlight">*</span>' : '';
|
|
$page .= <<<HTML
|
|
<td width="32%"><b><a hx-get="/buy/{$item['id']}" hx-target="#middle">{$item['name']}</a>$specialdot</b></td>
|
|
<td width="32%">$attrib <b>{$item['attribute']}</b></td>
|
|
<td width="32%">Price: <b>{$item['buycost']} gold</b></td>
|
|
HTML;
|
|
}
|
|
$page .= '</tr>';
|
|
}
|
|
$page .= <<<HTML
|
|
</table><br>
|
|
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
|
HTML;
|
|
|
|
return $htmx ? $page : display($page, $town['name'] . ' Shop');
|
|
}
|
|
|
|
/**
|
|
* Confirm user's intent to purchase item.
|
|
*/
|
|
function buy(int $id)
|
|
{
|
|
$town = get_town_by_xy(user()->longitude, user()->latitude);
|
|
if ($town === false) redirect('/');
|
|
if (!in_array($id, explode(',', $town['itemslist']))) redirect('/shop');
|
|
$item = get_item($id);
|
|
$can_afford = user()->gold >= $item['buycost'];
|
|
|
|
if (!$can_afford) {
|
|
$page = <<<HTML
|
|
You do not have enough gold to buy <b>{$item['name']}</b>.<br><br>
|
|
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.
|
|
HTML;
|
|
} elseif (is_post() && !$_POST['buy']) {
|
|
redirect('/shop');
|
|
} elseif (is_post() && $_POST['buy']) {
|
|
$type_mapping = [
|
|
1 => ['id' => 'weaponid', 'name' => 'weaponname', 'power' => 'attackpower'],
|
|
2 => ['id' => 'armorid', 'name' => 'armorname', 'power' => 'defensepower'],
|
|
3 => ['id' => 'shieldid', 'name' => 'shieldname', 'power' => 'defensepower']
|
|
];
|
|
|
|
if (!isset($type_mapping[$item["type"]])) { // should never happen
|
|
$page = 'Error! Invalid item type...<br>'.var_dump($item);
|
|
return is_htmx() ? $page : display($page, '');
|
|
}
|
|
|
|
// Retrieve current equipped item or create a default
|
|
$current_equip_id = user()->{$type_mapping[$item["type"]]['id']};
|
|
if ($current_equip_id != 0) {
|
|
$item2 = get_item($current_equip_id);
|
|
} else {
|
|
$item2 = ["attribute" => 0, "buycost" => 0, "special" => "X"];
|
|
}
|
|
|
|
// Process special item effects
|
|
$specialFields = [];
|
|
$specialValues = [];
|
|
$powerAdjustments = 0;
|
|
|
|
foreach ([$item, $item2] as $index => $process_item) {
|
|
if ($process_item["special"] != "X") {
|
|
$special = explode(",", $process_item["special"]);
|
|
$toChange = $special[0];
|
|
$changeAmount = $index === 0 ? $special[1] : -$special[1];
|
|
|
|
user()->$toChange += $changeAmount;
|
|
$specialFields[] = "$toChange = ?";
|
|
$specialValues[] = user()->$toChange;
|
|
|
|
// Adjust attack or defense power
|
|
if ($toChange == "strength" || $toChange == "dexterity") {
|
|
$powerType = $toChange == "strength" ? "attackpower" : "defensepower";
|
|
$powerAdjustments += $changeAmount;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Determine power and type-specific updates
|
|
$currentType = $type_mapping[$item['type']];
|
|
$powerField = $currentType['power'];
|
|
user()->$powerField += $item['attribute'] - $item2['attribute'];
|
|
|
|
// Calculate new gold with trade-in value
|
|
user()->gold += ceil($item2['buycost'] / 2) - $item['buycost'];
|
|
|
|
// Ensure current HP/MP/TP don't exceed max values
|
|
user()->currenthp = min(user()->currenthp, user()->maxhp);
|
|
user()->currentmp = min(user()->currentmp, user()->maxmp);
|
|
user()->currenttp = min(user()->currenttp, user()->maxtp);
|
|
|
|
// Update item info in user
|
|
user()->{$type_mapping[$item['type']]['id']} = $item['id'];
|
|
user()->{$type_mapping[$item['type']]['name']} = $item['name'];
|
|
|
|
user()->save();
|
|
|
|
$page = <<<HTML
|
|
Thank you for purchasing <b>{$item['name']}</b>.<br><br>
|
|
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.
|
|
HTML;
|
|
} else {
|
|
$type_to_row_mapping = [1 => 'weaponid', 2 => 'armorid', 3 => 'shieldid'];
|
|
$current_equipped_id = user()->{$type_to_row_mapping[$item['type']]} ?? 0;
|
|
|
|
if ($current_equipped_id != 0) {
|
|
$item2 = get_item($current_equipped_id);
|
|
$sell_price = ceil($item2['buycost'] / 2);
|
|
$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>
|
|
<form hx-post="/buy/$id" hx-target="#middle">
|
|
<button name="buy" value="1">Yes</button>
|
|
<button name="buy" value="0">No</button>
|
|
</form>
|
|
HTML;
|
|
} else {
|
|
$page = <<<HTML
|
|
You are buying {$item['name']} for {$item['buycost']} gold, is that ok?<br><br>
|
|
<form hx-post="/buy/$id" hx-target="#middle">
|
|
<button name="buy" value="1">Yes</button>
|
|
<button name="buy" value="0">No</button>
|
|
</form>
|
|
HTML;
|
|
}
|
|
}
|
|
|
|
page_title('Buying '.$item['name']);
|
|
return is_htmx() ? $page : display($page, 'Buying '.$item['name']);
|
|
}
|
|
|
|
/**
|
|
* List maps the user can buy.
|
|
*/
|
|
function maps()
|
|
{
|
|
$page = <<<HTML
|
|
Buying maps will put the town in your Travel To box, and it won't cost you as many TP to get there.<br><br>
|
|
Click a town name to purchase its map.<br><br>
|
|
<table>
|
|
HTML;
|
|
|
|
$mapped = explode(',', user()->towns);
|
|
$towns = db()->query('SELECT * FROM towns ORDER BY id;');
|
|
while ($town = $towns->fetchArray(SQLITE3_ASSOC)) {
|
|
$latitude = ($town["latitude"] >= 0) ? $town["latitude"] . "N," : ($town["latitude"] * -1) . "S,";
|
|
$longitude = ($town["longitude"] >= 0) ? $town["longitude"] . "E" : ($town["longitude"] * -1) . "W";
|
|
|
|
if (in_array($town['id'], $mapped)) {
|
|
$page .= <<<HTML
|
|
<tr>
|
|
<td width="25%"><span class="light">{$town['name']}</span></td>
|
|
<td width="25%"><span class="light">Already mapped.</span></td>
|
|
<td width="35%"><span class="light">Location: $latitude $longitude</span></td>
|
|
<td width="15%"><span class="light">TP: {$town['travelpoints']}</span></td>
|
|
</tr>
|
|
HTML;
|
|
} else {
|
|
$page .= <<<HTML
|
|
<tr>
|
|
<td width="25%"><a href="/maps/{$town['id']}">{$town['name']}</a></td>
|
|
<td width="25%">Price: {$town['mapprice']} gold</td>
|
|
<td width="50%" colspan="2">Buy map to reveal details.</td>
|
|
</tr>
|
|
HTML;
|
|
}
|
|
}
|
|
|
|
$page .= <<<HTML
|
|
</table><br>
|
|
If you've changed your mind, you may also return back to <a hx-get="/" hx-target="#middle">town</a>.
|
|
HTML;
|
|
|
|
page_title('Maps');
|
|
return is_htmx() ? $page : display($page, '');
|
|
}
|
|
|
|
function buy_map(int $id): string
|
|
{
|
|
$town = get_town_by_id($id);
|
|
if ($town === false) redirect('/maps');
|
|
|
|
if (user()->gold < $town['mapprice']) {
|
|
$page = <<<HTML
|
|
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.
|
|
HTML;
|
|
} elseif (is_post() && $_POST['buy']) {
|
|
user()->towns .= ",$id";
|
|
user()->gold -= $town['mapprice'];
|
|
user()->save();
|
|
|
|
$page = <<<HTML
|
|
Thank you for purchasing this map.<br><br>
|
|
You may return to <a hx-get="/" hx-target="#middle">town</a>, <a hx-get="/maps" hx-target="#middle">map shop</a>, or use the direction buttons on the left to start exploring.
|
|
HTML;
|
|
} elseif (is_post() && !$_POST['buy']) {
|
|
redirect('/maps');
|
|
} else {
|
|
$page = <<<HTML
|
|
You are buying the <b>{$town['name']}</b> map for {$town['mapprice']} gold. Is that ok?<br><br>
|
|
<form action="/maps/$id" method="post">
|
|
<button name="buy" value="1">Yes</button>
|
|
<button name="buy" value="0">No</button>
|
|
</form>
|
|
HTML;
|
|
}
|
|
|
|
page_title('Buying '.$town['name'].' Map');
|
|
return is_htmx() ? $page : display($page, '');
|
|
}
|
|
|
|
/**
|
|
* Send a user to a town from the Travel To menu.
|
|
*/
|
|
function travelto($id, bool $usepoints = true)
|
|
{
|
|
if (user()->currentaction == "Fighting") redirect('/fight');
|
|
|
|
$townrow = get_town_by_id($id);
|
|
|
|
if ($usepoints) {
|
|
if (user()->currenttp < $townrow["travelpoints"]) {
|
|
return display("You do not have enough TP to travel here. Please go back and try again when you get more TP.", "Travel To");
|
|
}
|
|
$mapped = explode(",",user()->towns);
|
|
if (!in_array($id, $mapped)) { display("Cheat attempt detected.<br><br>Get a life, loser.", "Error"); }
|
|
}
|
|
|
|
if ((user()->latitude == $townrow["latitude"]) && (user()->longitude == $townrow["longitude"])) {
|
|
return display("You are already in this town. <a href=\"/\">Click here</a> to return to the main town screen.", "Travel To");
|
|
}
|
|
|
|
$newtp = ($usepoints) ? user()->currenttp - $townrow["travelpoints"] : user()->currenttp;
|
|
|
|
$newlat = $townrow["latitude"];
|
|
$newlon = $townrow["longitude"];
|
|
|
|
// If they got here by exploring, add this town to their map.
|
|
$mapped = explode(",",user()->towns);
|
|
$town = false;
|
|
foreach($mapped as $b) if ($b == $id) $town = true;
|
|
$mapped = implode(",", $mapped);
|
|
if ($town == false) $mapped .= ",$id";
|
|
|
|
user()->currentaction = 'In Town';
|
|
user()->towns = $mapped;
|
|
user()->currenttp = $newtp;
|
|
user()->longitude = $newlon;
|
|
user()->latitude = $newlat;
|
|
user()->save();
|
|
|
|
$page = "You have travelled to ".$townrow["name"].". You may now <a href=\"/\">enter this town</a>.";
|
|
return display($page, "Travel To");
|
|
}
|