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

Last change on this file since 093c141 was 384b7e0, checked in by dportnoy <dmp1488@…>, 12 years ago

The client displays a small map upon login and lets the user move around

  • Property mode set to 100644
File size: 15.2 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 <sys/types.h>
16#include <cstdio>
17#include <cstdlib>
18#include <string>
19#include <iostream>
20#include <sstream>
21
22#include <map>
23
24#include <allegro5/allegro.h>
25#include <allegro5/allegro_font.h>
26#include <allegro5/allegro_ttf.h>
27#include <allegro5/allegro_primitives.h>
28
29#include "../../common/Message.h"
30#include "../../common/Common.h"
31#include "../../common/WorldMap.h"
32#include "../../common/Player.h"
33
34#include "Window.h"
35#include "Textbox.h"
36#include "Button.h"
37#include "chat.h"
38
39#ifdef WINDOWS
40 #pragma comment(lib, "ws2_32.lib")
41#endif
42
43using namespace std;
44
45void initWinSock();
46void shutdownWinSock();
47void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole, map<unsigned int, Player>& mapPlayers, unsigned int& curPlayerId);
48void drawMap(WorldMap* gameMap);
49void drawPlayers(map<unsigned int, Player>& mapPlayers, unsigned int curPlayerId);
50POSITION screenToMap(POSITION pos);
51POSITION mapToScreen(POSITION pos);
52
53// callbacks
54void registerAccount();
55void login();
56void logout();
57void quit();
58void sendChatMessage();
59
60void error(const char *);
61
62const float FPS = 60;
63const int SCREEN_W = 640;
64const int SCREEN_H = 480;
65const int BOUNCER_SIZE = 32;
66enum MYKEYS {
67 KEY_UP,
68 KEY_DOWN,
69 KEY_LEFT,
70 KEY_RIGHT
71};
72
73enum STATE {
74 STATE_START,
75 STATE_LOGIN // this means you're already logged in
76};
77
78int state;
79
80bool doexit;
81
82Window* wndLogin;
83Window* wndMain;
84Window* wndCurrent;
85
86Textbox* txtUsername;
87Textbox* txtPassword;
88Textbox* txtChat;
89
90int sock;
91struct sockaddr_in server, from;
92struct hostent *hp;
93NETWORK_MSG msgTo, msgFrom;
94string username;
95chat chatConsole;
96
97int main(int argc, char **argv)
98{
99 ALLEGRO_DISPLAY *display = NULL;
100 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
101 ALLEGRO_TIMER *timer = NULL;
102 ALLEGRO_BITMAP *bouncer = NULL;
103 bool key[4] = { false, false, false, false };
104 bool redraw = true;
105 doexit = false;
106 map<unsigned int, Player> mapPlayers;
107 unsigned int curPlayerId = -1;
108
109 float bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0;
110 float bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0;
111
112 state = STATE_START;
113
114 if(!al_init()) {
115 fprintf(stderr, "failed to initialize allegro!\n");
116 return -1;
117 }
118
119 if (al_init_primitives_addon())
120 cout << "Primitives initialized" << endl;
121 else
122 cout << "Primitives not initialized" << endl;
123
124 al_init_font_addon();
125 al_init_ttf_addon();
126
127 #if defined WINDOWS
128 ALLEGRO_FONT *font = al_load_ttf_font("../pirulen.ttf", 12, 0);
129 #elif defined LINUX
130 ALLEGRO_FONT *font = al_load_ttf_font("pirulen.ttf", 12, 0);
131 #endif
132
133 if (!font) {
134 fprintf(stderr, "Could not load 'pirulen.ttf'.\n");
135 getchar();
136 return -1;
137 }
138
139 if(!al_install_keyboard()) {
140 fprintf(stderr, "failed to initialize the keyboard!\n");
141 return -1;
142 }
143
144 if(!al_install_mouse()) {
145 fprintf(stderr, "failed to initialize the mouse!\n");
146 return -1;
147 }
148
149 timer = al_create_timer(1.0 / FPS);
150 if(!timer) {
151 fprintf(stderr, "failed to create timer!\n");
152 return -1;
153 }
154
155 display = al_create_display(SCREEN_W, SCREEN_H);
156 if(!display) {
157 fprintf(stderr, "failed to create display!\n");
158 al_destroy_timer(timer);
159 return -1;
160 }
161
162 WorldMap* gameMap = WorldMap::loadMapFromFile("../../data/map.txt");
163 //delete gameMap;
164 //gameMap = WorldMap::createDefaultMap();
165
166 wndLogin = new Window(0, 0, SCREEN_W, SCREEN_H);
167 wndLogin->addComponent(new Textbox(104, 40, 100, 20, font));
168 wndLogin->addComponent(new Textbox(104, 70, 100, 20, font));
169 wndLogin->addComponent(new Button(22, 100, 90, 20, font, "Register", registerAccount));
170 wndLogin->addComponent(new Button(122, 100, 60, 20, font, "Login", login));
171 wndLogin->addComponent(new Button(540, 10, 80, 20, font, "Quit", quit));
172
173 txtUsername = (Textbox*)wndLogin->getComponent(0);
174 txtPassword = (Textbox*)wndLogin->getComponent(1);
175
176 wndMain = new Window(0, 0, SCREEN_W, SCREEN_H);
177 wndMain->addComponent(new Textbox(95, 40, 525, 20, font));
178 wndMain->addComponent(new Button(95, 70, 160, 20, font, "Send Message", sendChatMessage));
179 wndMain->addComponent(new Button(540, 10, 80, 20, font, "Logout", logout));
180
181 txtChat = (Textbox*)wndMain->getComponent(0);
182
183 wndCurrent = wndLogin;
184
185 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE);
186 if(!bouncer) {
187 fprintf(stderr, "failed to create bouncer bitmap!\n");
188 al_destroy_display(display);
189 al_destroy_timer(timer);
190 return -1;
191 }
192
193 event_queue = al_create_event_queue();
194 if(!event_queue) {
195 fprintf(stderr, "failed to create event_queue!\n");
196 al_destroy_bitmap(bouncer);
197 al_destroy_display(display);
198 al_destroy_timer(timer);
199 return -1;
200 }
201
202 al_set_target_bitmap(bouncer);
203
204 al_clear_to_color(al_map_rgb(255, 0, 255));
205
206 al_set_target_bitmap(al_get_backbuffer(display));
207
208 al_register_event_source(event_queue, al_get_display_event_source(display));
209 al_register_event_source(event_queue, al_get_timer_event_source(timer));
210 al_register_event_source(event_queue, al_get_keyboard_event_source());
211 al_register_event_source(event_queue, al_get_mouse_event_source());
212
213 al_clear_to_color(al_map_rgb(0,0,0));
214
215 al_flip_display();
216
217 if (argc != 3) {
218 cout << "Usage: server port" << endl;
219 exit(1);
220 }
221
222 initWinSock();
223
224 sock = socket(AF_INET, SOCK_DGRAM, 0);
225 if (sock < 0)
226 error("socket");
227
228 set_nonblock(sock);
229
230 server.sin_family = AF_INET;
231 hp = gethostbyname(argv[1]);
232 if (hp==0)
233 error("Unknown host");
234
235 memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
236 server.sin_port = htons(atoi(argv[2]));
237
238 al_start_timer(timer);
239
240 while(!doexit)
241 {
242 ALLEGRO_EVENT ev;
243 al_wait_for_event(event_queue, &ev);
244
245 if(wndCurrent->handleEvent(ev)) {
246 // do nothing
247 }
248 else if(ev.type == ALLEGRO_EVENT_TIMER) {
249 if(key[KEY_UP] && bouncer_y >= 4.0) {
250 bouncer_y -= 4.0;
251 }
252
253 if(key[KEY_DOWN] && bouncer_y <= SCREEN_H - BOUNCER_SIZE - 4.0) {
254 bouncer_y += 4.0;
255 }
256
257 if(key[KEY_LEFT] && bouncer_x >= 4.0) {
258 bouncer_x -= 4.0;
259 }
260
261 if(key[KEY_RIGHT] && bouncer_x <= SCREEN_W - BOUNCER_SIZE - 4.0) {
262 bouncer_x += 4.0;
263 }
264
265 redraw = true;
266 }
267 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
268 doexit = true;
269 }
270 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) {
271 switch(ev.keyboard.keycode) {
272 case ALLEGRO_KEY_UP:
273 key[KEY_UP] = true;
274 break;
275
276 case ALLEGRO_KEY_DOWN:
277 key[KEY_DOWN] = true;
278 break;
279
280 case ALLEGRO_KEY_LEFT:
281 key[KEY_LEFT] = true;
282 break;
283
284 case ALLEGRO_KEY_RIGHT:
285 key[KEY_RIGHT] = true;
286 break;
287 }
288 }
289 else if(ev.type == ALLEGRO_EVENT_KEY_UP) {
290 switch(ev.keyboard.keycode) {
291 case ALLEGRO_KEY_UP:
292 key[KEY_UP] = false;
293 break;
294
295 case ALLEGRO_KEY_DOWN:
296 key[KEY_DOWN] = false;
297 break;
298
299 case ALLEGRO_KEY_LEFT:
300 key[KEY_LEFT] = false;
301 break;
302
303 case ALLEGRO_KEY_RIGHT:
304 key[KEY_RIGHT] = false;
305 break;
306
307 case ALLEGRO_KEY_ESCAPE:
308 doexit = true;
309 break;
310 }
311 }
312 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
313 if(wndCurrent == wndMain) {
314 msgTo.type = MSG_TYPE_PLAYER_MOVE;
315
316 POSITION pos;
317 pos.x = ev.mouse.x;
318 pos.y = ev.mouse.y;
319 pos = screenToMap(pos);
320
321 if (pos.x != -1)
322 {
323 memcpy(msgTo.buffer, &curPlayerId, 4);
324 memcpy(msgTo.buffer+4, &pos.x, 4);
325 memcpy(msgTo.buffer+8, &pos.y, 4);
326
327 sendMessage(&msgTo, sock, &server);
328 }
329 else
330 cout << "Invalid point: User did not click on the map" << endl;
331 }
332 }
333
334 if (receiveMessage(&msgFrom, sock, &from) >= 0)
335 {
336 processMessage(msgFrom, state, chatConsole, mapPlayers, curPlayerId);
337 cout << "state: " << state << endl;
338 }
339
340 if (redraw && al_is_event_queue_empty(event_queue))
341 {
342 redraw = false;
343
344 wndCurrent->draw(display);
345
346 chatConsole.draw(font, al_map_rgb(255,255,255));
347
348 if(wndCurrent == wndLogin) {
349 al_draw_text(font, al_map_rgb(0, 255, 0), 4, 43, ALLEGRO_ALIGN_LEFT, "Username:");
350 al_draw_text(font, al_map_rgb(0, 255, 0), 1, 73, ALLEGRO_ALIGN_LEFT, "Password:");
351 }
352 else if(wndCurrent == wndMain) {
353 al_draw_text(font, al_map_rgb(0, 255, 0), 4, 43, ALLEGRO_ALIGN_LEFT, "Message:");
354
355 drawMap(gameMap);
356 drawPlayers(mapPlayers, curPlayerId);
357 }
358
359 al_flip_display();
360 }
361 }
362
363 #if defined WINDOWS
364 closesocket(sock);
365 #elif defined LINUX
366 close(sock);
367 #endif
368
369 shutdownWinSock();
370
371 delete wndLogin;
372 delete wndMain;
373
374 delete gameMap;
375
376 al_destroy_event_queue(event_queue);
377 al_destroy_bitmap(bouncer);
378 al_destroy_display(display);
379 al_destroy_timer(timer);
380
381 return 0;
382}
383
384// need to make a function like this that works on windows
385void error(const char *msg)
386{
387 perror(msg);
388 shutdownWinSock();
389 exit(1);
390}
391
392void initWinSock()
393{
394#if defined WINDOWS
395 WORD wVersionRequested;
396 WSADATA wsaData;
397 int wsaerr;
398
399 wVersionRequested = MAKEWORD(2, 2);
400 wsaerr = WSAStartup(wVersionRequested, &wsaData);
401
402 if (wsaerr != 0) {
403 cout << "The Winsock dll not found." << endl;
404 exit(1);
405 }else
406 cout << "The Winsock dll was found." << endl;
407#endif
408}
409
410void shutdownWinSock()
411{
412#if defined WINDOWS
413 WSACleanup();
414#endif
415}
416
417POSITION screenToMap(POSITION pos)
418{
419 pos.x = pos.x-300;
420 pos.y = pos.y-100;
421
422 if (pos.x < 0 || pos.y < 0)
423 {
424 pos.x = -1;
425 pos.y = -1;
426 }
427
428 return pos;
429}
430
431POSITION mapToScreen(POSITION pos)
432{
433 pos.x = pos.x+300;
434 pos.y = pos.y+100;
435
436 return pos;
437}
438
439void processMessage(NETWORK_MSG &msg, int &state, chat &chatConsole, map<unsigned int, Player>& mapPlayers, unsigned int& curPlayerId)
440{
441 string response = string(msg.buffer);
442
443 cout << "Got message: " << msg.type << endl;
444
445 switch(state)
446 {
447 case STATE_START:
448 {
449 cout << "In STATE_START" << endl;
450
451 switch(msg.type)
452 {
453 case MSG_TYPE_REGISTER:
454 {
455 break;
456 }
457 case MSG_TYPE_LOGIN:
458 {
459 if (response.compare("Player has already logged in.") == 0)
460 {
461 username.clear();
462 cout << "User login failed" << endl;
463 }
464 else if (response.compare("Incorrect username or password") == 0)
465 {
466 username.clear();
467 cout << "User login failed" << endl;
468 }
469 else
470 {
471 state = STATE_LOGIN;
472 wndCurrent = wndMain;
473
474 Player p("", "");
475 p.deserialize(msg.buffer);
476 mapPlayers[p.id] = p;
477 curPlayerId = p.id;
478
479 cout << "Got a valid login response with the player" << endl;
480 cout << "Player id: " << curPlayerId << endl;
481 }
482
483 break;
484 }
485 }
486
487 break;
488 }
489 case STATE_LOGIN:
490 {
491 switch(msg.type)
492 {
493 case MSG_TYPE_REGISTER:
494 {
495 break;
496 }
497 case MSG_TYPE_LOGIN:
498 {
499 chatConsole.addLine(response);
500
501 if (response.compare("You have successfully logged out.") == 0)
502 {
503 cout << "Logged out" << endl;
504 state = STATE_START;
505 wndCurrent = wndLogin;
506 }
507 else
508 {
509 cout << "Added new line" << endl;
510 }
511
512 break;
513 }
514 case MSG_TYPE_PLAYER:
515 {
516 Player p("", "");
517 p.deserialize(msg.buffer);
518 mapPlayers[p.id] = p;
519
520 cout << "Received MSG_TYPE_PLAYER message" << endl;
521
522 break;
523 }
524 case MSG_TYPE_CHAT:
525 {
526 chatConsole.addLine(response);
527
528 break;
529 }
530 }
531
532 break;
533 }
534 default:
535 {
536 cout << "The state has an invalid value: " << state << endl;
537
538 break;
539 }
540 }
541}
542
543void drawMap(WorldMap* gameMap)
544{
545 POSITION mapPos;
546 mapPos.x = 0;
547 mapPos.y = 0;
548 mapPos = mapToScreen(mapPos);
549 for (int x=0; x<12; x++)
550 {
551 for (int y=0; y<12; y++)
552 {
553 WorldMap::TerrainType el = gameMap->getElement(x, y);
554
555 if (el == WorldMap::TERRAIN_GRASS)
556 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));
557 else if (el == WorldMap::TERRAIN_OCEAN)
558 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));
559 else if (el == WorldMap::TERRAIN_ROCK)
560 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));
561 }
562 }
563}
564
565void drawPlayers(map<unsigned int, Player>& mapPlayers, unsigned int curPlayerId)
566{
567 map<unsigned int, Player>::iterator it;
568
569 Player* p;
570 POSITION pos;
571
572 for(it = mapPlayers.begin(); it != mapPlayers.end(); it++)
573 {
574 p = &it->second;
575 pos = mapToScreen(p->pos);
576
577 if (p->id == curPlayerId)
578 al_draw_filled_circle(pos.x, pos.y, 12, al_map_rgb(255, 0, 0));
579 else
580 al_draw_filled_circle(pos.x, pos.y, 12, al_map_rgb(191, 0, 0));
581 }
582}
583
584void registerAccount()
585{
586 string username = txtUsername->getStr();
587 string password = txtPassword->getStr();
588
589 txtUsername->clear();
590 txtPassword->clear();
591
592 msgTo.type = MSG_TYPE_REGISTER;
593
594 strcpy(msgTo.buffer, username.c_str());
595 strcpy(msgTo.buffer+username.size()+1, password.c_str());
596
597 sendMessage(&msgTo, sock, &server);
598}
599
600void login()
601{
602 string strUsername = txtUsername->getStr();
603 string strPassword = txtPassword->getStr();
604 username = strUsername;
605
606 txtUsername->clear();
607 txtPassword->clear();
608
609 msgTo.type = MSG_TYPE_LOGIN;
610
611 strcpy(msgTo.buffer, strUsername.c_str());
612 strcpy(msgTo.buffer+username.size()+1, strPassword.c_str());
613
614 sendMessage(&msgTo, sock, &server);
615}
616
617void logout()
618{
619 txtChat->clear();
620
621 msgTo.type = MSG_TYPE_LOGOUT;
622
623 strcpy(msgTo.buffer, username.c_str());
624
625 sendMessage(&msgTo, sock, &server);
626}
627
628void quit()
629{
630 doexit = true;
631}
632
633void sendChatMessage()
634{
635 string msg = txtChat->getStr();
636
637 txtChat->clear();
638
639 msgTo.type = MSG_TYPE_CHAT;
640
641 strcpy(msgTo.buffer, msg.c_str());
642
643 sendMessage(&msgTo, sock, &server);
644}
Note: See TracBrowser for help on using the repository browser.