summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--public/assets/style.css1
-rw-r--r--src/Model/Event/SendResourcesCarriers.php3
-rw-r--r--src/View.php4
-rw-r--r--src/http/Controller/Event.php36
-rw-r--r--src/http/Controller/User.php57
-rw-r--r--src/http/Controller/Village.php44
-rw-r--r--src/http/Router.php3
-rw-r--r--src/http/Support/RouteLoader.php13
-rw-r--r--views/http/account.twig22
-rw-r--r--views/http/base.twig7
-rw-r--r--views/http/components/timer.twig6
-rw-r--r--views/http/village.twig72
12 files changed, 253 insertions, 15 deletions
diff --git a/public/assets/style.css b/public/assets/style.css
index 300d282..a6b425b 100644
--- a/public/assets/style.css
+++ b/public/assets/style.css
@@ -19,6 +19,7 @@ button, input[type="submit"] {
color: #fff;
border: none;
padding: 0.25rem 0.75rem;
+ cursor: pointer;
}
button:hover:not(:disabled), input[type="submit"]:hover:not(:disabled) {
diff --git a/src/Model/Event/SendResourcesCarriers.php b/src/Model/Event/SendResourcesCarriers.php
index b6c3772..d129732 100644
--- a/src/Model/Event/SendResourcesCarriers.php
+++ b/src/Model/Event/SendResourcesCarriers.php
@@ -34,6 +34,9 @@ class SendResourcesCarriers extends BaseEvent
}
}
+ public function cancel(): void
+ {}
+
public function dbInsert(): void
{
DB::query(
diff --git a/src/View.php b/src/View.php
index 10ce9db..761ef62 100644
--- a/src/View.php
+++ b/src/View.php
@@ -25,6 +25,10 @@ class View
// self::$twig->addExtension(new IntlExtension());
self::$twig->addFilter(new TwigFilter('buildTime', function ($buildTime) {
+ if ($buildTime > 3600*24) {
+ return @sprintf('%02d:%02d:%02d:%02d', $buildTime / (3600*24), $buildTime / 3600, ($buildTime / 60) % 60, $buildTime % 60);
+ }
+
return @sprintf('%02d:%02d:%02d', $buildTime / 3600, ($buildTime / 60) % 60, $buildTime % 60);
}));
}
diff --git a/src/http/Controller/Event.php b/src/http/Controller/Event.php
index 8b9b92a..264fa26 100644
--- a/src/http/Controller/Event.php
+++ b/src/http/Controller/Event.php
@@ -8,7 +8,10 @@ use App\Model\Event\SendResources;
use App\Model\Event\SendUnits;
use App\Model\Event\TrainUnits;
use App\Model\Event\UpgradeBuilding;
+use App\Model\Unit;
+use App\Model\Unit\MailCarrier;
use App\Model\Village;
+use App\View;
use App\http\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -20,6 +23,39 @@ class Event
#[Route(path: '/village/{x}/{y}/send-resources', methods: ['POST'])]
public function sendResources(Request $request): Response
{
+ $village = Village::getByCoordinates($request->get('x'), $request->get('y'));
+
+ $totalAmount = $request->get('wood') + $request->get('clay') + $request->get('iron') + $request->get('food');
+
+ $resourceCapabilities = MailCarrier::getResourceCapabilities($village);
+ $necessaryMailCarriers = ceil($totalAmount / $resourceCapabilities);
+ $mailCarriers = DB::fetch(MailCarrier::class, 'select sum(amount) as amount from village_units where type=:type and residence_village_id=:villageId and is_traveling=false', ['villageId' => $village->id, 'type' => 'MailCarrier'])[0]->amount ?? 0;
+ if ($mailCarriers === 0 || $totalAmount > $resourceCapabilities) {
+ return new Response(View::render('error.twig', ['message' => 'Insufficient Mail Carriers']), 403);
+ }
+
+ $destination = Village::get($request->get('village'));
+
+ // event
+ $event = new Model();
+ $event->time = (new \DateTime())->add(
+ \DateInterval::createFromDateString(
+ Unit::getTravelTime(new MailCarrier(), Village::getDistance($village->x, $village->y, $destination->x, $destination->y))
+ . ' seconds'
+ )
+ );
+ $event->villageId = $village->id;
+ $sendResourcesEvent = new SendResources();
+ $sendResourcesEvent->event = $event;
+ $sendResourcesEvent->wood = $request->get('wood');
+ $sendResourcesEvent->clay = $request->get('clay');
+ $sendResourcesEvent->iron = $request->get('iron');
+ $sendResourcesEvent->food = $request->get('food');
+ $sendResourcesEvent->source = $village->id;
+ $sendResourcesEvent->destination = $destination->id;
+ $sendResourcesEvent->dbInsert();
+
+
return new RedirectResponse(
Router::generate(
'village.show',
diff --git a/src/http/Controller/User.php b/src/http/Controller/User.php
new file mode 100644
index 0000000..c47e32e
--- /dev/null
+++ b/src/http/Controller/User.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace App\http\Controller;
+
+use App\DB;
+use App\View;
+use App\http\Router;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Attribute\Route;
+
+class User
+{
+ #[Route(path: '/account', methods: ['GET'])]
+ public function account(Request $request): Response
+ {
+ $user = DB::query('select username,email from users where id=:id', ['id' => $_SESSION['user']['id']])->fetch();
+
+ return new Response(View::render('account.twig', [
+ 'user' => $user,
+ ]));
+ }
+ #[Route(path: '/account', methods: ['POST'])]
+ public function accountSave(Request $request): Response
+ {
+ $username = $request->get('username');
+ $email = $request->get('email');
+
+ if ($request->get('password')) {
+ $password = password_hash($request->get('password'), PASSWORD_DEFAULT);
+ DB::query(
+ 'update users set username=:username, email=:email, password=:password where id=:id',
+ [
+ 'username' => $username,
+ 'email' => $email,
+ 'password' => $password,
+ 'id' => $_SESSION['user']['id'],
+ ]
+ );
+ } else {
+ DB::query(
+ 'update users set username=:username, email=:email where id=:id',
+ [
+ 'username' => $username,
+ 'email' => $email,
+ 'id' => $_SESSION['user']['id'],
+ ]
+ );
+ }
+
+ $_SESSION['user']['username'] = $request->get('username');
+
+
+ return new RedirectResponse(Router::generate('user.account'));
+ }
+}
diff --git a/src/http/Controller/Village.php b/src/http/Controller/Village.php
index 7b1f227..2d6aa39 100644
--- a/src/http/Controller/Village.php
+++ b/src/http/Controller/Village.php
@@ -4,6 +4,8 @@ namespace App\http\Controller;
use App\DB;
use App\Guard;
+use App\Model\Event\SendResources;
+use App\Model\Event\SendResourcesCarriers;
use App\Model\Event\SendUnits;
use App\Model\Event\TrainUnits;
use App\Model\Event\UpgradeBuilding;
@@ -27,7 +29,7 @@ class Village
join user_villages on villages.id = user_villages.village_id
where user_villages.user_id=:id
SQL,
- ['id' => $_SESSION['user']['id']]
+ ['id' => $_SESSION['user']['id'] ?? -1]
);
return new Response(View::render('villages.twig', [
@@ -90,6 +92,46 @@ class Village
$events['SendUnits'][] = DB::convertToModel(SendUnits::class, $row);;
}
+ $eventsResourcesSendOwn = DB::query(
+ <<<SQL
+ select * from events_send_resources as event
+ left join events on event.event_id = events.id
+ where village_id=:id
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ $eventsResourcesSendOther = DB::query(
+ <<<SQL
+ select * from events_send_resources as event
+ left join events on event.event_id = events.id
+ where (destination=:id or source=:id) and village_id!=:id and is_canceled=false
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ foreach ([...$eventsResourcesSendOwn, ...$eventsResourcesSendOther] as $row) {
+ $events['SendResources'][] = DB::convertToModel(SendResources::class, $row);;
+ }
+
+ $eventsResourcesCarriersSendOwn = DB::query(
+ <<<SQL
+ select * from events_send_resources_carriers as event
+ left join events on event.event_id = events.id
+ where village_id=:id
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ $eventsResourcesCarriersSendOther = DB::query(
+ <<<SQL
+ select * from events_send_resources_carriers as event
+ left join events on event.event_id = events.id
+ where (destination=:id or source=:id) and village_id!=:id
+ SQL, ['id' => $village->id]
+ )->fetchAll();
+
+ foreach ([...$eventsResourcesCarriersSendOwn, ...$eventsResourcesCarriersSendOther] as $row) {
+ $events['SendResourcesCarriers'][] = DB::convertToModel(SendResourcesCarriers::class, $row);;
+ }
+
$buildings = [];
foreach (Model::getBuildings($village->id, true) as $building) {
$buildings[$building->type] = $building;
diff --git a/src/http/Router.php b/src/http/Router.php
index db75f81..62f0514 100644
--- a/src/http/Router.php
+++ b/src/http/Router.php
@@ -10,6 +10,7 @@ use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\Loader\AnnotationFileLoader;
+use Symfony\Component\Routing\Loader\AttributeFileLoader;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
@@ -28,7 +29,7 @@ class Router
self::$context->fromRequest($request);
self::$routes = new RouteCollection();
- $loader = new AnnotationFileLoader(new FileLocator(), new RouteLoader());
+ $loader = new AttributeFileLoader(new FileLocator(), new RouteLoader());
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/Controller'));
foreach ($iterator as $file) {
/**@var \SplFileInfo $file*/
diff --git a/src/http/Support/RouteLoader.php b/src/http/Support/RouteLoader.php
index b0e74cb..d11011c 100644
--- a/src/http/Support/RouteLoader.php
+++ b/src/http/Support/RouteLoader.php
@@ -2,10 +2,10 @@
namespace App\http\Support;
-use Symfony\Component\Routing\Loader\AnnotationClassLoader;
+use Symfony\Component\Routing\Loader\AttributeClassLoader;
use Symfony\Component\Routing\Route;
-class RouteLoader extends AnnotationClassLoader
+class RouteLoader extends AttributeClassLoader
{
protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annotation) {
$route->setDefault('_', compact('class', 'method', 'annotation'));
@@ -15,10 +15,9 @@ class RouteLoader extends AnnotationClassLoader
{
$name = parent::getDefaultRouteName($class, $method);
- return str_replace(
- '_',
- '.',
- str_replace('app_controller_', '', $name)
- );
+ $name = preg_replace('/app_\w+_controller_/', '', $name);
+ $name = str_replace('_', '.', $name);
+
+ return $name;
}
}
diff --git a/views/http/account.twig b/views/http/account.twig
new file mode 100644
index 0000000..8b32feb
--- /dev/null
+++ b/views/http/account.twig
@@ -0,0 +1,22 @@
+{% extends 'base.twig' %}
+
+{% block main %}
+<h1>Account</h1>
+
+<form action="/account" method="post">
+ <label>
+ Username
+ <input type="text" name="username" value="{{ user.username }}">
+ </label>
+ <label>
+ E-Mail
+ <input type="email" name="email" value="{{ user.email }}">
+ </label>
+ <label>
+ Password
+ <input type="password" name="password">
+ </label>
+
+ <input type="submit" value="Save">
+</form>
+{% endblock %}
diff --git a/views/http/base.twig b/views/http/base.twig
index 15ddafd..bd59207 100644
--- a/views/http/base.twig
+++ b/views/http/base.twig
@@ -5,7 +5,12 @@
<header>
<nav>
<a href="/villages">Overview</a>
- <a href="/logout">Logout</a>
+ {% if session.user %}
+ <a href="/account">Account</a>
+ <a href="/logout">Logout</a>
+ {% else %}
+ <a href="/login">Login</a>
+ {% endif %}
</nav>
<span>Logged in as {{ session.user.username }}</span>
</header>
diff --git a/views/http/components/timer.twig b/views/http/components/timer.twig
index ccb31a7..4898a2e 100644
--- a/views/http/components/timer.twig
+++ b/views/http/components/timer.twig
@@ -14,12 +14,18 @@ document.addEventListener('DOMContentLoaded', function (ev) {
window.location.reload();
}
+ const dd = Math.floor(diff/1000/60/60/24);
+ diff -= dd*1000*60*60*24;
const hh = Math.floor(diff/1000/60/60);
diff -= hh*1000*60*60;
const mm = Math.floor(diff/1000/60);
diff -= mm*1000*60;
const ss = Math.floor(diff/1000);
+
timer.innerHTML = `${('00' + hh).slice(-2)}:${('00' + mm).slice(-2)}:${('00' + ss).slice(-2)}`;
+ if (dd > 0) {
+ timer.innerHTML = `${('00' + dd).slice(-2)}:${timer.innerHTML}`;
+ }
}
setTime();
});
diff --git a/views/http/village.twig b/views/http/village.twig
index c157a04..a498ea6 100644
--- a/views/http/village.twig
+++ b/views/http/village.twig
@@ -132,7 +132,7 @@
{% endif %}
{% if events['SendUnits'] %}
- <h4>Send Resources / Units</h4>
+ <h4>Send Units</h4>
<table>
<thead>
<tr>
@@ -172,6 +172,68 @@
</tbody>
</table>
{% endif %}
+
+ {% if events['SendResources'] %}
+ <h4>Send Resources</h4>
+ <table>
+ <thead>
+ <tr>
+ <th>Source</th>
+ <th>Destination</th>
+ <th>Resources</th>
+ <th>Time</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for event in events['SendResources'] %}
+ <tr>
+ <td>{{ village.get(event.source).name }}</td>
+ <td>{{ village.get(event.destination).name }}</td>
+ <td>Resources</td>
+ <td class="timer">
+ {% include 'components/timer.twig' with { 'time': event.event.time|date('c') } %}
+ </td>
+ <td>
+ {% if event.isCanceled %}
+ Canceled
+ {% else %}
+ {% if event.event.villageId == village.id %}
+ <form action="/event/{{ event.event.id }}/cancel" method="post">
+ <input type="submit" value="Cancel">
+ </form>
+ {% endif %}
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endif %}
+
+ {% if events['SendResourcesCarriers'] %}
+ <h4>Send Resources Carriers</h4>
+ <table>
+ <thead>
+ <tr>
+ <th>Source</th>
+ <th>Destination</th>
+ <th>Time</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for event in events['SendResourcesCarriers'] %}
+ <tr>
+ <td>{{ village.get(event.source).name }}</td>
+ <td>{{ village.get(event.destination).name }}</td>
+ <td class="timer">
+ {% include 'components/timer.twig' with { 'time': event.event.time|date('c') } %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endif %}
</div>
<div class="village__main">
@@ -344,10 +406,10 @@
{% if village.getBuilding(village.id, 'PostOffice') %}
<h3>Send Resources</h3>
<form action="/village/{{ village.x }}/{{ village.y }}/send-resources" method="post">
- <input type="number" min="1" name="wood" placeholder="Amount Wood" required>
- <input type="number" min="1" name="clay" placeholder="Amount Clay" required>
- <input type="number" min="1" name="iron" placeholder="Amount Iron" required>
- <input type="number" min="1" name="food" placeholder="Amount Food" required>
+ <input type="number" min="0" name="wood" placeholder="Amount Wood" required>
+ <input type="number" min="0" name="clay" placeholder="Amount Clay" required>
+ <input type="number" min="0" name="iron" placeholder="Amount Iron" required>
+ <input type="number" min="0" name="food" placeholder="Amount Food" required>
<select name="village">
{% for v in villages %}
<option value="{{ v.id }}">{{ v.name }}</option>