source: network-game/common/Game.cpp@ 84f9797

Last change on this file since 84f9797 was 64a1f4e, checked in by dportnoy <dmp1488@…>, 11 years ago

Game.addPlayer reset all the player's stats as well

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