Zappy Server
C++ game server: world, rules, scheduler, network
Loading...
Searching...
No Matches
AiHandlers.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <cctype>
3#include <string>
4
9
11 int fx;
12 int fy;
13 int rx;
14 int ry;
15};
16
18{
19 switch (o) {
20 case Orientation::N:
21 return {0, -1, 1, 0};
22 case Orientation::S:
23 return {0, 1, -1, 0};
24 case Orientation::E:
25 return {1, 0, 0, 1};
26 case Orientation::W:
27 return {-1, 0, 0, -1};
28 }
29 return {0, -1, 1, 0};
30}
31
32static std::string _tileContent(const Tile& tile)
33{
34 std::string s;
35 for (size_t i = 0; i < tile.playerIds.size(); i++) {
36 if (!s.empty()) s += " ";
37 s += "player";
38 }
39 for (int res = 0; res < Resources::TYPE_COUNT; res++) {
40 auto type = static_cast<ResourceType>(res);
41 std::string name = Resources::get_name(type);
42 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
43 for (int c = 0; c < tile.resources[type]; c++) {
44 if (!s.empty()) s += " ";
45 s += name;
46 }
47 }
48 return s;
49}
50
52{
53 int playerId = _clients.getConnection(connectionId).playerId();
54 int delayMs = 7000;
55
56 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
57 [this, connectionId, playerId] {
58 if (!_world.getPlayers().count(playerId)) {
59 _executeNext(connectionId);
60 return;
61 }
62 auto& p = _world.getPlayer(playerId);
63
64 int dx = 0, dy = 0;
65 switch (p.orientation) {
66 case Orientation::N:
67 dy = -1;
68 break;
69 case Orientation::S:
70 dy = 1;
71 break;
72 case Orientation::E:
73 dx = 1;
74 break;
75 case Orientation::W:
76 dx = -1;
77 break;
78 }
79 _world.movePlayer(playerId, p.x + dx, p.y + dy);
80
81 _clients.send(connectionId, "ok\n");
82 _executeNext(connectionId);
83 });
84}
85
86void CommandDispatcher::_handleRight(int connectionId)
87{
88 int playerId = _clients.getConnection(connectionId).playerId();
89 int delayMs = 7000;
90
91 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
92 [this, connectionId, playerId] {
93 if (!_world.getPlayers().count(playerId)) {
94 _executeNext(connectionId);
95 return;
96 }
97 auto& p = _world.getPlayer(playerId);
98
99 _world.turnPlayer(playerId, turnRight(p.orientation));
100 _clients.send(connectionId, "ok\n");
101 _executeNext(connectionId);
102 });
103}
104
105void CommandDispatcher::_handleLeft(int connectionId)
106{
107 int playerId = _clients.getConnection(connectionId).playerId();
108 int delayMs = 7000;
109
110 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
111 [this, connectionId, playerId] {
112 if (!_world.getPlayers().count(playerId)) {
113 _executeNext(connectionId);
114 return;
115 }
116 auto& p = _world.getPlayer(playerId);
117 _world.turnPlayer(playerId, turnLeft(p.orientation));
118 _clients.send(connectionId, "ok\n");
119 _executeNext(connectionId);
120 });
121}
122
123void CommandDispatcher::_handleLook(int connectionId)
124{
125 int playerId = _clients.getConnection(connectionId).playerId();
126 int delayMs = 7000;
127
128 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
129 [this, connectionId, playerId] {
130 if (!_world.getPlayers().count(playerId)) {
131 _executeNext(connectionId);
132 return;
133 }
134 auto& p = _world.getPlayer(playerId);
135 auto look = _lookForwardRight(p.orientation);
136 int tileCount = (p.level + 1) * (p.level + 1);
137
138 std::string r = "[";
139 for (int i = 0; i < tileCount; i++) {
140 int d = 0;
141 while ((d + 1) * (d + 1) <= i) d++;
142 int xRel = i - d * d - d;
143
144 int dx = d * look.fx + xRel * look.rx;
145 int dy = d * look.fy + xRel * look.ry;
146
147 if (i > 0) r += ", ";
148 r += _tileContent(_world.at(p.x + dx, p.y + dy));
149 }
150 r += "]\n";
151
152 _clients.send(connectionId, r);
153 _executeNext(connectionId);
154 });
155}
156
158{
159 int playerId = _clients.getConnection(connectionId).playerId();
160 int delayMs = 1000;
161
163 std::chrono::milliseconds(delayMs / _clock.freq()), [this, connectionId, playerId] {
164 if (!_world.getPlayers().count(playerId)) {
165 _executeNext(connectionId);
166 return;
167 }
168 auto& p = _world.getPlayer(playerId);
169
170 std::string r = "[ food " + std::to_string(p.inventory.food) + ", linemate " +
171 std::to_string(p.inventory.linemate) + ", deraumere " +
172 std::to_string(p.inventory.deraumere) + ", sibur " +
173 std::to_string(p.inventory.sibur) + ", mendiane " +
174 std::to_string(p.inventory.mendiane) + ", phiras " +
175 std::to_string(p.inventory.phiras) + ", thystame " +
176 std::to_string(p.inventory.thystame) + " ]\n";
177
178 _clients.send(connectionId, r);
179 _executeNext(connectionId);
180 });
181}
182
183void CommandDispatcher::_handleBroadcast(int connectionId, const std::string& msg)
184{
185 int playerId = _clients.getConnection(connectionId).playerId();
186 int delayMs = 7000;
187
188 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()), [this, connectionId,
189 playerId, msg] {
190 if (!_world.getPlayers().count(playerId)) {
191 _executeNext(connectionId);
192 return;
193 }
194 auto& src = _world.getPlayer(playerId);
195 for (auto& [pid, dst] : _world.getPlayers()) {
196 if (pid == playerId) continue;
197 int dir = broadcastDirection(src.x, src.y, dst.x, dst.y, _world.width(),
198 _world.height(), dst.orientation);
199 _clients.send(dst.connectionId, "message " + std::to_string(dir) + "," + msg + "\n");
200 }
201 _world.playerBroadcast(playerId, msg);
202 _clients.send(connectionId, "ok\n");
203 _executeNext(connectionId);
204 });
205}
206
207void CommandDispatcher::_handleFork(int connectionId)
208{
209 int playerId = _clients.getConnection(connectionId).playerId();
210 int delayMs = 42000;
211
212 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
213 [this, connectionId, playerId] {
214 if (!_world.getPlayers().count(playerId)) {
215 _executeNext(connectionId);
216 return;
217 }
218 _world.addEgg(playerId);
219 _clients.send(connectionId, "ok\n");
220 _executeNext(connectionId);
221 });
222}
223
225{
226 int playerId = _clients.getConnection(connectionId).playerId();
227 int delayMs = 7000;
228
230 std::chrono::milliseconds(delayMs / _clock.freq()), [this, connectionId, playerId] {
231 if (!_world.getPlayers().count(playerId)) {
232 _executeNext(connectionId);
233 return;
234 }
235 auto result = _world.ejectPlayers(playerId);
236
237 if (result.ejectedPlayerIds.empty()) {
238 _clients.send(connectionId, "ko\n");
239 _executeNext(connectionId);
240 return;
241 }
242
243 for (int eid : result.ejectedPlayerIds) {
244 auto& ejected = _world.getPlayer(eid);
245 int dir = broadcastDirection(ejected.x - result.dx, ejected.y - result.dy,
246 ejected.x, ejected.y, _world.width(), _world.height(),
247 ejected.orientation);
248 _clients.send(ejected.connectionId, "eject: " + std::to_string(dir) + "\n");
249 }
250
251 _clients.send(connectionId, "ok\n");
252 _executeNext(connectionId);
253 });
254}
255
256void CommandDispatcher::_handleTake(int connectionId, ResourceType resource)
257{
258 int playerId = _clients.getConnection(connectionId).playerId();
259 int delayMs = 7000;
260
261 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
262 [this, connectionId, playerId, resource] {
263 if (!_world.getPlayers().count(playerId)) {
264 _executeNext(connectionId);
265 return;
266 }
267 if (_world.takeResource(playerId, resource))
268 _clients.send(connectionId, "ok\n");
269 else
270 _clients.send(connectionId, "ko\n");
271 _executeNext(connectionId);
272 });
273}
274
275void CommandDispatcher::_handleSet(int connectionId, ResourceType resource)
276{
277 int playerId = _clients.getConnection(connectionId).playerId();
278 int delayMs = 7000;
279
280 _scheduler.schedule(std::chrono::milliseconds(delayMs / _clock.freq()),
281 [this, connectionId, playerId, resource] {
282 if (!_world.getPlayers().count(playerId)) {
283 _executeNext(connectionId);
284 return;
285 }
286
287 if (_world.setResource(playerId, resource))
288 _clients.send(connectionId, "ok\n");
289 else
290 _clients.send(connectionId, "ko\n");
291 _executeNext(connectionId);
292 });
293}
294
296{
297 int playerId = _clients.getConnection(connectionId).playerId();
298 int delayMs = 300000;
299
300 auto participants = _world.startIncantation(playerId);
301 if (!participants) {
302 _clients.send(connectionId, "ko\n");
303 _executeNext(connectionId);
304 return;
305 }
306
307 auto& p = _world.getPlayer(playerId);
308 int x = p.x;
309 int y = p.y;
310
311 for (int pid : *participants)
312 _clients.send(_world.getPlayer(pid).connectionId, "Elevation underway\n");
313
315 std::chrono::milliseconds(delayMs / _clock.freq()),
316 [this, connectionId, participants = *participants, x, y] {
317 bool success = _world.finalizeIncantation(x, y, participants);
318
319 auto& players = _world.getPlayers();
320 for (int pid : participants) {
321 auto it = players.find(pid);
322 if (it == players.end()) continue;
323
324 if (success) {
325 _clients.send(it->second.connectionId,
326 "Current level: " + std::to_string(it->second.level) + "\n");
327 } else {
328 _clients.send(it->second.connectionId, "ko\n");
329 }
330 }
331
332 _executeNext(connectionId);
333 });
334}
static LookVectors _lookForwardRight(Orientation o)
static std::string _tileContent(const Tile &tile)
Orientation turnRight(Orientation o)
Orientation
Orientation turnLeft(Orientation o)
ResourceType
Enumerate the different types of resources in the game.
Definition Resources.hpp:12
static std::string res(const Resources &r)
Definition Serializer.cpp:5
int broadcastDirection(int srcX, int srcY, int dstX, int dstY, int mapW, int mapH, Orientation dstFacing)
void send(int connectionId, const std::string &msg)
Queue msg to be sent to a client (flushed during poll()).
Connection & getConnection(int connectionId)
Access the underlying Connection (e.g. to set its type/playerId).
void _handleFork(int connectionId)
void _handleIncantation(int connectionId)
void _handleTake(int connectionId, ResourceType resource)
void _handleLeft(int connectionId)
void _handleLook(int connectionId)
void _executeNext(int connectionId)
Run the next queued AI command (or go idle if none left).
ClientManager & _clients
void _handleForward(int connectionId)
void _handleInventory(int connectionId)
void _handleBroadcast(int connectionId, const std::string &msg)
void _handleRight(int connectionId)
void _handleSet(int connectionId, ResourceType resource)
void _handleEject(int connectionId)
int playerId() const
Player this connection drives (-1 for GUI / not yet assigned).
int freq() const
Definition GameClock.hpp:32
static std::string get_name(int index)
Definition Resources.hpp:33
static constexpr int TYPE_COUNT
void schedule(std::chrono::milliseconds delay, std::function< void()> cb)
Definition Scheduler.cpp:3
bool takeResource(int playerId, ResourceType type)
Definition World.cpp:110
void movePlayer(int id, int x, int y)
Definition World.cpp:91
bool finalizeIncantation(int x, int y, const std::vector< int > &participantIds)
Finalize an incantation after the 300/f second delay. Re-checks prerequisites. On success,...
Definition World.cpp:331
const std::unordered_map< int, Player > & getPlayers() const
Definition World.cpp:402
void turnPlayer(int id, Orientation orientation)
Definition World.cpp:103
Tile & at(int x, int y)
Access a tile by position. Map is toroidal, coordinates wrap.
Definition World.cpp:12
EjectResult ejectPlayers(int ejectorId)
Definition World.cpp:154
void playerBroadcast(int playerId, const std::string &message)
Fire onBroadcast to observers (GUI animation, logging). No state change.
Definition World.cpp:149
int height() const
Definition World.cpp:401
bool setResource(int playerId, ResourceType type)
Definition World.cpp:123
std::optional< std::vector< int > > startIncantation(int playerId)
Validate and start an incantation for playerId. Returns the list of participant IDs on success,...
Definition World.cpp:304
Player & getPlayer(int id)
Definition World.cpp:147
int addEgg(int playerId)
Definition World.cpp:216
int width() const
Definition World.cpp:400
int connectionId
Definition Player.hpp:19
int x
Definition Player.hpp:17
Represents a tile on the game map, containing resources, player IDs, and egg IDs.
Definition Tile.hpp:10
Resources resources
Definition Tile.hpp:11
std::vector< int > playerIds
Definition Tile.hpp:12