source: network-game/client/Client/main.cpp@ 3eac3b3

Last change on this file since 3eac3b3 was 85bf1e2, checked in by Dmitry Portnoy <dportnoy@…>, 11 years ago

Fixed taking/dropping flags, which was broken by the new lobby code

  • Property mode set to 100644
File size: 32.3 KB
RevLine 
[4c202e0]1#include "../../common/Compiler.h"
2
[e08572c]3#if defined WINDOWS
[0dde5da]4 #include <winsock2.h>
5 #include <WS2tcpip.h>
[e08572c]6#elif defined LINUX
[0dde5da]7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <netdb.h>
12 #include <cstring>
[a845faf]13#endif
[1912323]14
[88cdae2]15#include <cstdio>
16#include <cstdlib>
[8c74150]17#include <cmath>
18#include <sys/types.h>
[a845faf]19#include <string>
[1912323]20#include <iostream>
[88cdae2]21#include <sstream>
[8271c78]22#include <fstream>
[3a79253]23#include <map>
24
[d352805]25#include <allegro5/allegro.h>
26#include <allegro5/allegro_font.h>
27#include <allegro5/allegro_ttf.h>
[88cdae2]28#include <allegro5/allegro_primitives.h>
[7d7df47]29
[e607c0f]30#include "../../common/Common.h"
[b35b2b2]31#include "../../common/MessageContainer.h"
[10f6fc2]32#include "../../common/MessageProcessor.h"
[62ee2ce]33#include "../../common/WorldMap.h"
[4c202e0]34#include "../../common/Player.h"
[fbcfc35]35#include "../../common/Projectile.h"
[7d7df47]36
[87b3ee2]37#include "Window.h"
38#include "Textbox.h"
39#include "Button.h"
[5c95436]40#include "RadioButtonList.h"
[365e156]41#include "TextLabel.h"
[6475138]42#include "chat.h"
43
[a845faf]44#ifdef WINDOWS
[6475138]45 #pragma comment(lib, "ws2_32.lib")
[a845faf]46#endif
[1912323]47
48using namespace std;
49
[0dde5da]50void initWinSock();
51void shutdownWinSock();
[fbcfc35]52void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole, WorldMap *gameMap, map<unsigned int, Player>& mapPlayers, map<unsigned int, Projectile>& mapProjectiles, unsigned int& curPlayerId, int &scoreBlue, int &scoreRed);
[62ee2ce]53void drawMap(WorldMap* gameMap);
[d09fe76]54void drawPlayers(map<unsigned int, Player>& mapPlayers, ALLEGRO_FONT* font, unsigned int curPlayerId);
[62ee2ce]55POSITION screenToMap(POSITION pos);
56POSITION mapToScreen(POSITION pos);
[1f1eb58]57int getRefreshRate(int width, int height);
[87b3ee2]58
59// callbacks
[5c95436]60void goToLoginScreen();
61void goToRegisterScreen();
[87b3ee2]62void registerAccount();
63void login();
64void logout();
65void quit();
66void sendChatMessage();
[b35b2b2]67void toggleDebugging();
68void drawMessageStatus(ALLEGRO_FONT* font);
[4da5aa3]69
[1912323]70void error(const char *);
[7d7df47]71
[d352805]72const float FPS = 60;
[9b1e12c]73const int SCREEN_W = 1024;
74const int SCREEN_H = 768;
[0cc431d]75
76enum STATE {
77 STATE_START,
[1785314]78 STATE_LOBBY,
79 STATE_GAME
[d352805]80};
[87b3ee2]81
82int state;
83
84bool doexit;
85
86Window* wndLogin;
[5c95436]87Window* wndRegister;
[1785314]88Window* wndLobby;
89Window* wndGame;
90Window* wndGameDebug;
[87b3ee2]91Window* wndCurrent;
92
[5c95436]93// wndLogin
[87b3ee2]94Textbox* txtUsername;
95Textbox* txtPassword;
[365e156]96TextLabel* lblLoginStatus;
[5c95436]97
98// wndRegister
99Textbox* txtUsernameRegister;
100Textbox* txtPasswordRegister;
101RadioButtonList* rblClasses;
[365e156]102TextLabel* lblRegisterStatus;
[5c95436]103
[1785314]104// wndGame
[87b3ee2]105Textbox* txtChat;
106
107int sock;
108struct sockaddr_in server, from;
109struct hostent *hp;
110NETWORK_MSG msgTo, msgFrom;
111string username;
[b35b2b2]112chat chatConsole, debugConsole;
113bool debugging;
[1f1eb58]114
[10f6fc2]115MessageProcessor msgProcessor;
[753fa8a]116ofstream outputLog;
[10f6fc2]117
[d352805]118int main(int argc, char **argv)
119{
120 ALLEGRO_DISPLAY *display = NULL;
121 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
122 ALLEGRO_TIMER *timer = NULL;
123 bool key[4] = { false, false, false, false };
124 bool redraw = true;
[87b3ee2]125 doexit = false;
[eb8adb1]126 map<unsigned int, Player> mapPlayers;
[fbcfc35]127 map<unsigned int, Projectile> mapProjectiles;
[88cdae2]128 unsigned int curPlayerId = -1;
[15efb4e]129 int scoreBlue, scoreRed;
[1f1eb58]130 bool fullscreen = false;
[b35b2b2]131 debugging = false;
[15efb4e]132
133 scoreBlue = 0;
134 scoreRed = 0;
[9a3e6b1]135
[87b3ee2]136 state = STATE_START;
[9a3e6b1]137
[d352805]138 if(!al_init()) {
139 fprintf(stderr, "failed to initialize allegro!\n");
140 return -1;
141 }
142
[8271c78]143 outputLog.open("client.log", ios::app);
144 outputLog << "Started client on " << getCurrentDateTimeString() << endl;
145
[88cdae2]146 if (al_init_primitives_addon())
147 cout << "Primitives initialized" << endl;
148 else
149 cout << "Primitives not initialized" << endl;
150
[d352805]151 al_init_font_addon();
152 al_init_ttf_addon();
153
[88cdae2]154 #if defined WINDOWS
155 ALLEGRO_FONT *font = al_load_ttf_font("../pirulen.ttf", 12, 0);
156 #elif defined LINUX
157 ALLEGRO_FONT *font = al_load_ttf_font("pirulen.ttf", 12, 0);
158 #endif
159
[d352805]160 if (!font) {
161 fprintf(stderr, "Could not load 'pirulen.ttf'.\n");
162 getchar();
163 return -1;
164 }
165
166 if(!al_install_keyboard()) {
167 fprintf(stderr, "failed to initialize the keyboard!\n");
168 return -1;
169 }
[87b3ee2]170
171 if(!al_install_mouse()) {
172 fprintf(stderr, "failed to initialize the mouse!\n");
173 return -1;
174 }
[d352805]175
176 timer = al_create_timer(1.0 / FPS);
177 if(!timer) {
178 fprintf(stderr, "failed to create timer!\n");
179 return -1;
180 }
181
[1f1eb58]182 int refreshRate = getRefreshRate(SCREEN_W, SCREEN_H);
183 // if the computer doesn't support this resolution, just use windowed mode
184 if (refreshRate > 0 && fullscreen) {
185 al_set_new_display_flags(ALLEGRO_FULLSCREEN);
186 al_set_new_display_refresh_rate(refreshRate);
187 }
188 display = al_create_display(SCREEN_W, SCREEN_H);
[d352805]189 if(!display) {
190 fprintf(stderr, "failed to create display!\n");
191 al_destroy_timer(timer);
192 return -1;
193 }
[87b3ee2]194
[384b7e0]195 WorldMap* gameMap = WorldMap::loadMapFromFile("../../data/map.txt");
[62ee2ce]196
[365e156]197 cout << "Loaded map" << endl;
198
[b35b2b2]199 debugConsole.addLine("Debug console:");
200 debugConsole.addLine("");
201
[87b3ee2]202 wndLogin = new Window(0, 0, SCREEN_W, SCREEN_H);
[9b1e12c]203 wndLogin->addComponent(new Textbox(516, 40, 100, 20, font));
204 wndLogin->addComponent(new Textbox(516, 70, 100, 20, font));
[365e156]205 wndLogin->addComponent(new TextLabel(410, 40, 100, 20, font, "Username:", ALLEGRO_ALIGN_RIGHT));
206 wndLogin->addComponent(new TextLabel(410, 70, 100, 20, font, "Password:", ALLEGRO_ALIGN_RIGHT));
207 wndLogin->addComponent(new TextLabel((SCREEN_W-600)/2, 100, 600, 20, font, "", ALLEGRO_ALIGN_CENTRE));
208 wndLogin->addComponent(new Button(SCREEN_W/2-100, 130, 90, 20, font, "Register", goToRegisterScreen));
209 wndLogin->addComponent(new Button(SCREEN_W/2+10, 130, 90, 20, font, "Login", login));
[9b1e12c]210 wndLogin->addComponent(new Button(920, 10, 80, 20, font, "Quit", quit));
[b35b2b2]211 wndLogin->addComponent(new Button(20, 10, 160, 20, font, "Toggle Debugging", toggleDebugging));
[87b3ee2]212
213 txtUsername = (Textbox*)wndLogin->getComponent(0);
214 txtPassword = (Textbox*)wndLogin->getComponent(1);
[365e156]215 lblLoginStatus = (TextLabel*)wndLogin->getComponent(4);
216
217 cout << "Created login screen" << endl;
[87b3ee2]218
[5c95436]219 wndRegister = new Window(0, 0, SCREEN_W, SCREEN_H);
[9b1e12c]220 wndRegister->addComponent(new Textbox(516, 40, 100, 20, font));
221 wndRegister->addComponent(new Textbox(516, 70, 100, 20, font));
[365e156]222 wndRegister->addComponent(new TextLabel(410, 40, 100, 20, font, "Username:", ALLEGRO_ALIGN_RIGHT));
223 wndRegister->addComponent(new TextLabel(410, 70, 100, 20, font, "Password:", ALLEGRO_ALIGN_RIGHT));
224 wndRegister->addComponent(new RadioButtonList(432, 100, "Pick a class", font));
225 wndRegister->addComponent(new TextLabel((SCREEN_W-600)/2, 190, 600, 20, font, "", ALLEGRO_ALIGN_CENTRE));
226 wndRegister->addComponent(new Button(SCREEN_W/2-100, 220, 90, 20, font, "Back", goToLoginScreen));
227 wndRegister->addComponent(new Button(SCREEN_W/2+10, 220, 90, 20, font, "Submit", registerAccount));
[9b1e12c]228 wndRegister->addComponent(new Button(920, 10, 80, 20, font, "Quit", quit));
[b35b2b2]229 wndRegister->addComponent(new Button(20, 10, 160, 20, font, "Toggle Debugging", toggleDebugging));
[5c95436]230
231 txtUsernameRegister = (Textbox*)wndRegister->getComponent(0);
232 txtPasswordRegister = (Textbox*)wndRegister->getComponent(1);
233
[365e156]234 rblClasses = (RadioButtonList*)wndRegister->getComponent(4);
[5c95436]235 rblClasses->addRadioButton("Warrior");
236 rblClasses->addRadioButton("Ranger");
237
[365e156]238 lblRegisterStatus = (TextLabel*)wndRegister->getComponent(5);
239
240 cout << "Created register screen" << endl;
241
[1785314]242 wndLobby = new Window(0, 0, SCREEN_W, SCREEN_H);
[87b3ee2]243
[1785314]244 cout << "Created lobby screen" << endl;
[87b3ee2]245
[1785314]246 wndGame = new Window(0, 0, SCREEN_W, SCREEN_H);
247 wndGame->addComponent(new Textbox(95, 40, 300, 20, font));
248 wndGame->addComponent(new Button(95, 70, 60, 20, font, "Send", sendChatMessage));
249 wndGame->addComponent(new Button(20, 10, 160, 20, font, "Toggle Debugging", toggleDebugging));
250 wndGame->addComponent(new Button(920, 10, 80, 20, font, "Logout", logout));
[b35b2b2]251
[1785314]252 txtChat = (Textbox*)wndGame->getComponent(0);
253
254 wndGameDebug = new Window(0, 0, SCREEN_W, SCREEN_H);
255 wndGameDebug->addComponent(new Button(20, 10, 160, 20, font, "Toggle Debugging", toggleDebugging));
256 wndGameDebug->addComponent(new Button(920, 10, 80, 20, font, "Logout", logout));
257
258 cout << "Created game screen" << endl;
[365e156]259
[49da01a]260 goToLoginScreen();
[d352805]261
262 event_queue = al_create_event_queue();
263 if(!event_queue) {
264 fprintf(stderr, "failed to create event_queue!\n");
265 al_destroy_display(display);
266 al_destroy_timer(timer);
267 return -1;
268 }
269
270 al_set_target_bitmap(al_get_backbuffer(display));
271
272 al_register_event_source(event_queue, al_get_display_event_source(display));
273 al_register_event_source(event_queue, al_get_timer_event_source(timer));
274 al_register_event_source(event_queue, al_get_keyboard_event_source());
[87b3ee2]275 al_register_event_source(event_queue, al_get_mouse_event_source());
[d352805]276
277 al_clear_to_color(al_map_rgb(0,0,0));
278
279 al_flip_display();
[9a3e6b1]280
281 if (argc != 3) {
282 cout << "Usage: server port" << endl;
283 exit(1);
284 }
285
286 initWinSock();
287
288 sock = socket(AF_INET, SOCK_DGRAM, 0);
289 if (sock < 0)
290 error("socket");
291
[e607c0f]292 set_nonblock(sock);
293
[9a3e6b1]294 server.sin_family = AF_INET;
295 hp = gethostbyname(argv[1]);
296 if (hp==0)
297 error("Unknown host");
298
299 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
300 server.sin_port = htons(atoi(argv[2]));
301
[d352805]302 al_start_timer(timer);
[e607c0f]303
[d352805]304 while(!doexit)
305 {
306 ALLEGRO_EVENT ev;
[3d81c0d]307
[d352805]308 al_wait_for_event(event_queue, &ev);
[87b3ee2]309
310 if(wndCurrent->handleEvent(ev)) {
311 // do nothing
312 }
313 else if(ev.type == ALLEGRO_EVENT_TIMER) {
[a1a3bd5]314 redraw = true; // seems like we should just call a draw function here instead
[d352805]315 }
316 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
[9a3e6b1]317 doexit = true;
[d352805]318 }
319 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) {
320 }
321 else if(ev.type == ALLEGRO_EVENT_KEY_UP) {
322 switch(ev.keyboard.keycode) {
323 case ALLEGRO_KEY_ESCAPE:
324 doexit = true;
325 break;
[4926168]326 case ALLEGRO_KEY_S: // pickup an item next to you
[85bf1e2]327 if (state == STATE_GAME) {
[4926168]328 msgTo.type = MSG_TYPE_PICKUP_FLAG;
329 memcpy(msgTo.buffer, &curPlayerId, 4);
[753fa8a]330 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[4926168]331 }
332 break;
[626e5b0]333 case ALLEGRO_KEY_D: // drop the current item
[85bf1e2]334 if (state == STATE_GAME) {
[4926168]335 // find the current player in the player list
[626e5b0]336 map<unsigned int, Player>::iterator it;
337 Player* p = NULL;
338 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
339 {
340 if (it->second.id == curPlayerId)
341 p = &it->second;
342 }
343
344 if (p != NULL) {
345 int flagType = WorldMap::OBJECT_NONE;
346
347 if (p->hasBlueFlag)
348 flagType = WorldMap::OBJECT_BLUE_FLAG;
349 else if (p->hasRedFlag)
350 flagType = WorldMap::OBJECT_RED_FLAG;
351
352 if (flagType != WorldMap::OBJECT_NONE) {
353 msgTo.type = MSG_TYPE_DROP_FLAG;
354 memcpy(msgTo.buffer, &curPlayerId, 4);
[753fa8a]355 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[626e5b0]356 }
357 }
358 }
359 break;
[d352805]360 }
361 }
[88cdae2]362 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
[1785314]363 if(wndCurrent == wndLobby) {
364 if (ev.mouse.button == 1) { // left click
365 state = STATE_GAME;
366 wndCurrent = wndGame;
367 }
368 }else if(wndCurrent == wndGame) {
[e1f78f5]369 if (ev.mouse.button == 1) { // left click
370 msgTo.type = MSG_TYPE_PLAYER_MOVE;
[88cdae2]371
[e1f78f5]372 POSITION pos;
373 pos.x = ev.mouse.x;
374 pos.y = ev.mouse.y;
375 pos = screenToMap(pos);
[62ee2ce]376
[e1f78f5]377 if (pos.x != -1)
378 {
379 memcpy(msgTo.buffer, &curPlayerId, 4);
380 memcpy(msgTo.buffer+4, &pos.x, 4);
381 memcpy(msgTo.buffer+8, &pos.y, 4);
382
[753fa8a]383 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[e1f78f5]384 }
385 else
386 cout << "Invalid point: User did not click on the map" << endl;
387 }else if (ev.mouse.button == 2) { // right click
388 map<unsigned int, Player>::iterator it;
389
[fbcfc35]390 cout << "Detected a right-click" << endl;
391
[e1f78f5]392 Player* curPlayer;
393 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
394 {
395 if (it->second.id == curPlayerId)
396 curPlayer = &it->second;
397 }
398
399 Player* target;
400 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
401 {
[fbcfc35]402 // need to check if the right-click was actually on this player
[f3cf1a5]403 // right now, this code will target all players other than the current one
[e1f78f5]404 target = &it->second;
405 if (target->id != curPlayerId && target->team != curPlayer->team) {
406 msgTo.type = MSG_TYPE_START_ATTACK;
407 memcpy(msgTo.buffer, &curPlayerId, 4);
408 memcpy(msgTo.buffer+4, &target->id, 4);
[88cdae2]409
[753fa8a]410 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[e1f78f5]411 }
412 }
[62ee2ce]413 }
[ad5d122]414 }
[88cdae2]415 }
[e607c0f]416
[753fa8a]417 if (msgProcessor.receiveMessage(&msgFrom, sock, &from, &outputLog) >= 0)
[fbcfc35]418 processMessage(msgFrom, state, chatConsole, gameMap, mapPlayers, mapProjectiles, curPlayerId, scoreBlue, scoreRed);
[054b50b]419
[a1a3bd5]420 if (redraw)
[e607c0f]421 {
[d352805]422 redraw = false;
[88cdae2]423
[753fa8a]424 msgProcessor.resendUnackedMessages(sock, &outputLog);
425 //msgProcessor.cleanAckedMessages(&outputLog);
[10f6fc2]426
[1785314]427 if (debugging && wndCurrent == wndGame)
428 wndGameDebug->draw(display);
[b35b2b2]429 else
430 wndCurrent->draw(display);
[9a3e6b1]431
[1785314]432 if(wndCurrent == wndGame) {
[b35b2b2]433 if (!debugging)
434 chatConsole.draw(font, al_map_rgb(255,255,255));
[bc70282]435
[87b3ee2]436 al_draw_text(font, al_map_rgb(0, 255, 0), 4, 43, ALLEGRO_ALIGN_LEFT, "Message:");
[62ee2ce]437
[15efb4e]438 ostringstream ossScoreBlue, ossScoreRed;
439
440 ossScoreBlue << "Blue: " << scoreBlue << endl;
441 ossScoreRed << "Red: " << scoreRed << endl;
442
443 al_draw_text(font, al_map_rgb(0, 255, 0), 330, 80, ALLEGRO_ALIGN_LEFT, ossScoreBlue.str().c_str());
444 al_draw_text(font, al_map_rgb(0, 255, 0), 515, 80, ALLEGRO_ALIGN_LEFT, ossScoreRed.str().c_str());
445
[032e550]446 // update players
[a1a3bd5]447 map<unsigned int, Player>::iterator it;
[032e550]448 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
449 {
450 it->second.updateTarget(mapPlayers);
451 }
452
[a1a3bd5]453 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
454 {
[227baaa]455 it->second.move(gameMap); // ignore return value
[a1a3bd5]456 }
457
[8c74150]458 // update projectile positions
459 map<unsigned int, Projectile>::iterator it2;
460 for (it2 = mapProjectiles.begin(); it2 != mapProjectiles.end(); it2++)
461 {
462 it2->second.move(mapPlayers);
463 }
464
[62ee2ce]465 drawMap(gameMap);
[d09fe76]466 drawPlayers(mapPlayers, font, curPlayerId);
[8c74150]467
468 // draw projectiles
469 for (it2 = mapProjectiles.begin(); it2 != mapProjectiles.end(); it2++)
470 {
471 Projectile proj = it2->second;
472
473 FLOAT_POSITION target = mapPlayers[proj.target].pos;
474 float angle = atan2(target.y-proj.pos.toFloat().y, target.x-proj.pos.toFloat().x);
475
476 POSITION start, end;
477 start.x = cos(angle)*15+proj.pos.x;
478 start.y = sin(angle)*15+proj.pos.y;
479 end.x = proj.pos.x;
480 end.y = proj.pos.y;
481
482 start = mapToScreen(start);
483 end = mapToScreen(end);
484
485 al_draw_line(start.x, start.y, end.x, end.y, al_map_rgb(0, 0, 0), 4);
486 }
[87b3ee2]487 }
488
[b35b2b2]489 if (debugging) {
490 //debugConsole.draw(font, al_map_rgb(255,255,255));
491 drawMessageStatus(font);
492 }
493
[d352805]494 al_flip_display();
495 }
496 }
[9a3e6b1]497
498 #if defined WINDOWS
499 closesocket(sock);
500 #elif defined LINUX
501 close(sock);
502 #endif
503
504 shutdownWinSock();
[d352805]505
[87b3ee2]506 delete wndLogin;
[1785314]507 delete wndRegister;
508 delete wndLobby;
509 delete wndGame;
510 delete wndGameDebug;
[87b3ee2]511
[62ee2ce]512 delete gameMap;
513
[d352805]514 al_destroy_event_queue(event_queue);
515 al_destroy_display(display);
516 al_destroy_timer(timer);
[8271c78]517
518 outputLog << "Stopped client on " << getCurrentDateTimeString() << endl;
519 outputLog.close();
520
[d352805]521 return 0;
522}
523
[1f1eb58]524
525
[4da5aa3]526// need to make a function like this that works on windows
527void error(const char *msg)
528{
529 perror(msg);
530 shutdownWinSock();
531 exit(1);
532}
533
[0dde5da]534void initWinSock()
535{
536#if defined WINDOWS
537 WORD wVersionRequested;
538 WSADATA wsaData;
539 int wsaerr;
540
541 wVersionRequested = MAKEWORD(2, 2);
542 wsaerr = WSAStartup(wVersionRequested, &wsaData);
543
544 if (wsaerr != 0) {
545 cout << "The Winsock dll not found." << endl;
546 exit(1);
547 }else
548 cout << "The Winsock dll was found." << endl;
549#endif
550}
551
552void shutdownWinSock()
553{
554#if defined WINDOWS
555 WSACleanup();
556#endif
[1912323]557}
558
[62ee2ce]559POSITION screenToMap(POSITION pos)
560{
561 pos.x = pos.x-300;
562 pos.y = pos.y-100;
563
564 if (pos.x < 0 || pos.y < 0)
565 {
566 pos.x = -1;
567 pos.y = -1;
568 }
569
570 return pos;
571}
572
573POSITION mapToScreen(POSITION pos)
574{
575 pos.x = pos.x+300;
576 pos.y = pos.y+100;
577
578 return pos;
579}
580
[ca44f82]581POSITION mapToScreen(FLOAT_POSITION pos)
582{
583 POSITION p;
584 p.x = pos.x+300;
585 p.y = pos.y+100;
586
587 return p;
588}
589
[fbcfc35]590void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole, WorldMap *gameMap, map<unsigned int, Player>& mapPlayers, map<unsigned int, Projectile>& mapProjectiles, unsigned int& curPlayerId, int &scoreBlue, int &scoreRed)
[1912323]591{
[4da5aa3]592 string response = string(msg.buffer);
593
594 switch(state)
595 {
596 case STATE_START:
597 {
[e607c0f]598 cout << "In STATE_START" << endl;
599
[87b3ee2]600 switch(msg.type)
[4da5aa3]601 {
[87b3ee2]602 case MSG_TYPE_REGISTER:
603 {
[365e156]604 lblRegisterStatus->setText(response);
[87b3ee2]605 break;
606 }
[bc70282]607 default:
608 {
609 cout << "(STATE_REGISTER) Received invalid message of type " << msg.type << endl;
610 break;
611 }
612 }
613
614 break;
615 }
[1785314]616 case STATE_LOBBY:
617 case STATE_GAME:
[bc70282]618 {
619 switch(msg.type)
620 {
[87b3ee2]621 case MSG_TYPE_LOGIN:
622 {
623 if (response.compare("Player has already logged in.") == 0)
624 {
[bc70282]625 goToLoginScreen();
626 state = STATE_START;
627
[365e156]628 lblLoginStatus->setText(response);
[87b3ee2]629 }
630 else if (response.compare("Incorrect username or password") == 0)
631 {
[bc70282]632 goToLoginScreen();
633 state = STATE_START;
634
[365e156]635 lblLoginStatus->setText(response);
[87b3ee2]636 }
637 else
638 {
[1785314]639 wndCurrent = wndLobby;
[88cdae2]640
641 Player p("", "");
642 p.deserialize(msg.buffer);
643 mapPlayers[p.id] = p;
644 curPlayerId = p.id;
645
646 cout << "Got a valid login response with the player" << endl;
[1f1eb58]647 cout << "Player id: " << curPlayerId << endl;
648 cout << "Player health: " << p.health << endl;
[bc70282]649 cout << "player map size: " << mapPlayers.size() << endl;
[87b3ee2]650 }
[88cdae2]651
[a1a3bd5]652 break;
653 }
654 case MSG_TYPE_LOGOUT:
655 {
[054b50b]656 cout << "Got a logout message" << endl;
[a1a3bd5]657
[87b3ee2]658 if (response.compare("You have successfully logged out.") == 0)
659 {
660 cout << "Logged out" << endl;
661 state = STATE_START;
[49da01a]662 goToLoginScreen();
[87b3ee2]663 }
[054b50b]664
665 break;
666 }
[4c202e0]667 case MSG_TYPE_PLAYER:
668 {
[1f1eb58]669 cout << "Received MSG_TYPE_PLAYER" << endl;
670
[60776f2]671 Player p("", "");
672 p.deserialize(msg.buffer);
[054b50b]673 p.timeLastUpdated = getCurrentMillis();
[032e550]674 p.isChasing = false;
[5a5f131]675 if (p.health <= 0)
676 p.isDead = true;
677 else
678 p.isDead = false;
679
[3a79253]680 mapPlayers[p.id] = p;
[4c202e0]681
[eb8adb1]682 break;
683 }
[a1a3bd5]684 case MSG_TYPE_PLAYER_MOVE:
685 {
686 unsigned int id;
687 int x, y;
688
689 memcpy(&id, msg.buffer, 4);
690 memcpy(&x, msg.buffer+4, 4);
691 memcpy(&y, msg.buffer+8, 4);
692
693 mapPlayers[id].target.x = x;
694 mapPlayers[id].target.y = y;
695
696 break;
697 }
[eb8adb1]698 case MSG_TYPE_CHAT:
699 {
700 chatConsole.addLine(response);
[4c202e0]701
[87b3ee2]702 break;
703 }
[45b2750]704 case MSG_TYPE_OBJECT:
705 {
[1785314]706 cout << "Received object message in STATE_LOBBY." << endl;
[45b2750]707
708 WorldMap::Object o(0, WorldMap::OBJECT_NONE, 0, 0);
709 o.deserialize(msg.buffer);
[bc70282]710 cout << "object id: " << o.id << endl;
[45b2750]711 gameMap->updateObject(o.id, o.type, o.pos.x, o.pos.y);
712
713 break;
714 }
[2df63d6]715 case MSG_TYPE_REMOVE_OBJECT:
716 {
[7511a2b]717 cout << "Received REMOVE_OBJECT message!" << endl;
718
[2df63d6]719 int id;
720 memcpy(&id, msg.buffer, 4);
[7511a2b]721
722 cout << "Removing object with id " << id << endl;
723
[2df63d6]724 if (!gameMap->removeObject(id))
725 cout << "Did not remove the object" << endl;
[7511a2b]726
727 break;
[2df63d6]728 }
[15efb4e]729 case MSG_TYPE_SCORE:
730 {
731 memcpy(&scoreBlue, msg.buffer, 4);
732 memcpy(&scoreRed, msg.buffer+4, 4);
733
734 break;
735 }
[b978503]736 case MSG_TYPE_ATTACK:
737 {
[032e550]738 cout << "Received ATTACK message" << endl;
739
740 break;
741 }
742 case MSG_TYPE_START_ATTACK:
743 {
744 cout << "Received START_ATTACK message" << endl;
745
746 unsigned int id, targetID;
747 memcpy(&id, msg.buffer, 4);
748 memcpy(&targetID, msg.buffer+4, 4);
749
750 cout << "source id: " << id << endl;
751 cout << "target id: " << targetID << endl;
752
753 Player* source = &mapPlayers[id];
754 source->targetPlayer = targetID;
755 source->isChasing = true;
756
[b978503]757 break;
758 }
759 case MSG_TYPE_PROJECTILE:
760 {
[8c74150]761 cout << "Received a PROJECTILE message" << endl;
[fbcfc35]762
763 int id, x, y, targetId;
764
765 memcpy(&id, msg.buffer, 4);
766 memcpy(&x, msg.buffer+4, 4);
767 memcpy(&y, msg.buffer+8, 4);
768 memcpy(&targetId, msg.buffer+12, 4);
769
[8c74150]770 cout << "id: " << id << endl;
771 cout << "x: " << x << endl;
772 cout << "y: " << y << endl;
773 cout << "Target: " << targetId << endl;
774
775 Projectile proj(x, y, targetId, 0);
776 proj.setId(id);
777
778 mapProjectiles[id] = proj;
[fbcfc35]779
[b978503]780 break;
781 }
782 case MSG_TYPE_REMOVE_PROJECTILE:
783 {
[8c74150]784 cout << "Received a REMOVE_PROJECTILE message" << endl;
785
786 int id;
787
788 memcpy(&id, msg.buffer, 4);
789
790 mapProjectiles.erase(id);
791
[b978503]792 break;
793 }
[45b2750]794 default:
795 {
[1785314]796 cout << "(STATE_LOBBY) Received invlaid message of type " << msg.type << endl;
[365e156]797 break;
[45b2750]798 }
[4da5aa3]799 }
[eb8adb1]800
[4da5aa3]801 break;
802 }
803 default:
804 {
805 cout << "The state has an invalid value: " << state << endl;
806
807 break;
808 }
809 }
[0dde5da]810}
[87b3ee2]811
[d436ac4]812// this should probably be in the WorldMap class
[62ee2ce]813void drawMap(WorldMap* gameMap)
814{
815 POSITION mapPos;
816 mapPos.x = 0;
817 mapPos.y = 0;
818 mapPos = mapToScreen(mapPos);
[6e66ffd]819
[147f662]820 for (int x=0; x<gameMap->width; x++)
[62ee2ce]821 {
[147f662]822 for (int y=0; y<gameMap->height; y++)
[62ee2ce]823 {
824 WorldMap::TerrainType el = gameMap->getElement(x, y);
[cc1c6c1]825 WorldMap::StructureType structure = gameMap->getStructure(x, y);
[62ee2ce]826
827 if (el == WorldMap::TERRAIN_GRASS)
828 al_draw_filled_rectangle(x*25+mapPos.x, y*25+mapPos.y, x*25+25+mapPos.x, y*25+25+mapPos.y, al_map_rgb(0, 255, 0));
829 else if (el == WorldMap::TERRAIN_OCEAN)
830 al_draw_filled_rectangle(x*25+mapPos.x, y*25+mapPos.y, x*25+25+mapPos.x, y*25+25+mapPos.y, al_map_rgb(0, 0, 255));
831 else if (el == WorldMap::TERRAIN_ROCK)
832 al_draw_filled_rectangle(x*25+mapPos.x, y*25+mapPos.y, x*25+25+mapPos.x, y*25+25+mapPos.y, al_map_rgb(100, 100, 0));
[a1a3bd5]833
[6e66ffd]834 if (structure == WorldMap::STRUCTURE_BLUE_FLAG) {
835 al_draw_circle(x*25+12+mapPos.x, y*25+12+mapPos.y, 12, al_map_rgb(0, 0, 0), 3);
836 //al_draw_filled_rectangle(x*25+5+mapPos.x, y*25+5+mapPos.y, x*25+20+mapPos.x, y*25+20+mapPos.y, al_map_rgb(0, 0, 255));
837 }else if (structure == WorldMap::STRUCTURE_RED_FLAG) {
838 al_draw_circle(x*25+12+mapPos.x, y*25+12+mapPos.y, 12, al_map_rgb(0, 0, 0), 3);
839 //al_draw_filled_rectangle(x*25+5+mapPos.x, y*25+5+mapPos.y, x*25+20+mapPos.x, y*25+20+mapPos.y, al_map_rgb(255, 0, 0));
840 }
841 }
842 }
843
[f3cf1a5]844 for (int x=0; x<gameMap->width; x++)
[6e66ffd]845 {
[f3cf1a5]846 for (int y=0; y<gameMap->height; y++)
[6e66ffd]847 {
848 vector<WorldMap::Object> vctObjects = gameMap->getObjects(x, y);
849
850 vector<WorldMap::Object>::iterator it;
851 for(it = vctObjects.begin(); it != vctObjects.end(); it++) {
852 switch(it->type) {
853 case WorldMap::OBJECT_BLUE_FLAG:
854 al_draw_filled_rectangle(it->pos.x-8+mapPos.x, it->pos.y-8+mapPos.y, it->pos.x+8+mapPos.x, it->pos.y+8+mapPos.y, al_map_rgb(0, 0, 255));
855 break;
856 case WorldMap::OBJECT_RED_FLAG:
857 al_draw_filled_rectangle(it->pos.x-8+mapPos.x, it->pos.y-8+mapPos.y, it->pos.x+8+mapPos.x, it->pos.y+8+mapPos.y, al_map_rgb(255, 0, 0));
858 break;
859 }
860 }
[62ee2ce]861 }
862 }
863}
864
[d09fe76]865void drawPlayers(map<unsigned int, Player>& mapPlayers, ALLEGRO_FONT* font, unsigned int curPlayerId)
[88cdae2]866{
867 map<unsigned int, Player>::iterator it;
868
[62ee2ce]869 Player* p;
870 POSITION pos;
[d09fe76]871 ALLEGRO_COLOR color;
[62ee2ce]872
[88cdae2]873 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
874 {
[62ee2ce]875 p = &it->second;
[5a5f131]876
877 if (p->isDead)
878 continue;
879
[62ee2ce]880 pos = mapToScreen(p->pos);
[88cdae2]881
[7efed11]882 if (p->id == curPlayerId)
[a6066e8]883 al_draw_filled_circle(pos.x, pos.y, 14, al_map_rgb(0, 0, 0));
884
885 if (p->team == 0)
[d09fe76]886 color = al_map_rgb(0, 0, 255);
[a6066e8]887 else if (p->team == 1)
[d09fe76]888 color = al_map_rgb(255, 0, 0);
889
890 al_draw_filled_circle(pos.x, pos.y, 12, color);
891
892 // draw player class
893 int fontHeight = al_get_font_line_height(font);
894
895 string strClass;
896 switch (p->playerClass) {
897 case Player::CLASS_WARRIOR:
898 strClass = "W";
899 break;
900 case Player::CLASS_RANGER:
901 strClass = "R";
902 break;
903 case Player::CLASS_NONE:
904 strClass = "";
905 break;
906 default:
907 strClass = "";
908 break;
909 }
910 al_draw_text(font, al_map_rgb(0, 0, 0), pos.x, pos.y-fontHeight/2, ALLEGRO_ALIGN_CENTRE, strClass.c_str());
911
912 // draw player health
913 al_draw_filled_rectangle(pos.x-12, pos.y-24, pos.x+12, pos.y-16, al_map_rgb(0, 0, 0));
914 if (it->second.maxHealth != 0)
[e1f78f5]915 al_draw_filled_rectangle(pos.x-11, pos.y-23, pos.x-11+(22*it->second.health)/it->second.maxHealth, pos.y-17, al_map_rgb(255, 0, 0));
[7efed11]916
[7d91bbe]917 if (p->hasBlueFlag)
[7efed11]918 al_draw_filled_rectangle(pos.x+4, pos.y-18, pos.x+18, pos.y-4, al_map_rgb(0, 0, 255));
[a6066e8]919 else if (p->hasRedFlag)
[7efed11]920 al_draw_filled_rectangle(pos.x+4, pos.y-18, pos.x+18, pos.y-4, al_map_rgb(255, 0, 0));
[88cdae2]921 }
922}
923
[5c95436]924void goToRegisterScreen()
925{
926 txtUsernameRegister->clear();
927 txtPasswordRegister->clear();
[49da01a]928 lblRegisterStatus->setText("");
929 rblClasses->setSelectedButton(-1);
930
931 wndCurrent = wndRegister;
[5c95436]932}
933
934void goToLoginScreen()
[87b3ee2]935{
936 txtUsername->clear();
937 txtPassword->clear();
[49da01a]938 lblLoginStatus->setText("");
939
940 wndCurrent = wndLogin;
[5c95436]941}
942
[bc70282]943// maybe need a goToGameScreen function as well and add state changes to these functions as well
944
[5c95436]945void registerAccount()
946{
947 string username = txtUsernameRegister->getStr();
948 string password = txtPasswordRegister->getStr();
949
950 txtUsernameRegister->clear();
951 txtPasswordRegister->clear();
952 // maybe clear rblClasses as well (add a method to RadioButtonList to enable this)
953
954 Player::PlayerClass playerClass;
955
956 switch (rblClasses->getSelectedButton()) {
957 case 0:
958 playerClass = Player::CLASS_WARRIOR;
959 break;
960 case 1:
961 playerClass = Player::CLASS_RANGER;
962 break;
963 default:
964 cout << "Invalid class selection" << endl;
965 playerClass = Player::CLASS_NONE;
966 break;
967 }
[87b3ee2]968
969 msgTo.type = MSG_TYPE_REGISTER;
970
971 strcpy(msgTo.buffer, username.c_str());
972 strcpy(msgTo.buffer+username.size()+1, password.c_str());
[5c95436]973 memcpy(msgTo.buffer+username.size()+password.size()+2, &playerClass, 4);
[87b3ee2]974
[753fa8a]975 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[87b3ee2]976}
977
978void login()
979{
980 string strUsername = txtUsername->getStr();
981 string strPassword = txtPassword->getStr();
982 username = strUsername;
983
984 txtUsername->clear();
985 txtPassword->clear();
986
987 msgTo.type = MSG_TYPE_LOGIN;
988
989 strcpy(msgTo.buffer, strUsername.c_str());
990 strcpy(msgTo.buffer+username.size()+1, strPassword.c_str());
991
[753fa8a]992 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[bc70282]993
[1785314]994 state = STATE_LOBBY;
[87b3ee2]995}
996
997void logout()
998{
999 txtChat->clear();
[297682c]1000 chatConsole.clear();
[87b3ee2]1001
1002 msgTo.type = MSG_TYPE_LOGOUT;
1003
1004 strcpy(msgTo.buffer, username.c_str());
1005
[753fa8a]1006 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[87b3ee2]1007}
1008
1009void quit()
1010{
1011 doexit = true;
1012}
1013
1014void sendChatMessage()
1015{
1016 string msg = txtChat->getStr();
1017
1018 txtChat->clear();
1019
1020 msgTo.type = MSG_TYPE_CHAT;
1021
1022 strcpy(msgTo.buffer, msg.c_str());
1023
[753fa8a]1024 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
[87b3ee2]1025}
[1f1eb58]1026
[b35b2b2]1027void toggleDebugging()
1028{
1029 debugging = !debugging;
1030}
1031
1032int getRefreshRate(int width, int height)
1033{
[1f1eb58]1034 int numRefreshRates = al_get_num_display_modes();
1035 ALLEGRO_DISPLAY_MODE displayMode;
1036
1037 for(int i=0; i<numRefreshRates; i++) {
1038 al_get_display_mode(i, &displayMode);
1039
1040 if (displayMode.width == width && displayMode.height == height)
1041 return displayMode.refresh_rate;
1042 }
1043
1044 return 0;
[dee75cc]1045}
[b35b2b2]1046
1047void drawMessageStatus(ALLEGRO_FONT* font)
1048{
[753fa8a]1049 int clientMsgOffset = 5;
1050 int serverMsgOffset = 950;
[b35b2b2]1051
[753fa8a]1052 al_draw_text(font, al_map_rgb(0, 255, 255), 0+clientMsgOffset, 43, ALLEGRO_ALIGN_LEFT, "ID");
1053 al_draw_text(font, al_map_rgb(0, 255, 255), 20+clientMsgOffset, 43, ALLEGRO_ALIGN_LEFT, "Type");
1054 al_draw_text(font, al_map_rgb(0, 255, 255), 240+clientMsgOffset, 43, ALLEGRO_ALIGN_LEFT, "Acked?");
[b35b2b2]1055
[753fa8a]1056 al_draw_text(font, al_map_rgb(0, 255, 255), serverMsgOffset, 43, ALLEGRO_ALIGN_LEFT, "ID");
[b35b2b2]1057
1058 map<unsigned int, map<unsigned long, MessageContainer> >& sentMessages = msgProcessor.getSentMessages();
1059 int id, type;
1060 bool acked;
1061 ostringstream ossId, ossAcked;
1062
1063 map<unsigned int, map<unsigned long, MessageContainer> >::iterator it;
1064
1065 int msgCount = 0;
1066 for (it = sentMessages.begin(); it != sentMessages.end(); it++) {
1067 map<unsigned long, MessageContainer> playerMessage = it->second;
1068 map<unsigned long, MessageContainer>::iterator it2;
1069 for (it2 = playerMessage.begin(); it2 != playerMessage.end(); it2++) {
1070
1071 id = it->first;
1072 ossId.str("");;
1073 ossId << id;
1074
1075 type = it2->second.getMessage()->type;
1076 string typeStr = MessageContainer::getMsgTypeString(type);
1077
1078 acked = it2->second.getAcked();
1079 ossAcked.str("");;
1080 ossAcked << boolalpha << acked;
1081
[753fa8a]1082 al_draw_text(font, al_map_rgb(0, 255, 0), clientMsgOffset, 60+15*msgCount, ALLEGRO_ALIGN_LEFT, ossId.str().c_str());
1083 al_draw_text(font, al_map_rgb(0, 255, 0), 20+clientMsgOffset, 60+15*msgCount, ALLEGRO_ALIGN_LEFT, typeStr.c_str());
1084 al_draw_text(font, al_map_rgb(0, 255, 0), 240+clientMsgOffset, 60+15*msgCount, ALLEGRO_ALIGN_LEFT, ossAcked.str().c_str());
[b35b2b2]1085
1086 msgCount++;
1087 }
1088 }
1089
[753fa8a]1090 if (msgProcessor.getAckedMessages().size() > 0) {
1091 map<unsigned int, unsigned long long> ackedMessages = msgProcessor.getAckedMessages()[0];
1092 map<unsigned int, unsigned long long>::iterator it3;
[b35b2b2]1093
[753fa8a]1094 msgCount = 0;
1095 for (it3 = ackedMessages.begin(); it3 != ackedMessages.end(); it3++) {
1096 ossId.str("");;
1097 ossId << it3->first;
[b35b2b2]1098
[753fa8a]1099 al_draw_text(font, al_map_rgb(255, 0, 0), 25+serverMsgOffset, 60+15*msgCount, ALLEGRO_ALIGN_LEFT, ossId.str().c_str());
[b35b2b2]1100
[753fa8a]1101 msgCount++;
1102 }
[b35b2b2]1103 }
1104}
Note: See TracBrowser for help on using the repository browser.