source: network-game/common/Game.cpp@ 53643ca

Last change on this file since 53643ca was 53643ca, checked in by Dmitry Portnoy <dmp1488@…>, 10 years ago

Server loads user profile and game history info from the database, saves game history to the db after every game, and uses a lua settings file to load db settings

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