diff options
author | Daniel Weipert <code@drogueronin.de> | 2023-11-29 09:35:27 +0100 |
---|---|---|
committer | Daniel Weipert <code@drogueronin.de> | 2023-11-29 09:35:27 +0100 |
commit | 3afcaef927391db23fe23c6c8c26b8960e8dae32 (patch) | |
tree | 143b9f6df9e8c795c8c6ed901bffdc7119f40df1 | |
parent | c4ce3e884a6aa527bcc138771617215cf03265a4 (diff) |
intermediate commit
32 files changed, 542 insertions, 91 deletions
diff --git a/.env.example b/.env.example index 072c25f..6cd359f 100644 --- a/.env.example +++ b/.env.example @@ -10,3 +10,4 @@ BASE_UNIT_BUILD_TIME_FACTOR=256 BASE_UNIT_TRAVEL_TIME_FACTOR=60 BASE_UNIT_RESOURCE_REQUIREMENT_FACTOR=64 BASE_RESOURCE_GENERATION_FACTOR=128 +BASE_STORAGE_CAPACITY_FACTOR=2048 @@ -1,3 +1,4 @@ .env +config.yml /vendor/ diff --git a/bin/villages.php b/bin/db.php index 092a754..951c0b3 100644 --- a/bin/villages.php +++ b/bin/db.php @@ -25,8 +25,8 @@ DB::query(<<<SQL "food" bigint not null, "satisfaction" bigint not null, - "created_at" timestamp(0) not null, - "updated_at" timestamp(0) not null, + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp, unique ("x", "y") ); @@ -43,8 +43,8 @@ DB::query(<<<SQL constraint "relation_village" foreign key ("village_id") references villages("id") on delete cascade, - "created_at" timestamp(0) not null, - "updated_at" timestamp(0) not null, + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp, unique ("type", "village_id") ); @@ -67,8 +67,8 @@ DB::query(<<<SQL constraint "relation_village_residence" foreign key ("residence_village_id") references villages("id") on delete cascade, - "created_at" timestamp(0) not null, - "updated_at" timestamp(0) not null, + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp, unique ("type", "home_village_id", "residence_village_id") ); @@ -87,8 +87,8 @@ DB::query(<<<SQL constraint "relation_village" foreign key ("village_id") references villages("id") on delete cascade, - "created_at" timestamp(0) not null, - "updated_at" timestamp(0) not null + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp ); SQL); @@ -96,9 +96,7 @@ DB::query(<<<SQL create table if not exists "events" ( "id" bigserial primary key, - "type" character varying(255) not null, "time" timestamp(0) not null, - "payload" jsonb not null, "village_id" bigint not null, constraint "relation_village" @@ -110,6 +108,21 @@ DB::query(<<<SQL SQL); DB::query(<<<SQL + create table if not exists "events_upgrade_building" ( + "id" bigserial primary key, + + "event_id" bigint not null, + constraint "relation_event" + foreign key ("event_id") references events("id") on delete cascade, + + "type" character varying(255) not null, + + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp + ); +SQL); + +DB::query(<<<SQL create table if not exists "users" ( "id" bigserial primary key, @@ -117,8 +130,8 @@ DB::query(<<<SQL "password" character varying(255) not null, "email" character varying(255) not null, - "created_at" timestamp(0) not null, - "updated_at" timestamp(0) not null, + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp, unique ("username") ); @@ -134,8 +147,8 @@ DB::query(<<<SQL constraint "relation_user" foreign key ("user_id") references users("id") on delete cascade, - "created_at" timestamp(0) not null, - "updated_at" timestamp(0) not null + "created_at" timestamp(0) not null default current_timestamp, + "updated_at" timestamp(0) not null default current_timestamp ); SQL); diff --git a/public/assets/img/map.jpg b/public/assets/img/map.jpg Binary files differnew file mode 100644 index 0000000..0ad74a7 --- /dev/null +++ b/public/assets/img/map.jpg diff --git a/public/assets/style.css b/public/assets/style.css index 8a40e43..e7472ed 100644 --- a/public/assets/style.css +++ b/public/assets/style.css @@ -3,6 +3,10 @@ body { color: #000; } +* { + box-sizing: border-box; +} + .wrap { max-width: 1200px; @@ -63,6 +67,22 @@ button:disabled, input[type="submit"]:disabled { background-image: url("/assets/img/icons/1F4E5.svg"); } +.icon-arrow-up { + background-image: url("/assets/img/icons/1F53A.svg"); +} +.icon-arrow-down { + background-image: url("/assets/img/icons/1F53A.svg"); + transform: rotate(180deg); +} +.icon-arrow-left { + background-image: url("/assets/img/icons/1F53A.svg"); + transform: rotate(270deg); +} +.icon-arrow-right { + background-image: url("/assets/img/icons/1F53A.svg"); + transform: rotate(90deg); +} + /* Village */ @@ -91,14 +111,76 @@ button:disabled, input[type="submit"]:disabled { /* Map */ +.map { + position: relative; + padding: 2rem; +} + +.map__up, .map__down { + position: absolute; + width: 100%; + text-align: center; +} + +.map__up { + top: 0; + left: 0; +} + +.map__down { + bottom: 0; + left: 0; +} + +.map__left, .map__right { + position: absolute; + height: 100%; + + display: flex; + align-items: center; +} + +.map__left { + left: 0; + top: 0; +} + +.map__right { + right: 0; + top: 0; +} + +.map .icon { + font-size: 1.5rem; +} + + .map__villages { --map-range: 1; display: grid; + + background-image: url('/assets/img/map.jpg'); + background-position: center; + background-size: cover; + + min-height: 75vh; } + .map__village { border: 1px solid #000; min-width: 1rem; min-height: 1rem; + + display: flex; + justify-content: center; + align-items: center; +} + +.map__village a { + text-decoration: none; + border: 2px solid #fff; + padding: 0 0.25rem; + background: rgba(255, 255, 255, 0.8); } diff --git a/src/Controller/Building.php b/src/Controller/Building.php index d8fe656..6199286 100644 --- a/src/Controller/Building.php +++ b/src/Controller/Building.php @@ -5,6 +5,7 @@ namespace App\Controller; use App\DB; use App\Model\Building as Model; use App\Model\Event; +use App\Model\Event\UpgradeBuilding; use App\Model\Village; use App\Router; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -18,7 +19,7 @@ class Building public function levelUp(Request $request): Response { $village = Village::getByCoordinates($request->get('x'), $request->get('y')); - $building = Model::getByVillage($village->id, $request->get('type')); + $building = Model::getByVillage($village->id, $request->get('type')) ?? Model::getEmpty($village->id, $request->get('type')); // resources foreach ($building->getResourceRequirements() as $resourceType => $resourceValue) { @@ -27,11 +28,12 @@ class Building $village->updateResources(); // event - $event = new Event(); + $event = new UpgradeBuilding(); $event->type = 'UpgradeBuilding'; $event->time = (new \DateTime())->add(\DateInterval::createFromDateString($building->getBuildTime() . ' seconds')); $event->payload = json_encode([ - 'id' => $building->id, + 'type' => $building->type, + 'village_id' => $building->villageId, ]); DB::query( diff --git a/src/Controller/Event.php b/src/Controller/Event.php new file mode 100644 index 0000000..a6538fe --- /dev/null +++ b/src/Controller/Event.php @@ -0,0 +1,65 @@ +<?php + +namespace App\Controller; + +use App\DB; +use App\Model\Event as Model; +use App\Model\Village; +use App\Router; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; + +class Event +{ + #[Route(path: '/village/{x}/{y}/send-resources', methods: ['POST'])] + public function sendResources(Request $request): Response + { + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $request->get('x'), 'y' => $request->get('y')] + ) + ); + } + + #[Route(path: '/event/{id}/cancel', methods: ['POST'])] + public function cancel(Request $request): Response + { + $event = DB::fetch(Model::class, 'select * from events where id=:id', ['id' => $request->get('id')])[0] ?? null; + $village = Village::get($event->villageId); + + if ($event->type === 'SendUnits') { + $payload = json_decode($event->payload, true); + + if ($payload['type'] === 'SendBack') { + $cancelTimeDiff = $event->createdAt->diff(new \DateTime()); + $cancelTime = (new \DateTime())->add($cancelTimeDiff); + + $cancelPayload = array_replace_recursive($payload, [ + 'cancel' => [ + 'home' => $payload['destination'], + 'residence' => $payload['source'], + ], + ]); + + DB::query( + 'update events set time=:time, payload=:payload where id=:id', + ['time' => $cancelTime->format('c'), 'payload' => json_encode($cancelPayload), 'id' => $request->get('id')] + ); + } + } + + else { + DB::query('delete from event where id=:id', ['id' => $request->get('id')]); + } + + return new RedirectResponse( + Router::generate( + 'village.show', + ['x' => $village->x, 'y' => $village->y] + ) + ); + } +} diff --git a/src/Controller/Unit.php b/src/Controller/Unit.php index 602c6e8..c57ff01 100644 --- a/src/Controller/Unit.php +++ b/src/Controller/Unit.php @@ -226,7 +226,7 @@ class Unit ) ); $event->payload = json_encode([ - 'type' => 'Borrow', + 'type' => $request->get('type'), 'unit' => $request->get('unit'), 'amount' => $amount, 'source' => $village->id, diff --git a/src/Controller/Village.php b/src/Controller/Village.php index dfca298..59e6d4b 100644 --- a/src/Controller/Village.php +++ b/src/Controller/Village.php @@ -34,9 +34,7 @@ class Village $eventsBuilding = DB::query( <<<SQL - select events.*, village_buildings.type as building from events - join village_buildings - on village_buildings.id=(events.payload->'id')::bigint + select * from events where events.village_id=:id and events.type=:type SQL, ['id' => $village->id, 'type' => 'UpgradeBuilding'] )->fetchAll(); @@ -44,9 +42,7 @@ class Village foreach ($eventsBuilding as $row) { $events[$row['type']][] = [ 'event' => DB::convertToModel(UpgradeBuilding::class, $row), - 'data' => [ - 'building' => $row['building'], - ], + 'data' => json_decode($row['payload']), ]; } @@ -64,23 +60,36 @@ class Village ]; } - $eventsUnitsSend = DB::query( + $eventsUnitsSendOwn = DB::query( <<<SQL select * from events - where type=:type and (village_id=:id or (payload->>'destination')::bigint=:id) + where type=:type and village_id=:id SQL, ['type' => 'SendUnits', 'id' => $village->id] )->fetchAll(); - foreach ($eventsUnitsSend as $row) { + $eventsUnitsSendOther = DB::query( + <<<SQL + select * from events + where type=:type and (payload->>'destination')::bigint=:id and (payload->>'cancel') is null + SQL, ['type' => 'SendUnits', 'id' => $village->id] + )->fetchAll(); + + foreach ([...$eventsUnitsSendOwn, ...$eventsUnitsSendOther] as $row) { $events[$row['type']][] = [ 'event' => DB::convertToModel(SendUnits::class, $row), 'data' => json_decode($row['payload'], true), ]; } + $buildings = []; + foreach (Model::getBuildings($village->id, true) as $building) { + $buildings[$building->type] = $building; + } + return new Response(View::render('village.twig', [ 'village' => $village, 'events' => $events, + 'buildings' => $buildings, 'villages' => DB::fetch(Model::class, "select * from villages where id!=:id", ['id' => $village->id]), ])); } @@ -3,7 +3,7 @@ namespace App; class DB { - private static \PDO $connection; + public static \PDO $connection; public static function init(): void { diff --git a/src/EventRunner.php b/src/EventRunner.php index 4f3bce9..a071d32 100644 --- a/src/EventRunner.php +++ b/src/EventRunner.php @@ -31,6 +31,15 @@ class EventRunner ); } + # Upgrade Building + + $results = DB::query(<<<SQL + select * from events + inner join event_upgrade_building as event + on events.id = event.event_id + where events.time < now() + SQL)->fetchAll(); + // Resources diff --git a/src/Model.php b/src/Model.php index 5f45ed4..2720486 100644 --- a/src/Model.php +++ b/src/Model.php @@ -9,7 +9,7 @@ class Model $object = new $cast(); foreach (get_class_vars(get_class($original)) as $property => $_) { - if (! empty($original->$property) && empty($object->$property)) { + if (isset($original->$property) && ! isset($object->$property)) { $object->$property = $original->$property; } } diff --git a/src/Model/Building.php b/src/Model/Building.php index 78d1aa5..7cae067 100644 --- a/src/Model/Building.php +++ b/src/Model/Building.php @@ -54,6 +54,16 @@ class Building return isset($results[0]) ? $results[0]->cast() : null; } + public static function getEmpty(int $villageId, string $buildingType): Building + { + $building = new Building(); + $building->type = $buildingType; + $building->level = 0; + $building->villageId = $villageId; + + return $building->cast(); + } + public function getBuildTime(): int { diff --git a/src/Model/Building/ClayPit.php b/src/Model/Building/ClayPit.php index 8127818..b4905eb 100644 --- a/src/Model/Building/ClayPit.php +++ b/src/Model/Building/ClayPit.php @@ -10,6 +10,8 @@ class ClayPit extends ResourceGenerator public array $resourceRequirements = [ 'wood' => 1.0, + 'clay' => 2.0, + 'iron' => 1.0, ]; public string $resourceType = 'clay'; diff --git a/src/Model/Building/Embassy.php b/src/Model/Building/Embassy.php new file mode 100644 index 0000000..3be1f7f --- /dev/null +++ b/src/Model/Building/Embassy.php @@ -0,0 +1,17 @@ +<?php + +namespace App\Model\Building; + +use App\Model\Building; + +class Embassy extends Building +{ + public int $buildTimeFactor = 1; + public int $maxLevel = 25; + + public array $resourceRequirements = [ + 'wood' => 25.0, + 'clay' => 25.0, + 'iron' => 30.0, + ]; +} diff --git a/src/Model/Building/Farm.php b/src/Model/Building/Farm.php index aaa58b5..222d8cd 100644 --- a/src/Model/Building/Farm.php +++ b/src/Model/Building/Farm.php @@ -13,6 +13,8 @@ class Farm extends ResourceGenerator public array $resourceRequirements = [ 'wood' => 1.0, + 'clay' => 1.0, + 'iron' => 1.0, ]; public string $resourceType = 'food'; diff --git a/src/Model/Building/IronMine.php b/src/Model/Building/IronMine.php index 4bf5cc6..d240e3a 100644 --- a/src/Model/Building/IronMine.php +++ b/src/Model/Building/IronMine.php @@ -10,6 +10,8 @@ class IronMine extends ResourceGenerator public array $resourceRequirements = [ 'wood' => 1.0, + 'clay' => 1.0, + 'iron' => 2.0, ]; public string $resourceType = 'iron'; diff --git a/src/Model/Building/Marketplace.php b/src/Model/Building/Marketplace.php new file mode 100644 index 0000000..714de0d --- /dev/null +++ b/src/Model/Building/Marketplace.php @@ -0,0 +1,17 @@ +<?php + +namespace App\Model\Building; + +use App\Model\Building; + +class Marketplace extends Building +{ + public int $buildTimeFactor = 1; + public int $maxLevel = 25; + + public array $resourceRequirements = [ + 'wood' => 10.0, + 'clay' => 10.0, + 'iron' => 8.0, + ]; +} diff --git a/src/Model/Building/Storage.php b/src/Model/Building/Storage.php index fde4c4e..de2df92 100644 --- a/src/Model/Building/Storage.php +++ b/src/Model/Building/Storage.php @@ -12,11 +12,13 @@ class Storage extends Building public array $resourceRequirements = [ 'wood' => 1.0, + 'clay' => 1.0, + 'iron' => 1.0, ]; public function getCapacity(): int { - return $this->level * 2560; + return $this->level * $_ENV['BASE_STORAGE_CAPACITY_FACTOR']; } public function getResourceCapacity(string $resourceType): int diff --git a/src/Model/Building/WoodCutter.php b/src/Model/Building/WoodCutter.php index 86bde9b..726cdbc 100644 --- a/src/Model/Building/WoodCutter.php +++ b/src/Model/Building/WoodCutter.php @@ -9,7 +9,9 @@ class WoodCutter extends ResourceGenerator public int $maxLevel = 25; public array $resourceRequirements = [ - 'wood' => 1.0, + 'wood' => 2.0, + 'clay' => 1.0, + 'iron' => 1.0, ]; public string $resourceType = 'wood'; diff --git a/src/Model/Event.php b/src/Model/Event.php index aa235f9..b4c131e 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -14,6 +14,9 @@ class Event public int $villageId; + public \DateTime $createdAt; + public \DateTime $updatedAt; + /* OOP */ diff --git a/src/Model/Event/BaseEvent.php b/src/Model/Event/BaseEvent.php new file mode 100644 index 0000000..d3cc3fb --- /dev/null +++ b/src/Model/Event/BaseEvent.php @@ -0,0 +1,14 @@ +<?php + +namespace App\Model\Event; + +abstract class BaseEvent +{ + public int $id; + public int $eventId; + + public \DateTime $createdAt; + public \DateTime $updatedAt; + + abstract function sqlInsert(): void; +} diff --git a/src/Model/Event/SendUnits.php b/src/Model/Event/SendUnits.php index f104a08..bf81031 100644 --- a/src/Model/Event/SendUnits.php +++ b/src/Model/Event/SendUnits.php @@ -14,28 +14,75 @@ class SendUnits extends Event { $payload = json_decode($this->payload, true); - if ($payload['type'] === 'Recall' || $payload['type'] === 'SendBack') { - DB::query( - <<<SQL - insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) - values (:amount, :type, false, :id, :id) - on conflict (type, home_village_id, residence_village_id) - do update set amount = village_units.amount+:amount - SQL, - ['amount' => $payload['amount'], 'type' => $payload['unit'], 'id' => $payload['destination']] - ); + if (isset($payload['cancel'])) { + if ($payload['type'] === 'SendBack') { + $payload['source'] = $payload['cancel']['home']; + $payload['destination'] = $payload['cancel']['residence']; + + $this->borrow($payload); + } } - else if ($payload['type'] === 'Borrow') { - DB::query( - <<<SQL - insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id, created_at, updated_at) - values (:amount, :type, false, :home, :residence, now(), now()) - on conflict (type, home_village_id, residence_village_id) - do update set amount = village_units.amount+:amount - SQL, - ['amount' => $payload['amount'], 'type' => $payload['unit'], 'home' => $this->villageId, 'residence' => $payload['destination']] - ); + else { + if ($payload['type'] === 'Recall' || $payload['type'] === 'SendBack') { + $this->return($payload); + } + + else if ($payload['type'] === 'Borrow') { + $this->borrow($payload); + } + + else if ($payload['type'] === 'Gift') { + $this->gift($payload); + } } } + + /** + * @param array $payload + */ + private function return(array $payload): void + { + DB::query( + <<<SQL + insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) + values (:amount, :type, false, :id, :id) + on conflict (type, home_village_id, residence_village_id) + do update set amount = village_units.amount+:amount + SQL, + ['amount' => $payload['amount'], 'type' => $payload['unit'], 'id' => $payload['destination']] + ); + } + + /** + * @param array $payload + */ + private function borrow(array $payload): void + { + DB::query( + <<<SQL + insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) + values (:amount, :type, false, :home, :residence) + on conflict (type, home_village_id, residence_village_id) + do update set amount = village_units.amount+:amount + SQL, + ['amount' => $payload['amount'], 'type' => $payload['unit'], 'home' => $payload['source'], 'residence' => $payload['destination']] + ); + } + + /** + * @param array $payload + */ + private function gift(array $payload): void + { + DB::query( + <<<SQL + insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id) + values (:amount, :type, false, :home, :residence) + on conflict (type, home_village_id, residence_village_id) + do update set amount = village_units.amount+:amount + SQL, + ['amount' => $payload['amount'], 'type' => $payload['unit'], 'home' => $payload['destination'], 'residence' => $payload['destination']] + ); + } } diff --git a/src/Model/Event/UpgradeBuilding.php b/src/Model/Event/UpgradeBuilding.php index c014cfe..f4f427d 100644 --- a/src/Model/Event/UpgradeBuilding.php +++ b/src/Model/Event/UpgradeBuilding.php @@ -5,23 +5,43 @@ namespace App\Model\Event; use App\DB; use App\Model\Event; -class UpgradeBuilding extends Event +class UpgradeBuilding extends BaseEvent { + public Event $event; + public string $type; + + public function __construct(Event $event, string $type) + { + $this->event = $event; + $this->type = $type; + } + /** * @return void */ public function __invoke(): void { - $payload = json_decode($this->payload, true); + DB::query( + <<<SQL + insert into village_buildings (level, type, village_id) + values (1, :type, :village_id) + on conflict (type, village_id) + do update set level = village_buildings.level+1 + SQL, + ['type' => $this->type, 'village_id' => $this->event->villageId] + ); + } + public function sqlInsert(): void + { DB::query( - 'update village_buildings set level=level+1 where id=:id', - ['id' => $payload['id']] + 'insert into events (time, village_id) values (:time, :village_id)', + ['time' => $this->event->time->format('c'), 'village_id' => $this->event->villageId] ); DB::query( - 'delete from events where id=:id', - ['id' => $this->id] + 'insert into events_upgrade_building (event_id, type) values (:event_id, :type)', + ['event_id' => DB::$connection->lastInsertId(), $this->type] ); } } diff --git a/src/Model/Unit.php b/src/Model/Unit.php index 621651c..d563682 100644 --- a/src/Model/Unit.php +++ b/src/Model/Unit.php @@ -25,9 +25,26 @@ class Unit public array $resourceRequirements = []; + public static function getEmpty(int $villageId, string $unitType): Unit + { + $unit = new Unit(); + $unit->type = $unitType; + $unit->homeVillageId = $villageId; + $unit->amount = 0; + + return $unit->cast(); + } + + public function getBuildTime(int $amount): int { - return intval(($_ENV['BASE_UNIT_BUILD_TIME_FACTOR'] / ($this->getBuilding()->level ?: 1)) * $amount); + $building = $this->getBuilding(); + + if (! $building) { + return -1; + } + + return intval(($_ENV['BASE_UNIT_BUILD_TIME_FACTOR'] / ($building->level ?: 1)) * $amount); } public static function getTravelTime(Unit $unit, int $distance): int @@ -63,7 +80,16 @@ class Unit function ($resourceRequirement) use ($amount, $currentAmount, $building) { $r = 0; for ($i = 0; $i <= $amount; $i++) { - $r += ceil((pow($_ENV['BASE_UNIT_RESOURCE_REQUIREMENT_BASE'], $currentAmount + 1) * $resourceRequirement * $_ENV['BASE_UNIT_RESOURCE_REQUIREMENT_FACTOR']) / ($building->level ?? 1)); + $r += ceil( + ( + pow( + $_ENV['BASE_UNIT_RESOURCE_REQUIREMENT_BASE'], + $currentAmount + 1 + ) + * $resourceRequirement * $_ENV['BASE_UNIT_RESOURCE_REQUIREMENT_FACTOR'] + ) + / ($building->level ?? 1) + ); } return $r; diff --git a/src/Model/Unit/Diplomat.php b/src/Model/Unit/Diplomat.php new file mode 100644 index 0000000..e263cd3 --- /dev/null +++ b/src/Model/Unit/Diplomat.php @@ -0,0 +1,18 @@ +<?php + +namespace App\Model\Unit; + +use App\Model\Unit; + +class Diplomat extends Unit +{ + public string $buildingType = 'Embassy'; + public int $travelTime = 1; + public int $populationDemandFactor = 1; + public array $resourceRequirements = [ + 'wood' => 5.0, + 'clay' => 5.0, + 'iron' => 5.0, + 'food' => 5.0, + ]; +} diff --git a/src/Model/Unit/Merchant.php b/src/Model/Unit/Merchant.php new file mode 100644 index 0000000..61e2090 --- /dev/null +++ b/src/Model/Unit/Merchant.php @@ -0,0 +1,18 @@ +<?php + +namespace App\Model\Unit; + +use App\Model\Unit; + +class Merchant extends Unit +{ + public string $buildingType = 'Marketplace'; + public int $travelTime = 1; + public int $populationDemandFactor = 1; + public array $resourceRequirements = [ + 'wood' => 2.0, + 'clay' => 2.0, + 'iron' => 2.0, + 'food' => 2.0, + ]; +} diff --git a/src/Model/Village.php b/src/Model/Village.php index b1ab19e..6c80ed0 100644 --- a/src/Model/Village.php +++ b/src/Model/Village.php @@ -80,10 +80,21 @@ class Village /* DB - Relations */ - public static function getBuildings(int $villageId): array + public static function getBuildings(int $villageId, bool $withEmpty = false): array { $buildings = DB::fetch(Building::class, 'select * from village_buildings where village_id=:id', ['id' => $villageId]); + if ($withEmpty) { + $nonBuiltBuildings = array_diff( + ['TownHall', 'Embassy', 'Marketplace', 'Storage', 'WoodCutter', 'ClayPit', 'IronMine', 'Farm'], + array_column($buildings, 'type'), + ); + + foreach ($nonBuiltBuildings as $type) { + $buildings[] = Building::getEmpty($villageId, $type); + } + } + return array_map(function (Building $building) { return $building->cast(); }, $buildings); @@ -121,30 +132,51 @@ class Village public const FETCH_UNIT_SUPPORT_AT_HOME = 3; public const FETCH_UNIT_RESIDENCE = 4; + public const RETURN_UNIT_EXISTING = 1; + public const RETURN_UNIT_ALL = 2; + public const RETURN_UNIT_TRAINABLE = 3; + public static function getUnit(string $unitType, int $flag): ?Unit { } /** - * @param int $flag + * @param int $fetchFlag * * @return array<int, Unit> */ - public static function getUnits(int $villageId, $flag = Village::FETCH_UNIT_ALL): array + public static function getUnits(int $villageId, int $fetchFlag = Village::FETCH_UNIT_ALL, int $returnFlag = Village::RETURN_UNIT_EXISTING): array { - if ($flag == Village::FETCH_UNIT_HOME_AT_HOME) { + if ($fetchFlag == Village::FETCH_UNIT_HOME_AT_HOME) { $units = DB::fetch(Unit::class, 'select * from village_units where home_village_id=:id and residence_village_id=:id', ['id' => $villageId]); } - else if ($flag == Village::FETCH_UNIT_HOME_AT_SUPPORT) { + else if ($fetchFlag == Village::FETCH_UNIT_HOME_AT_SUPPORT) { $units = DB::fetch(Unit::class, 'select * from village_units where home_village_id=:id and residence_village_id!=:id', ['id' => $villageId]); } - else if ($flag == Village::FETCH_UNIT_SUPPORT_AT_HOME) { + else if ($fetchFlag == Village::FETCH_UNIT_SUPPORT_AT_HOME) { $units = DB::fetch(Unit::class, 'select * from village_units where home_village_id!=:id and residence_village_id=:id', ['id' => $villageId]); } - else if ($flag == Village::FETCH_UNIT_RESIDENCE) { + else if ($fetchFlag == Village::FETCH_UNIT_RESIDENCE) { $units = DB::fetch(Unit::class, 'select * from village_units where residence_village_id=:id', ['id' => $villageId]); } + if ($returnFlag == Village::RETURN_UNIT_ALL || $returnFlag == Village::RETURN_UNIT_TRAINABLE) { + $nonExistingUnits = array_diff( + ['WoodCutter', 'PitWorker', 'Miner', 'Farmer', 'Merchant', 'Diplomat'], + array_column($units, 'type'), + ); + + foreach ($nonExistingUnits as $type) { + $units[] = Unit::getEmpty($villageId, $type); + } + + if ($returnFlag == Village::RETURN_UNIT_TRAINABLE) { + $units = array_filter($units, function (Unit $unit) { + return !! $unit->cast()->getBuilding(); + }); + } + } + return array_map(function (Unit $unit) { return $unit->cast(); }, $units); diff --git a/views/components/timer.twig b/views/components/timer.twig index 97977da..ccb31a7 100644 --- a/views/components/timer.twig +++ b/views/components/timer.twig @@ -9,8 +9,9 @@ document.addEventListener('DOMContentLoaded', function (ev) { const interval = setInterval(setTime, 1000); function setTime() { let diff = time - new Date(); - if (diff <= -1) { + if (diff <= 0) { clearInterval(interval); + window.location.reload(); } const hh = Math.floor(diff/1000/60/60); diff --git a/views/map.twig b/views/map.twig index 43f1a5b..29f0294 100644 --- a/views/map.twig +++ b/views/map.twig @@ -3,30 +3,40 @@ {% block main %} <div class="map"> <div class="map__up"> - <a href="/map/{{ x }}/{{ y - 1 }}">Up</a> + <a href="/map/{{ x }}/{{ y - 1 }}"> + <i class="icon icon-arrow-up"></i> + </a> </div> <div> <div class="map__left"> - <a href="/map/{{ x - 1 }}/{{ y }}">Left</a> + <a href="/map/{{ x - 1 }}/{{ y }}"> + <i class="icon icon-arrow-left"></i> + </a> </div> <div class="map__villages" style="grid-template-columns: repeat({{ range*2+1 }}, 1fr); grid-template-rows: repeat({{ range*2+1 }}, 1fr);"> {% for row in range(-range, range) %} {% for column in range(-range, range) %} {% set village = map[x + column][y + row] %} - <div class="map__village"> - <a href="/village/{{ village.x }}/{{ village.y }}"> - {{ map[x + column][y + row].name }} - </a> - </div> + <div class="map__village"> + {% if village %} + <a href="/village/{{ village.x }}/{{ village.y }}"> + {{ map[x + column][y + row].name }} + </a> + {% endif %} + </div> {% endfor %} {% endfor %} </div> <div class="map__right"> - <a href="/map/{{ x + 1 }}/{{ y }}">Right</a> + <a href="/map/{{ x + 1 }}/{{ y }}"> + <i class="icon icon-arrow-right"></i> + </a> </div> </div> <div class="map__down"> - <a href="/map/{{ x }}/{{ y + 1 }}">Down</a> + <a href="/map/{{ x }}/{{ y + 1 }}"> + <i class="icon icon-arrow-down"></i> + </a> </div> </div> {% endblock %} diff --git a/views/village.twig b/views/village.twig index ea6635c..b843ef4 100644 --- a/views/village.twig +++ b/views/village.twig @@ -49,7 +49,7 @@ <h3 align="center">Storage Config</h3> <form method="post" action="/village/{{ village.x }}/{{ village.y }}/storage/config"> <label> - Wood: + <i class="icon icon-wood"></i> <input type="text" name="wood" value="{{ village.getStorageConfig(village.id).wood }}"> </label> <label> @@ -86,12 +86,12 @@ <tbody> {% for event in events['UpgradeBuilding'] %} <tr> - <td>{{ event.data.building }}</td> + <td>{{ event.data.type }}</td> <td class="timer"> {% include 'components/timer.twig' with { 'time': event.event.time|date('c') } %} </td> <td> - <a class="btn" href="/village/{{ village.x }}/{{ village.y }}/building/{{ event.data.building }}/build/cancel"> + <a class="btn" href="/village/{{ village.x }}/{{ village.y }}/building/{{ event.data.type }}/build/cancel"> Cancel </a> </td> @@ -119,7 +119,7 @@ {% include 'components/timer.twig' with { 'time': event.event.time|date('c') } %} </td> <td> - <a class="btn" href="/village/{{ village.x }}/{{ village.y }}/unit/{{ event.data.type }}/train/cancel"> + <a class="btn" href="/village/{{ village.x }}/{{ village.y }}/unit/train/cancel"> Cancel </a> </td> @@ -155,9 +155,15 @@ {% include 'components/timer.twig' with { 'time': event.event.time|date('c') } %} </td> <td> - <a class="btn" href="/village/{{ village.x }}/{{ village.y }}/unit/{{ event.data.type }}/train/cancel"> - Cancel - </a> + {% if event.data.cancel %} + 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 %} @@ -180,10 +186,10 @@ </tr> </thead> <tbody> - {% for building in village.getBuildings(village.id) %} + {% for building in buildings %} <tr class="village__buildings__row"> - <td>{{ building.type }}</td> - <td>{{ building.level }}</td> + <td>{{ building.type | default(type) }}</td> + <td>{{ building.level | default(0) }}</td> <td>{{ building.getBuildTime() | buildTime }}</td> <td class="resources"> <span> @@ -225,7 +231,7 @@ </tr> </thead> <tbody> - {% for unit in village.getUnits(village.id, 1) %} + {% for unit in village.getUnits(village.id, 1, 3) %} <tr> <td>{{ unit.type }}</td> <td>{{ unit.amount }}</td> @@ -256,7 +262,7 @@ <td> <form action="/village/{{ village.x }}/{{ village.y }}/unit/{{ unit.type }}/create" method="post" class="inline"> <input type="number" min="0" name="amount" placeholder="Amount"> - <input type="submit" value="Train"> + <input type="submit" value="Train" {{ village.canTrain(village, unit, 1) ? '' : 'disabled' }}> </form> </td> </tr> @@ -311,15 +317,35 @@ <option>{{ unit.type }}</option> {% endfor %} </select> + <input type="number" min="1" name="amount" placeholder="Amount" required> <select name="village"> {% for v in villages %} <option value="{{ v.id }}">{{ v.name }}</option> {% endfor %} </select> - <input type="number" min="1" name="amount" placeholder="Amount" required> + <select name="type"> + <option>Borrow</option> + <option>Gift</option> + </select> <button>Send</button> </form> </div> + + {% if village.getBuilding(village.id, 'Marketplace') %} + <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> + <select name="village"> + {% for v in villages %} + <option value="{{ v.id }}">{{ v.name }}</option> + {% endfor %} + </select> + <button>Send</button> + </form> + {% endif %} </div> </div> {% endblock %} diff --git a/views/villages.twig b/views/villages.twig index 21d8cec..bdb87be 100644 --- a/views/villages.twig +++ b/views/villages.twig @@ -11,7 +11,7 @@ <td>Iron</td> <td>Food</td> <td>Storage</td> - <td>Reputation</td> + <td>Satisfaction</td> </tr> </thead> <tbody> @@ -30,7 +30,7 @@ <td>{{ village.iron }}</td> <td>{{ village.food }}</td> <td>{{ village.getStorage(village.id).getCapacity() * (25 / 100) }}</td> - <td>{{ village.reputation }}</td> + <td>{{ village.satisfaction }}</td> </tr> {% endfor %} </tbody> |