source: network-game/common/Game.cpp@ 3476207

Last change on this file since 3476207 was ea17281, checked in by dportnoy <dmp1488@…>, 10 years ago

Game.addPlayer takes a boolean to indicate wheter it runs on the server. If it's not, the team isn't randomly generated.

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