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

Last change on this file since d6b5f74 was 99cf349, checked in by dportnoy <dmp1488@…>, 11 years ago

When a player starts moving, the server clears that player's target player

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