editor: #undef O after use
[0verkill.git] / client.c
blob191e8d244ab6204df33cc322f8c42e8ded4c8979
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 return 1;
565 default:
566 server_error("Connection refused. Press ENTER.", E_CONN);
567 return 1;
570 case P_PLAYER_ACCEPTED:
571 my_id=get_int(packet+35);
572 if (r<41) {
573 send_quit();
574 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN);
575 return 1;
577 maj=packet[39];
578 min=packet[40];
579 if (maj!=VERSION_MAJOR||min<MIN_SERVER_VERSION_MINOR) {
580 send_quit();
581 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN);
582 return 1;
584 game_start_offset=get_time();
585 game_start_offset-=get_long_long(packet+27);
586 health=100;
587 armor=0;
588 for(a=0;a<ARMS;a++)
589 ammo[a]=0;
590 ammo[WEAPON_GUN]=weapon[WEAPON_GUN].basic_ammo;
591 ammo[WEAPON_CHAINSAW]=weapon[WEAPON_CHAINSAW].basic_ammo;
592 current_weapon=0;
593 weapons=WEAPON_MASK_GUN |
594 WEAPON_MASK_GRENADE |
595 WEAPON_MASK_CHAINSAW |
596 WEAPON_MASK_BLOODRAIN; /* gun, grenades, chainsaw and blodrain */
597 hero=new_obj(
598 get_int(packet+1), /* ID */
599 T_PLAYER, /* type */
600 0, /* time to live */
601 get_int16(packet+5), /* sprite */
602 0, /* position */
603 get_int(packet+23), /* status */
604 get_int(packet+7), /* X */
605 get_int(packet+11), /* Y */
606 get_int(packet+15), /* XSPEED */
607 get_int(packet+19), /* YSPEED */
610 break;
612 default:
613 server_error("Connection error. Press ENTER.", E_CONN);
614 return 1;
616 server_error("",
617 #ifdef HAVE_LIBPTHREAD
618 E_CONN_SUCC
619 #else
620 E_NONE
621 #endif
623 return 0;
627 /* send me top X players */
628 void send_info_request(void)
630 char packet;
631 packet=P_INFO;
632 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
636 /* I want to be born again */
637 void send_reenter_game(void)
639 char packet;
640 packet=P_REENTER_GAME;
641 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
645 /* send end of game to server */
646 void end_game(void)
648 char packet;
649 packet=P_END;
650 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
654 /* send chat message */
655 void send_message(char *msg, char flags)
657 static char packet[MAX_MESSAGE_LENGTH + 2];
658 int len;
660 len = strlen(msg) + 1;
661 packet[0] = P_MESSAGE;
662 packet[1] = flags;
663 memcpy(packet + 2, msg, len);
664 send_packet(packet, len + 2, (struct sockaddr *)(&server), my_id, 0);
668 /* send end of game to server */
669 void send_keyboard(void)
671 char packet[3];
672 packet[0]=P_KEYBOARD;
673 packet[1]=keyboard_status.status;
674 packet[2]=keyboard_status.weapon;
675 send_packet(packet,3,(struct sockaddr*)(&server),my_id,0);
679 void reset_keyboard(void)
681 keyboard_status.status=0;
682 keyboard_status.weapon=0;
685 /* recompute object positions */
686 void update_game(void)
688 struct object_list *p;
689 int w,h;
690 unsigned char stop_x,stop_y,sy;
691 unsigned long_long t;
692 int x,y,x1,y1,DELTA_TIME;
694 for(p=&objects;p->next;p=p->next)
696 if (p->next->member.type==T_NOTHING)
697 continue;
698 if (p->next->member.status & S_DEAD)
699 continue; /* dead player */
700 /* decrement time to live */
701 if (p->next->member.ttl>0)
703 p->next->member.ttl--;
704 if (!p->next->member.ttl)
706 if ((p->next->member.type)==T_PLAYER)
707 p->next->member.status &= ~S_SHOOTING;
708 else
710 if (p->next->member.type!=T_GRENADE &&
711 p->next->member.type!=T_BFGCELL){ /* client's waiting for P_EXPLODE_GRENADE and doesn't delete the grenade yet */
712 p=p->prev;
713 delete_obj(p->next->next->member.id);
714 continue;}
718 /* maintain only objects that you are allowed to maintain */
719 if (!(obj_attr[p->next->member.type].maintainer&1))continue;
722 /* if not falling slow down x motion */
723 if (!(p->next->member.status & S_FALLING))
724 p->next->member.xspeed=mul(p->next->member.xspeed,obj_attr[p->next->member.type].slow_down_x);
726 /* fall */
727 if (obj_attr[p->next->member.type].fall)
729 p->next->member.status |= S_FALLING;
730 p->next->member.yspeed+=FALL_ACCEL;
731 /* but not too fast */
732 if (p->next->member.yspeed>MAX_Y_SPEED)p->next->member.yspeed=MAX_Y_SPEED;
735 get_dimensions(p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions,&w,&h);
736 x=p->next->member.x;
737 y=p->next->member.y;
738 t=get_time();
739 DELTA_TIME=float2double(((double)(long_long)(t-p->next->member.last_updated))/MICROSECONDS);
740 update_position(
741 &(p->next->member),
742 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
743 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
744 w,h,&stop_x,&stop_y);
745 p->next->member.last_updated=t;
747 /* walk up the stairs */
748 if (stop_x&&p->next->member.type==T_PLAYER&&!(p->next->member.status & S_CREEP))
750 x1=p->next->member.x;
751 y1=p->next->member.y;
752 p->next->member.x=x;
753 p->next->member.y=y-int2double(1);
754 update_position(
755 &(p->next->member),
756 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
757 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
758 w,h,0,&sy);
759 if ((p->next->member.xspeed>0&&p->next->member.x<=x1)||(p->next->member.xspeed<0&&p->next->member.x>=x1)) /* restore original values */
761 p->next->member.x=x1;
762 p->next->member.y=y1;
764 else
766 stop_y=sy;
767 stop_x=0;
771 if (stop_x)
772 p->next->member.xspeed=-mul(p->next->member.xspeed,obj_attr[p->next->member.type].bounce_x);
773 if (my_abs(p->next->member.xspeed)<MIN_X_SPEED)
775 p->next->member.xspeed=0;
776 p->next->member.status &= ~S_WALKING;
780 if (stop_y)
782 p->next->member.yspeed=mul(p->next->member.yspeed,obj_attr[p->next->member.type].bounce_y);
783 p->next->member.yspeed=-p->next->member.yspeed;
784 if (my_abs(p->next->member.yspeed)<MIN_Y_SPEED)
786 p->next->member.yspeed=0;
787 if (stop_y==1)p->next->member.status &= ~S_FALLING;
791 if ((p->next->member.type == T_SHRAPNEL || p->next->member.type == T_BULLET ||
792 p->next->member.type == T_BFGCELL || p->next->member.type == T_CHAIN ||
793 p->next->member.type == T_JETFIRE) &&
794 (stop_x || stop_y)) { /* bullet and shrapnel die crashing into wall */
795 p=p->prev; /* deleting object makes a great mess in for cycle, so we must cheat the cycle */
796 delete_obj(p->next->next->member.id);
797 continue;
803 #define FIRE_SHOOTING weapon[current_weapon].cadence-4+HOLD_GUN_AFTER_SHOOT
805 /* hero's next anim position when walking to the right */
806 int _next_anim_right(int pos,int status, int ttl)
808 int start,offset;
810 if (pos<=18)
811 start=10; /* normal */
812 else
814 if (pos<=46)start=(status & S_CHAINSAW)?97:38; /* holding gun */
815 else
817 if (pos<=55)start=(status & S_CHAINSAW)?106:47; /* shooting */
818 else start=64; /* creeping */
821 offset=pos-start;
823 if (status & S_CREEP)
824 start=64; /* creeping */
825 else
827 if (status & S_SHOOTING)
829 if (ttl>=FIRE_SHOOTING) start=(status & S_CHAINSAW)?106:47; /* shooting */
830 else start=(status & S_CHAINSAW)?97:38; /* holding a gun */
832 else start=10; /* normal */
835 return (status & S_CREEP)?((offset+1)&7)+start:start+(offset&7)+1;
839 /* hero's next anim position when walking to the left */
840 int _next_anim_left(int pos,int status, int ttl)
842 int start,offset;
844 if (pos<=8)start=0; /* normal */
845 else
847 if (pos<=28)start=(status & S_CHAINSAW)?79:20; /* holding gun */
848 else
850 if (pos<=37)start=(status & S_CHAINSAW)?88:29; /* shooting */
851 else start=56; /* creeping */
854 offset=pos-start;
856 if (status & S_CREEP)
857 start=56; /* creeping */
858 else
860 if (status & S_SHOOTING)
862 if (ttl>=FIRE_SHOOTING) start=(status & S_CHAINSAW)?88:29; /* shooting */
863 else start=(status & S_CHAINSAW)?79:20; /* holding a gun */
865 else start=0; /* normal */
868 return (status & S_CREEP)?((offset+1)&7)+start:start+(offset&7)+1;
872 /* update hero animating position */
873 void update_anim(struct it* obj)
875 if (!(obj->status & S_WALKING)) /* not walking */
876 switch((obj->status & (S_LOOKLEFT | S_LOOKRIGHT)))
878 case 0: /* look at me */
879 obj->anim_pos=(obj->status & S_CREEP)?72:9;
880 break;
881 case S_LOOKLEFT: /* look left */
882 if (obj->status & S_SHOOTING)
884 if (obj->status & S_GRENADE)
885 obj->anim_pos = (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>1)+HOLD_GUN_AFTER_SHOOT)) ?
886 73 : (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>2)+HOLD_GUN_AFTER_SHOOT)) ?
887 74 : ((obj->ttl>=HOLD_GUN_AFTER_SHOOT) ? 75 : 0);
888 else if (obj->status & S_CHAINSAW) /* maniak ma motorovku */
889 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 88 : 79;
890 else
891 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 29 : 20;
892 } else
893 obj->anim_pos=0;
894 if (obj->status & S_CREEP)
895 obj->anim_pos=56;
896 break;
897 case S_LOOKRIGHT: /* look right */
898 if (obj->status & S_SHOOTING)
900 if (obj->status & S_GRENADE)
901 obj->anim_pos = (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>1)+HOLD_GUN_AFTER_SHOOT)) ?
902 76 : (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>2)+HOLD_GUN_AFTER_SHOOT)) ?
903 77 : ((obj->ttl>=HOLD_GUN_AFTER_SHOOT) ? 78 : 10);
904 else if (obj->status & S_CHAINSAW) /* maniak ma motorovku */
905 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 106 : 97;
906 else
907 obj->anim_pos=(obj->ttl>=FIRE_SHOOTING) ? 47 : 38;
908 } else
909 obj->anim_pos=10;
910 if (obj->status & S_CREEP)
911 obj->anim_pos=64;
912 break;
914 else /* walking */
916 switch (obj->status & (S_LOOKLEFT | S_LOOKRIGHT))
918 case S_LOOKLEFT: /* walk left */
919 obj->anim_pos=_next_anim_left(obj->anim_pos,obj->status,obj->ttl);
920 break;
922 case S_LOOKRIGHT: /* walk right */
923 obj->anim_pos=_next_anim_right(obj->anim_pos,obj->status,obj->ttl);
924 break;
930 /* draw scene into screenbuffer*/
931 void draw_scene(void)
933 struct object_list *p;
934 unsigned char fore;
936 #ifdef TRI_D
937 if (TRI_D_ON)
939 tri_d=1;
940 show_window(double2int(hero->x)-SCREEN_XOFFSET,double2int(hero->y)-SCREEN_YOFFSET);
941 tri_d=0;
943 #endif
945 show_window(double2int(hero->x)-SCREEN_XOFFSET,double2int(hero->y)-SCREEN_YOFFSET);
946 for (fore=0;fore<=1;fore++)
948 for(p=&objects;p->next;p=p->next)
950 if ((obj_attr[p->next->member.type].foreground)!=fore)continue;
951 if (&(p->next->member)==hero)continue;
952 if (p->next->member.type==T_PLAYER)update_anim(&(p->next->member));
953 else {p->next->member.anim_pos++;p->next->member.anim_pos%=sprites[p->next->member.sprite].n_steps;}
954 if (p->next->member.status == WEAPON_CHAINSAW) continue;
955 if (!(p->next->member.status & S_DEAD)&&!(p->next->member.status & S_INVISIBLE)) /* don't draw hidden objects and dead players */
957 #ifdef TRI_D
958 if(TRI_D_ON)
960 tri_d=1;
961 put_sprite(
962 double2int(p->next->member.x-hero->x)+fore+SCREEN_XOFFSET,
963 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET,
964 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],
967 tri_d=0;
969 #endif
971 put_sprite(
972 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET,
973 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET,
974 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],
978 if (p->next->member.type == T_PLAYER) {
979 if ((p->next->member.status & S_JETPACK_ON) && !(p->next->member.status & S_CREEP)) {
980 if (p->next->member.status & S_LOOKRIGHT)
981 put_sprite(
982 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET-1,
983 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+4,
984 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[1], 1);
985 else if (p->next->member.status & S_LOOKLEFT)
986 put_sprite(
987 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+PLAYER_WIDTH-4,
988 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+4,
989 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[0], 1);
991 if ((gsbi += 10) > 1000) {
992 gsbi++;
993 gsbi %= 3;
995 if (p->next->member.status & S_ONFIRE) {
996 if (p->next->member.status & S_CREEP)
997 put_sprite(
998 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET-5,
999 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET-2,
1000 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3 + 3], 1);
1001 else
1002 put_sprite(
1003 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+3,
1004 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET-3,
1005 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3], 1);
1007 if ((p->next->member.status & S_CHAINSAW) && (p->next->member.ttl >= FIRE_SHOOTING) && !(hero->status & S_CREEP)) {
1008 if (p->next->member.status & S_LOOKRIGHT)
1009 put_sprite(
1010 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+15,
1011 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+6,
1012 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1013 else if (p->next->member.status & S_LOOKLEFT)
1014 put_sprite(
1015 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET-8,
1016 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+6,
1017 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1021 if (p->next->member.type==T_PLAYER&&p->next->member.status & S_HIT) /* hit */
1023 p->next->member.status &= ~S_HIT;
1024 if (!(p->next->member.status & S_DEAD)) /* don't draw blood splash to dead players */
1026 #ifdef TRI_D
1027 if (TRI_D_ON)
1029 tri_d=1;
1030 put_sprite(
1031 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+fore+((long)(p->next->member.data)&255),
1032 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+(((long)(p->next->member.data)>>8)&255),
1033 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)p->next->member.data)>>16],
1036 tri_d=0;
1038 #endif
1040 put_sprite(
1041 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+((long)(p->next->member.data)&255),
1042 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+(((long)(p->next->member.data)>>8)&255),
1043 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)p->next->member.data)>>16],
1049 if (obj_attr[T_PLAYER].foreground!=fore)continue;
1050 update_anim(hero);
1051 if (hero->status & S_DEAD)
1052 continue; /* don't draw dead hero */
1053 #ifdef TRI_D
1054 if (TRI_D_ON)
1056 tri_d=1;
1057 put_sprite(
1058 SCREEN_XOFFSET,
1059 SCREEN_YOFFSET,
1060 sprites[hero->sprite].positions+sprites[hero->sprite].steps[hero->anim_pos],
1063 tri_d=0;
1065 #endif
1066 put_sprite(
1067 SCREEN_XOFFSET,
1068 SCREEN_YOFFSET,
1069 sprites[hero->sprite].positions+sprites[hero->sprite].steps[hero->anim_pos],
1073 if ((hero->status & S_JETPACK_ON) && !(hero->status & S_CREEP)) {
1074 if (hero->status & S_LOOKRIGHT)
1075 put_sprite(SCREEN_XOFFSET-1, SCREEN_YOFFSET+4,
1076 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[1], 1);
1077 else if (hero->status & S_LOOKLEFT)
1078 put_sprite(SCREEN_XOFFSET+PLAYER_WIDTH-4, SCREEN_YOFFSET+4,
1079 sprites[jetpack_sprite].positions+sprites[jetpack_sprite].steps[0], 1);
1081 if ((gsbi += 10) > 1000) {
1082 gsbi++;
1083 gsbi %= 3;
1085 if (hero->status & S_ONFIRE) {
1086 if (hero->status & S_CREEP)
1087 put_sprite(SCREEN_XOFFSET-5, SCREEN_YOFFSET-2,
1088 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3 + 3], 1);
1089 else
1090 put_sprite(SCREEN_XOFFSET+3, SCREEN_YOFFSET-3,
1091 sprites[fire_sprite].positions+sprites[fire_sprite].steps[gsbi % 3], 1);
1093 if ((hero->status & S_CHAINSAW) && (hero->ttl >= FIRE_SHOOTING) && !(hero->status & S_CREEP)) {
1094 if (hero->status & S_LOOKRIGHT)
1095 put_sprite(SCREEN_XOFFSET+15, SCREEN_YOFFSET+6,
1096 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1097 else if (hero->status & S_LOOKLEFT)
1098 put_sprite(SCREEN_XOFFSET-8, SCREEN_YOFFSET+6,
1099 sprites[chain_sprite].positions+sprites[chain_sprite].steps[(gsbi / 10) % 2], 1);
1101 if (hero->status & S_HIT) /* hit */
1103 hero->status &= ~S_HIT;
1104 #ifdef TRI_D
1105 if (TRI_D_ON)
1107 tri_d=1;
1108 put_sprite(
1109 SCREEN_XOFFSET+((long)(hero->data)&255),
1110 SCREEN_YOFFSET+(((long)(hero->data)>>8)&255),
1111 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)hero->data)>>16],
1114 tri_d=0;
1116 #endif
1117 put_sprite(
1118 SCREEN_XOFFSET+((long)(hero->data)&255),
1119 SCREEN_YOFFSET+(((long)(hero->data)>>8)&255),
1120 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((long)hero->data)>>16],
1128 void change_level(void)
1130 char *LEVEL;
1131 char txt[256];
1133 clean_memory();
1134 free_sprites(level_sprites_start);
1135 reinit_area();
1137 LEVEL=load_level(level_number);
1138 snprintf(txt,sizeof(txt),"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
1139 load_sprites(txt);
1140 snprintf(txt,sizeof(txt),"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
1141 load_data(txt);
1142 mem_free(LEVEL);
1146 /* returns number of read bytes */
1147 int process_packet(char *packet,int l)
1149 int a,n=l;
1151 switch(*packet)
1153 case P_CHUNK:
1154 for (a=1;a<l&&a<MAX_PACKET_LENGTH;a+=n)
1155 n=process_packet(packet+a,l-a);
1156 break;
1158 case P_NEW_OBJ:
1159 if (l < (n=30))break; /* invalid packet */
1160 new_obj(
1161 get_int(packet+1), /* ID */
1162 packet[27], /* type */
1163 get_int16(packet+28), /* time to live */
1164 get_int16(packet+5), /* sprite */
1165 0, /* anim position */
1166 get_int(packet+23), /* status */
1167 get_int(packet+7), /* x */
1168 get_int(packet+11), /* y */
1169 get_int(packet+15), /* xspeed */
1170 get_int(packet+19), /* yspeed */
1171 0 /* data */
1173 break;
1175 case P_PLAYER_DELETED:
1176 n=1;
1177 *error_message=0;
1178 return -1;
1180 case P_DELETE_OBJECT:
1181 if (l<5)break; /* invalid packet */
1182 delete_obj(get_int(packet+1));
1183 n=5;
1184 break;
1186 case P_UPDATE_OBJECT:
1187 if (l< (n=28))break; /* invalid packet */
1189 struct object_list *p;
1191 p=find_in_table(get_int(packet+1));
1192 if (!p)break;
1193 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1194 p->member.update_counter=packet[5];
1195 p->member.x=get_int(packet+6);
1196 p->member.y=get_int(packet+10);
1197 p->member.xspeed=get_int(packet+14);
1198 p->member.yspeed=get_int(packet+18);
1199 p->member.status=get_int(packet+22);
1200 p->member.data=0;
1201 p->member.ttl=get_int16(packet+26);
1202 /* kdyz tasi, tak se nahodi ttl */
1203 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1204 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1206 break;
1208 case P_UPDATE_OBJECT_POS:
1209 if (l<22)break; /* invalid packet */
1211 struct object_list *p;
1213 n=22;
1214 p=find_in_table(get_int(packet+1));
1215 if (!p)break;
1216 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1217 p->member.update_counter=packet[5];
1218 p->member.x=get_int(packet+6);
1219 p->member.y=get_int(packet+10);
1220 p->member.xspeed=get_int(packet+14);
1221 p->member.yspeed=get_int(packet+18);
1223 break;
1225 case P_UPDATE_OBJECT_SPEED:
1226 if (l<14)break; /* invalid packet */
1228 struct object_list *p;
1230 n=14;
1231 p=find_in_table(get_int(packet+1));
1232 if (!p)break;
1233 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1234 p->member.update_counter=packet[5];
1235 p->member.xspeed=get_int(packet+6);
1236 p->member.yspeed=get_int(packet+10);
1238 break;
1240 case P_UPDATE_OBJECT_COORDS:
1241 if (l<14)break; /* invalid packet */
1243 struct object_list *p;
1245 n=14;
1246 p=find_in_table(get_int(packet+1));
1247 if (!p)break;
1248 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1249 p->member.update_counter=packet[5];
1250 p->member.x=get_int(packet+6);
1251 p->member.y=get_int(packet+10);
1253 break;
1255 case P_UPDATE_OBJECT_SPEED_STATUS:
1256 if (l < (n=18))break; /* invalid packet */
1258 struct object_list *p;
1260 p=find_in_table(get_int(packet+1));
1261 if (!p)break;
1262 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1263 p->member.update_counter=packet[5];
1264 p->member.xspeed=get_int(packet+6);
1265 p->member.yspeed=get_int(packet+10);
1266 p->member.status=get_int(packet+14);
1267 /* kdyz tasi, tak se nahodi ttl */
1268 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1269 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1271 break;
1273 case P_UPDATE_OBJECT_COORDS_STATUS:
1274 if (l < (n=18))break; /* invalid packet */
1276 struct object_list *p;
1278 p=find_in_table(get_int(packet+1));
1279 if (!p)break;
1280 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1281 p->member.update_counter=packet[5];
1282 p->member.x=get_int(packet+6);
1283 p->member.y=get_int(packet+10);
1284 p->member.status=get_int(packet+14);
1285 /* kdyz tasi, tak se nahodi ttl */
1286 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1287 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1289 break;
1291 case P_UPDATE_OBJECT_SPEED_STATUS_TTL:
1292 if (l < (n=20))break; /* invalid packet */
1294 struct object_list *p;
1296 p=find_in_table(get_int(packet+1));
1297 if (!p)break;
1298 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1299 p->member.update_counter=packet[5];
1300 p->member.xspeed=get_int(packet+6);
1301 p->member.yspeed=get_int(packet+10);
1302 p->member.status=get_int(packet+14);
1303 p->member.ttl=get_int16(packet+18);
1304 /* kdyz tasi, tak se nahodi ttl */
1305 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1306 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1308 break;
1310 case P_UPDATE_OBJECT_COORDS_STATUS_TTL:
1311 if (l < (n=20))break; /* invalid packet */
1313 struct object_list *p;
1315 p=find_in_table(get_int(packet+1));
1316 if (!p)break;
1317 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1318 p->member.update_counter=packet[5];
1319 p->member.x=get_int(packet+6);
1320 p->member.y=get_int(packet+10);
1321 p->member.status=get_int(packet+14);
1322 p->member.ttl=get_int16(packet+18);
1323 /* kdyz tasi, tak se nahodi ttl */
1324 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1325 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1327 break;
1329 case P_UPDATE_STATUS:
1330 if (l < (n=9))break; /* invalid packet */
1332 struct object_list *p;
1334 p=find_in_table(get_int(packet+1));
1335 if (!p)break; /* ignore objects we don't have */
1336 p->member.status=get_int(packet+5);
1337 /* kdyz tasi, tak se nahodi ttl */
1338 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1339 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1341 break;
1343 case P_HIT:
1344 if (l<8)break; /* invalid packet */
1346 struct object_list *p;
1348 n=8;
1349 p=find_in_table(get_int(packet+1));
1350 if (!p)break; /* ignore objects we don't have */
1351 p->member.status|=S_HIT;
1352 p->member.data=(void*)(long)((packet[5]<<16)+(packet[7]<<8)+(packet[6]));
1353 /* kdyz tasi, tak se nahodi ttl */
1354 if (p->member.type==T_PLAYER&&(p->member.status & S_HOLDING)&&(p->member.status & S_SHOOTING))
1355 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1357 break;
1359 case P_UPDATE_PLAYER:
1360 if (l<15+2*ARMS)break; /* invalid packet */
1361 health=packet[1];
1362 armor=packet[2];
1363 for (a=0;a<ARMS;a++)
1364 ammo[a]=get_int16(packet+3+(a<<1));
1365 frags=get_int(packet+3+ARMS*2);
1366 deaths=get_int(packet+7+ARMS*2);
1367 current_weapon=get_int16(packet+11+ARMS*2);
1368 weapons=get_int16(packet+13+ARMS*2);
1369 n=15+2*ARMS;
1370 break;
1372 case P_MESSAGE:
1373 if (l < 3)
1374 break; /* invalid packet */
1375 add_message(packet + 2, packet[1]);
1376 n = 3 + strlen(packet + 2);
1377 break;
1379 case P_CHANGE_LEVEL:
1381 char txt[256];
1382 char *name;
1383 char *md5;
1384 int a;
1385 char p;
1387 if (l<38)break; /* invalid packet */
1388 a=get_int(packet+1);
1389 if (level_number==a)goto level_changed;
1390 level_number=a;
1391 snprintf(txt, sizeof(txt), "Trying to change level to number %d", level_number);
1392 add_message(txt, M_INFO);
1393 name=load_level(level_number);
1394 if (!name) {
1395 snprintf(error_message,1024,"Cannot find level "
1396 "number %d. Game terminated. Press ENTER.",
1397 level_number);
1398 send_quit();
1399 return -1;
1401 snprintf(txt,256,"Changing level to \"%s\"",name);
1402 mem_free(name);
1403 add_message(txt, M_INFO);
1405 md5=md5_level(level_number);
1406 if (strcmp((char *)md5,packet+5)) /* MD5s differ */
1408 mem_free(md5);
1409 snprintf(error_message,1024,"Invalid MD5 sum. Can't change level. Game terminated. Press ENTER.");
1410 add_message("Invalid MD5 sum. Can't change level. Exiting...", M_INFO);
1411 send_quit();
1412 return -1;
1414 mem_free(md5);
1416 /* OK we can change it */
1417 change_level();
1418 level_changed:
1420 p=P_LEVEL_ACCEPTED;
1421 send_packet(&p,1,(struct sockaddr *)(&server),my_id,0);
1422 n=38;
1424 break;
1426 case P_END:
1427 if (l<2)
1428 snprintf(error_message,1024,"Game terminated. Press ENTER.");
1429 else
1430 snprintf(error_message,1024,"Game terminated by %s. Press ENTER.",packet+1);
1431 return -1;
1433 case P_BELL:
1434 n=1;
1435 c_bell();
1436 break;
1438 case P_INFO:
1439 if (l<=5)break;
1440 active_players=get_int(packet+1);
1441 l=6;
1442 for (a=0;a<packet[5]&&a<TOP_PLAYERS_N;a++)
1444 int x;
1445 top_players[a].frags=get_int(packet+l);
1446 top_players[a].deaths=get_int(packet+l+4);
1447 top_players[a].color=packet[l+8];
1448 x=strlen(packet+l+9)+1;
1449 memcpy(top_players[a].name,packet+l+9,x);
1450 l+=x+9;
1452 n=l;
1453 break;
1455 case P_EXPLODE_GRENADE:
1456 case P_EXPLODE_BFG:
1457 case P_EXPLODE_BLOODRAIN:
1459 unsigned int i,j;
1460 struct object_list *p;
1461 int b;
1463 if (l<9)break;
1464 n=9;
1465 i=get_int(packet+1);
1466 j=get_int(packet+5);
1467 p=find_in_table(j);
1468 if (!p)break;
1470 for (b=0;b<N_SHRAPNELS_EXPLODE;b++)
1472 double angle=(double)b*2*M_PI/N_SHRAPNELS_EXPLODE;
1473 int spd=add_int(mul_int(my_and(mul_int(weapon[WEAPON_GRENADE].speed,b+1),15),16),100);
1475 new_obj(
1477 T_SHRAPNEL,
1478 SHRAPNEL_TTL,
1479 (*packet==P_EXPLODE_GRENADE)?
1480 shrapnel_sprite[random()%N_SHRAPNELS]:
1481 (*packet==P_EXPLODE_BFG)?
1482 bfgbit_sprite[random()%N_SHRAPNELS]:
1483 bloodrain_sprite[random()%N_SHRAPNELS],
1485 WEAPON_GRENADE,
1486 p->member.x,
1487 p->member.y,
1488 p->member.xspeed+mul(spd,float2double(cos(angle))),
1489 p->member.yspeed+mul(spd,float2double(sin(angle))),
1490 0);
1491 i++;
1493 if (*packet != P_EXPLODE_BLOODRAIN)
1494 delete_obj(j);
1497 break;
1499 return n;
1503 /* read packet from socket */
1504 int read_data(void)
1506 fd_set rfds;
1507 struct timeval tv;
1508 struct sockaddr_in client;
1509 static char packet[MAX_PACKET_LENGTH];
1510 int a=sizeof(client);
1511 int l;
1513 tv.tv_sec=0;
1514 tv.tv_usec=0;
1515 FD_ZERO(&rfds);
1516 FD_SET(fd,&rfds);
1517 while(select(fd+1,&rfds,0,0,&tv))
1519 if ((l=recv_packet(packet,MAX_PACKET_LENGTH,(struct sockaddr*)(&client),&a,1,my_id,0))<0)
1520 return 0; /* something's strange */
1521 if (process_packet(packet,l)<0)return 1;
1524 return 0;
1528 /* select color for numeric value (red=lack, yellow=edium, green=fill) */
1529 int select_color(int value,int max)
1531 return value>=(max>>1)?10:(value>=(max>>2)?11:9);
1535 /* draw board at the bottom of the screen */
1536 void draw_board(void)
1538 int offs=SCREEN_X*(SCREEN_Y-2);
1539 int space=(SCREEN_X-60)/5;
1540 char txt[16];
1541 int offset=0;
1543 memset(screen_a+offs,4,SCREEN_X);
1544 memset(screen+offs,'-',SCREEN_X);
1545 memset(screen+offs+SCREEN_X,0,SCREEN_X);
1546 print2screen(0,SCREEN_Y-1,7,"HEALTH");
1547 snprintf(txt, sizeof(txt), "% 3d%%",health);
1548 print2screen(6,SCREEN_Y-1,select_color(health,100),txt);
1550 print2screen(11+(space>>1),SCREEN_Y-2,4,",");
1551 print2screen(11+(space>>1),SCREEN_Y-1,4,"|");
1552 print2screen(11+space,SCREEN_Y-1,7,"FRAGS");
1553 snprintf(txt, sizeof(txt), "% 4d",frags);
1554 print2screen(11+space+6,SCREEN_Y-1,11,txt);
1556 print2screen(21+space+(space>>1),SCREEN_Y-2,4,",");
1557 print2screen(21+space+(space>>1),SCREEN_Y-1,4,"|");
1558 print2screen(21+(space<<1),SCREEN_Y-1,7,"DEATHS");
1559 snprintf(txt, sizeof(txt), "% 4d",deaths);
1560 print2screen(21+(space<<1)+7,SCREEN_Y-1,11,txt);
1562 print2screen(31+(space<<1)+(space>>1),SCREEN_Y-2,4,",");
1563 print2screen(31+(space<<1)+(space>>1),SCREEN_Y-1,4,"|");
1564 snprintf(txt, sizeof(txt), "%10s",weapon[current_weapon].name);
1565 print2screen(31+3*space,SCREEN_Y-1,11,txt);
1567 print2screen(41+(3*space)+(space>>1),SCREEN_Y-2,4,",");
1568 print2screen(41+(3*space)+(space>>1),SCREEN_Y-1,4,"|");
1569 print2screen(41+(space<<2),SCREEN_Y-1,7,"AMMO");
1570 snprintf(txt, sizeof(txt), "% 4d",ammo[current_weapon]);
1571 print2screen(41+5+(space<<2),SCREEN_Y-1,select_color(ammo[current_weapon],weapon[current_weapon].max_ammo),txt);
1573 print2screen(49+(space<<2)+(space>>1),SCREEN_Y-2,4,",");
1574 print2screen(49+(space<<2)+(space>>1),SCREEN_Y-1,4,"|");
1575 print2screen(49+5*space,SCREEN_Y-1,7,"ARMOR");
1576 snprintf(txt, sizeof(txt), "% 4d%%",armor);
1577 print2screen(49+5+5*space,SCREEN_Y-1,select_color(armor,100),txt);
1578 if (hero->status & S_INVISIBLE)print2screen(SCREEN_X-(offset += 14),SCREEN_Y-2,C_YELLOW,"INVISIBILITY");
1579 if (hero->status & S_ILL)print2screen(SCREEN_X-(offset += 14),SCREEN_Y-2,C_RED,"! INFECTED !");
1580 if (hero->status & S_ONFIRE)print2screen(SCREEN_X-(offset += 9),SCREEN_Y-2,C_RED,"ON FIRE");
1581 if (autorun)print2screen(2,SCREEN_Y-2,15,"AUTORUN");
1582 if (autocreep)print2screen(10,SCREEN_Y-2,15,"AUTOCREEP");
1586 /* read string from input, returns everytime, not when string's read */
1587 int read_str_online(int y,char *pointer,char *message, int max_len)
1589 int a,b,c,shift=0;
1591 a=strlen(message);
1592 b=strlen(pointer);
1593 c=SCREEN_X*y;
1595 #ifdef TRI_D
1596 if (TRI_D_ON)
1598 memcpy(screen2+c,message,a);
1599 memcpy(screen2+c+a,pointer,b);
1600 memset(screen2_a+c,15,a);
1601 memset(screen2_a+c+a,7,b);
1602 memset(screen2_a+c+a+b,0,SCREEN_X-b-a);
1604 #endif
1606 memcpy(screen+c,message,a);
1607 memcpy(screen+c+a,pointer,b);
1608 memset(screen_a+c,15,a);
1609 memset(screen_a+c+a,7,b);
1610 memset(screen_a+c+a+b,0,SCREEN_X-b-a);
1612 c_update_kbd();
1614 if (c_was_pressed(K_ESCAPE))
1616 pointer[0]=0;
1617 return 2;
1619 if (c_was_pressed(K_ENTER))
1621 return 1;
1623 if (c_pressed(K_BACKSPACE)&&b)
1625 b--;
1626 pointer[b]=0;
1628 shift=c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT);
1629 for (c=' ';c<128&&b<max_len;c++)
1630 if (c_was_pressed(c))
1632 pointer[b]=shift?my_toupper(c):c;
1633 b++;
1634 pointer[b]=0;
1636 return 0;
1640 /* read number from input, returns everytime, not when number's read */
1641 int read_num_online(int y,char *pointer,char *message, int max_len)
1643 int a,b,c;
1645 a=strlen(message);
1646 b=strlen(pointer);
1647 c=SCREEN_X*y;
1649 #ifdef TRI_D
1650 if (TRI_D_ON)
1652 memcpy(screen2+c,message,a);
1653 memcpy(screen2+c+a,pointer,b);
1654 memset(screen2_a+c,15,a);
1655 memset(screen2_a+c+a,7,b);
1656 memset(screen2_a+c+a+b,0,SCREEN_X-b-a);
1658 #endif
1660 memcpy(screen+c,message,a);
1661 memcpy(screen+c+a,pointer,b);
1662 memset(screen_a+c,15,a);
1663 memset(screen_a+c+a,7,b);
1664 memset(screen_a+c+a+b,0,SCREEN_X-b-a);
1666 c_update_kbd();
1668 if (c_was_pressed(K_ESCAPE))
1670 pointer[0]=0;
1671 return 2;
1673 if (c_was_pressed(K_ENTER))
1675 return 1;
1677 if (c_pressed(K_BACKSPACE)&&b)
1679 b--;
1680 pointer[b]=0;
1682 for (c='0';c<='9'&&b<max_len;c++)
1683 if (c_was_pressed(c))
1685 pointer[b]=c;
1686 b++;
1687 pointer[b]=0;
1689 return 0;
1693 /* load banner.dat */
1694 void load_banner(char **banner)
1696 FILE *s;
1697 char line[1025];
1698 int a,b;
1700 #ifndef WIN32
1701 s=fopen(DATA_PATH BANNER_FILE,"r");
1702 #else
1703 fopen_s(&s,DATA_PATH BANNER_FILE,"r");
1704 #endif
1705 if (!s){shut_down(0);ERROR("Error: Can't load file \""DATA_PATH BANNER_FILE"\".\n");EXIT(1);}
1706 *banner=mem_alloc(1);
1707 **banner=0;
1708 if (!(*banner)){shut_down(0);ERROR("Error: Not enough memory.\n");EXIT(1);}
1709 while (fgets(line,1024,s))
1711 if (line[strlen(line)-1]==10)line[strlen(line)-1]=0;
1712 if (line[strlen(line)-1]==13)line[strlen(line)-1]=0; /* crlf shit */
1713 a=strlen(*banner);
1714 b=strlen(line);
1715 *banner=mem_realloc((*banner),a+b+SCREEN_X+1);
1716 memcpy((*banner)+a,line,b);
1717 memset((*banner)+a+b,' ',SCREEN_X);
1718 (*banner)[a+b+SCREEN_X]=0;
1720 fclose(s);
1723 #define ERRBOX_HEIGHT 1
1724 #define ERRBOX_Y ((SCREEN_Y-2-ERRBOX_HEIGHT)>>1)
1726 /* draw error box */
1727 void print_error(char *text)
1729 int width = strlen(text) + 6;
1730 int x = (SCREEN_X-2-width) >> 1;
1732 draw_frame(x, ERRBOX_Y, width, ERRBOX_HEIGHT, 15);
1733 print2screen(x + 2, ERRBOX_Y + 1, C_RED, "/!\\");
1734 print2screen(x + 6, ERRBOX_Y + 1, C_YELLOW, text);
1738 /* draw initial screen */
1739 void menu_screen(struct config *cfg)
1741 char txt[8];
1742 int sprite,anim=0,title_anim=0,bulge_anim=0;
1743 unsigned long_long t;
1744 char port[MAX_PORT_LEN+1];
1745 int a=0;
1746 char *m;
1747 char *color_name[15]={"red","green","brown","blue","violet","cyan","gray","black","light red","light green","yellow","light blue","magenta","light cyan","white"};
1748 char *banner;
1749 int l,banner_pos=0;
1750 int help=0;
1751 #ifdef HAVE_LIBPTHREAD
1752 pthread_t
1753 #else
1755 #endif
1756 pt = 0;
1758 load_banner(&banner);
1759 l=strlen(banner);
1760 snprintf(port, sizeof(port), "%d",cfg->port);
1761 snprintf(txt, sizeof(txt), "hero%d",cfg->color);
1762 if (find_sprite(txt,&sprite))
1764 char msg[256];
1765 mem_free(banner);
1766 shut_down(0);
1767 snprintf(msg,256,"Error: Can't find sprite \"%s\".\n",txt);
1768 ERROR(msg);
1769 EXIT(1);
1772 cycle:
1773 t=get_time();
1774 clear_screen();
1775 #ifdef TRI_D
1776 if (TRI_D_ON)
1778 tri_d=1;
1779 put_sprite((SCREEN_X+1-TITLE_WIDTH)>>1,0,sprites[title_sprite].positions+sprites[title_sprite].steps[title_anim],0);
1780 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);
1781 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);
1782 tri_d=0;
1784 #endif
1785 put_sprite((SCREEN_X-TITLE_WIDTH)>>1,0,sprites[title_sprite].positions+sprites[title_sprite].steps[title_anim],0);
1786 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);
1787 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);
1788 print2screen(0,TITLE_HEIGHT+4,11,"N");
1789 print2screen(1,TITLE_HEIGHT+4,2,"AME:");
1790 print2screen(6,TITLE_HEIGHT+4,7,cfg->name);
1791 print2screen(0,TITLE_HEIGHT+6,2,"COLOR:");
1792 print2screen(7,TITLE_HEIGHT+6,7,color_name[(cfg->color-1)%15]);
1793 print2screen(0,TITLE_HEIGHT+0,11,"S");
1794 print2screen(1,TITLE_HEIGHT+0,2,"ERVER ADDRESS:");
1795 print2screen(16,TITLE_HEIGHT+0,7,cfg->host);
1796 print2screen(0,TITLE_HEIGHT+2,11,"P");
1797 print2screen(1,TITLE_HEIGHT+2,2,"ORT:");
1798 print2screen(6,TITLE_HEIGHT+2,7,port);
1799 print2screen((SCREEN_X-26)>>1,SCREEN_Y-3,7,"Use arrows to change color");
1800 print2screen((SCREEN_X-52)>>1,SCREEN_Y-2,7,"Press ENTER to connect, H for help, ESC or Q to quit");
1801 print2screen(0,SCREEN_Y-1,15,banner+(banner_pos>>1));
1802 banner_pos++;
1803 banner_pos%=l<<1;
1804 anim++;
1805 anim&=15;
1806 title_anim++;
1807 title_anim%=sprites[title_sprite].n_steps;
1808 bulge_anim++;
1809 bulge_anim%=sprites[bulge_sprite].n_steps;
1810 if (*error_message)
1812 print2screen(((SCREEN_X-strlen(error_message))>>1),SCREEN_Y-1,9,error_message);
1814 #ifdef TRI_D
1815 if (TRI_D_ON)
1817 tri_d=1;
1818 blit_screen(1);
1819 tri_d=0;
1822 #endif
1823 blit_screen(1);
1824 wait_for_enter();
1825 *error_message=0;
1826 goto cc1;
1828 if (help)print_help_window();
1829 #ifdef HAVE_LIBPTHREAD
1830 if (pt && errormsg.flags) {
1831 pthread_kill(pt, 9); /* good bye */
1832 pt = 0;
1834 if (!pt && errormsg.flags == E_CONN_SUCC) {
1835 errormsg.flags = 0;
1836 mem_free(banner);
1837 return;
1839 #endif
1840 if (errormsg.flags)
1841 print_error(errormsg.text);
1843 switch(a)
1845 case 1:
1846 if (read_str_online(SCREEN_Y-1,cfg->name,"Enter your name: ",MAX_NAME_LEN)) {
1847 cfg->override &= ~OVERRIDE_FLAG_NAME;
1848 a=0;
1850 break;
1852 case 3:
1853 if (read_str_online(SCREEN_Y-1,cfg->host,"Enter address: ",MAX_HOST_LEN)) {
1854 cfg->override &= ~OVERRIDE_FLAG_HOST;
1855 a=0;
1857 break;
1859 case 2:
1860 if (read_num_online(SCREEN_Y-1,port,"Enter port: ",MAX_PORT_LEN)) {
1861 cfg->override &= ~OVERRIDE_FLAG_PORT;
1862 cfg->port = strtol(port, 0, 10);
1863 a=0;
1865 break;
1867 c_update_kbd();
1869 #ifdef TRI_D
1870 if (TRI_D_ON)
1872 tri_d=1;
1873 blit_screen(1);
1874 tri_d=0;
1876 #endif
1878 blit_screen(1);
1879 if (!a && !pt)
1881 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)
1883 (cfg->color)++;
1884 if (cfg->color>30)
1885 cfg->color=1;
1886 snprintf(txt, sizeof(txt), "hero%d",cfg->color);
1887 if (find_sprite(txt,&sprite))
1888 {shut_down(0);mem_free(banner);fprintf(stderr,"Error: Can't find sprite \"%s\".\n",txt);}
1889 cfg->override &= ~OVERRIDE_FLAG_COLOR;
1892 if ((c_was_pressed('-')||c_was_pressed(K_NUM_MINUS)||c_was_pressed(K_DOWN)||c_was_pressed(K_LEFT)) && !errormsg.flags)
1894 cfg->color--;
1895 if (cfg->color<1)
1896 cfg->color=30;
1897 snprintf(txt, sizeof(txt), "hero%d",cfg->color);
1898 if (find_sprite(txt,&sprite))
1899 {shut_down(0);mem_free(banner);fprintf(stderr,"Error: Can't find sprite \"%s\".\n",txt);}
1900 cfg->override &= ~OVERRIDE_FLAG_COLOR;
1903 if (c_was_pressed('h') && !errormsg.flags)help^=1;
1904 if (c_was_pressed(K_ENTER))
1906 if (errormsg.flags) {
1907 errormsg.flags = E_NONE;
1908 goto cycle;
1910 save_cfg(cfg);
1911 cfg->port=strtol(port,0,10);
1912 if ((m=find_server(cfg)))
1914 print2screen(((SCREEN_X-strlen(m))>>1),SCREEN_Y-1,9,m);
1915 #ifdef TRI_D
1916 if (TRI_D_ON)
1918 tri_d=1;
1919 blit_screen(1);
1920 tri_d=0;
1922 #endif
1923 blit_screen(1);
1924 wait_for_enter();
1925 goto cc1;
1927 if ((m=init_socket()))
1929 print2screen(((SCREEN_X-strlen(m))>>1),SCREEN_Y-1,9,m);
1930 #ifdef TRI_D
1931 if (TRI_D_ON)
1933 tri_d=1;
1934 blit_screen(1);
1935 tri_d=0;
1937 #endif
1938 blit_screen(1);
1939 wait_for_enter();
1940 goto cc1;
1942 #ifdef HAVE_LIBPTHREAD
1943 if (!pt) {
1944 pthread_create(&pt, NULL, (void *)contact_server, cfg);
1945 pthread_detach(pt);
1946 goto cycle;
1948 #else
1949 if(contact_server(cfg))
1950 goto cycle;
1951 else {
1952 mem_free(banner);
1953 return;
1955 #endif
1957 cc1:
1958 if ((c_was_pressed('q')||c_was_pressed(K_ESCAPE)) && !errormsg.flags)
1960 save_cfg(cfg);
1961 mem_free(banner);
1962 shut_down(1);
1965 if (c_was_pressed('n') && !errormsg.flags)
1966 a=1;
1968 if ((c_was_pressed('a')||c_was_pressed('s')) && !errormsg.flags)
1969 a=3;
1971 if (c_was_pressed('p') && !errormsg.flags)
1972 a=2;
1974 sleep_until(t+MENU_PERIOD_USEC);
1975 goto cycle;
1979 /* handle fatal signal (sigabrt, sigsegv, ...) */
1980 void signal_handler(int signum)
1983 if (connected)send_quit();
1984 shut_down(0);
1985 #ifdef HAVE_PSIGNAL
1986 psignal(signum,"Exiting on signal");
1987 #else
1988 fprintf(stderr, "Exiting on signal: %d\n", signum);
1989 #endif
1990 EXIT(1);
1994 /* change size of the screen */
1995 void sigwinch_handler(int signum)
1997 signum=signum;
1998 resize_screen();
1999 #ifdef WIN32
2000 c_shutdown();
2001 c_init(SCREEN_X,SCREEN_Y);
2002 #endif
2003 c_cls();
2004 c_refresh();
2005 #ifndef WIN32
2006 #ifdef SIGWINCH
2007 signal(SIGWINCH,sigwinch_handler);
2008 #endif
2009 #endif
2013 /* print command line help */
2014 void print_help(void)
2016 char *x = "";
2017 char *y = "";
2018 #ifdef XWINDOW
2019 x = " for X windows";
2020 y = " [-d <display>] [-f <font name>]";
2021 #endif
2022 printf(
2023 "0verkill client%s"
2024 ".\n"
2025 "(c)2000 Brainsoft\n"
2026 "Usage: 0verkill [-h] [-3] [-i <server address>] \n"
2027 "[-c <color>] [-n <player name>] [-p <port>] \n"
2028 "[-s <width>x<height>]%s"
2029 "\n", x, y
2034 void parse_dimensions(char *txt)
2036 char *p;
2037 char *e;
2038 p=txt;
2039 for (p=txt;(*p)&&(*p)!='x';p++);
2040 if (!(*p)){ERROR("Error: Expected dimensions in form WIDTHxHEIGHT.\n");EXIT(1);}
2041 (*p)=0;
2042 p++;
2043 if (!strlen(txt)||!strlen(p)){fprintf(stderr,"Error: Decimal number expected.\n");EXIT(1);}
2044 SCREEN_X=strtoul(txt,&e,10);
2045 if (*e){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2046 SCREEN_Y=strtoul(p,&e,10);
2047 if (*e){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2048 set_size=1;
2052 void parse_command_line(struct config *cfg)
2054 int a;
2056 while(1)
2058 #ifdef TRI_D
2060 #ifdef XWINDOW
2061 a=getopt(cfg->argc,cfg->argv,"3hl:f:d:s:n:i:p:c:");
2062 #endif
2063 #ifndef XWINDOW
2064 a=getopt(cfg->argc,cfg->argv,"3hl:s:n:i:p:c:");
2065 #endif
2066 #else
2067 #ifdef XWINDOW
2068 a=getopt(cfg->argc,cfg->argv,"hf:d:s:n:i:p:c:");
2069 #endif
2070 #ifndef XWINDOW
2071 a=getopt(cfg->argc,cfg->argv,"hs:n:i:p:c:");
2072 #endif
2073 #endif
2074 switch(a)
2076 case EOF:
2077 return;
2079 case '?':
2080 case ':':
2081 EXIT(1);
2083 case 'h':
2084 print_help();
2085 EXIT(0);
2087 #ifdef TRI_D
2088 case '3':
2089 TRI_D_ON=1;
2090 break;
2091 #endif
2093 case 's':
2094 parse_dimensions(optarg);
2095 break;
2096 #ifdef XWINDOW
2097 case 'd':
2098 x_display_name=optarg;
2099 break;
2101 case 'f':
2102 x_font_name=optarg;
2103 break;
2104 #endif
2105 case 'i':
2106 memcpy(cfg->host, optarg, strlen(optarg) + 1);
2107 cfg->override |= OVERRIDE_FLAG_HOST;
2108 break;
2110 case 'n':
2111 memcpy(cfg->name, optarg, strlen(optarg) + 1);
2112 cfg->override |= OVERRIDE_FLAG_NAME;
2113 break;
2115 case 'p':
2116 cfg->port = strtol(optarg, 0, 10);
2117 cfg->override |= OVERRIDE_FLAG_PORT;
2118 break;
2120 case 'c':
2121 cfg->color = strtol(optarg, 0, 10);
2122 cfg->override |= OVERRIDE_FLAG_COLOR;
2123 break;
2128 #define HALL_FAME_WIDTH (MAX_NAME_LEN+17)
2129 #define HALL_FAME_HEIGHT ((active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players)+5)
2130 #define HALL_FAME_X ((SCREEN_X-2-HALL_FAME_WIDTH)>>1)
2131 #define HALL_FAME_Y ((SCREEN_Y-2-HALL_FAME_HEIGHT)>>1)
2133 void print_hall_of_fame(void)
2135 int a;
2136 char txt[32];
2137 unsigned char color;
2139 if (!active_players)return;
2140 snprintf(txt, sizeof(txt), "TOP %d PLAYERS",TOP_PLAYERS_N);
2141 draw_frame(HALL_FAME_X,HALL_FAME_Y,HALL_FAME_WIDTH,HALL_FAME_HEIGHT,15);
2142 print2screen(HALL_FAME_X+1+((HALL_FAME_WIDTH-strlen(txt))>>1),HALL_FAME_Y+1,11,txt);
2143 print2screen(HALL_FAME_X+2,HALL_FAME_Y+3,15,"NAME");
2144 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+2,HALL_FAME_Y+3,15,"FRAGS");
2145 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+9,HALL_FAME_Y+3,15,"DEATHS");
2146 for (a=0;a<active_players&&a<TOP_PLAYERS_N;a++)
2148 color=((top_players[a].color-1)%15)+1;
2149 print2screen(HALL_FAME_X+2,HALL_FAME_Y+4+a,color,top_players[a].name);
2150 snprintf(txt, sizeof(txt), "% 5d",top_players[a].frags);
2151 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+2,HALL_FAME_Y+4+a,color,txt);
2152 snprintf(txt, sizeof(txt), "% 5d",top_players[a].deaths);
2153 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+9,HALL_FAME_Y+4+a,color,txt);
2155 snprintf(txt, sizeof(txt), "%d",active_players);
2156 print2screen(HALL_FAME_X+2,HALL_FAME_Y+HALL_FAME_HEIGHT,11,"Players in the game:");
2157 print2screen(HALL_FAME_X+23,HALL_FAME_Y+HALL_FAME_HEIGHT,7,txt);
2161 void play(void)
2163 #ifdef PAUSE
2164 int p=0;
2165 #endif
2166 char string[80];
2167 unsigned char chat=0;
2168 unsigned char help=0;
2169 unsigned char hall_fame=0;
2170 unsigned long_long last_time;
2172 last_time=get_time();
2173 while(1)
2175 last_time+=CLIENT_PERIOD_USEC;
2176 if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
2177 if (read_data())return; /* game terminated */
2178 #ifdef PAUSE
2179 if(!p)clear_screen();
2180 #else
2181 clear_screen();
2182 #endif
2183 update_game();
2184 #ifdef PAUSE
2185 if (!p)draw_scene();
2186 #else
2187 draw_scene();
2188 #endif
2189 update_messages(last_time);
2190 print_messages();
2191 if (chat)
2193 switch (read_str_online(SCREEN_Y-3,string,"> ",78))
2195 case 2:
2196 chat=0;
2197 break;
2199 case 1:
2200 chat=0;
2201 send_message(string, M_CHAT);
2202 break;
2205 if (help)print_help_window();
2206 if (hall_fame)print_hall_of_fame();
2207 draw_board();
2209 #ifdef TRI_D
2210 if (TRI_D_ON)
2212 tri_d=1;
2213 blit_screen(1);
2214 tri_d=0;
2216 #endif
2218 blit_screen(1);
2220 creep=0;
2221 if (!chat)c_update_kbd();
2223 #ifdef PAUSE
2224 if (c_was_pressed('p'))p^=1;
2225 #endif
2226 if (!chat&&c_was_pressed('r'))
2228 c_cls();
2229 redraw_screen();
2231 if (!chat&&c_was_pressed('h'))help^=1;
2232 if (!chat&&c_was_pressed(K_TAB))
2234 hall_fame^=1;
2235 if (hall_fame)send_info_request();
2237 if (c_was_pressed(K_CAPS_LOCK)||(!chat&&c_was_pressed('a')))autorun^=1;
2238 if (c_was_pressed(K_F10)||(!chat&&c_was_pressed('q')))
2240 send_quit();
2241 *error_message=0;
2242 return;
2244 if (c_pressed(K_F12))
2245 end_game();
2247 if (!chat && c_was_pressed(K_ENTER))
2249 memset(string,0,80);
2250 #ifdef WIN32
2251 c_update_kbd();
2252 c_was_pressed('d');
2253 #endif
2254 chat=1;
2256 reset_keyboard();
2257 if (!chat&&c_was_pressed(' '))send_reenter_game();
2258 if (!chat&&c_was_pressed('c'))
2259 autocreep^=1;
2260 if (c_pressed(K_DOWN)||autocreep)
2261 keyboard_status.status |= KBD_CREEP;
2262 if (c_pressed(K_UP))
2263 keyboard_status.status |= KBD_JUMP;
2264 if (c_pressed(K_LEFT_CTRL)||c_pressed(K_RIGHT_CTRL)||(!chat&&c_pressed('z')))
2265 keyboard_status.status |= KBD_FIRE;
2266 if (!chat && c_pressed('d'))
2267 keyboard_status.status |= KBD_DOWN_LADDER;
2268 if (!chat && c_pressed('j'))
2269 keyboard_status.status |= KBD_JETPACK;
2270 if (!chat && c_was_pressed('1'))
2271 keyboard_status.weapon=1;
2272 if (!chat && c_was_pressed('2'))
2273 keyboard_status.weapon=2;
2274 if (!chat && c_was_pressed('3'))
2275 keyboard_status.weapon=3;
2276 if (!chat && c_was_pressed('4'))
2277 keyboard_status.weapon=4;
2278 if (!chat && c_was_pressed('5'))
2279 keyboard_status.weapon=5;
2280 if (!chat && c_was_pressed('6'))
2281 keyboard_status.weapon=6;
2282 if (!chat && c_was_pressed('7'))
2283 keyboard_status.weapon=7;
2284 if (!chat && c_was_pressed('8'))
2285 keyboard_status.weapon=8;
2286 if (c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT)||autorun)
2287 keyboard_status.status |= KBD_SPEED;
2288 if (c_pressed(K_LEFT))
2289 keyboard_status.status |= KBD_LEFT;
2290 if (c_pressed(K_RIGHT))
2291 keyboard_status.status |= KBD_RIGHT;
2293 send_keyboard();
2294 sleep_until(last_time+CLIENT_PERIOD_USEC);
2298 /*----------------------------------------------------------------------------*/
2299 int main(int argc,char **argv)
2301 int a;
2302 char txt[256];
2303 struct config cfg = {argc, argv, "", "", DEFAULT_PORT, 1, 0};
2305 #ifdef WIN32
2306 WSADATA wd;
2308 WSAStartup(0x101, &wd);
2309 printf("Started WinSock version %X.%02X\n", wd.wVersion/0x100, wd.wVersion&0xFF);
2310 #endif
2312 chdir_to_data_files();
2313 #ifdef XWINDOW
2314 x_display_name=0;
2315 x_font_name=0;
2316 #endif
2318 last_message=-1;
2319 autorun=0;
2320 autocreep=0;
2321 memset(cfg.host,0,MAX_HOST_LEN+1);
2322 memset(cfg.name,0,MAX_NAME_LEN+1);
2323 load_cfg(&cfg);
2324 last_obj=&objects;
2325 *error_message=0;
2327 parse_command_line(&cfg);
2328 hash_table_init();
2329 if (!set_size)c_get_size(&SCREEN_X,&SCREEN_Y);
2330 init_sprites();
2331 init_area();
2332 #ifndef WIN32
2333 load_sprites(DATA_PATH GAME_SPRITES_FILE);
2334 #else
2335 snprintf(txt,sizeof(txt),"%s\\data\\sprites.dat",_getcwd(NULL, 0));
2336 load_sprites(txt);
2337 #endif
2338 /* sprites are stored in memory in this order: game sprites (players,
2339 * bullets, corpses, blood, meat...) followed by level sprites
2342 level_sprites_start=n_sprites;
2343 if (find_sprite("hit",&hit_sprite)){ERROR("Error: Can't find sprite \"hit\".\n");EXIT(1);}
2344 if (find_sprite("title",&title_sprite)){ERROR("Error: Can't find sprite \"title\".\n");EXIT(1);}
2345 if (find_sprite("bulge",&bulge_sprite)){ERROR("Error: Can't find sprite \"bulge\".\n");EXIT(1);}
2346 for (a=0;a<N_SHRAPNELS;a++)
2348 snprintf(txt, sizeof(txt), "shrapnel%d",a+1);
2349 if (find_sprite(txt,&shrapnel_sprite[a])) {
2350 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2351 EXIT(1);
2353 snprintf(txt, sizeof(txt), "bfgbit%d",a+1);
2354 if (find_sprite(txt,&bfgbit_sprite[a])) {
2355 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2356 EXIT(1);
2358 snprintf(txt, sizeof(txt), "bloodrain%d",a+1);
2359 if (find_sprite(txt,&bloodrain_sprite[a])) {
2360 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2361 EXIT(1);
2364 snprintf(txt, sizeof(txt), "jetpack");
2365 if (find_sprite(txt,&jetpack_sprite)) {
2366 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2367 EXIT(1);
2369 snprintf(txt, sizeof(txt), "fire");
2370 if (find_sprite(txt,&fire_sprite)) {
2371 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2372 EXIT(1);
2374 snprintf(txt, sizeof(txt), "sawchain");
2375 if (find_sprite(txt,&chain_sprite)) {
2376 fprintf(stderr,"Can't find sprite \"%s\".\n",txt);
2377 EXIT(1);
2380 signal(SIGINT,signal_handler);
2381 signal(SIGTERM,signal_handler);
2382 signal(SIGILL,signal_handler);
2383 signal(SIGABRT,signal_handler);
2384 signal(SIGFPE,signal_handler);
2385 signal(SIGSEGV,signal_handler);
2386 #ifndef WIN32
2387 signal(SIGQUIT,signal_handler);
2388 signal(SIGBUS,signal_handler);
2389 #ifdef SIGWINCH
2390 signal(SIGWINCH,sigwinch_handler);
2391 #endif
2392 #endif
2393 c_init(SCREEN_X,SCREEN_Y);
2394 c_cls();
2395 c_cursor(C_HIDE);
2396 c_refresh();
2397 while(1)
2399 level_number=-1;
2400 connected=0;
2401 menu_screen(&cfg);
2402 connected=1;
2403 play();
2404 clean_memory();
2405 delete_obj(hero->id);