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

Last change on this file since 60017fc was 62ee2ce, checked in by dportnoy <dmp1488@…>, 12 years ago

The client shows the map and converts between screen and map coordinates

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