1 #include "button.h"
2 #include "files.h"
3 #include "satellite.h"
4 #include "update.h"
5 #include "network.h"
6 #include "client.h"
7 #include "beam.h"
8 #include "explosion.h"
9 #include "missile.h"
10 #include "teleport.h"
11 #include "floattext.h"
12 #include "player.h"
13 #include "tank.h"
14 
15 #include "sky.h"
16 
17 // Note: Don't guard everything. Empty compilation units are invalid.
18 #ifdef NETWORK
19 
20 // From gameloop.cpp:
21 void draw_top_bar();
22 
23 // Here we try to match the buffer with an action. We then attempt to
24 // perform the action. Remember, this is a command from the server, so
25 // it is either giving us some info or telling us to create something.
Parse_Client_Data(char * buffer)26 int Parse_Client_Data(char *buffer)
27 {
28    char args[CLIENT_ARGS][BUFFER_SIZE];
29    char letter;
30    int dest_string;
31    int line_length = strlen(buffer);
32    int sourceindex = 0, destindex = 0;
33 
34    // clear buffers
35    for (dest_string = 0; dest_string < CLIENT_ARGS; dest_string++)
36        memset(args[dest_string], '\0', BUFFER_SIZE);
37 
38    dest_string = 0;
39    // copy buffer into cmd and argument variables
40    while ( ( sourceindex < line_length ) && (dest_string < CLIENT_ARGS) )
41    {
42        letter = buffer[sourceindex];
43        if ( letter == ' ' )
44        {
45            letter = '\0';
46            args[dest_string][destindex] = letter;
47            destindex = 0;
48            dest_string++;
49        }
50        else
51        {
52           args[dest_string][destindex] = letter;
53           destindex++;
54        }
55        sourceindex++;
56    }
57 
58    // let us see what we have
59    if (! strcmp(args[0], "SERVERVERSION") )
60    {
61        if (! strcmp(args[1], VERSION) )
62           printf("Server version matchs us. OK.\n");
63        else
64           printf("Server version is %s, we are %s. This is likely to cause problems.\n",
65                  args[1], VERSION);
66        return TRUE;
67    }
68    else if (! strcmp(args[0], "CURRENTPOSITION") )
69    {
70       if ( (global.client_player) && (global.client_player->tank) )
71       {
72           sscanf(args[1], "%lf", &(global.client_player->tank->x));
73           sscanf(args[2], "%lf", &(global.client_player->tank->y));
74       }
75    }
76    else if (! strcmp(args[0], "BEAM") )
77    {
78       double my_x, my_y;
79       int my_angle, my_type;
80       sscanf(args[1], "%lf", &my_x);
81       sscanf(args[2], "%lf", &my_y);
82       sscanf(args[3], "%d", &my_angle);
83       sscanf(args[4], "%d", &my_type);
84       new BEAM(nullptr, my_x, my_y, my_angle, my_type, BT_WEAPON);
85    }
86    else if (! strcmp(args[0], "BOXED"))
87    {
88        int got_box;
89        sscanf(args[1], "%d", &got_box);
90        if (got_box)
91            env.isBoxed = true;
92        else
93            env.isBoxed = false;
94        return TRUE;
95    }
96    else if (! strcmp(args[0], "EXPLOSION") )
97    {
98         double my_x, my_y;
99         int my_type;
100         sscanf(args[1], "%lf", &my_x);
101         sscanf(args[2], "%lf", &my_y);
102         sscanf(args[3], "%d", &my_type);
103         new EXPLOSION(nullptr, my_x, my_y, 0., 0., my_type, true);
104         return FALSE;
105    }
106    else if (! strcmp(args[0], "ITEM"))
107    {
108        int itemindex, amount;
109        sscanf(args[1], "%d", &itemindex);
110        sscanf(args[2], "%d", &amount);
111        if ( (itemindex >= 0) && (itemindex < ITEMS) &&
112             (amount >= 0) && (amount <= 99) )
113        {
114           global.client_player->ni[itemindex] = amount;
115        }
116        if (itemindex == (ITEMS - 1) )
117           return TRUE;
118    }
119    else if (! strcmp(args[0], "HEALTH") )
120    {
121        int tankindex;
122        int health, shield, shield_type;
123        char some_text[32];
124 
125        sscanf(args[1], "%d", &tankindex);
126        if (tankindex >= 0)
127        {
128           sscanf(args[2], "%d", &health );
129           sscanf(args[3], "%d", &shield );
130           sscanf(args[4], "%d", &shield_type);
131           env.players[tankindex]->tank->l = health;
132           env.players[tankindex]->tank->sh = shield;
133           env.players[tankindex]->tank->sht = shield_type;
134           // set the text over the tank
135           sprintf(some_text, "%d", health);
136           env.players[tankindex]->tank->healthText.set_text(some_text);
137           env.players[tankindex]->tank->healthText.set_color(env.players[tankindex]->color);
138           sprintf(some_text, "%d", shield);
139           env.players[tankindex]->tank->shieldText.set_text(some_text);
140           env.players[tankindex]->tank->healthText.set_color(env.players[tankindex]->color);
141        }
142        if (tankindex == (env.numGamePlayers - 1) )
143           return TRUE;
144        else
145           return FALSE;
146    }
147    else if (! strcmp(args[0], "WIND") )
148    {
149        sscanf(args[1], "%lf", & (global.wind) );
150        return TRUE;
151    }
152    else if (! strcmp(args[0], "MISSILE") )
153    {
154        int my_type;
155        double my_x, my_y, delta_x, delta_y;
156        MISSILE *missile;
157        sscanf(args[1], "%lf", &my_x);
158        sscanf(args[2], "%lf", &my_y);
159        sscanf(args[3], "%lf", &delta_x);
160        sscanf(args[4], "%lf", &delta_y);
161        sscanf(args[5], "%d", &my_type);
162        missile = new MISSILE(nullptr, my_x, my_y, delta_x, delta_y, my_type,
163 							MT_WEAPON, 1);
164        if (! missile)
165          printf("Attempted to create missile failed in client code.\n");
166        return FALSE;
167    }
168    else if (! strcmp(args[0], "NUMPLAYERS") )
169    {
170       int counter;
171       sscanf(args[1], "%d", & (env.numGamePlayers) );
172       // create the players in question
173       for (counter = 0; counter < env.numGamePlayers; counter++)
174       {
175           env.players[counter] = new PLAYER();
176           env.players[counter]->tank = new TANK();
177           env.players[counter]->tank->player = env.players[counter];
178           env.players[counter]->tank->nameText.set_text(nullptr);
179       }
180       return TRUE;
181    }
182    // ping is a special case where we do not do anything it is just
183    // making sure we are still here because we are not talking
184    else if (! strcmp(args[0], "PING"))
185    {
186        return FALSE;
187    }
188    else if (! strcmp(args[0], "PLAYERNAME") )
189    {
190        int number;
191        sscanf(args[1], "%d", &number);
192        if ( (number < env.numGamePlayers) && (number >= 0) )
193            env.players[number]->setName(args[2]);
194        if (number == (env.numGamePlayers - 1) )
195           return TRUE;
196    }
197    else if (! strcmp(args[0], "REMOVETANK") )
198    {
199        int index;
200        sscanf(args[1], "%d", &index);
201        if ( (index >= 0) && (index < env.numGamePlayers) )
202        {
203            // make sure this tank exists before we get rid of it
204            if ( env.players[index]->tank )
205            {
206                delete env.players[index]->tank;
207                env.players[index]->tank = NULL;
208            }
209        }
210    }
211    else if (! strcmp(args[0], "ROUNDS") )
212    {
213        sscanf(args[1], "%u", &env.rounds);
214        sscanf(args[2], "%u", &global.currentround);
215        return TRUE;
216    }
217    else if (! strcmp(args[0], "SURFACE") )
218    {
219        int x, y;
220        int index;
221        int colour_change = 0;
222        int green = 150;
223        int my_height;
224 
225        sscanf(args[1], "%d", &x);
226        sscanf(args[2], "%d", &y);
227        global.surface[x].store(y);
228        my_height = env.screenHeight - y;
229        my_height = my_height / 50;      // ratio of change
230        // fill in terrain...
231        for (index = y; index < env.screenHeight; index++)
232        {
233            putpixel(global.terrain, x, index, makecol(0, green, 0));
234            colour_change++;
235            if (colour_change >= my_height)
236            {
237               colour_change = 0;
238               green--;
239            }
240        }
241        if (x >= (env.screenWidth - 1) )
242          return TRUE;
243    }
244    else if (! strcmp(args[0], "SCREEN") )
245    {
246        int width, height;
247 
248        sscanf(args[1], "%d", &width);
249        sscanf(args[2], "%d", &height);
250        if ( (width == env.screenWidth) &&
251             (height == env.screenHeight) )
252            printf("Host's screen resolution matches ours.\n");
253        else
254        {
255            printf("Host's screen resolution is %d by %d.\n", width, height);
256            printf("Ours is %d by %d. This is going to cause problems!\n",
257                   env.screenWidth, env.screenHeight);
258         }
259        return TRUE;
260    }
261    else if (! strcmp(args[0], "TANKPOSITION") )
262    {
263        int player_number, x, y;
264        PLAYER *my_player;
265 
266        sscanf(args[1], "%d", &player_number);
267        my_player = env.players[player_number];
268        if ( (my_player) && (my_player->tank) )
269        {
270            sscanf(args[2], "%d", &x);
271            sscanf(args[3], "%d", &y);
272            my_player->tank->x = x;
273            my_player->tank->y = y;
274        }
275        if (player_number == (env.numGamePlayers - 1))
276          return TRUE;
277    }
278    else if (! strcmp(args[0], "TEAM") )
279    {
280        int32_t player_number = 0;
281        int32_t  colour = BLACK;
282        int the_team;
283        sscanf(args[1], "%d", &player_number);
284        sscanf(args[2], "%d", & the_team);
285        if ( (the_team < env.numGamePlayers) && (the_team >= 0) )
286        {
287             env.players[player_number]->team =
288 				static_cast<eTeamTypes>(the_team);
289             if (the_team == TEAM_JEDI)
290                 colour = makecol(0, 255, 0);
291             else if (the_team == TEAM_SITH)
292                 colour = makecol(255, 0, 255);
293             else if (the_team == TEAM_NEUTRAL)
294                 colour = makecol(0, 0, 255);
295             if (env.players[player_number] == global.client_player)
296                 colour = makecol(255, 0, 0);
297             env.players[player_number]->color = colour;
298        }
299        if (player_number == (env.numGamePlayers - 1) )
300           return TRUE;
301    }
302    else if (! strcmp(args[0], "TELEPORT") )
303    {
304        int player_num;
305        int new_x, new_y;
306 
307        sscanf(args[1], "%d", &player_num);
308        sscanf(args[2], "%d", &new_x);
309        sscanf(args[3], "%d", &new_y);
310        if ( (player_num >= 0) && (player_num < env.numGamePlayers) &&
311             (env.players[player_num]->tank) )
312        {
313 			TANK* lt = env.players[player_num]->tank;
314           new TELEPORT(lt, new_x, new_y, lt->getDiameter(), 120, ITEM_TELEPORT);
315        }
316 
317    }
318    else if (! strcmp(args[0], "WALLTYPE"))
319    {
320         sscanf(args[1], "%d", &(env.current_wallType));
321         switch (env.current_wallType)
322         {
323            case WALL_RUBBER:
324            env.wallColour = makecol(0, 255, 0); // GREEN;
325            break;
326            case WALL_STEEL:
327            env.wallColour = makecol(255, 0, 0); // RED;
328            break;
329            case WALL_SPRING:
330            env.wallColour = makecol(0, 0, 255); //BLUE;
331            break;
332            case WALL_WRAP:
333            env.wallColour = makecol(255, 255, 0); // YELLOW;
334            break;
335         }
336        return TRUE;
337    }
338    else if (! strcmp(args[0], "WEAPON") )
339    {
340        int weaponindex, amount;
341        sscanf(args[1], "%d", &weaponindex);
342        sscanf(args[2], "%d", &amount);
343        if ( (weaponindex >= 0) && (weaponindex < WEAPONS) &&
344             (amount >= 0) && (amount <= 99) )
345        {
346             global.client_player->nm[weaponindex] = amount;
347        }
348        if (weaponindex == (WEAPONS - 1))
349           return TRUE;
350    }
351    else if (! strcmp(args[0], "YOUARE") )
352    {
353        int index;
354        sscanf(args[1], "%d", &index );
355        if ( (index >= 0) && (index < env.numGamePlayers) )
356        {
357           global.client_player = env.players[index];
358           global.set_curr_tank(global.client_player->tank);
359        }
360        return TRUE;
361    }
362 
363    return FALSE;
364 }
365 
366 
367 
Create_Sky()368 void Create_Sky()
369 {
370 	if (env.custom_background && env.bitmap_filenames) {
371 		if (env.sky)
372 			destroy_bitmap(env.sky);
373 		env.sky = load_bitmap(
374 		       env.bitmap_filenames[ rand() % env.number_of_bitmaps ], nullptr);
375 	}
376 
377 	if (!env.custom_background || !env.sky) {
378 		if (env.sky
379 		  && ( (env.sky->w  != env.screenWidth)
380 		    || (env.sky->h != (env.screenHeight - MENUHEIGHT) ) ) ) {
381 			destroy_bitmap(env.sky);
382 			env.sky = nullptr;
383 		}
384 
385 		if (!env.sky)
386 			env.sky = create_bitmap(env.screenWidth,
387 		                               env.screenHeight - MENUHEIGHT);
388 		generate_sky (nullptr, sky_gradients[global.cursky],
389 		                     (env.ditherGradients ? GENSKY_DITHERGRAD : 0 )
390 		                   | (env.detailedSky ? GENSKY_DETAILED : 0 ) );
391 	}
392 } // end of create sky function
393 
394 
395 
396 // Send a shot command to the server
Client_Fire(PLAYER * my_player,int my_socket)397 int Client_Fire(PLAYER *my_player, int my_socket)
398 {
399    char buffer[256];
400 
401    if (!my_player) return FALSE;
402    if (! my_player->tank) return FALSE;
403 
404    int32_t towrite, written;
405 
406 	SAFE_WRITE(my_socket, "FIRE %d %d %d", my_player->tank->cw,
407 				my_player->tank->a, my_player->tank->p)
408 
409    return TRUE;
410 }
411 
412 
413 // Adjust our power on the client side
Client_Power(PLAYER * my_player,int more_or_less)414 int Client_Power(PLAYER *my_player, int more_or_less)
415 {
416     if ( (my_player) && (my_player->tank) )
417     {
418         if ( (more_or_less == CLIENT_UP) && (my_player->tank->p < 1996) )
419            my_player->tank->p += 5;
420         else if ( (more_or_less == CLIENT_DOWN) && (my_player->tank->p > 5) )
421            my_player->tank->p -= 5;
422         return TRUE;
423     }
424     return FALSE;
425 }
426 
427 
428 
Client_Angle(PLAYER * my_player,int left_or_right)429 int Client_Angle(PLAYER *my_player, int left_or_right)
430 {
431     if (! my_player) return FALSE;
432     if (! my_player->tank) return FALSE;
433 
434     if ( (left_or_right == CLIENT_LEFT) && (my_player->tank->a < 270) )
435          my_player->tank->a++;
436     else if ( (left_or_right == CLIENT_RIGHT) && (my_player->tank->a > 90) )
437          my_player->tank->a--;
438     return TRUE;
439 }
440 
441 
Client_Cycle_Weapon(PLAYER * my_player,int forward_or_back)442 int Client_Cycle_Weapon(PLAYER *my_player, int forward_or_back)
443 {
444    bool found = false;
445 
446    if (! my_player->tank)
447        return FALSE;
448 
449    while (! found)
450    {
451         if (forward_or_back == CYCLE_FORWARD)
452             my_player->tank->cw++;
453         else
454             my_player->tank->cw--;
455 
456         if (my_player->tank->cw >= THINGS)
457            my_player->tank->cw = 0;
458         else if (my_player->tank->cw < 0)
459            my_player->tank->cw = THINGS - 1;
460 
461         // check if we have found a weapon
462         if (my_player->tank->cw < WEAPONS)
463         {
464              if (my_player->nm[my_player->tank->cw])
465                  found = true;
466         }
467         else      // an item
468         {
469              if ( (item[my_player->tank->cw - WEAPONS].selectable) &&
470                   (my_player->ni[my_player->tank->cw - WEAPONS]) )
471                  found = true;
472         }
473    }
474    return TRUE;
475 }
476 
477 
478 
479 // This function takes an error number and returns a string
480 // which contains useful information about that error.
481 // On success, a pointer to char is returned.
482 // On failure, a NULL is returned.
483 // The returned pointer does NOT need to be freed.
Explain_Error(int32_t error_code)484 const char* Explain_Error(int32_t error_code)
485 {
486 	switch (error_code) {
487 		case CLIENT_ERROR_VERSION:
488 			return env.ingame->Get_Line(77);
489 			break;
490 		case CLIENT_ERROR_SCREENSIZE:
491 			return env.ingame->Get_Line(78);
492 			break;
493 		case CLIENT_ERROR_DISCONNECT:
494 			return env.ingame->Get_Line(79);
495 			break;
496 	}
497 
498 	return nullptr;
499 }
500 
501 
502 // Client version of the game
503 // Really, this loop should do some basic things.
504 // 1. Find out what the landscape should look like from the server.
505 // 2. Place tanks on the battle field
506 // 3. Create missiles, beam weapons and such when the server asks us to
507 // 4. Get input from the player and forward it to the server.
508 // 5. Clean up at the end of the round.
509 //
510 // Function return TRUE if everything went well or FALSE
511 // if an error occured.
Game_Client(int socket_number)512 int Game_Client(int socket_number)
513 {
514     int surface_x = 1, tank_position = 1, team_number = 1, name_number = 1;
515     int weapon_number = 1, item_number = 1, tank_health = 1;
516     int end_of_round = FALSE, keep_playing = FALSE;
517     int game_stage = CLIENT_VERSION;
518     char buffer[BUFFER_SIZE];
519     int incoming;
520     int my_key;
521     int time_clock = 0;
522     bool screen_update = false;
523     int count;      // generic counter
524     int stuff_going_down = FALSE;    // explosions, missiles etc on the screen
525     VIRTUAL_OBJECT *my_object, *next_obj;
526 	int32_t class_ = 0;
527     bool fired = false;
528     int32_t towrite, written;
529 
530 
531     clear_to_color (global.terrain, PINK);    // get terrain ready
532     clear_to_color(global.canvas, BLACK);
533 
534     // clean up old text
535 	global.getHeadOfClass(CLASS_FLOATTEXT, &my_object);
536 	while (my_object) {
537 		my_object->getNext(&next_obj);
538 		static_cast<FLOATTEXT*>(my_object)->newRound();
539 		delete my_object;
540 	}
541 
542     Create_Sky();     // so we have a background
543 	SAFE_WRITE(socket_number, "%s", "VERSION")
544 
545     while (! end_of_round)
546     {
547         // check for waiting input from the server
548         incoming = Check_For_Incoming_Data(socket_number);
549         if (incoming)
550         {
551            int bytes_read;
552 
553            memset(buffer, '\0', BUFFER_SIZE);
554            bytes_read = read(socket_number, buffer, BUFFER_SIZE);
555            if (bytes_read > 0)
556            {
557                 // do something with this input
558                 if (! strncmp(buffer, "CLOSE", 5) )
559                 {
560                    end_of_round = TRUE;
561                    keep_playing = FALSE;
562                    printf("Got close message.\n");
563                    global.client_message = strdup(env.ingame->Get_Line(81));
564                 }
565                 else if (! strncmp(buffer, "NOROOM", 6) )
566                 {
567                    end_of_round = TRUE;
568                    keep_playing = FALSE;
569                    printf("The server is full or the game has not started. Please try again later.\n");
570                    global.client_message = strdup(env.ingame->Get_Line(80));
571                 }
572                 else if (! strncmp(buffer, "GAMEEND", 7) )
573                 {
574                     end_of_round = TRUE;
575                     keep_playing = FALSE;
576                     printf("The game is over.\n");
577                     if ( strlen(buffer) > 7)
578                         global.client_message = strdup(& (buffer[8])) ;
579                     else
580                         global.client_message = strdup(env.ingame->Get_Line(82));
581                 }
582                 else if (! strncmp(buffer, "ROUNDEND", 8) )
583                 {
584                    end_of_round = TRUE;
585                    keep_playing = TRUE;
586                    printf("Round is over.\n");
587                 }
588 
589                 else         // not a special command, parse it
590                 {
591                   if ( Parse_Client_Data(buffer) )
592                   {
593                       if (game_stage < CLIENT_PLAYING)
594                          game_stage++;
595 
596                       // Request more information
597                       if (game_stage < CLIENT_PLAYING)
598                       {
599                          switch (game_stage)
600                          {
601                             case CLIENT_SCREEN: strcpy(buffer, "SCREEN"); break;
602                             case CLIENT_WIND: strcpy(buffer, "WIND"); break;
603                             case CLIENT_NUMPLAYERS: strcpy(buffer, "NUMPLAYERS"); break;
604                             case CLIENT_TANK_POSITION: strcpy(buffer, "TANKPOSITION 0"); break;
605                             case CLIENT_SURFACE: strcpy(buffer, "SURFACE 0"); break;
606                             case CLIENT_WHOAMI: strcpy(buffer, "WHOAMI"); break;
607                             case CLIENT_WEAPONS: strcpy(buffer, "WEAPON 0"); break;
608                             case CLIENT_ITEMS:   strcpy(buffer, "ITEM 0"); break;
609                             case CLIENT_ROUNDS: strcpy(buffer, "ROUNDS"); break;
610                             case CLIENT_TEAMS: strcpy(buffer, "TEAMS 0");
611                                                global.updateMenu = TRUE; break;
612                             case CLIENT_WALL_TYPE: strcpy(buffer, "WALLTYPE"); break;
613                             case CLIENT_BOXED: strcpy(buffer, "BOXED"); break;
614                             case CLIENT_NAME: strcpy(buffer, "PLAYERNAME 0"); break;
615                             case CLIENT_TANK_HEALTH: strcpy(buffer, "HEALTH 0"); break;
616                             default: buffer[0] = '\0';
617                          }
618                          towrite = strlen(buffer);
619                          written = write(socket_number, buffer, strlen(buffer));
620                          if (written < towrite)
621 							fprintf(stderr,
622 								"%s:%d: Warning: Only %d/%d bytes sent to server\n",
623 								__FILE__, __LINE__, written, towrite);
624                        }   // end of getting more info
625                    }    // our game stage went up
626                    else  // we got data, but our game stage did not go up
627                    {
628                        if (fired)
629                        {
630                            if ( (global.client_player) && (global.client_player->tank) )
631                            {
632                                fired = false;
633                                if (global.client_player->tank->cw < WEAPONS)
634 								SAFE_WRITE(socket_number, "WEAPON %d",
635 												global.client_player->tank->cw)
636                                else
637 								SAFE_WRITE(socket_number, "ITEM %d",
638 												global.client_player->tank->cw - WEAPONS)
639                            }
640                        }
641                        else if (game_stage == CLIENT_SURFACE)
642                        {
643 								SAFE_WRITE(socket_number, "SURFACE %d", surface_x)
644                            surface_x++;
645                        }
646                        else if (game_stage == CLIENT_ITEMS)
647                        {
648 								SAFE_WRITE(socket_number, "ITEM %d", item_number)
649                             item_number++;
650                        }
651                        else if (game_stage == CLIENT_TANK_POSITION)
652                        {
653 								SAFE_WRITE(socket_number, "TANKPOSITION %d", tank_position)
654                             tank_position++;
655                             if (tank_position >= env.numGamePlayers)
656                               tank_position = 0;
657                        }
658                        else if (game_stage == CLIENT_TANK_HEALTH)
659                        {
660 								SAFE_WRITE(socket_number, "HEALTH %d", tank_health)
661                             tank_health++;
662                             if (tank_health >= env.numGamePlayers)
663                                 tank_health = 0;
664                        }
665                        else if (game_stage == CLIENT_TEAMS)
666                        {
667 								SAFE_WRITE(socket_number, "TEAMS %d", team_number)
668                             team_number++;
669                        }
670                        else if (game_stage == CLIENT_NAME)
671                        {
672 								SAFE_WRITE(socket_number, "PLAYERNAME %d", name_number)
673                             name_number++;
674                        }
675                        else if (game_stage == CLIENT_WEAPONS)
676                        {
677 								SAFE_WRITE(socket_number, "WEAPON %d", weapon_number)
678                             weapon_number++;
679                        }
680                        else if (game_stage == CLIENT_PLAYING)
681                        {
682                            time_clock++;
683                            if (time_clock > 1)   // check positions every few inputs
684                            {
685                                time_clock = 0;
686                                if (surface_x < env.screenWidth)
687                                {
688                                    game_stage = CLIENT_SURFACE;
689 								SAFE_WRITE(socket_number, "SURFACE %d", surface_x)
690                                    surface_x++;
691                                }
692                                else
693                                {
694                                  game_stage = CLIENT_TANK_POSITION;
695                                  tank_position = 1;
696 								SAFE_WRITE(socket_number, "TANKPOSITION %d", 0)
697                                }    // game stage stuff
698                            }
699                        }        // end of playing commands
700                    }
701 
702                 }      // end of we got something besides the close command
703 
704            }
705            else    // connection was broken
706            {
707               close(socket_number);
708               printf("Server closed connection.\n");
709               end_of_round = TRUE;
710            }
711         }
712 
713 		class_ = 0;
714 		while (class_ < CLASS_COUNT) {
715 			if (CLASS_TANK == class_) {
716 				++class_;
717 				continue;
718 			}
719 
720 			global.getHeadOfClass(static_cast<eClasses>(class_), &my_object);
721 			while(my_object) {
722 				my_object->getNext(&next_obj);
723 
724 				if (CLASS_EXPLOSION == class_)
725 					static_cast<EXPLOSION*>(my_object)->explode();
726 
727 				my_object->applyPhysics();
728 
729 				if (my_object->destroy) {
730 					my_object->requireUpdate();
731 					my_object->update();
732 					delete my_object;
733 					if (CLASS_TELEPORT == class_)
734 						time_clock = 2;
735 				}
736 
737 				if ( (CLASS_BEAM      == class_)
738 				  || (CLASS_MISSILE   == class_)
739 				  || (CLASS_EXPLOSION == class_)
740 				  || (CLASS_TELEPORT  == class_) )
741 					stuff_going_down = TRUE;
742 
743 				my_object = next_obj;
744 			}
745 			++class_;
746 		}
747 
748 		global.slideLand();
749 
750         // update everything on the screen
751         if (global.updateMenu)
752           draw_top_bar ();
753 
754         if (screen_update) {
755 			screen_update = false;
756 			global.make_fullUpdate();
757         }
758 		global.replace_canvas ();
759 
760         screen_update = true;
761 
762 		class_ = 0;
763 		while (class_ < CLASS_COUNT) {
764 			global.getHeadOfClass(static_cast<eClasses>(class_), &my_object);
765 			while(my_object) {
766 				my_object->draw();
767 				if (CLASS_FLOATTEXT == class_)
768 					my_object->requireUpdate();
769 				my_object->update();
770 				my_object->getNext(&my_object);
771 			}
772 			++class_;
773 		}
774 
775         global.do_updates();
776 
777 
778         // check for input from the user
779         if ( keypressed() )
780         {
781            my_key = readkey();
782            my_key = my_key >> 8;
783            if (my_key == KEY_SPACE)
784            {
785               Client_Fire(global.client_player, socket_number);
786               fired = true;
787            }
788            else if (my_key == KEY_ESC)
789            {
790               end_of_round = TRUE;
791               close(socket_number);
792            }
793            else if (my_key == KEY_UP)
794            {
795               Client_Power(global.client_player, CLIENT_UP);
796            }
797            else if (my_key == KEY_DOWN)
798            {
799               Client_Power(global.client_player, CLIENT_DOWN);
800            }
801            else if (my_key == KEY_LEFT)
802            {
803               Client_Angle(global.client_player, CLIENT_LEFT);
804            }
805            else if (my_key == KEY_RIGHT)
806            {
807               Client_Angle(global.client_player, CLIENT_RIGHT);
808            }
809            else if ( (my_key == KEY_Z) || (my_key == KEY_BACKSPACE) )
810            {
811                Client_Cycle_Weapon(global.client_player, CYCLE_BACK);
812            }
813            else if ( (my_key == KEY_C) || (my_key == KEY_TAB) )
814            {
815                Client_Cycle_Weapon(global.client_player, CYCLE_FORWARD);
816                global.updateMenu = TRUE;
817            }
818 
819            screen_update = false;
820            global.updateMenu = TRUE;
821         }
822 
823         // pause for a moment
824         // if (game_stage < CLIENT_PLAYING)
825         if (stuff_going_down)
826         {
827             LINUX_SLEEP;
828             stuff_going_down = FALSE;
829         }
830     }
831 
832     // we should clean up here
833     for (count = 0; count < env.numGamePlayers; count++)
834     {
835        if (env.players[count]->tank)
836        {
837            delete env.players[count]->tank;
838            env.players[count]->tank = NULL;
839        }
840     }
841 
842     return keep_playing;
843 }
844 
845 
846 #endif // NETWORK
847 
848