1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
<?php
namespace App\Model\Event;
use App\DB;
use App\Model\Event;
use App\Model\Unit;
use App\Model\Unit\Merchant;
use App\Model\Village;
class SendResources extends BaseEvent
{
public int $wood = 0;
public int $clay = 0;
public int $iron = 0;
public int $food = 0;
public int $source;
public int $destination;
public bool $isCanceled = false;
/**
* @return void
*/
public function __invoke(): void
{
if ($this->isCanceled) {
// TODO: switch destination and source
// TODO: add resources back to "destination"
// TODO: add merchants back to "destination"
}
else {
// TODO: account for storage capacity
DB::query(
'update villages set wood=wood+:wood, clay=clay+:clay, iron=iron+:iron, food=food+:food where id=:id',
[
'wood' => $this->wood,
'clay' => $this->clay,
'iron' => $this->iron,
'food' => $this->food,
'id' => $this->destination,
]
);
$source = Village::get($this->source);
$destination = Village::get($this->destination);
$event = new Event();
$event->time = (new \DateTime())->add(
\DateInterval::createFromDateString(
Unit::getTravelTime(new Merchant(), Village::getDistance($source->x, $source->y, $destination->x, $destination->y))
. ' seconds'
)
);
$event->villageId = $this->source;
$sendResourcesMerchants = new SendResourcesMerchants();
$sendResourcesMerchants->dbInsert($this->id);
// TODO: add resources to destination
// (TODO: add foreign merchants to destination)?
// TODO: create SendUnits event with merchants back to source
}
}
public function dbInsert(): void
{
DB::query(
'insert into events (time, village_id) VALUES (:time, :village_id)',
['time' => $this->event->time->format('c'), 'village_id' => $this->event->villageId]
);
DB::query(
<<<SQL
insert into events_send_resources (event_id, wood, clay, iron, food, source, destination, is_canceled)
VALUES (:event_id, :wood, :clay, :iron, :food, :source, :destination, :is_canceled)
SQL,
[
'event_id' => DB::$connection->lastInsertId(),
'wood' => $this->wood,
'clay' => $this->clay,
'iron' => $this->iron,
'food' => $this->food,
'source' => $this->source, 'destination' => $this->destination,
'is_canceled' => $this->isCanceled ?: 0, // @see https://www.php.net/manual/de/pdostatement.execute.php#126013
]
);
$sendResourcesEventId = DB::$connection->lastInsertId();
$resourceCapabilities = Merchant::getResourceCapabilities($this->event->villageId);
$resourcesTotal = $this->wood + $this->clay + $this->iron + $this->food;
$necessaryMerchants = ceil($resourcesTotal / $resourceCapabilities);
$merchantsAccountedFor = 0;
while ($merchantsAccountedFor < $necessaryMerchants) {
$merchants = DB::fetch(
Merchant::class,
'select * from village_units where type=:type and residence_village_id=:villageId and is_traveling=false',
['type' => 'Merchant', 'villageId' => $this->source]
);
foreach ($merchants as $merchant) {
/**@type Merchant $merchant*/
$currentlyNecessaryMerchants = $necessaryMerchants - $merchantsAccountedFor;
$currentlyUseableMerchants = $currentlyNecessaryMerchants - $merchant->amount < 0 ? $currentlyNecessaryMerchants : $merchant->amount;
$merchantsAccountedFor += $currentlyUseableMerchants;
DB::query(
<<<SQL
insert into village_units (amount, type, is_traveling, home_village_id, residence_village_id)
VALUES (:amount, :type, true, :home, :residence)
on conflict (type, home_village_id, residence_village_id, is_traveling)
do update set is_traveling=true
SQL,
[
'amount' => $currentlyUseableMerchants,
'type' => 'Merchant',
'home' => $merchant->homeVillageId,
'residence' => $merchant->residenceVillageId,
]
);
DB::query('update village_units set amount=amount-:amount where id=:unitId', ['amount' => $necessaryMerchants, 'unitId' => $merchant->id]);
DB::query(
<<<SQL
insert into events_send_resources_merchants (event_id, unit_id, amount)
VALUES (:event_id, :unit_id, :amount)
SQL,
[
'event_id' => $sendResourcesEventId,
'unit_id' => $merchant->id,
'amount' => $necessaryMerchants,
]
);
}
}
// TODO: remove resources from source
}
public function dbDelete(): void
{
DB::query('delete from events where id=:id', ['id' => $this->eventId]);
DB::query('delete from events_send_resources where id=:id', ['id' => $this->id]);
#DB::query('delete from events_send_resources_merchants where event_id=:id', ['id' => $this->id]);
}
}
|