Merge branches 'master-cosmetic' and 'feature-bot-name' of git://repo.or.cz/0verkill
[0verkill.git] / client.c
blobc65a42eb86cd8451cb246c0ad746cb20c44c91e6
1 /* When compiling with X support don't forget to define XWINDOW symbol */
3 #ifndef WIN32
4 #include "config.h"
5 #endif
6 #include <stdio.h>
7 #include <signal.h>
8 #include <math.h>
10 #ifdef HAVE_PTHREAD_H
11 #include <pthread.h>
12 #endif
14 #ifdef HAVE_FLOAT_H
15 #include <float.h>
16 #endif
18 #ifdef HAVE_SIGINFO_H
19 #include <siginfo.h>
20 #endif
22 #ifdef HAVE_SYS_SELECT_H
23 #include <sys/select.h>
24 #endif
26 #include <ctype.h>
28 #if (!defined(WIN32))
29 #ifdef TIME_WITH_SYS_TIME
30 #include <sys/time.h>
31 #include <time.h>
32 #else
33 #ifdef TM_IN_SYS_TIME
34 #include <sys/time.h>
35 #else
36 #include <time.h>
37 #endif
38 #endif
39 #else
40 #include <time.h>
41 #endif
43 #include <errno.h>
44 #include <stdlib.h>
45 #ifndef WIN32
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <netdb.h>
50 #ifndef __USE_GNU
51 #define __USE_GNU
52 #endif
53 #else
54 #include <winsock.h>
55 #endif
57 #include <string.h>
59 #include "blit.h"
60 #include "sprite.h"
61 #include "data.h"
62 #include "cfg.h"
63 #include "net.h"
64 #include "hash.h"
65 #include "console.h"
66 #include "time.h"
67 #include "math.h"
68 #include "help.h"
69 #include "getopt.h"
70 #include "error.h"
72 #ifdef XWINDOW
73 #include "x.h"
74 #endif
76 #undef PAUSE
78 #ifdef WIN32
79 int consoleApp=1;
80 #endif
82 /* settings */
83 #define OVERRIDE_FLAG_HOST 0x01
84 #define OVERRIDE_FLAG_NAME 0x02
85 #define OVERRIDE_FLAG_PORT 0x04
86 #define OVERRIDE_FLAG_COLOR 0x08
88 struct config {
89 int argc;
90 char **argv;
91 char host[MAX_HOST_LEN+1];
92 char name[MAX_NAME_LEN+1];
93 int port;
94 int color;
95 char override;
97 struct {
98 int flags;
99 char *text;
100 } errormsg = {0, ""};
102 /* my health, armor, frags, deaths, ammo, ... and ID */
103 unsigned char health,armor;
104 unsigned int frags,deaths;
105 unsigned short ammo[ARMS];
106 unsigned short current_weapon;
107 unsigned short weapons;
108 unsigned char creep;
109 unsigned char autorun,autocreep;
110 int my_id;
112 /* connection with server */
113 int connected;
115 int level_number=-1;
117 /* networking */
118 int fd; /* socket */
119 struct sockaddr_in server; /* server address */
121 /* objects */
122 struct object_list objects;
123 struct object_list *last_obj;
124 struct it* hero;
126 /* important sprites */
127 int hit_sprite;
128 int title_sprite;
129 int bulge_sprite;
130 int shrapnel_sprite[N_SHRAPNELS],bfgbit_sprite[N_SHRAPNELS],bloodrain_sprite[N_SHRAPNELS],jetpack_sprite,fire_sprite,chain_sprite;
132 int level_sprites_start; /* number of first sprite in the level (all other level sprites follow) */
134 unsigned long_long game_start_offset; /* time difference between game start on this machine and on server */
136 int gsbi = 0;
138 /* top players table */
139 struct
141 char name[MAX_NAME_LEN+1];
142 int frags,deaths;
143 unsigned char color;
144 }top_players[TOP_PLAYERS_N];
146 /* # of active players in the game */
147 int active_players;
150 #define KBD_RIGHT (1 << 0)
151 #define KBD_LEFT (1 << 1)
152 #define KBD_JUMP (1 << 2)
153 #define KBD_CREEP (1 << 3)
154 #define KBD_SPEED (1 << 4)
155 #define KBD_FIRE (1 << 5)
156 #define KBD_DOWN_LADDER (1 << 6)
157 #define KBD_JETPACK (1 << 7)
159 struct /* keyboard status */
161 unsigned char status, weapon;
162 } keyboard_status;
164 /* message */
165 struct msgline_type
167 unsigned long_long time;
168 char color;
169 char *msg;
170 }msg_line[N_MESSAGES];
172 int last_message;
173 char error_message[1024];
175 unsigned char set_size; /* -s option was on the command line */
177 /* convert key to key with shift */
178 int my_toupper(int c)
180 switch(c)
182 case '1': return '!';
183 case '2': return '@';
184 case '3': return '#';
185 case '4': return '$';
186 case '5': return '%';
187 case '6': return '^';
188 case '7': return '&';
189 case '8': return '*';
190 case '9': return '(';
191 case '0': return ')';
192 case '-': return '_';
193 case '=': return '+';
194 case '\\': return '|';
195 case '[': return '{';
196 case ']': return '}';
197 case ';': return ':';
198 case '\'': return '"';
199 case ',': return '<';
200 case '.': return '>';
201 case '/': return '?';
202 case '`': return '~';
203 default: return toupper(c);
209 void wait_for_enter(void)
211 c_update_kbd();
212 while (!c_was_pressed(K_ENTER))
214 c_wait_for_key();
215 c_update_kbd();
220 /* load configure file from player's home directory */
221 int read_cfg_entry(FILE *stream, char *retval, int len)
223 int l;
224 if (!fgets(retval,len+2,stream))
225 return 0;
226 l = strlen(retval);
227 if (retval[l-1] == 10)
228 retval[l-1] = 0;
229 return l;
232 int load_default_cfg(struct config *cfg, char state)
234 char *host = "localhost";
235 char *name = "Player";
236 /* we dont want to loose argc and argv here ... */
237 memcpy(cfg->host, host, strlen(host));
238 memcpy(cfg->name, name, strlen(name));
239 cfg->port = 6666;
240 cfg->color = C_D_GREY;
241 errormsg.flags = (state >> 1) ? E_DEFAULTS : 0;
242 errormsg.text = "Error loading configuration file, defaults loaded. Press ENTER.";
243 return state;
246 int load_cfg(struct config *cfg)
248 FILE *stream;
249 int a;
250 char txt[256];
252 #ifndef WIN32
253 snprintf(txt, sizeof(txt), "%s/%s",getenv("HOME"),CFG_FILE);
254 stream=fopen(txt,"r");
255 #else
256 snprintf(txt, sizeof(txt), "./%s", CFG_FILE);
257 fopen_s(&stream, txt, "r");
258 #endif
259 if (!stream)
260 return load_default_cfg(cfg, 1);
262 if (a = read_cfg_entry(stream, txt, MAX_HOST_LEN))
263 memcpy(cfg->host,txt,a+1);
264 else
265 return load_default_cfg(cfg, 2);
267 if (a = read_cfg_entry(stream, txt, MAX_NAME_LEN))
268 memcpy(cfg->name,txt,a+1);
269 else
270 return load_default_cfg(cfg, 3);
272 if (a = read_cfg_entry(stream, txt, MAX_PORT_LEN))
273 cfg->port = strtol(txt,0,10);
274 else
275 return load_default_cfg(cfg, 4);
277 if (a = read_cfg_entry(stream, txt, 4))
278 cfg->color = strtol(txt,0,10);
279 else
280 return load_default_cfg(cfg, 5);
282 fclose(stream);
283 return 0;
287 /* save configure file to player's home */
288 void save_cfg(struct config *cfg)
290 FILE *stream;
291 char txt[256];
292 struct config dcfg;
293 memcpy(&dcfg, cfg, sizeof(struct config));
295 #ifndef WIN32
296 snprintf(txt, sizeof(txt), "%s/%s",getenv("HOME"),CFG_FILE);
297 #else
298 snprintf(txt, sizeof(txt), "./%s",CFG_FILE);
299 #endif
300 if (cfg->override) {
301 load_cfg(&dcfg);
302 if (!(cfg->override & OVERRIDE_FLAG_HOST))
303 memcpy(dcfg.host, cfg->host, strlen(cfg->host));
304 if (!(cfg->override & OVERRIDE_FLAG_NAME))
305 memcpy(dcfg.name, cfg->name, strlen(cfg->name));
306 if (!(cfg->override & OVERRIDE_FLAG_PORT))
307 dcfg.port = cfg->port;
308 if (!(cfg->override & OVERRIDE_FLAG_COLOR))
309 dcfg.color = cfg->color;
312 #ifndef WIN32
313 stream=fopen(txt,"w");
314 #else
315 fopen_s(&stream, txt, "w");
316 #endif
317 if (!stream)
318 return;
319 fprintf(stream, "%s\n%s\n%d\n%d\n", dcfg.host, dcfg.name,
320 dcfg.port, dcfg.color);
321 fclose(stream);
325 void scroll_messages(void)
327 int a;
329 if (last_message<0)return;
330 for (a=0;a<=last_message-1;a++)
332 msg_line[a].time=msg_line[a+1].time;
333 msg_line[a].color=msg_line[a+1].color;
334 msg_line[a].msg=mem_realloc(msg_line[a].msg,strlen(msg_line[a+1].msg)+1);
335 memcpy(msg_line[a].msg,msg_line[a+1].msg,strlen(msg_line[a+1].msg)+1);
337 mem_free(msg_line[last_message].msg);
338 msg_line[last_message].msg=0;
339 last_message--;
343 void add_message(char *message, unsigned char flags)
345 int last;
346 if (last_message == N_MESSAGES - 1)
347 scroll_messages();
348 last = last_message + 1;
349 msg_line[last].time = get_time() + MESSAGE_TTL;
350 switch (flags) {
351 case M_CHAT:
352 msg_line[last].color = C_YELLOW;
353 break;
354 case M_INFO:
355 msg_line[last].color = C_CYAN;
356 break;
357 case M_ENTER:
358 msg_line[last].color = C_GREEN;
359 break;
360 case M_LEAVE:
361 msg_line[last].color = C_D_RED;
362 break;
363 case M_AMMO:
364 msg_line[last].color = C_GREY;
365 break;
366 case M_WEAPON:
367 msg_line[last].color = C_BLUE;
368 break;
369 case M_ITEM:
370 msg_line[last].color = C_MAGENTA;
371 break;
372 case M_DEATH:
373 msg_line[last].color = C_RED;
374 break;
375 default:
376 msg_line[last].color = MESSAGE_COLOR;
377 break;
379 msg_line[last].msg = mem_alloc(strlen(message) + 1);
380 if (!msg_line[last].msg)
381 return; /* not such a fatal errror */
382 memcpy(msg_line[last].msg, message, strlen(message) + 1);
383 last_message = last;
387 void print_messages(void)
389 int a;
390 for (a=0;a<=last_message;a++)
391 print2screen(0,a,msg_line[a].color,msg_line[a].msg);
395 /* throw out old messages */
396 void update_messages(unsigned long_long time)
398 int a,b;
400 for(a=0,b=0;a<=last_message;a++)
401 if (msg_line[b].time<=time)scroll_messages();
402 else b++;
406 /* destroys all objects and messages */
407 void clean_memory(void)
409 int a;
410 struct object_list *o;
412 /* delete all objects except hero */
413 for (o=&objects;o->next;)
414 if ((hero->id)!=(o->next->member.id))delete_obj(o->next->member.id);
415 else o=o->next;
417 /* delete messages */
418 for (a=0;a<=last_message;a++)
419 mem_free(msg_line[a].msg);
420 msg_line[last_message].msg=0;
421 last_message=-1;
425 /* shut down the client */
426 void shut_down(int x)
428 struct object_list *o;
429 int a;
431 c_shutdown();
432 free_sprites(0);
433 free_area();
434 if (!x&&hero)delete_obj(hero->id);
437 /* delete all objects except hero */
438 for (o=&objects;o->next;)
439 delete_obj(o->next->member.id);
441 /* delete messages */
442 for (a=0;a<=last_message;a++)
443 mem_free(msg_line[a].msg);
444 msg_line[last_message].msg=0;
446 shutdown_sprites();
447 free_packet_buffer();
448 check_memory_leaks();
449 if (x)EXIT(0);
453 /* find address of server and fill the server address structure */
454 char * find_server(struct config *cfg)
456 struct hostent *h;
458 h=gethostbyname(cfg->host);
459 if (!h)
460 return "Error: Can't resolve server address.";
462 server.sin_family=AF_INET;
463 server.sin_port=htons(cfg->port);
464 server.sin_addr=*((struct in_addr*)(h->h_addr_list[0]));
465 return 0;
469 /* initialize socket */
470 char * init_socket(void)
472 fd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
473 if(fd<0)return "Can't get socket.\n";
474 return 0;
478 #define MAX_COUNT 32
480 /* send quit request to server */
481 void send_quit(void)
483 char p;
484 fd_set rfds;
485 struct timeval tv;
486 int a=sizeof(server);
487 int count=0;
489 tv.tv_sec=2;
490 tv.tv_usec=0;
491 FD_ZERO(&rfds);
492 FD_SET(fd,&rfds);
494 send_again:
495 p=P_QUIT_REQUEST;
496 count ++;
497 send_packet(&p,1,(struct sockaddr *)(&server),my_id,0);
498 if (!select(fd+1,&rfds,0,0,&tv)&&count<=MAX_COUNT)goto send_again;
499 recv_packet(&p,1,(struct sockaddr*)(&server),&a,1,my_id,0);
500 if (p!=P_PLAYER_DELETED&&count<=MAX_COUNT)goto send_again;
501 if(fd) close(fd);
504 #undef MAX_COUNT
506 void server_error(char *msg, int err)
508 errormsg.text = msg;
509 errormsg.flags = err;
511 /* initiate connection with server */
512 int contact_server(struct config *cfg)
514 char *name = cfg->name;
515 int color = cfg->color;
516 static char packet[256];
517 int l=strlen(name)+1;
518 int a,r;
519 int min,maj;
520 fd_set fds;
521 struct timeval tv;
523 tv.tv_sec=4;
524 tv.tv_usec=0;
525 FD_ZERO(&fds);
526 FD_SET(fd,&fds);
528 packet[0]=P_NEW_PLAYER;
529 packet[1]=0;
530 packet[2]=VERSION_MAJOR;
531 packet[3]=VERSION_MINOR;
532 packet[4]=color;
533 memcpy(packet+5,name,l);
535 send_packet(packet,l+5,(struct sockaddr*)(&server),my_id,0);
537 if (!select(fd+1,&fds,NULL,NULL,&tv)) {
538 server_error("No reply within 4 seconds. Press ENTER.", E_CONN);
539 return 1;
542 if ((r=recv_packet(packet,256,0,0,1,0,0))<0)
544 if (errno==EINTR) {
545 server_error("Server hung up. Press ENTER.", E_CONN);
546 return 1;
547 } else {
548 server_error("Connection error. Press ENTER.", E_CONN);
549 return 1;
553 switch(*packet)
555 case P_PLAYER_REFUSED:
556 switch(packet[1])
558 case E_INCOMPATIBLE_VERSION:
559 server_error("Incompatible client version. Connection refused. Press Enter.", E_CONN);
560 return 1;
562 case E_NAME_IN_USE:
563 server_error("Another player on this server uses the same name. Press Enter.", E_CONN);
564 default:
565 server_error("Connection refused. Press ENTER.", E_CONN);
566 return 1;
569 case P_PLAYER_ACCEPTED:
570 my_id=get_int(packet+35);
571 if (r<41) {
572 send_quit();
573 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN);
574 return 1;
576 maj=packet[39];
577 min=packet[40];
578 if (maj!=VERSION_MAJOR||min<MIN_SERVER_VERSION_MINOR) {
579 send_quit();
580 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN);
581 return 1;
583 game_start_offset=get_time();
584 game_start_offset-=get_long_long(packet+27);
585 health=100;
586 armor=0;
587 for(a=0;a<ARMS;a++)
588 ammo[a]=0;
589 ammo[WEAPON_GUN]=weapon[WEAPON_GUN].basic_ammo;
590 ammo[WEAPON_CHAINSAW]=weapon[WEAPON_CHAINSAW].basic_ammo;
591 current_weapon=0;
592 weapons=WEAPON_MASK_GUN |
593 WEAPON_MASK_GRENADE |
594 WEAPON_MASK_CHAINSAW |
595 WEAPON_MASK_BLOODRAIN; /* gun, grenades, chainsaw and blodrain */
596 hero=new_obj(
597 get_int(packet+1), /* ID */
598 T_PLAYER, /* type */
599 0, /* time to live */
600 get_int16(packet+5), /* sprite */
601 0, /* position */
602 get_int(packet+23), /* status */
603 get_int(packet+7), /* X */
604 get_int(packet+11), /* Y */
605 get_int(packet+15), /* XSPEED */
606 get_int(packet+19), /* YSPEED */
609 break;
611 default:
612 server_error("Connection error. Press ENTER.", E_CONN);
613 return 1;
615 server_error("",
616 #ifdef HAVE_LIBPTHREAD
617 E_CONN_SUCC
618 #else
619 E_NONE
620 #endif
622 return 0;
626 /* send me top X players */
627 void send_info_request(void)
629 char packet;
630 packet=P_INFO;
631 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
635 /* I want to be born again */
636 void send_reenter_game(void)
638 char packet;
639 packet=P_REENTER_GAME;
640 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
644 /* send end of game to server */
645 void end_game(void)
647 char packet;
648 packet=P_END;
649 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
653 /* send chat message */
654 void send_message(char *msg, char flags)
656 static char packet[MAX_MESSAGE_LENGTH + 2];
657 int len;
659 len = strlen(msg) + 1;
660 packet[0] = P_MESSAGE;
661 packet[1] = flags;
662 memcpy(packet + 2, msg, len);
663 send_packet(packet, len + 2, (struct sockaddr *)(&server), my_id, 0);
667 /* send end of game to server */
668 void send_keyboard(void)
670 char packet[3];
671 packet[0]=P_KEYBOARD;
672 packet[1]=keyboard_status.status;
673 packet[2]=keyboard_status.weapon;
674 send_packet(packet,3,(struct sockaddr*)(&server),my_id,0);
678 void reset_keyboard(void)
680 keyboard_status.status=0;
681 keyboard_status.weapon=0;
684 /* recompute object positions */
685 void update_game(void)
687 struct object_list *p;
688 int w,h;
689 unsigned char stop_x,stop_y,sy;
690 unsigned long_long t;
691 int x,y,x1,y1,DELTA_TIME;
693 for(p=&objects;p->next;p=p->next)
695 if (p->next->member.type==T_NOTHING)
696 continue;
697 if (p->next->member.status & S_DEAD)
698 continue; /* dead player */
699 /* decrement time to live */
700 if (p->next->member.ttl>0)
702 p->next->member.ttl--;
703 if (!p->next->member.ttl)
705 if ((p->next->member.type)==T_PLAYER)
706 p->next->member.status &= ~S_SHOOTING;
707 else
709 if (p->next->member.type!=T_GRENADE &&
710 p->next->member.type!=T_BFGCELL){ /* client's waiting for P_EXPLODE_GRENADE and doesn't delete the grenade yet */
711 p=p->prev;
712 delete_obj(p->next->next->member.id);
713 continue;}
717 /* maintain only objects that you are allowed to maintain */
718 if (!(obj_attr[p->next->member.type].maintainer&1))continue;
721 /* if not falling slow down x motion */
722 if (!(p->next->member.status & S_FALLING))
723 p->next->member.xspeed=mul(p->next->member.xspeed,obj_attr[p->next->member.type].slow_down_x);
725 /* fall */
726 if (obj_attr[p->next->member.type].fall)
728 p->next->member.status |= S_FALLING;
729 p->next->member.yspeed+=FALL_ACCEL;
730 /* but not too fast */
731 if (p->next->member.yspeed>MAX_Y_SPEED)p->next->member.yspeed=MAX_Y_SPEED;
734 get_dimensions(p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions,&w,&h);
735 x=p->next->member.x;
736 y=p->next->member.y;
737 t=get_time();
738 DELTA_TIME=float2double(((double)(long_long)(t-p->next->member.last_updated))/MICROSECONDS);
739 update_position(
740 &(p->next->member),
741 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
742 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
743 w,h,&stop_x,&stop_y);
744 p->next->member.last_updated=t;
746 /* walk up the stairs */
747 if (stop_x&&p->next->member.type==T_PLAYER&&!(p->next->member.status & S_CREEP))
749 x1=p->next->member.x;
750 y1=p->next->member.y;
751 p->next->member.x=x;
752 p->next->member.y=y-int2double(1);
753 update_position(
754 &(p->next->member),
755 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
756 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
757 w,h,0,&sy);
758 if ((p->next->member.xspeed>0&&p->next->member.x<=x1)||(p->next->member.xspeed<0&&p->next->member.x>=x1)) /* restore original values */
760 p->next->member.x=x1;
761 p->next->member.y=y1;
763 else
765 stop_y=sy;
766 stop_x=0;
770 if (stop_x)
771 p->next->member.xspeed=-mul(p->next->member.xspeed,obj_attr[p->next->member.type].bounce_x);
772 if (my_abs(p->next->member.xspeed)<MIN_X_SPEED)
774 p->next->member.xspeed=0;
775 p->next->member.status &= ~S_WALKING;
779 if (stop_y)
781 p->next->member.yspeed=mul(p->next->member.yspeed,obj_attr[p->next->member.type].bounce_y);
782 p->next->member.yspeed=-p->next->member.yspeed;
783 if (my_abs(p->next->member.yspeed)<MIN_Y_SPEED)
785 p->next->member.yspeed=0;
786 if (stop_y==1)p->next->member.status &= ~S_FALLING;
790 if ((p->next->member.type == T_SHRAPNEL || p->next->member.type == T_BULLET ||
791 p->next->member.type == T_BFGCELL || p->next->member.type == T_CHAIN ||
792 p->next->member.type == T_JETFIRE) &&
793 (stop_x || stop_y)) { /* bullet and shrapnel die crashing into wall */
794 p=p->prev; /* deleting object makes a great mess in for cycle, so we must cheat the cycle */
795 delete_obj(p->next->next->member.id);
796 continue;
802 #define FIRE_SHOOTING weapon[current_weapon].cadence-4+HOLD_GUN_AFTER_SHOOT
804 /* hero's next anim position when walking to the right */
805 int _next_anim_right(int pos,int status, int ttl)
807 int start,offset;
809 if (pos<=18)
810 start=10; /* normal */
811 else
813 if (pos<=46)start=(status & S_CHAINSAW)?97:38; /* holding gun */
814 else
816 if (pos<=55)start=(status & S_CHAINSAW)?106:47; /* shooting */
817 else start=64; /* creeping */
820 offset=pos-start;
822 if (status & S_CREEP)
823 start=64; /* creeping */
824 else
826 if (status & S_SHOOTING)
828 if (ttl>=FIRE_SHOOTING) start=(status & S_CHAINSAW)?106:47; /* shooting */
829 else start=(status & S_CHAINSAW)?97:38; /* holding a gun */
831 else start=10; /* normal */
834 return (status & S_CREEP)?((offset+1)&7)+start:start+(offset&7)+1;
838 /* hero's next anim position when walking to the left */
839 int _next_anim_left(int pos,int status, int ttl)
841 int start,offset;
843 if (pos<=8)start=0; /* normal */
844 else
846 if (pos<=28)start=(status & S_CHAINSAW)?79:20; /* holding gun */
847 else
849 if (pos<=37)start=(status & S_CHAINSAW)?88:29; /* shooting */
850 else start=56; /* creeping */
853 offset=pos-start;
855 if (status & S_CREEP)
856 start=56; /* creeping */
857 else
859 if (status & S_SHOOTING)
861 if (ttl>=FIRE_SHOOTING) start=(status & S_CHAINSAW)?88:29; /* shooting */
862 else start=(status & S_CHAINSAW)?79:20; /* holding a gun */
864 else start=0; /* normal */
867 return (status & S_CREEP)?((offset+1)&7)+start:start+(offset&7)+1;
871 /* update hero animating position */
872 void update_anim(struct it* obj)
874 if (!(obj->status & S_WALKING)) /* not walking */
875 switch((obj->status & (S_LOOKLEFT | S_LOOKRIGHT)))
877 case 0: /* look at me */
878 obj->anim_pos=(obj->status & S_CREEP)?72:9;
879 break;
880 case S_LOOKLEFT: /* look left */
881 if (obj->status & S_SHOOTING)
883 if (obj->status & S_GRENADE)
884 obj->anim_pos = (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>1)+HOLD_GUN_AFTER_SHOOT)) ?
885 73 : (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>2)+HOLD_GUN_AFTER_SHOOT)) ?
886 74 : ((obj->ttl>=HOLD_GUN_AFTER_SHOOT) ? 75 : 0);
887 else if (obj->status & S_CHAINSAW) /* maniak ma motorovku */
888 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 88 : 79;
889 else
890 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 29 : 20;
891 } else
892 obj->anim_pos=0;
893 if (obj->status & S_CREEP)
894 obj->anim_pos=56;
895 break;
896 case S_LOOKRIGHT: /* look right */
897 if (obj->status & S_SHOOTING)
899 if (obj->status & S_GRENADE)
900 obj->anim_pos = (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>1)+HOLD_GUN_AFTER_SHOOT)) ?
901 76 : (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>2)+HOLD_GUN_AFTER_SHOOT)) ?
902 77 : ((obj->ttl>=HOLD_GUN_AFTER_SHOOT) ? 78 : 10);
903 else if (obj->status & S_CHAINSAW) /* maniak ma motorovku */
904 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 106 : 97;
905 else
906 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 47 : 38;
907 } else
908 obj->anim_pos=10;
909 if (obj->status & S_CREEP)
910 obj->anim_pos=64;
911 break;
913 else /* walking */
915 switch (obj->status & (S_LOOKLEFT | S_LOOKRIGHT))
917 case S_LOOKLEFT: /* walk left */
918 obj->anim_pos=_next_anim_left(obj->anim_pos,obj->status,obj->ttl);
919 break;
921 case S_LOOKRIGHT: /* walk right */
922 obj->anim_pos=_next_anim_right(obj->anim_pos,obj->status,obj->ttl);
923 break;
929 /* draw scene into screenbuffer*/
930 void draw_scene(void)
932 struct object_list *p;
933 unsigned char fore;
935 #ifdef TRI_D
936 if (TRI_D_ON)
938 tri_d=1;
939 show_window(double2int(hero->x)-SCREEN_XOFFSET,double2int(hero->y)-SCREEN_YOFFSET);
940 tri_d=0;
942 #endif
944 show_window(double2int(hero->x)-SCREEN_XOFFSET,double2int(hero->y)-SCREEN_YOFFSET);
945 for (fore=0;fore<=1;fore++)
947 for(p=&objects;p->next;p=p->next)
949 if ((obj_attr[p->next->member.type].foreground)!=fore)continue;
950 if (&(p->next->member)==hero)continue;
951 if (p->next->member.type==T_PLAYER)update_anim(&(p->next->member));
952 else {p->next->member.anim_pos++;p->next->member.anim_pos%=sprites[p->next->member.sprite].n_steps;}
953 if (p->next->member.status == WEAPON_CHAINSAW) continue;
954 if (!(p->next->member.status & S_DEAD)&&!(p->next->member.status & S_INVISIBLE)) /* don't draw hidden objects and dead players */
956 #ifdef TRI_D
957 if(TRI_D_ON)
959 tri_d=1;
960 put_sprite(
961 double2int(p->next->member.x-hero->x)+fore+SCREEN_XOFFSET,
962 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET,
963 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],
966 tri_d=0;
968 #endif
970 put_sprite(
971 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET,
972 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET,
973 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],
977 if (p->next->member.type == T_PLAYER) {
978 if ((p->next->member.status & S_JETPACK_ON) && !(p->next->member.status & S_CREEP)) {
979 if (p->next->member.status & S_LOOKRIGHT)
980 put_sprite(
981 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET-1,
982 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+4,
983 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[1], 1);
984 else if (p->next->member.status & S_LOOKLEFT)
985 put_sprite(
986 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+PLAYER_WIDTH-4,
987 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+4,
988 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[0], 1);
990 if ((gsbi += 10) > 1000) {
991 gsbi++;
992 gsbi %= 3;
994 if (p->next->member.status & S_ONFIRE) {
995 if (p->next->member.status & S_CREEP)
996 put_sprite(
997 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET-5,
998 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET-2,
999 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3 + 3], 1);
1000 else
1001 put_sprite(
1002 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+3,
1003 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET-3,
1004 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3], 1);
1006 if ((p->next->member.status & S_CHAINSAW) && (p->next->member.ttl >= FIRE_SHOOTING) && !(hero->status & S_CREEP)) {
1007 if (p->next->member.status & S_LOOKRIGHT)
1008 put_sprite(
1009 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+15,
1010 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+6,
1011 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1012 else if (p->next->member.status & S_LOOKLEFT)
1013 put_sprite(
1014 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET-8,
1015 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+6,
1016 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1020 if (p->next->member.type==T_PLAYER&&p->next->member.status & S_HIT) /* hit */
1022 p->next->member.status &= ~S_HIT;
1023 if (!(p->next->member.status & S_DEAD)) /* don't draw blood splash to dead players */
1025 #ifdef TRI_D
1026 if (TRI_D_ON)
1028 tri_d=1;
1029 put_sprite(
1030 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+fore+((long)(p->next->member.data)&255),
1031 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+(((long)(p->next->member.data)>>8)&255),
1032 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)p->next->member.data)>>16],
1035 tri_d=0;
1037 #endif
1039 put_sprite(
1040 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+((long)(p->next->member.data)&255),
1041 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+(((long)(p->next->member.data)>>8)&255),
1042 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)p->next->member.data)>>16],
1048 if (obj_attr[T_PLAYER].foreground!=fore)continue;
1049 update_anim(hero);
1050 if (hero->status & S_DEAD)
1051 continue; /* don't draw dead hero */
1052 #ifdef TRI_D
1053 if (TRI_D_ON)
1055 tri_d=1;
1056 put_sprite(
1057 SCREEN_XOFFSET,
1058 SCREEN_YOFFSET,
1059 sprites[hero->sprite].positions+sprites[hero->sprite].steps[hero->anim_pos],
1062 tri_d=0;
1064 #endif
1065 put_sprite(
1066 SCREEN_XOFFSET,
1067 SCREEN_YOFFSET,
1068 sprites[hero->sprite].positions+sprites[hero->sprite].steps[hero->anim_pos],
1072 if ((hero->status & S_JETPACK_ON) && !(hero->status & S_CREEP)) {
1073 if (hero->status & S_LOOKRIGHT)
1074 put_sprite(SCREEN_XOFFSET-1, SCREEN_YOFFSET+4,
1075 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[1], 1);
1076 else if (hero->status & S_LOOKLEFT)
1077 put_sprite(SCREEN_XOFFSET+PLAYER_WIDTH-4, SCREEN_YOFFSET+4,
1078 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[0], 1);
1080 if ((gsbi += 10) > 1000) {
1081 gsbi++;
1082 gsbi %= 3;
1084 if (hero->status & S_ONFIRE) {
1085 if (hero->status & S_CREEP)
1086 put_sprite(SCREEN_XOFFSET-5, SCREEN_YOFFSET-2,
1087 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3 + 3], 1);
1088 else
1089 put_sprite(SCREEN_XOFFSET+3, SCREEN_YOFFSET-3,
1090 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3], 1);
1092 if ((hero->status & S_CHAINSAW) && (hero->ttl >= FIRE_SHOOTING) && !(hero->status & S_CREEP)) {
1093 if (hero->status & S_LOOKRIGHT)
1094 put_sprite(SCREEN_XOFFSET+15, SCREEN_YOFFSET+6,
1095 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1096 else if (hero->status & S_LOOKLEFT)
1097 put_sprite(SCREEN_XOFFSET-8, SCREEN_YOFFSET+6,
1098 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1100 if (hero->status & S_HIT) /* hit */
1102 hero->status &= ~S_HIT;
1103 #ifdef TRI_D
1104 if (TRI_D_ON)
1106 tri_d=1;
1107 put_sprite(
1108 SCREEN_XOFFSET+((long)(hero->data)&255),
1109 SCREEN_YOFFSET+(((long)(hero->data)>>8)&255),
1110 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)hero->data)>>16],
1113 tri_d=0;
1115 #endif
1116 put_sprite(
1117 SCREEN_XOFFSET+((long)(hero->data)&255),
1118 SCREEN_YOFFSET+(((long)(hero->data)>>8)&255),
1119 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)hero->data)>>16],
1127 void change_level(void)
1129 char *LEVEL;
1130 char txt[256];
1132 clean_memory();
1133 free_sprites(level_sprites_start);
1134 reinit_area();
1136 LEVEL=load_level(level_number);
1137 snprintf(txt,sizeof(txt),"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
1138 load_sprites(txt);
1139 snprintf(txt,sizeof(txt),"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
1140 load_data(txt);
1141 mem_free(LEVEL);
1145 /* returns number of read bytes */
1146 int process_packet(char *packet,int l)
1148 int a,n=l;
1150 switch(*packet)
1152 case P_CHUNK:
1153 for (a=1;a<l&&a<MAX_PACKET_LENGTH;a+=n)
1154 n=process_packet(packet+a,l-a);
1155 break;
1157 case P_NEW_OBJ:
1158 if (l < (n=30))break; /* invalid packet */
1159 new_obj(
1160 get_int(packet+1), /* ID */
1161 packet[27], /* type */
1162 get_int16(packet+28), /* time to live */
1163 get_int16(packet+5), /* sprite */
1164 0, /* anim position */
1165 get_int(packet+23), /* status */
1166 get_int(packet+7), /* x */
1167 get_int(packet+11), /* y */
1168 get_int(packet+15), /* xspeed */
1169 get_int(packet+19), /* yspeed */
1170 0 /* data */
1172 break;
1174 case P_PLAYER_DELETED:
1175 n=1;
1176 *error_message=0;
1177 return -1;
1179 case P_DELETE_OBJECT:
1180 if (l<5)break; /* invalid packet */
1181 delete_obj(get_int(packet+1));
1182 n=5;
1183 break;
1185 case P_UPDATE_OBJECT:
1186 if (l< (n=28))break; /* invalid packet */
1188 struct object_list *p;
1190 p=find_in_table(get_int(packet+1));
1191 if (!p)break;
1192 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1193 p->member.update_counter=packet[5];
1194 p->member.x=get_int(packet+6);
1195 p->member.y=get_int(packet+10);
1196 p->member.xspeed=get_int(packet+14);
1197 p->member.yspeed=get_int(packet+18);
1198 p->member.status=get_int(packet+22);
1199 p->member.data=0;
1200 p->member.ttl=get_int16(packet+26);
1201 /* kdyz tasi, tak se nahodi ttl */
1202 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1203 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1205 break;
1207 case P_UPDATE_OBJECT_POS:
1208 if (l<22)break; /* invalid packet */
1210 struct object_list *p;
1212 n=22;
1213 p=find_in_table(get_int(packet+1));
1214 if (!p)break;
1215 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1216 p->member.update_counter=packet[5];
1217 p->member.x=get_int(packet+6);
1218 p->member.y=get_int(packet+10);
1219 p->member.xspeed=get_int(packet+14);
1220 p->member.yspeed=get_int(packet+18);
1222 break;
1224 case P_UPDATE_OBJECT_SPEED:
1225 if (l<14)break; /* invalid packet */
1227 struct object_list *p;
1229 n=14;
1230 p=find_in_table(get_int(packet+1));
1231 if (!p)break;
1232 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1233 p->member.update_counter=packet[5];
1234 p->member.xspeed=get_int(packet+6);
1235 p->member.yspeed=get_int(packet+10);
1237 break;
1239 case P_UPDATE_OBJECT_COORDS:
1240 if (l<14)break; /* invalid packet */
1242 struct object_list *p;
1244 n=14;
1245 p=find_in_table(get_int(packet+1));
1246 if (!p)break;
1247 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1248 p->member.update_counter=packet[5];
1249 p->member.x=get_int(packet+6);
1250 p->member.y=get_int(packet+10);
1252 break;
1254 case P_UPDATE_OBJECT_SPEED_STATUS:
1255 if (l < (n=18))break; /* invalid packet */
1257 struct object_list *p;
1259 p=find_in_table(get_int(packet+1));
1260 if (!p)break;
1261 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1262 p->member.update_counter=packet[5];
1263 p->member.xspeed=get_int(packet+6);
1264 p->member.yspeed=get_int(packet+10);
1265 p->member.status=get_int(packet+14);
1266 /* kdyz tasi, tak se nahodi ttl */
1267 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1268 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1270 break;
1272 case P_UPDATE_OBJECT_COORDS_STATUS:
1273 if (l < (n=18))break; /* invalid packet */
1275 struct object_list *p;
1277 p=find_in_table(get_int(packet+1));
1278 if (!p)break;
1279 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1280 p->member.update_counter=packet[5];
1281 p->member.x=get_int(packet+6);
1282 p->member.y=get_int(packet+10);
1283 p->member.status=get_int(packet+14);
1284 /* kdyz tasi, tak se nahodi ttl */
1285 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1286 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1288 break;
1290 case P_UPDATE_OBJECT_SPEED_STATUS_TTL:
1291 if (l < (n=20))break; /* invalid packet */
1293 struct object_list *p;
1295 p=find_in_table(get_int(packet+1));
1296 if (!p)break;
1297 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1298 p->member.update_counter=packet[5];
1299 p->member.xspeed=get_int(packet+6);
1300 p->member.yspeed=get_int(packet+10);
1301 p->member.status=get_int(packet+14);
1302 p->member.ttl=get_int16(packet+18);
1303 /* kdyz tasi, tak se nahodi ttl */
1304 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1305 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1307 break;
1309 case P_UPDATE_OBJECT_COORDS_STATUS_TTL:
1310 if (l < (n=20))break; /* invalid packet */
1312 struct object_list *p;
1314 p=find_in_table(get_int(packet+1));
1315 if (!p)break;
1316 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1317 p->member.update_counter=packet[5];
1318 p->member.x=get_int(packet+6);
1319 p->member.y=get_int(packet+10);
1320 p->member.status=get_int(packet+14);
1321 p->member.ttl=get_int16(packet+18);
1322 /* kdyz tasi, tak se nahodi ttl */
1323 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1324 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1326 break;
1328 case P_UPDATE_STATUS:
1329 if (l < (n=9))break; /* invalid packet */
1331 struct object_list *p;
1333 p=find_in_table(get_int(packet+1));
1334 if (!p)break; /* ignore objects we don't have */
1335 p->member.status=get_int(packet+5);
1336 /* kdyz tasi, tak se nahodi ttl */
1337 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1338 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1340 break;
1342 case P_HIT:
1343 if (l<8)break; /* invalid packet */
1345 struct object_list *p;
1347 n=8;
1348 p=find_in_table(get_int(packet+1));
1349 if (!p)break; /* ignore objects we don't have */
1350 p->member.status|=S_HIT;
1351 p->member.data=(void*)(long)((packet[5]<<16)+(packet[7]<<8)+(packet[6]));
1352 /* kdyz tasi, tak se nahodi ttl */
1353 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1354 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1356 break;
1358 case P_UPDATE_PLAYER:
1359 if (l<15+2*ARMS)break; /* invalid packet */
1360 health=packet[1];
1361 armor=packet[2];
1362 for (a=0;a<ARMS;a++)
1363 ammo[a]=get_int16(packet+3+(a<<1));
1364 frags=get_int(packet+3+ARMS*2);
1365 deaths=get_int(packet+7+ARMS*2);
1366 current_weapon=get_int16(packet+11+ARMS*2);
1367 weapons=get_int16(packet+13+ARMS*2);
1368 n=15+2*ARMS;
1369 break;
1371 case P_MESSAGE:
1372 if (l < 3)
1373 break; /* invalid packet */
1374 add_message(packet + 2, packet[1]);
1375 n = 3 + strlen(packet + 2);
1376 break;
1378 case P_CHANGE_LEVEL:
1380 char txt[256];
1381 char *name;
1382 char *md5;
1383 int a;
1384 char p;
1386 if (l<38)break; /* invalid packet */
1387 a=get_int(packet+1);
1388 if (level_number==a)goto level_changed;
1389 level_number=a;
1390 snprintf(txt, sizeof(txt), "Trying to change level to number %d", level_number);
1391 add_message(txt, M_INFO);
1392 name=load_level(level_number);
1393 if (!name) {
1394 snprintf(error_message,1024,"Cannot find level "
1395 "number %d. Game terminated. Press ENTER.",
1396 level_number);
1397 send_quit();
1398 return -1;
1400 snprintf(txt,256,"Changing level to \"%s\"",name);
1401 mem_free(name);
1402 add_message(txt, M_INFO);
1404 md5=md5_level(level_number);
1405 if (strcmp((char *)md5,packet+5)) /* MD5s differ */
1407 mem_free(md5);
1408 snprintf(error_message,1024,"Invalid MD5 sum. Can't change level. Game terminated. Press ENTER.");
1409 add_message("Invalid MD5 sum. Can't change level. Exiting...", M_INFO);
1410 send_quit();
1411 return -1;
1413 mem_free(md5);
1415 /* OK we can change it */
1416 change_level();
1417 level_changed:
1419 p=P_LEVEL_ACCEPTED;
1420 send_packet(&p,1,(struct sockaddr *)(&server),my_id,0);
1421 n=38;
1423 break;
1425 case P_END:
1426 if (l<2)
1427 snprintf(error_message,1024,"Game terminated. Press ENTER.");
1428 else
1429 snprintf(error_message,1024,"Game terminated by %s. Press ENTER.",packet+1);
1430 return -1;
1432 case P_BELL:
1433 n=1;
1434 c_bell();
1435 break;
1437 case P_INFO:
1438 if (l<=5)break;
1439 active_players=get_int(packet+1);
1440 l=6;
1441 for (a=0;a<packet[5]&&a<TOP_PLAYERS_N;a++)
1443 int x;
1444 top_players[a].frags=get_int(packet+l);
1445 top_players[a].deaths=get_int(packet+l+4);
1446 top_players[a].color=packet[l+8];
1447 x=strlen(packet+l+9)+1;
1448 memcpy(top_players[a].name,packet+l+9,x);
1449 l+=x+9;
1451 n=l;
1452 break;
1454 case P_EXPLODE_GRENADE:
1455 case P_EXPLODE_BFG:
1456 case P_EXPLODE_BLOODRAIN:
1458 unsigned int i,j;
1459 struct object_list *p;
1460 int b;
1462 if (l<9)break;
1463 n=9;
1464 i=get_int(packet+1);
1465 j=get_int(packet+5);
1466 p=find_in_table(j);
1467 if (!p)break;
1469 for (b=0;b<N_SHRAPNELS_EXPLODE;b++)
1471 double angle=(double)b*2*M_PI/N_SHRAPNELS_EXPLODE;
1472 int spd=add_int(mul_int(my_and(mul_int(weapon[WEAPON_GRENADE].speed,b+1),15),16),100);
1474 new_obj(
1476 T_SHRAPNEL,
1477 SHRAPNEL_TTL,
1478 (*packet==P_EXPLODE_GRENADE)?
1479 shrapnel_sprite[random()%N_SHRAPNELS]:
1480 (*packet==P_EXPLODE_BFG)?
1481 bfgbit_sprite[random()%N_SHRAPNELS]:
1482 bloodrain_sprite[random()%N_SHRAPNELS],
1484 WEAPON_GRENADE,
1485 p->member.x,
1486 p->member.y,
1487 p->member.xspeed+mul(spd,float2double(cos(angle))),
1488 p->member.yspeed+mul(spd,float2double(sin(angle))),
1489 0);
1490 i++;
1492 if (*packet != P_EXPLODE_BLOODRAIN)
1493 delete_obj(j);
1496 break;
1498 return n;
1502 /* read packet from socket */
1503 int read_data(void)
1505 fd_set rfds;
1506 struct timeval tv;
1507 struct sockaddr_in client;
1508 static char packet[MAX_PACKET_LENGTH];
1509 int a=sizeof(client);
1510 int l;
1512 tv.tv_sec=0;
1513 tv.tv_usec=0;
1514 FD_ZERO(&rfds);
1515 FD_SET(fd,&rfds);
1516 while(select(fd+1,&rfds,0,0,&tv))
1518 if ((l=recv_packet(packet,MAX_PACKET_LENGTH,(struct sockaddr*)(&client),&a,1,my_id,0))<0)
1519 return 0; /* something's strange */
1520 if (process_packet(packet,l)<0)return 1;
1523 return 0;
1527 /* select color for numeric value (red=lack, yellow=edium, green=fill) */
1528 int select_color(int value,int max)
1530 return value>=(max>>1)?10:(value>=(max>>2)?11:9);
1534 /* draw board at the bottom of the screen */
1535 void draw_board(void)
1537 int offs=SCREEN_X*(SCREEN_Y-2);
1538 int space=(SCREEN_X-60)/5;
1539 char txt[16];
1540 int offset=0;
1542 memset(screen_a+offs,4,SCREEN_X);
1543 memset(screen+offs,'-',SCREEN_X);
1544 memset(screen+offs+SCREEN_X,0,SCREEN_X);
1545 print2screen(0,SCREEN_Y-1,7,"HEALTH");
1546 snprintf(txt, sizeof(txt), "% 3d%%",health);
1547 print2screen(6,SCREEN_Y-1,select_color(health,100),txt);
1549 print2screen(11+(space>>1),SCREEN_Y-2,4,",");
1550 print2screen(11+(space>>1),SCREEN_Y-1,4,"|");
1551 print2screen(11+space,SCREEN_Y-1,7,"FRAGS");
1552 snprintf(txt, sizeof(txt), "% 4d",frags);
1553 print2screen(11+space+6,SCREEN_Y-1,11,txt);
1555 print2screen(21+space+(space>>1),SCREEN_Y-2,4,",");
1556 print2screen(21+space+(space>>1),SCREEN_Y-1,4,"|");
1557 print2screen(21+(space<<1),SCREEN_Y-1,7,"DEATHS");
1558 snprintf(txt, sizeof(txt), "% 4d",deaths);
1559 print2screen(21+(space<<1)+7,SCREEN_Y-1,11,txt);
1561 print2screen(31+(space<<1)+(space>>1),SCREEN_Y-2,4,",");
1562 print2screen(31+(space<<1)+(space>>1),SCREEN_Y-1,4,"|");
1563 snprintf(txt, sizeof(txt), "%10s",weapon[current_weapon].name);
1564 print2screen(31+3*space,SCREEN_Y-1,11,txt);
1566 print2screen(41+(3*space)+(space>>1),SCREEN_Y-2,4,",");
1567 print2screen(41+(3*space)+(space>>1),SCREEN_Y-1,4,"|");
1568 print2screen(41+(space<<2),SCREEN_Y-1,7,"AMMO");
1569 snprintf(txt, sizeof(txt), "% 4d",ammo[current_weapon]);
1570 print2screen(41+5+(space<<2),SCREEN_Y-1,select_color(ammo[current_weapon],weapon[current_weapon].max_ammo),txt);
1572 print2screen(49+(space<<2)+(space>>1),SCREEN_Y-2,4,",");
1573 print2screen(49+(space<<2)+(space>>1),SCREEN_Y-1,4,"|");
1574 print2screen(49+5*space,SCREEN_Y-1,7,"ARMOR");
1575 snprintf(txt, sizeof(txt), "% 4d%%",armor);
1576 print2screen(49+5+5*space,SCREEN_Y-1,select_color(armor,100),txt);
1577 if (hero->status & S_INVISIBLE)print2screen(SCREEN_X-(offset += 14),SCREEN_Y-2,C_YELLOW,"INVISIBILITY");
1578 if (hero->status & S_ILL)print2screen(SCREEN_X-(offset += 14),SCREEN_Y-2,C_RED,"! INFECTED !");
1579 if (hero->status & S_ONFIRE)print2screen(SCREEN_X-(offset += 9),SCREEN_Y-2,C_RED,"ON FIRE");
1580 if (autorun)print2screen(2,SCREEN_Y-2,15,"AUTORUN");
1581 if (autocreep)print2screen(10,SCREEN_Y-2,15,"AUTOCREEP");
1585 /* read string from input, returns everytime, not when string's read */
1586 int read_str_online(int y,char *pointer,char *message, int max_len)
1588 int a,b,c,shift=0;
1590 a=strlen(message);
1591 b=strlen(pointer);
1592 c=SCREEN_X*y;
1594 #ifdef TRI_D
1595 if (TRI_D_ON)
1597 memcpy(screen2+c,message,a);
1598 memcpy(screen2+c+a,pointer,b);
1599 memset(screen2_a+c,15,a);
1600 memset(screen2_a+c+a,7,b);
1601 memset(screen2_a+c+a+b,0,SCREEN_X-b-a);
1603 #endif
1605 memcpy(screen+c,message,a);
1606 memcpy(screen+c+a,pointer,b);
1607 memset(screen_a+c,15,a);
1608 memset(screen_a+c+a,7,b);
1609 memset(screen_a+c+a+b,0,SCREEN_X-b-a);
1611 c_update_kbd();
1613 if (c_was_pressed(K_ESCAPE))
1615 pointer[0]=0;
1616 return 2;
1618 if (c_was_pressed(K_ENTER))
1620 return 1;
1622 if (c_pressed(K_BACKSPACE)&&b)
1624 b--;
1625 pointer[b]=0;
1627 shift=c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT);
1628 for (c=' ';c<128&&b<max_len;c++)
1629 if (c_was_pressed(c))
1631 pointer[b]=shift?my_toupper(c):c;
1632 b++;
1633 pointer[b]=0;
1635 return 0;
1639 /* read number from input, returns everytime, not when number's read */
1640 int read_num_online(int y,char *pointer,char *message, int max_len)
1642 int a,b,c;
1644 a=strlen(message);
1645 b=strlen(pointer);
1646 c=SCREEN_X*y;
1648 #ifdef TRI_D
1649 if (TRI_D_ON)
1651 memcpy(screen2+c,message,a);
1652 memcpy(screen2+c+a,pointer,b);
1653 memset(screen2_a+c,15,a);
1654 memset(screen2_a+c+a,7,b);
1655 memset(screen2_a+c+a+b,0,SCREEN_X-b-a);
1657 #endif
1659 memcpy(screen+c,message,a);
1660 memcpy(screen+c+a,pointer,b);
1661 memset(screen_a+c,15,a);
1662 memset(screen_a+c+a,7,b);
1663 memset(screen_a+c+a+b,0,SCREEN_X-b-a);
1665 c_update_kbd();
1667 if (c_was_pressed(K_ESCAPE))
1669 pointer[0]=0;
1670 return 2;
1672 if (c_was_pressed(K_ENTER))
1674 return 1;
1676 if (c_pressed(K_BACKSPACE)&&b)
1678 b--;
1679 pointer[b]=0;
1681 for (c='0';c<='9'&&b<max_len;c++)
1682 if (c_was_pressed(c))
1684 pointer[b]=c;
1685 b++;
1686 pointer[b]=0;
1688 return 0;
1692 /* load banner.dat */
1693 void load_banner(char **banner)
1695 FILE *s;
1696 char line[1025];
1697 int a,b;
1699 #ifndef WIN32
1700 s=fopen(DATA_PATH BANNER_FILE,"r");
1701 #else
1702 fopen_s(&s,DATA_PATH BANNER_FILE,"r");
1703 #endif
1704 if (!s){shut_down(0);ERROR("Error: Can't load file \""DATA_PATH BANNER_FILE"\".\n");EXIT(1);}
1705 *banner=mem_alloc(1);
1706 **banner=0;
1707 if (!(*banner)){shut_down(0);ERROR("Error: Not enough memory.\n");EXIT(1);}
1708 while (fgets(line,1024,s))
1710 if (line[strlen(line)-1]==10)line[strlen(line)-1]=0;
1711 if (line[strlen(line)-1]==13)line[strlen(line)-1]=0; /* crlf shit */
1712 a=strlen(*banner);
1713 b=strlen(line);
1714 *banner=mem_realloc((*banner),a+b+SCREEN_X+1);
1715 memcpy((*banner)+a,line,b);
1716 memset((*banner)+a+b,' ',SCREEN_X);
1717 (*banner)[a+b+SCREEN_X]=0;
1719 fclose(s);
1722 #define ERRBOX_HEIGHT 1
1723 #define ERRBOX_Y ((SCREEN_Y-2-ERRBOX_HEIGHT)>>1)
1725 /* draw error box */
1726 void print_error(char *text)
1728 int width = strlen(text) + 6;
1729 int x = (SCREEN_X-2-width) >> 1;
1731 draw_frame(x, ERRBOX_Y, width, ERRBOX_HEIGHT, 15);
1732 print2screen(x + 2, ERRBOX_Y + 1, C_RED, "/!\\");
1733 print2screen(x + 6, ERRBOX_Y + 1, C_YELLOW, text);
1737 /* draw initial screen */
1738 void menu_screen(struct config *cfg)
1740 char txt[8];
1741 int sprite,anim=0,title_anim=0,bulge_anim=0;
1742 unsigned long_long t;
1743 char port[MAX_PORT_LEN+1];
1744 int a=0;
1745 char *m;
1746 char *color_name[15]={"red","green","brown","blue","violet","cyan","gray","black","light red","light green","yellow","light blue","magenta","light cyan","white"};
1747 char *banner;
1748 int l,banner_pos=0;
1749 int help=0;
1750 #ifdef HAVE_LIBPTHREAD
1751 pthread_t
1752 #else
1754 #endif
1755 pt = 0;
1757 load_banner(&banner);
1758 l=strlen(banner);
1759 snprintf(port, sizeof(port), "%d",cfg->port);
1760 snprintf(txt, sizeof(txt), "hero%d",cfg->color);
1761 if (find_sprite(txt,&sprite))
1763 char msg[256];
1764 mem_free(banner);
1765 shut_down(0);
1766 snprintf(msg,256,"Error: Can't find sprite \"%s\".\n",txt);
1767 ERROR(msg);
1768 EXIT(1);
1771 cycle:
1772 t=get_time();
1773 clear_screen();
1774 #ifdef TRI_D
1775 if (TRI_D_ON)
1777 tri_d=1;
1778 put_sprite((SCREEN_X+1-TITLE_WIDTH)>>1,0,sprites[title_sprite].positions+sprites[title_sprite].steps[title_anim],0);
1779 put_sprite(SCREEN_XOFFSET+1+PLAYER_WIDTH+((SCREEN_X-SCREEN_XOFFSET-PLAYER_WIDTH-BULGE_WIDTH)>>1),TITLE_HEIGHT+((SCREEN_Y-3-BULGE_HEIGHT-TITLE_HEIGHT)>>1),sprites[bulge_sprite].positions+sprites[bulge_sprite].steps[bulge_anim],0);
1780 put_sprite(SCREEN_XOFFSET+1,TITLE_HEIGHT+((SCREEN_Y-3-PLAYER_HEIGHT-TITLE_HEIGHT)>>1),sprites[sprite].positions+sprites[sprite].steps[(anim<2?48:39)+(anim&7)],0);
1781 tri_d=0;
1783 #endif
1784 put_sprite((SCREEN_X-TITLE_WIDTH)>>1,0,sprites[title_sprite].positions+sprites[title_sprite].steps[title_anim],0);
1785 put_sprite(SCREEN_XOFFSET+PLAYER_WIDTH+((SCREEN_X-SCREEN_XOFFSET-PLAYER_WIDTH-BULGE_WIDTH)>>1),TITLE_HEIGHT+((SCREEN_Y-3-BULGE_HEIGHT-TITLE_HEIGHT)>>1),sprites[bulge_sprite].positions+sprites[bulge_sprite].steps[bulge_anim],0);
1786 put_sprite(SCREEN_XOFFSET,TITLE_HEIGHT+((SCREEN_Y-3-PLAYER_HEIGHT-TITLE_HEIGHT)>>1),sprites[sprite].positions+sprites[sprite].steps[(anim<2?48:39)+(anim&7)],0);
1787 print2screen(0,TITLE_HEIGHT+4,11,"N:");
1788 print2screen(1,TITLE_HEIGHT+4,2,"AME:");
1789 print2screen(6,TITLE_HEIGHT+4,7,cfg->name);
1790 print2screen(0,TITLE_HEIGHT+6,2,"COLOR:");
1791 print2screen(7,TITLE_HEIGHT+6,7,color_name[(cfg->color-1)%15]);
1792 print2screen(0,TITLE_HEIGHT+0,11,"S");
1793 print2screen(1,TITLE_HEIGHT+0,2,"ERVER ADDRESS:");
1794 print2screen(16,TITLE_HEIGHT+0,7,cfg->host);
1795 print2screen(0,TITLE_HEIGHT+2,11,"P");
1796 print2screen(1,TITLE_HEIGHT+2,2,"ORT:");
1797 print2screen(6,TITLE_HEIGHT+2,7,port);
1798 print2screen((SCREEN_X-26)>>1,SCREEN_Y-3,7,"Use arrows to change color");
1799 print2screen((SCREEN_X-52)>>1,SCREEN_Y-2,7,"Press ENTER to connect, H for help, ESC or Q to quit");
1800 print2screen(0,SCREEN_Y-1,15,banner+(banner_pos>>1));
1801 banner_pos++;
1802 banner_pos%=l<<1;
1803 anim++;
1804 anim&=15;
1805 title_anim++;
1806 title_anim%=sprites[title_sprite].n_steps;
1807 bulge_anim++;
1808 bulge_anim%=sprites[bulge_sprite].n_steps;
1809 if (*error_message)
1811 print2screen(((SCREEN_X-strlen(error_message))>>1),SCREEN_Y-1,9,error_message);
1813 #ifdef TRI_D
1814 if (TRI_D_ON)
1816 tri_d=1;
1817 blit_screen(1);
1818 tri_d=0;
1821 #endif
1822 blit_screen(1);
1823 wait_for_enter();
1824 *error_message=0;
1825 goto cc1;
1827 if (help)print_help_window();
1828 #ifdef HAVE_LIBPTHREAD
1829 if (pt && errormsg.flags) {
1830 pthread_kill(pt, 9); /* good bye */
1831 pt = 0;
1833 if (!pt && errormsg.flags == E_CONN_SUCC) {
1834 errormsg.flags = 0;
1835 mem_free(banner);
1836 return;
1838 #endif
1839 if (errormsg.flags)
1840 print_error(errormsg.text);
1842 switch(a)
1844 case 1:
1845 if (read_str_online(SCREEN_Y-1,cfg->name,"Enter your name: ",MAX_NAME_LEN)) {
1846 cfg->override &= ~OVERRIDE_FLAG_NAME;
1847 a=0;
1849 break;
1851 case 3:
1852 if (read_str_online(SCREEN_Y-1,cfg->host,"Enter address: ",MAX_HOST_LEN)) {
1853 cfg->override &= ~OVERRIDE_FLAG_HOST;
1854 a=0;
1856 break;
1858 case 2:
1859 if (read_num_online(SCREEN_Y-1,port,"Enter port: ",MAX_PORT_LEN)) {
1860 cfg->override &= ~OVERRIDE_FLAG_PORT;
1861 cfg->port = strtol(port, 0, 10);
1862 a=0;
1864 break;
1866 c_update_kbd();
1868 #ifdef TRI_D
1869 if (TRI_D_ON)
1871 tri_d=1;
1872 blit_screen(1);
1873 tri_d=0;
1875 #endif
1877 blit_screen(1);
1878 if (!a && !pt)
1880 if ((c_was_pressed('+')||c_was_pressed('=')||c_was_pressed(K_UP)||c_was_pressed(K_RIGHT)||c_was_pressed(K_NUM_PLUS)) && !errormsg.flags)
1882 (cfg->color)++;
1883 if (cfg->color>30)
1884 cfg->color=1;
1885 snprintf(txt, sizeof(txt), "hero%d",cfg->color);
1886 if (find_sprite(txt,&sprite))
1887 {shut_down(0);mem_free(banner);fprintf(stderr,"Error: Can't find sprite \"%s\".\n",txt);}
1888 cfg->override &= ~OVERRIDE_FLAG_COLOR;
1891 if ((c_was_pressed('-')||c_was_pressed(K_NUM_MINUS)||c_was_pressed(K_DOWN)||c_was_pressed(K_LEFT)) && !errormsg.flags)
1893 cfg->color--;
1894 if (cfg->color<1)
1895 cfg->color=30;
1896 snprintf(txt, sizeof(txt), "hero%d",cfg->color);
1897 if (find_sprite(txt,&sprite))
1898 {shut_down(0);mem_free(banner);fprintf(stderr,"Error: Can't find sprite \"%s\".\n",txt);}
1899 cfg->override &= ~OVERRIDE_FLAG_COLOR;
1902 if (c_was_pressed('h') && !errormsg.flags)help^=1;
1903 if (c_was_pressed(K_ENTER))
1905 if (errormsg.flags) {
1906 errormsg.flags = E_NONE;
1907 goto cycle;
1909 save_cfg(cfg);
1910 cfg->port=strtol(port,0,10);
1911 if ((m=find_server(cfg)))
1913 print2screen(((SCREEN_X-strlen(m))>>1),SCREEN_Y-1,9,m);
1914 #ifdef TRI_D
1915 if (TRI_D_ON)
1917 tri_d=1;
1918 blit_screen(1);
1919 tri_d=0;
1921 #endif
1922 blit_screen(1);
1923 wait_for_enter();
1924 goto cc1;
1926 if ((m=init_socket()))
1928 print2screen(((SCREEN_X-strlen(m))>>1),SCREEN_Y-1,9,m);
1929 #ifdef TRI_D
1930 if (TRI_D_ON)
1932 tri_d=1;
1933 blit_screen(1);
1934 tri_d=0;
1936 #endif
1937 blit_screen(1);
1938 wait_for_enter();
1939 goto cc1;
1941 #ifdef HAVE_LIBPTHREAD
1942 if (!pt) {
1943 pthread_create(&pt, NULL, (void *)contact_server, cfg);
1944 pthread_detach(pt);
1945 goto cycle;
1947 #else
1948 if(contact_server(cfg))
1949 goto cycle;
1950 else {
1951 mem_free(banner);
1952 return;
1954 #endif
1956 cc1:
1957 if ((c_was_pressed('q')||c_was_pressed(K_ESCAPE)) && !errormsg.flags)
1959 save_cfg(cfg);
1960 mem_free(banner);
1961 shut_down(1);
1964 if (c_was_pressed('n') && !errormsg.flags)
1965 a=1;
1967 if ((c_was_pressed('a')||c_was_pressed('s')) && !errormsg.flags)
1968 a=3;
1970 if (c_was_pressed('p') && !errormsg.flags)
1971 a=2;
1973 sleep_until(t+MENU_PERIOD_USEC);
1974 goto cycle;
1978 /* handle fatal signal (sigabrt, sigsegv, ...) */
1979 void signal_handler(int signum)
1982 if (connected)send_quit();
1983 shut_down(0);
1984 #ifdef HAVE_PSIGNAL
1985 psignal(signum,"Exiting on signal");
1986 #else
1987 fprintf(stderr, "Exiting on signal: %d\n", signum);
1988 #endif
1989 EXIT(1);
1993 /* change size of the screen */
1994 void sigwinch_handler(int signum)
1996 signum=signum;
1997 resize_screen();
1998 #ifdef WIN32
1999 c_shutdown();
2000 c_init(SCREEN_X,SCREEN_Y);
2001 #endif
2002 c_cls();
2003 c_refresh();
2004 #ifndef WIN32
2005 #ifdef SIGWINCH
2006 signal(SIGWINCH,sigwinch_handler);
2007 #endif
2008 #endif
2012 /* print command line help */
2013 void print_help(void)
2015 char *x = "";
2016 char *y = "";
2017 #ifdef XWINDOW
2018 x = " for X windows";
2019 y = " [-d <display>] [-f <font name>]";
2020 #endif
2021 printf(
2022 "0verkill client%s"
2023 ".\n"
2024 "(c)2000 Brainsoft\n"
2025 "Usage: 0verkill [-h] [-3] [-i <server address>] \n"
2026 "[-c <color>] [-n <player name>] [-p <port>] \n"
2027 "[-s <width>x<height>]%s"
2028 "\n", x, y
2033 void parse_dimensions(char *txt)
2035 char *p;
2036 char *e;
2037 p=txt;
2038 for (p=txt;(*p)&&(*p)!='x';p++);
2039 if (!(*p)){ERROR("Error: Expected dimensions in form WIDTHxHEIGHT.\n");EXIT(1);}
2040 (*p)=0;
2041 p++;
2042 if (!strlen(txt)||!strlen(p)){fprintf(stderr,"Error: Decimal number expected.\n");EXIT(1);}
2043 SCREEN_X=strtoul(txt,&e,10);
2044 if (*e){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2045 SCREEN_Y=strtoul(p,&e,10);
2046 if (*e){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2047 set_size=1;
2051 void parse_command_line(struct config *cfg)
2053 int a;
2055 while(1)
2057 #ifdef TRI_D
2059 #ifdef XWINDOW
2060 a=getopt(cfg->argc,cfg->argv,"3hl:f:d:s:n:i:p:c:");
2061 #endif
2062 #ifndef XWINDOW
2063 a=getopt(cfg->argc,cfg->argv,"3hl:s:n:i:p:c:");
2064 #endif
2065 #else
2066 #ifdef XWINDOW
2067 a=getopt(cfg->argc,cfg->argv,"hf:d:s:n:i:p:c:");
2068 #endif
2069 #ifndef XWINDOW
2070 a=getopt(cfg->argc,cfg->argv,"hs:n:i:p:c:");
2071 #endif
2072 #endif
2073 switch(a)
2075 case EOF:
2076 return;
2078 case '?':
2079 case ':':
2080 EXIT(1);
2082 case 'h':
2083 print_help();
2084 EXIT(0);
2086 #ifdef TRI_D
2087 case '3':
2088 TRI_D_ON=1;
2089 break;
2090 #endif
2092 case 's':
2093 parse_dimensions(optarg);
2094 break;
2095 #ifdef XWINDOW
2096 case 'd':
2097 x_display_name=optarg;
2098 break;
2100 case 'f':
2101 x_font_name=optarg;
2102 break;
2103 #endif
2104 case 'i':
2105 memcpy(cfg->host, optarg, strlen(optarg) + 1);
2106 cfg->override |= OVERRIDE_FLAG_HOST;
2107 break;
2109 case 'n':
2110 memcpy(cfg->name, optarg, strlen(optarg) + 1);
2111 cfg->override |= OVERRIDE_FLAG_NAME;
2112 break;
2114 case 'p':
2115 cfg->port = strtol(optarg, 0, 10);
2116 cfg->override |= OVERRIDE_FLAG_PORT;
2117 break;
2119 case 'c':
2120 cfg->color = strtol(optarg, 0, 10);
2121 cfg->override |= OVERRIDE_FLAG_COLOR;
2122 break;
2127 #define HALL_FAME_WIDTH (MAX_NAME_LEN+17)
2128 #define HALL_FAME_HEIGHT ((active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players)+5)
2129 #define HALL_FAME_X ((SCREEN_X-2-HALL_FAME_WIDTH)>>1)
2130 #define HALL_FAME_Y ((SCREEN_Y-2-HALL_FAME_HEIGHT)>>1)
2132 void print_hall_of_fame(void)
2134 int a;
2135 char txt[32];
2136 unsigned char color;
2138 if (!active_players)return;
2139 snprintf(txt, sizeof(txt), "TOP %d PLAYERS",TOP_PLAYERS_N);
2140 draw_frame(HALL_FAME_X,HALL_FAME_Y,HALL_FAME_WIDTH,HALL_FAME_HEIGHT,15);
2141 print2screen(HALL_FAME_X+1+((HALL_FAME_WIDTH-strlen(txt))>>1),HALL_FAME_Y+1,11,txt);
2142 print2screen(HALL_FAME_X+2,HALL_FAME_Y+3,15,"NAME");
2143 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+2,HALL_FAME_Y+3,15,"FRAGS");
2144 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+9,HALL_FAME_Y+3,15,"DEATHS");
2145 for (a=0;a<active_players&&a<TOP_PLAYERS_N;a++)
2147 color=((top_players[a].color-1)%15)+1;
2148 print2screen(HALL_FAME_X+2,HALL_FAME_Y+4+a,color,top_players[a].name);
2149 snprintf(txt, sizeof(txt), "% 5d",top_players[a].frags);
2150 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+2,HALL_FAME_Y+4+a,color,txt);
2151 snprintf(txt, sizeof(txt), "% 5d",top_players[a].deaths);
2152 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+9,HALL_FAME_Y+4+a,color,txt);
2154 snprintf(txt, sizeof(txt), "%d",active_players);
2155 print2screen(HALL_FAME_X+2,HALL_FAME_Y+HALL_FAME_HEIGHT,11,"Players in the game:");
2156 print2screen(HALL_FAME_X+23,HALL_FAME_Y+HALL_FAME_HEIGHT,7,txt);
2160 void play(void)
2162 #ifdef PAUSE
2163 int p=0;
2164 #endif
2165 char string[80];
2166 unsigned char chat=0;
2167 unsigned char help=0;
2168 unsigned char hall_fame=0;
2169 unsigned long_long last_time;
2171 last_time=get_time();
2172 while(1)
2174 last_time+=CLIENT_PERIOD_USEC;
2175 if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
2176 if (read_data())return; /* game terminated */
2177 #ifdef PAUSE
2178 if(!p)clear_screen();
2179 #else
2180 clear_screen();
2181 #endif
2182 update_game();
2183 #ifdef PAUSE
2184 if (!p)draw_scene();
2185 #else
2186 draw_scene();
2187 #endif
2188 update_messages(last_time);
2189 print_messages();
2190 if (chat)
2192 switch (read_str_online(SCREEN_Y-3,string,"> ",78))
2194 case 2:
2195 chat=0;
2196 break;
2198 case 1:
2199 chat=0;
2200 send_message(string, M_CHAT);
2201 break;
2204 if (help)print_help_window();
2205 if (hall_fame)print_hall_of_fame();
2206 draw_board();
2208 #ifdef TRI_D
2209 if (TRI_D_ON)
2211 tri_d=1;
2212 blit_screen(1);
2213 tri_d=0;
2215 #endif
2217 blit_screen(1);
2219 creep=0;
2220 if (!chat)c_update_kbd();
2222 #ifdef PAUSE
2223 if (c_was_pressed('p'))p^=1;
2224 #endif
2225 if (!chat&&c_was_pressed('r'))
2227 c_cls();
2228 redraw_screen();
2230 if (!chat&&c_was_pressed('h'))help^=1;
2231 if (!chat&&c_was_pressed(K_TAB))
2233 hall_fame^=1;
2234 if (hall_fame)send_info_request();
2236 if (c_was_pressed(K_CAPS_LOCK)||(!chat&&c_was_pressed('a')))autorun^=1;
2237 if (c_was_pressed(K_F10)||(!chat&&c_was_pressed('q')))
2239 send_quit();
2240 *error_message=0;
2241 return;
2243 if (c_pressed(K_F12))
2244 end_game();
2246 if (!chat && c_was_pressed(K_ENTER))
2248 memset(string,0,80);
2249 #ifdef WIN32
2250 c_update_kbd();
2251 c_was_pressed('d');
2252 #endif
2253 chat=1;
2255 reset_keyboard();
2256 if (!chat&&c_was_pressed(' '))send_reenter_game();
2257 if (!chat&&c_was_pressed('c'))
2258 autocreep^=1;
2259 if (c_pressed(K_DOWN)||autocreep)
2260 keyboard_status.status |= KBD_CREEP;
2261 if (c_pressed(K_UP))
2262 keyboard_status.status |= KBD_JUMP;
2263 if (c_pressed(K_LEFT_CTRL)||c_pressed(K_RIGHT_CTRL)||(!chat&&c_pressed('z')))
2264 keyboard_status.status |= KBD_FIRE;
2265 if (!chat && c_pressed('d'))
2266 keyboard_status.status |= KBD_DOWN_LADDER;
2267 if (!chat && c_pressed('j'))
2268 keyboard_status.status |= KBD_JETPACK;
2269 if (!chat && c_was_pressed('1'))
2270 keyboard_status.weapon=1;
2271 if (!chat && c_was_pressed('2'))
2272 keyboard_status.weapon=2;
2273 if (!chat && c_was_pressed('3'))
2274 keyboard_status.weapon=3;
2275 if (!chat && c_was_pressed('4'))
2276 keyboard_status.weapon=4;
2277 if (!chat && c_was_pressed('5'))
2278 keyboard_status.weapon=5;
2279 if (!chat && c_was_pressed('6'))
2280 keyboard_status.weapon=6;
2281 if (!chat && c_was_pressed('7'))
2282 keyboard_status.weapon=7;
2283 if (!chat && c_was_pressed('8'))
2284 keyboard_status.weapon=8;
2285 if (c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT)||autorun)
2286 keyboard_status.status |= KBD_SPEED;
2287 if (c_pressed(K_LEFT))
2288 keyboard_status.status |= KBD_LEFT;
2289 if (c_pressed(K_RIGHT))
2290 keyboard_status.status |= KBD_RIGHT;
2292 send_keyboard();
2293 sleep_until(last_time+CLIENT_PERIOD_USEC);
2297 /*----------------------------------------------------------------------------*/
2298 int main(int argc,char **argv)
2300 int a;
2301 char txt[256];
2302 struct config cfg = {argc, argv, "", "", DEFAULT_PORT, 1, 0};
2304 #ifdef WIN32
2305 WSADATA wd;
2307 WSAStartup(0x101, &wd);
2308 printf("Started WinSock version %X.%02X\n", wd.wVersion/0x100, wd.wVersion&0xFF);
2309 #endif
2311 chdir_to_data_files();
2312 #ifdef XWINDOW
2313 x_display_name=0;
2314 x_font_name=0;
2315 #endif
2317 last_message=-1;
2318 autorun=0;
2319 autocreep=0;
2320 memset(cfg.host,0,MAX_HOST_LEN+1);
2321 memset(cfg.name,0,MAX_NAME_LEN+1);
2322 load_cfg(&cfg);
2323 last_obj=&objects;
2324 *error_message=0;
2326 parse_command_line(&cfg);
2327 hash_table_init();
2328 if (!set_size)c_get_size(&SCREEN_X,&SCREEN_Y);
2329 init_sprites();
2330 init_area();
2331 #ifndef WIN32
2332 load_sprites(DATA_PATH GAME_SPRITES_FILE);
2333 #else
2334 snprintf(txt,sizeof(txt),"%s\\data\\sprites.dat",_getcwd(NULL, 0));
2335 load_sprites(txt);
2336 #endif
2337 /* sprites are stored in memory in this order: game sprites (players,
2338 * bullets, corpses, blood, meat...) followed by level sprites
2341 level_sprites_start=n_sprites;
2342 if (find_sprite("hit",&hit_sprite)){ERROR("Error: Can't find sprite \"hit\".\n");EXIT(1);}
2343 if (find_sprite("title",&title_sprite)){ERROR("Error: Can't find sprite \"title\".\n");EXIT(1);}
2344 if (find_sprite("bulge",&bulge_sprite)){ERROR("Error: Can't find sprite \"bulge\".\n");EXIT(1);}
2345 for (a=0;a<N_SHRAPNELS;a++)
2347 snprintf(txt, sizeof(txt), "shrapnel%d",a+1);
2348 if (find_sprite(txt,&shrapnel_sprite[a])) {
2349 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2350 EXIT(1);
2352 snprintf(txt, sizeof(txt), "bfgbit%d",a+1);
2353 if (find_sprite(txt,&bfgbit_sprite[a])) {
2354 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2355 EXIT(1);
2357 snprintf(txt, sizeof(txt), "bloodrain%d",a+1);
2358 if (find_sprite(txt,&bloodrain_sprite[a])) {
2359 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2360 EXIT(1);
2363 snprintf(txt, sizeof(txt), "jetpack");
2364 if (find_sprite(txt,&jetpack_sprite)) {
2365 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2366 EXIT(1);
2368 snprintf(txt, sizeof(txt), "fire");
2369 if (find_sprite(txt,&fire_sprite)) {
2370 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2371 EXIT(1);
2373 snprintf(txt, sizeof(txt), "sawchain");
2374 if (find_sprite(txt,&chain_sprite)) {
2375 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2376 EXIT(1);
2379 signal(SIGINT,signal_handler);
2380 signal(SIGTERM,signal_handler);
2381 signal(SIGILL,signal_handler);
2382 signal(SIGABRT,signal_handler);
2383 signal(SIGFPE,signal_handler);
2384 signal(SIGSEGV,signal_handler);
2385 #ifndef WIN32
2386 signal(SIGQUIT,signal_handler);
2387 signal(SIGBUS,signal_handler);
2388 #ifdef SIGWINCH
2389 signal(SIGWINCH,sigwinch_handler);
2390 #endif
2391 #endif
2392 c_init(SCREEN_X,SCREEN_Y);
2393 c_cls();
2394 c_cursor(C_HIDE);
2395 c_refresh();
2396 while(1)
2398 level_number=-1;
2399 connected=0;
2400 menu_screen(&cfg);
2401 connected=1;
2402 play();
2403 clean_memory();
2404 delete_obj(hero->id);