source: network-game/common/Game.cpp@ 1f6233e

Last change on this file since 1f6233e was d05c484, checked in by dportnoy <dmp1488@…>, 11 years ago

Some game-specific functions moved from server.cpp to the Game class and a function moved to the MessageProcessor class

  • Property mode set to 100644
File size: 12.9 KB
Line 
1#include "Game.h"
2
3#include <iostream>
4#include <cstring>
5
6#include "Common.h"
7
8using namespace std;
9
10Game::Game() {
11 this->id = 0;
12 this->name = "";
13 this->blueScore = 0;
14 this->redScore = 0;
15 this->worldMap = NULL;
16 this->msgProcessor = NULL;
17}
18
19Game::Game(string name, string filepath, MessageProcessor* msgProcessor) {
20 this->id = 0;
21 this->name = name;
22 this->blueScore = 0;
23 this->redScore = 0;
24 this->worldMap = WorldMap::loadMapFromFile(filepath);
25 this->msgProcessor = msgProcessor;
26}
27
28Game::~Game() {
29 delete this->worldMap;
30}
31
32string Game::getName() {
33 return this->name;
34}
35
36int Game::getNumPlayers() {
37 return this->players.size();
38}
39
40map<unsigned int, Player*>& Game::getPlayers() {
41 return this->players;
42}
43
44bool Game::addPlayer(Player* p) {
45 if (players.find(p->id) == players.end()) {
46 players[p->id] = p;
47 return true;
48 }
49 else
50 return false;
51}
52
53bool Game::removePlayer(unsigned int id) {
54 if (players.erase(id) == 1)
55 return true;
56 else
57 return false;
58}
59
60map<unsigned int, Projectile>& Game::getProjectiles() {
61 return this->projectiles;
62}
63
64bool Game::addProjectile(Projectile p) {
65 if (projectiles.find(p.id) == projectiles.end()) {
66 projectiles[p.id] = p;
67 return true;
68 }
69 else
70 return false;
71}
72
73bool Game::removeProjectile(unsigned int id) {
74 if (projectiles.erase(id) == 1)
75 return true;
76 else
77 return false;
78}
79
80unsigned int Game::getRedScore() {
81 return this->redScore;
82}
83
84unsigned int Game::getBlueScore() {
85 return this->blueScore;
86}
87
88WorldMap* Game::getMap() {
89 return this->worldMap;
90}
91
92void Game::setId(unsigned int id) {
93 this->id = id;
94}
95
96void Game::setRedScore(unsigned int score) {
97 this->redScore = score;
98}
99
100void Game::setBlueScore(unsigned int score) {
101 this->blueScore = score;
102}
103
104void Game::addObjectToMap(WorldMap::ObjectType objectType, int x, int y) {
105 NETWORK_MSG serverMsg;
106
107 this->getMap()->addObject(objectType, x, y);
108
109 serverMsg.type = MSG_TYPE_OBJECT;
110 this->worldMap->getObjects()->back().serialize(serverMsg.buffer);
111
112 this->msgProcessor->broadcastMessage(serverMsg, this->players);
113}
114
115bool Game::startPlayerMovement(unsigned int id, int x, int y) {
116 // need to check if players actually contains the id
117 Player* p = players[id];
118
119 // we need to make sure the player can move here
120 if (0 <= x && x < this->worldMap->width*25 &&
121 0 <= y && y < this->worldMap->height*25 &&
122 this->worldMap->getElement(x/25, y/25) == WorldMap::TERRAIN_GRASS)
123 {
124 p->target.x = x;
125 p->target.y = y;
126
127 p->isChasing = false;
128 p->isAttacking = false;
129
130 return true;
131 }
132 else
133 return false;
134}
135
136// returns true if the movement should be canceled
137bool Game::processPlayerMovement(Player* p, FLOAT_POSITION oldPos) {
138
139 // check if the move needs to be canceled
140 switch(this->worldMap->getElement(p->pos.x/25, p->pos.y/25))
141 {
142 case WorldMap::TERRAIN_NONE:
143 case WorldMap::TERRAIN_OCEAN:
144 case WorldMap::TERRAIN_ROCK:
145 {
146 p->pos = oldPos;
147 p->target.x = p->pos.x;
148 p->target.y = p->pos.y;
149 p->isChasing = false;
150 return true;
151 break;
152 }
153 default:
154 // if there are no obstacles, don't cancel movement
155 return false;
156 break;
157 }
158}
159
160// returns the id of the picked-up flag or -1 if none was picked up
161int Game::processFlagPickupRequest(Player* p) {
162 vector<WorldMap::Object>* vctObjects = this->worldMap->getObjects();
163 vector<WorldMap::Object>::iterator it;
164 int playerId = -1;
165
166 for (it = vctObjects->begin(); it != vctObjects->end(); it++) {
167 if (posDistance(p->pos, it->pos.toFloat()) < 10) {
168 switch (it->type) {
169 case WorldMap::OBJECT_BLUE_FLAG:
170 if (p->team == 1) {
171 p->hasBlueFlag = true;
172 playerId = it->id;
173 }
174 break;
175 case WorldMap::OBJECT_RED_FLAG:
176 if (p->team == 0) {
177 p->hasRedFlag = true;
178 playerId = it->id;
179 }
180 break;
181 }
182
183 if (playerId > -1) {
184 vctObjects->erase(it);
185 return playerId;
186 }
187 }
188 }
189
190 return playerId;
191}
192
193void Game::dealDamageToPlayer(Player* p, int damage) {
194 p->takeDamage(damage);
195
196 if (p->isDead)
197 {
198 WorldMap::ObjectType flagType = WorldMap::OBJECT_NONE;
199 if (p->hasBlueFlag)
200 flagType = WorldMap::OBJECT_BLUE_FLAG;
201 else if (p->hasRedFlag)
202 flagType = WorldMap::OBJECT_RED_FLAG;
203
204 if (flagType != WorldMap::OBJECT_NONE)
205 this->addObjectToMap(flagType, p->pos.x, p->pos.y);
206 }
207
208 // send a PLAYER message after dealing damage
209 NETWORK_MSG serverMsg;
210 serverMsg.type = MSG_TYPE_PLAYER;
211 p->serialize(serverMsg.buffer);
212 msgProcessor->broadcastMessage(serverMsg, this->players);
213}
214
215bool Game::handleGameEvents() {
216 NETWORK_MSG serverMsg;
217 map<unsigned int, Player*>::iterator it;
218 bool gameFinished = false;
219
220 for (it = this->getPlayers().begin(); it != this->getPlayers().end(); it++)
221 {
222 gameFinished = gameFinished ||
223 this->handlePlayerEvents(it->second);
224 }
225
226 if (gameFinished) {
227 for (it = this->players.begin(); it != this->players.end(); it++)
228 {
229 it->second->currentGame = NULL;
230 }
231 }
232
233 return gameFinished;
234}
235
236bool Game::handlePlayerEvents(Player* p) {
237 NETWORK_MSG serverMsg;
238 FLOAT_POSITION oldPos;
239 bool gameFinished = false;
240 bool broadcastMove = false;
241
242 cout << "moving player" << endl;
243
244 // move player and perform associated tasks
245 oldPos = p->pos;
246 if (p->move(this->worldMap)) {
247
248 cout << "player moved" << endl;
249 if (this->processPlayerMovement(p, oldPos))
250 broadcastMove = true;
251 cout << "player move processed" << endl;
252
253 WorldMap::ObjectType flagType;
254 POSITION pos;
255 bool flagTurnedIn = false;
256 bool flagReturned = false;
257 bool ownFlagAtBase = false;
258
259 switch(this->worldMap->getStructure(p->pos.x/25, p->pos.y/25))
260 {
261 case WorldMap::STRUCTURE_BLUE_FLAG:
262 {
263 if (p->team == 0 && p->hasRedFlag)
264 {
265 // check that your flag is at your base
266 pos = this->worldMap->getStructureLocation(WorldMap::STRUCTURE_BLUE_FLAG);
267
268 vector<WorldMap::Object>* vctObjects = this->worldMap->getObjects();
269 vector<WorldMap::Object>::iterator itObjects;
270
271 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++)
272 {
273 if (itObjects->type == WorldMap::OBJECT_BLUE_FLAG)
274 {
275 if (itObjects->pos.x == pos.x*25+12 && itObjects->pos.y == pos.y*25+12)
276 {
277 ownFlagAtBase = true;
278 break;
279 }
280 }
281 }
282
283 if (ownFlagAtBase)
284 {
285 p->hasRedFlag = false;
286 flagType = WorldMap::OBJECT_RED_FLAG;
287 pos = this->worldMap->getStructureLocation(WorldMap::STRUCTURE_RED_FLAG);
288 flagTurnedIn = true;
289 this->blueScore++;
290 }
291 }
292
293 break;
294 }
295 case WorldMap::STRUCTURE_RED_FLAG:
296 {
297 if (p->team == 1 && p->hasBlueFlag)
298 {
299 // check that your flag is at your base
300 pos = this->worldMap->getStructureLocation(WorldMap::STRUCTURE_RED_FLAG);
301
302 vector<WorldMap::Object>* vctObjects = this->worldMap->getObjects();
303 vector<WorldMap::Object>::iterator itObjects;
304
305 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++)
306 {
307 if (itObjects->type == WorldMap::OBJECT_RED_FLAG)
308 {
309 if (itObjects->pos.x == pos.x*25+12 && itObjects->pos.y == pos.y*25+12)
310 {
311 ownFlagAtBase = true;
312 break;
313 }
314 }
315 }
316
317 if (ownFlagAtBase)
318 {
319 p->hasBlueFlag = false;
320 flagType = WorldMap::OBJECT_BLUE_FLAG;
321 pos = this->worldMap->getStructureLocation(WorldMap::STRUCTURE_BLUE_FLAG);
322 flagTurnedIn = true;
323 this->redScore++;
324 }
325 }
326
327 break;
328 }
329 }
330
331 if (flagTurnedIn)
332 {
333 unsigned int blueScore = this->blueScore;
334 unsigned int redScore = this->redScore;
335
336 pos.x = pos.x*25+12;
337 pos.y = pos.y*25+12;
338 this->addObjectToMap(flagType, pos.x, pos.y);
339
340 serverMsg.type = MSG_TYPE_SCORE;
341 memcpy(serverMsg.buffer, &blueScore, 4);
342 memcpy(serverMsg.buffer+4, &redScore, 4);
343 msgProcessor->broadcastMessage(serverMsg, this->players);
344
345 // check to see if the game should end
346 // move to its own method
347 if (this->blueScore == 3 || this->redScore == 3) {
348 gameFinished = true;
349
350 unsigned int winningTeam;
351 if (this->blueScore == 3)
352 winningTeam = 0;
353 else if (this->redScore == 3)
354 winningTeam = 1;
355
356 serverMsg.type = MSG_TYPE_FINISH_GAME;
357
358 // I should create an instance of the GameSummary object here and just serialize it into this message
359 memcpy(serverMsg.buffer, &winningTeam, 4);
360 memcpy(serverMsg.buffer+4, &blueScore, 4);
361 memcpy(serverMsg.buffer+8, &redScore, 4);
362 strcpy(serverMsg.buffer+12, this->getName().c_str());
363 msgProcessor->broadcastMessage(serverMsg, this->players);
364 }
365
366 // this means a PLAYER message will be sent
367 broadcastMove = true;
368 }
369
370 // go through all objects and check if the player is close to one and if its their flag
371 vector<WorldMap::Object>* vctObjects = this->worldMap->getObjects();
372 vector<WorldMap::Object>::iterator itObjects;
373 POSITION structPos;
374
375 for (itObjects = vctObjects->begin(); itObjects != vctObjects->end(); itObjects++)
376 {
377 POSITION pos = itObjects->pos;
378
379 if (posDistance(p->pos, pos.toFloat()) < 10)
380 {
381 if (p->team == 0 &&
382 itObjects->type == WorldMap::OBJECT_BLUE_FLAG)
383 {
384 structPos = this->worldMap->getStructureLocation(WorldMap::STRUCTURE_BLUE_FLAG);
385 flagReturned = true;
386 break;
387 }
388 else if (p->team == 1 &&
389 itObjects->type == WorldMap::OBJECT_RED_FLAG)
390 {
391 structPos = this->worldMap->getStructureLocation(WorldMap::STRUCTURE_RED_FLAG);
392 flagReturned = true;
393 break;
394 }
395 }
396 }
397
398 if (flagReturned)
399 {
400 itObjects->pos.x = structPos.x*25+12;
401 itObjects->pos.y = structPos.y*25+12;
402
403 serverMsg.type = MSG_TYPE_OBJECT;
404 itObjects->serialize(serverMsg.buffer);
405 msgProcessor->broadcastMessage(serverMsg, this->players);
406 }
407
408 if (broadcastMove)
409 {
410 serverMsg.type = MSG_TYPE_PLAYER;
411 p->serialize(serverMsg.buffer);
412 msgProcessor->broadcastMessage(serverMsg, this->players);
413 }
414 }
415
416 cout << "processing player attack" << endl;
417
418 // check if the player's attack animation is complete
419 if (p->isAttacking && p->timeAttackStarted+p->attackCooldown <= getCurrentMillis())
420 {
421 p->isAttacking = false;
422 cout << "Attack animation is complete" << endl;
423
424 //send everyone an ATTACK message
425 cout << "about to broadcast attack" << endl;
426
427 if (p->attackType == Player::ATTACK_MELEE)
428 {
429 cout << "Melee attack" << endl;
430
431 Player* target = players[p->targetPlayer];
432 this->dealDamageToPlayer(target, p->damage);
433 }
434 else if (p->attackType == Player::ATTACK_RANGED)
435 {
436 cout << "Ranged attack" << endl;
437
438 Projectile proj(p->pos.x, p->pos.y, p->targetPlayer, p->damage);
439 this->assignProjectileId(&proj);
440 this->addProjectile(proj);
441
442 int x = p->pos.x;
443 int y = p->pos.y;
444
445 serverMsg.type = MSG_TYPE_PROJECTILE;
446 memcpy(serverMsg.buffer, &proj.id, 4);
447 memcpy(serverMsg.buffer+4, &x, 4);
448 memcpy(serverMsg.buffer+8, &y, 4);
449 memcpy(serverMsg.buffer+12, &p->targetPlayer, 4);
450 msgProcessor->broadcastMessage(serverMsg, players);
451 }
452 else
453 cout << "Invalid attack type: " << p->attackType << endl;
454 }
455
456 return gameFinished;
457}
458
459void Game::assignProjectileId(Projectile* p) {
460 p->id = unusedProjectileId;
461 updateUnusedProjectileId();
462}
463
464void Game::updateUnusedProjectileId() {
465 while (projectiles.find(unusedProjectileId) != projectiles.end())
466 unusedProjectileId++;
467}
Note: See TracBrowser for help on using the repository browser.