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

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

Added a lobby screen to the client where players will create and join games

  • Property mode set to 100644
File size: 32.3 KB
Line 
1#include "../../common/Compiler.h"
2
3#if defined WINDOWS
4 #include <winsock2.h>
5 #include <WS2tcpip.h>
6#elif defined LINUX
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>
13#endif
14
15#include <cstdio>
16#include <cstdlib>
17#include <cmath>
18#include <sys/types.h>
19#include <string>
20#include <iostream>
21#include <sstream>
22#include <fstream>
23#include <map>
24
25#include <allegro5/allegro.h>
26#include <allegro5/allegro_font.h>
27#include <allegro5/allegro_ttf.h>
28#include <allegro5/allegro_primitives.h>
29
30#include "../../common/Common.h"
31#include "../../common/MessageContainer.h"
32#include "../../common/MessageProcessor.h"
33#include "../../common/WorldMap.h"
34#include "../../common/Player.h"
35#include "../../common/Projectile.h"
36
37#include "Window.h"
38#include "Textbox.h"
39#include "Button.h"
40#include "RadioButtonList.h"
41#include "TextLabel.h"
42#include "chat.h"
43
44#ifdef WINDOWS
45 #pragma comment(lib, "ws2_32.lib")
46#endif
47
48using namespace std;
49
50void initWinSock();
51void shutdownWinSock();
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);
53void drawMap(WorldMap* gameMap);
54void drawPlayers(map<unsigned int, Player>& mapPlayers, ALLEGRO_FONT* font, unsigned int curPlayerId);
55POSITION screenToMap(POSITION pos);
56POSITION mapToScreen(POSITION pos);
57int getRefreshRate(int width, int height);
58
59// callbacks
60void goToLoginScreen();
61void goToRegisterScreen();
62void registerAccount();
63void login();
64void logout();
65void quit();
66void sendChatMessage();
67void toggleDebugging();
68void drawMessageStatus(ALLEGRO_FONT* font);
69
70void error(const char *);
71
72const float FPS = 60;
73const int SCREEN_W = 1024;
74const int SCREEN_H = 768;
75
76enum STATE {
77 STATE_START,
78 STATE_LOBBY,
79 STATE_GAME
80};
81
82int state;
83
84bool doexit;
85
86Window* wndLogin;
87Window* wndRegister;
88Window* wndLobby;
89Window* wndGame;
90Window* wndGameDebug;
91Window* wndCurrent;
92
93// wndLogin
94Textbox* txtUsername;
95Textbox* txtPassword;
96TextLabel* lblLoginStatus;
97
98// wndRegister
99Textbox* txtUsernameRegister;
100Textbox* txtPasswordRegister;
101RadioButtonList* rblClasses;
102TextLabel* lblRegisterStatus;
103
104// wndGame
105Textbox* txtChat;
106
107int sock;
108struct sockaddr_in server, from;
109struct hostent *hp;
110NETWORK_MSG msgTo, msgFrom;
111string username;
112chat chatConsole, debugConsole;
113bool debugging;
114
115MessageProcessor msgProcessor;
116ofstream outputLog;
117
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;
125 doexit = false;
126 map<unsigned int, Player> mapPlayers;
127 map<unsigned int, Projectile> mapProjectiles;
128 unsigned int curPlayerId = -1;
129 int scoreBlue, scoreRed;
130 bool fullscreen = false;
131 debugging = false;
132
133 scoreBlue = 0;
134 scoreRed = 0;
135
136 state = STATE_START;
137
138 if(!al_init()) {
139 fprintf(stderr, "failed to initialize allegro!\n");
140 return -1;
141 }
142
143 outputLog.open("client.log", ios::app);
144 outputLog << "Started client on " << getCurrentDateTimeString() << endl;
145
146 if (al_init_primitives_addon())
147 cout << "Primitives initialized" << endl;
148 else
149 cout << "Primitives not initialized" << endl;
150
151 al_init_font_addon();
152 al_init_ttf_addon();
153
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
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 }
170
171 if(!al_install_mouse()) {
172 fprintf(stderr, "failed to initialize the mouse!\n");
173 return -1;
174 }
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
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);
189 if(!display) {
190 fprintf(stderr, "failed to create display!\n");
191 al_destroy_timer(timer);
192 return -1;
193 }
194
195 WorldMap* gameMap = WorldMap::loadMapFromFile("../../data/map.txt");
196
197 cout << "Loaded map" << endl;
198
199 debugConsole.addLine("Debug console:");
200 debugConsole.addLine("");
201
202 wndLogin = new Window(0, 0, SCREEN_W, SCREEN_H);
203 wndLogin->addComponent(new Textbox(516, 40, 100, 20, font));
204 wndLogin->addComponent(new Textbox(516, 70, 100, 20, font));
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));
210 wndLogin->addComponent(new Button(920, 10, 80, 20, font, "Quit", quit));
211 wndLogin->addComponent(new Button(20, 10, 160, 20, font, "Toggle Debugging", toggleDebugging));
212
213 txtUsername = (Textbox*)wndLogin->getComponent(0);
214 txtPassword = (Textbox*)wndLogin->getComponent(1);
215 lblLoginStatus = (TextLabel*)wndLogin->getComponent(4);
216
217 cout << "Created login screen" << endl;
218
219 wndRegister = new Window(0, 0, SCREEN_W, SCREEN_H);
220 wndRegister->addComponent(new Textbox(516, 40, 100, 20, font));
221 wndRegister->addComponent(new Textbox(516, 70, 100, 20, font));
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));
228 wndRegister->addComponent(new Button(920, 10, 80, 20, font, "Quit", quit));
229 wndRegister->addComponent(new Button(20, 10, 160, 20, font, "Toggle Debugging", toggleDebugging));
230
231 txtUsernameRegister = (Textbox*)wndRegister->getComponent(0);
232 txtPasswordRegister = (Textbox*)wndRegister->getComponent(1);
233
234 rblClasses = (RadioButtonList*)wndRegister->getComponent(4);
235 rblClasses->addRadioButton("Warrior");
236 rblClasses->addRadioButton("Ranger");
237
238 lblRegisterStatus = (TextLabel*)wndRegister->getComponent(5);
239
240 cout << "Created register screen" << endl;
241
242 wndLobby = new Window(0, 0, SCREEN_W, SCREEN_H);
243
244 cout << "Created lobby screen" << endl;
245
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));
251
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;
259
260 goToLoginScreen();
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());
275 al_register_event_source(event_queue, al_get_mouse_event_source());
276
277 al_clear_to_color(al_map_rgb(0,0,0));
278
279 al_flip_display();
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
292 set_nonblock(sock);
293
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
302 al_start_timer(timer);
303
304 while(!doexit)
305 {
306 ALLEGRO_EVENT ev;
307
308 al_wait_for_event(event_queue, &ev);
309
310 if(wndCurrent->handleEvent(ev)) {
311 // do nothing
312 }
313 else if(ev.type == ALLEGRO_EVENT_TIMER) {
314 redraw = true; // seems like we should just call a draw function here instead
315 }
316 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
317 doexit = true;
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;
326 case ALLEGRO_KEY_S: // pickup an item next to you
327 if (state == STATE_LOBBY) {
328 msgTo.type = MSG_TYPE_PICKUP_FLAG;
329 memcpy(msgTo.buffer, &curPlayerId, 4);
330 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
331 }
332 break;
333 case ALLEGRO_KEY_D: // drop the current item
334 if (state == STATE_LOBBY) {
335 // find the current player in the player list
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);
355 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
356 }
357 }
358 }
359 break;
360 }
361 }
362 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
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) {
369 if (ev.mouse.button == 1) { // left click
370 msgTo.type = MSG_TYPE_PLAYER_MOVE;
371
372 POSITION pos;
373 pos.x = ev.mouse.x;
374 pos.y = ev.mouse.y;
375 pos = screenToMap(pos);
376
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
383 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
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
390 cout << "Detected a right-click" << endl;
391
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 {
402 // need to check if the right-click was actually on this player
403 // right now, this code will target all players other than the current one
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);
409
410 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
411 }
412 }
413 }
414 }
415 }
416
417 if (msgProcessor.receiveMessage(&msgFrom, sock, &from, &outputLog) >= 0)
418 processMessage(msgFrom, state, chatConsole, gameMap, mapPlayers, mapProjectiles, curPlayerId, scoreBlue, scoreRed);
419
420 if (redraw)
421 {
422 redraw = false;
423
424 msgProcessor.resendUnackedMessages(sock, &outputLog);
425 //msgProcessor.cleanAckedMessages(&outputLog);
426
427 if (debugging && wndCurrent == wndGame)
428 wndGameDebug->draw(display);
429 else
430 wndCurrent->draw(display);
431
432 if(wndCurrent == wndGame) {
433 if (!debugging)
434 chatConsole.draw(font, al_map_rgb(255,255,255));
435
436 al_draw_text(font, al_map_rgb(0, 255, 0), 4, 43, ALLEGRO_ALIGN_LEFT, "Message:");
437
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
446 // update players
447 map<unsigned int, Player>::iterator it;
448 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
449 {
450 it->second.updateTarget(mapPlayers);
451 }
452
453 for (it = mapPlayers.begin(); it != mapPlayers.end(); it++)
454 {
455 it->second.move(gameMap); // ignore return value
456 }
457
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
465 drawMap(gameMap);
466 drawPlayers(mapPlayers, font, curPlayerId);
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 }
487 }
488
489 if (debugging) {
490 //debugConsole.draw(font, al_map_rgb(255,255,255));
491 drawMessageStatus(font);
492 }
493
494 al_flip_display();
495 }
496 }
497
498 #if defined WINDOWS
499 closesocket(sock);
500 #elif defined LINUX
501 close(sock);
502 #endif
503
504 shutdownWinSock();
505
506 delete wndLogin;
507 delete wndRegister;
508 delete wndLobby;
509 delete wndGame;
510 delete wndGameDebug;
511
512 delete gameMap;
513
514 al_destroy_event_queue(event_queue);
515 al_destroy_display(display);
516 al_destroy_timer(timer);
517
518 outputLog << "Stopped client on " << getCurrentDateTimeString() << endl;
519 outputLog.close();
520
521 return 0;
522}
523
524
525
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
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
557}
558
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
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
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)
591{
592 string response = string(msg.buffer);
593
594 switch(state)
595 {
596 case STATE_START:
597 {
598 cout << "In STATE_START" << endl;
599
600 switch(msg.type)
601 {
602 case MSG_TYPE_REGISTER:
603 {
604 lblRegisterStatus->setText(response);
605 break;
606 }
607 default:
608 {
609 cout << "(STATE_REGISTER) Received invalid message of type " << msg.type << endl;
610 break;
611 }
612 }
613
614 break;
615 }
616 case STATE_LOBBY:
617 case STATE_GAME:
618 {
619 switch(msg.type)
620 {
621 case MSG_TYPE_LOGIN:
622 {
623 if (response.compare("Player has already logged in.") == 0)
624 {
625 goToLoginScreen();
626 state = STATE_START;
627
628 lblLoginStatus->setText(response);
629 }
630 else if (response.compare("Incorrect username or password") == 0)
631 {
632 goToLoginScreen();
633 state = STATE_START;
634
635 lblLoginStatus->setText(response);
636 }
637 else
638 {
639 wndCurrent = wndLobby;
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;
647 cout << "Player id: " << curPlayerId << endl;
648 cout << "Player health: " << p.health << endl;
649 cout << "player map size: " << mapPlayers.size() << endl;
650 }
651
652 break;
653 }
654 case MSG_TYPE_LOGOUT:
655 {
656 cout << "Got a logout message" << endl;
657
658 if (response.compare("You have successfully logged out.") == 0)
659 {
660 cout << "Logged out" << endl;
661 state = STATE_START;
662 goToLoginScreen();
663 }
664
665 break;
666 }
667 case MSG_TYPE_PLAYER:
668 {
669 cout << "Received MSG_TYPE_PLAYER" << endl;
670
671 Player p("", "");
672 p.deserialize(msg.buffer);
673 p.timeLastUpdated = getCurrentMillis();
674 p.isChasing = false;
675 if (p.health <= 0)
676 p.isDead = true;
677 else
678 p.isDead = false;
679
680 mapPlayers[p.id] = p;
681
682 break;
683 }
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 }
698 case MSG_TYPE_CHAT:
699 {
700 chatConsole.addLine(response);
701
702 break;
703 }
704 case MSG_TYPE_OBJECT:
705 {
706 cout << "Received object message in STATE_LOBBY." << endl;
707
708 WorldMap::Object o(0, WorldMap::OBJECT_NONE, 0, 0);
709 o.deserialize(msg.buffer);
710 cout << "object id: " << o.id << endl;
711 gameMap->updateObject(o.id, o.type, o.pos.x, o.pos.y);
712
713 break;
714 }
715 case MSG_TYPE_REMOVE_OBJECT:
716 {
717 cout << "Received REMOVE_OBJECT message!" << endl;
718
719 int id;
720 memcpy(&id, msg.buffer, 4);
721
722 cout << "Removing object with id " << id << endl;
723
724 if (!gameMap->removeObject(id))
725 cout << "Did not remove the object" << endl;
726
727 break;
728 }
729 case MSG_TYPE_SCORE:
730 {
731 memcpy(&scoreBlue, msg.buffer, 4);
732 memcpy(&scoreRed, msg.buffer+4, 4);
733
734 break;
735 }
736 case MSG_TYPE_ATTACK:
737 {
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
757 break;
758 }
759 case MSG_TYPE_PROJECTILE:
760 {
761 cout << "Received a PROJECTILE message" << endl;
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
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;
779
780 break;
781 }
782 case MSG_TYPE_REMOVE_PROJECTILE:
783 {
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
792 break;
793 }
794 default:
795 {
796 cout << "(STATE_LOBBY) Received invlaid message of type " << msg.type << endl;
797 break;
798 }
799 }
800
801 break;
802 }
803 default:
804 {
805 cout << "The state has an invalid value: " << state << endl;
806
807 break;
808 }
809 }
810}
811
812// this should probably be in the WorldMap class
813void drawMap(WorldMap* gameMap)
814{
815 POSITION mapPos;
816 mapPos.x = 0;
817 mapPos.y = 0;
818 mapPos = mapToScreen(mapPos);
819
820 for (int x=0; x<gameMap->width; x++)
821 {
822 for (int y=0; y<gameMap->height; y++)
823 {
824 WorldMap::TerrainType el = gameMap->getElement(x, y);
825 WorldMap::StructureType structure = gameMap->getStructure(x, y);
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));
833
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
844 for (int x=0; x<gameMap->width; x++)
845 {
846 for (int y=0; y<gameMap->height; y++)
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 }
861 }
862 }
863}
864
865void drawPlayers(map<unsigned int, Player>& mapPlayers, ALLEGRO_FONT* font, unsigned int curPlayerId)
866{
867 map<unsigned int, Player>::iterator it;
868
869 Player* p;
870 POSITION pos;
871 ALLEGRO_COLOR color;
872
873 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
874 {
875 p = &it->second;
876
877 if (p->isDead)
878 continue;
879
880 pos = mapToScreen(p->pos);
881
882 if (p->id == curPlayerId)
883 al_draw_filled_circle(pos.x, pos.y, 14, al_map_rgb(0, 0, 0));
884
885 if (p->team == 0)
886 color = al_map_rgb(0, 0, 255);
887 else if (p->team == 1)
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)
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));
916
917 if (p->hasBlueFlag)
918 al_draw_filled_rectangle(pos.x+4, pos.y-18, pos.x+18, pos.y-4, al_map_rgb(0, 0, 255));
919 else if (p->hasRedFlag)
920 al_draw_filled_rectangle(pos.x+4, pos.y-18, pos.x+18, pos.y-4, al_map_rgb(255, 0, 0));
921 }
922}
923
924void goToRegisterScreen()
925{
926 txtUsernameRegister->clear();
927 txtPasswordRegister->clear();
928 lblRegisterStatus->setText("");
929 rblClasses->setSelectedButton(-1);
930
931 wndCurrent = wndRegister;
932}
933
934void goToLoginScreen()
935{
936 txtUsername->clear();
937 txtPassword->clear();
938 lblLoginStatus->setText("");
939
940 wndCurrent = wndLogin;
941}
942
943// maybe need a goToGameScreen function as well and add state changes to these functions as well
944
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 }
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());
973 memcpy(msgTo.buffer+username.size()+password.size()+2, &playerClass, 4);
974
975 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
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
992 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
993
994 state = STATE_LOBBY;
995}
996
997void logout()
998{
999 txtChat->clear();
1000 chatConsole.clear();
1001
1002 msgTo.type = MSG_TYPE_LOGOUT;
1003
1004 strcpy(msgTo.buffer, username.c_str());
1005
1006 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
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
1024 msgProcessor.sendMessage(&msgTo, sock, &server, &outputLog);
1025}
1026
1027void toggleDebugging()
1028{
1029 debugging = !debugging;
1030}
1031
1032int getRefreshRate(int width, int height)
1033{
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;
1045}
1046
1047void drawMessageStatus(ALLEGRO_FONT* font)
1048{
1049 int clientMsgOffset = 5;
1050 int serverMsgOffset = 950;
1051
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?");
1055
1056 al_draw_text(font, al_map_rgb(0, 255, 255), serverMsgOffset, 43, ALLEGRO_ALIGN_LEFT, "ID");
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
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());
1085
1086 msgCount++;
1087 }
1088 }
1089
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;
1093
1094 msgCount = 0;
1095 for (it3 = ackedMessages.begin(); it3 != ackedMessages.end(); it3++) {
1096 ossId.str("");;
1097 ossId << it3->first;
1098
1099 al_draw_text(font, al_map_rgb(255, 0, 0), 25+serverMsgOffset, 60+15*msgCount, ALLEGRO_ALIGN_LEFT, ossId.str().c_str());
1100
1101 msgCount++;
1102 }
1103 }
1104}
Note: See TracBrowser for help on using the repository browser.