1 /* When compiling with X support don't forget to define XWINDOW symbol */
2
3 #ifndef WIN32
4 #include "config.h"
5 #endif
6
7 #include <stdio.h>
8 #include <signal.h>
9 #include <math.h>
10
11 #ifdef HAVE_FLOAT_H
12 #include <float.h>
13 #endif
14
15 #ifdef HAVE_SIGINFO_H
16 #include <siginfo.h>
17 #endif
18
19 #ifdef HAVE_SYS_SELECT_H
20 #include <sys/select.h>
21 #endif
22
23 #include <ctype.h>
24
25 #if (!defined(WIN32))
26 #ifdef TIME_WITH_SYS_TIME
27 #include <sys/time.h>
28 #include <time.h>
29 #else
30 #ifdef TM_IN_SYS_TIME
31 #include <sys/time.h>
32 #else
33 #include <time.h>
34 #endif
35 #endif
36 #else
37 #include <time.h>
38 #endif
39
40 #include <errno.h>
41 #include <stdlib.h>
42 #ifndef WIN32
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <netdb.h>
47 #ifndef __USE_GNU
48 #define __USE_GNU
49 #endif
50 #else
51 #include <winsock.h>
52 #endif
53
54 #include <string.h>
55
56 #include "blit.h"
57 #include "sprite.h"
58 #include "data.h"
59 #include "cfg.h"
60 #include "net.h"
61 #include "hash.h"
62 #include "console.h"
63 #include "time.h"
64 #include "math.h"
65 #include "help.h"
66 #include "getopt.h"
67 #include "error.h"
68
69 #ifdef XWINDOW
70 #include "x.h"
71 #endif
72
73 #undef PAUSE
74
75 #ifdef WIN32
76 int consoleApp=1;
77 #endif
78
79 /* my health, armor, frags, deaths, ammo, ... and ID */
80 unsigned char health,armor;
81 unsigned int frags,deaths;
82 unsigned short ammo[ARMS];
83 unsigned char current_weapon;
84 unsigned char weapons;
85 unsigned char creep;
86 unsigned char autorun,autocreep;
87 int my_id;
88
89 /* connection with server */
90 int connected;
91
92 int level_number=-1;
93
94 /* networking */
95 int fd; /* socket */
96 struct sockaddr_in server; /* server address */
97
98 /* objects */
99 struct object_list objects;
100 struct object_list *last_obj;
101 struct it* hero;
102
103 /* important sprites */
104 int hit_sprite;
105 int title_sprite;
106 int bulge_sprite;
107 int shrapnel_sprite[N_SHRAPNELS];
108
109 int level_sprites_start; /* number of first sprite in the level (all other level sprites follow) */
110
111 unsigned long_long game_start_offset; /* time difference between game start on this machine and on server */
112
113
114 /* top players table */
115 struct
116 {
117 char name[MAX_NAME_LEN+1];
118 int frags,deaths;
119 unsigned char color;
120 }top_players[TOP_PLAYERS_N];
121
122 /* # of active players in the game */
123 int active_players;
124
125
126 struct /* keyboard status */
127 {
128 unsigned char right,left,jump,creep,speed,fire,weapon,down_ladder;
129 }keyboard_status;
130
131 /* message */
132 struct msgline_type
133 {
134 unsigned long_long time;
135 char *msg;
136 }msg_line[N_MESSAGES];
137
138 int last_message;
139 unsigned char error_message[1024];
140
141 unsigned char set_size; /* -s option was on the command line */
142
143 /* convert key to key with shift */
my_toupper(int c)144 int my_toupper(int c)
145 {
146 switch(c)
147 {
148 case '1': return '!';
149 case '2': return '@';
150 case '3': return '#';
151 case '4': return '$';
152 case '5': return '%';
153 case '6': return '^';
154 case '7': return '&';
155 case '8': return '*';
156 case '9': return '(';
157 case '0': return ')';
158 case '-': return '_';
159 case '=': return '+';
160 case '\\': return '|';
161 case '[': return '{';
162 case ']': return '}';
163 case ';': return ':';
164 case '\'': return '"';
165 case ',': return '<';
166 case '.': return '>';
167 case '/': return '?';
168 case '`': return '~';
169 default: return toupper(c);
170 }
171 }
172
173
174
wait_for_enter(void)175 void wait_for_enter(void)
176 {
177 c_update_kbd();
178 while (!c_was_pressed(K_ENTER))
179 {
180 c_wait_for_key();
181 c_update_kbd();
182 }
183 }
184
185
186 /* load configure file from player's home directory */
load_cfg(char * host,char * name,int * color)187 void load_cfg(char *host,char *name,int *color)
188 {
189 FILE *stream;
190 int a;
191 unsigned char txt[256];
192
193 #ifndef WIN32
194 snprintf(txt,sizeof(txt),"%s/%s",getenv("HOME"),CFG_FILE);
195 #else
196 snprintf(txt,sizeof(txt),"./%s",CFG_FILE);
197 #endif
198 stream=fopen(txt,"r");
199 if (!stream)return;
200
201 if (!fgets(txt,MAX_HOST_LEN+2,stream))
202 return;
203 a=strlen(txt);
204 if (txt[a-1]==10)txt[a-1]=0;
205 memcpy(host,txt,strlen(txt)+1);
206
207 if (!fgets(txt,MAX_NAME_LEN+2,stream))
208 return;
209 a=strlen(txt);
210 if (txt[a-1]==10)txt[a-1]=0;
211 memcpy(name,txt,strlen(txt)+1);
212 if (!fgets(txt,256,stream))
213 return;
214 *color=strtol(txt,0,10);
215 fclose(stream);
216 }
217
218
219 /* save configure file to player's home */
save_cfg(char * host,char * name,int color)220 void save_cfg(char *host,char *name,int color)
221 {
222 FILE *stream;
223 unsigned char txt[256];
224
225 #ifndef WIN32
226 snprintf(txt,sizeof(txt),"%s/%s",getenv("HOME"),CFG_FILE);
227 #else
228 snprintf(txt,sizeof(txt),"./%s",CFG_FILE);
229 #endif
230 stream=fopen(txt,"w");
231 if (!stream)return;
232 fprintf(stream,"%s\n%s\n%d\n",host,name,color);
233 fclose(stream);
234 }
235
236
scroll_messages(void)237 void scroll_messages(void)
238 {
239 int a;
240
241 if (last_message<0)return;
242 for (a=0;a<=last_message-1;a++)
243 {
244 msg_line[a].time=msg_line[a+1].time;
245 msg_line[a].msg=mem_realloc(msg_line[a].msg,strlen(msg_line[a+1].msg)+1);
246 memcpy(msg_line[a].msg,msg_line[a+1].msg,strlen(msg_line[a+1].msg)+1);
247 }
248 mem_free(msg_line[last_message].msg);
249 msg_line[last_message].msg=0;
250 last_message--;
251 }
252
253
add_message(char * message)254 void add_message(char *message)
255 {
256 if (last_message==N_MESSAGES-1)scroll_messages();
257 msg_line[last_message+1].time=get_time()+MESSAGE_TTL;
258 msg_line[last_message+1].msg=mem_alloc(strlen(message)+1);
259 if (!msg_line[last_message+1].msg)return; /* not such a fatal errror */
260 memcpy(msg_line[last_message+1].msg,message,strlen(message)+1);
261 last_message++;
262 }
263
264
print_messages(void)265 void print_messages(void)
266 {
267 int a;
268
269 for (a=0;a<=last_message;a++)
270 print2screen(0,a,MESSAGE_COLOR,msg_line[a].msg);
271 }
272
273
274 /* throw out old messages */
update_messages(unsigned long_long time)275 void update_messages(unsigned long_long time)
276 {
277 int a,b;
278
279 for(a=0,b=0;a<=last_message;a++)
280 if (msg_line[b].time<=time)scroll_messages();
281 else b++;
282 }
283
284
285 /* destroys all objects and messages */
clean_memory(void)286 void clean_memory(void)
287 {
288 int a;
289 struct object_list *o;
290
291 /* delete all objects except hero */
292 for (o=&objects;o->next;)
293 if ((hero->id)!=(o->next->member.id))delete_obj(o->next->member.id);
294 else o=o->next;
295
296 /* delete messages */
297 for (a=0;a<=last_message;a++)
298 mem_free(msg_line[a].msg);
299 msg_line[last_message].msg=0;
300 last_message=-1;
301 }
302
303
304 /* shut down the client */
shut_down(int x)305 void shut_down(int x)
306 {
307 struct object_list *o;
308 int a;
309
310 c_shutdown();
311 free_sprites(0);
312 free_area();
313 if (hero)delete_obj(hero->id);
314
315
316 /* delete all objects except hero */
317 for (o=&objects;o->next;)
318 delete_obj(o->next->member.id);
319
320 /* delete messages */
321 for (a=0;a<=last_message;a++)
322 mem_free(msg_line[a].msg);
323 msg_line[last_message].msg=0;
324
325 shutdown_sprites();
326 check_memory_leaks();
327 if (x)EXIT(0);
328 }
329
330
331 /* find address of server and fill the server address structure */
find_server(char * name,unsigned short port)332 char * find_server(char *name,unsigned short port)
333 {
334 struct hostent *h;
335
336 h=gethostbyname(name);
337 if (!h)return "Error: Can't resolve server address.";
338
339 server.sin_family=AF_INET;
340 server.sin_port=htons(port);
341 server.sin_addr=*((struct in_addr*)(h->h_addr_list[0]));
342 return 0;
343 }
344
345
346 /* initialize socket */
init_socket(void)347 char * init_socket(void)
348 {
349 fd=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
350 if(fd<0)return "Can't get socket.\n";
351 return 0;
352 }
353
354
355 #define MAX_COUNT 32
356
357 /* send quit request to server */
send_quit(void)358 void send_quit(void)
359 {
360 unsigned char p;
361 fd_set rfds;
362 struct timeval tv;
363 int a=sizeof(server);
364 int count=0;
365
366 tv.tv_sec=2;
367 tv.tv_usec=0;
368 FD_ZERO(&rfds);
369 FD_SET(fd,&rfds);
370
371 send_again:
372 p=P_QUIT_REQUEST;
373 count ++;
374 send_packet(&p,1,(struct sockaddr *)(&server),my_id,0);
375 if (!select(fd+1,&rfds,0,0,&tv)&&count<=MAX_COUNT)goto send_again;
376 recv_packet(&p,1,(struct sockaddr*)(&server),&a,1,my_id,0);
377 if (p!=P_PLAYER_DELETED&&count<=MAX_COUNT)goto send_again;
378 }
379
380 #undef MAX_COUNT
381
382
383 /* initiate connection with server */
contact_server(int color,unsigned char * name)384 char * contact_server(int color,unsigned char *name)
385 {
386 static unsigned char packet[256];
387 int l=strlen(name)+1;
388 int a,r;
389 int min,maj;
390
391 fd_set fds;
392 struct timeval tv;
393 tv.tv_sec=4;
394 tv.tv_usec=0;
395 FD_ZERO(&fds);
396 FD_SET(fd,&fds);
397
398 packet[0]=P_NEW_PLAYER;
399 packet[1]=0;
400 packet[2]=VERSION_MAJOR;
401 packet[3]=VERSION_MINOR;
402 packet[4]=color;
403 memcpy(packet+5,name,l);
404
405 send_packet(packet,l+5,(struct sockaddr*)(&server),my_id,0);
406
407
408 if (!select(fd+1,&fds,NULL,NULL,&tv))return "No reply within 4 seconds. Press ENTER.";
409
410 if ((r=recv_packet(packet,256,0,0,1,0,0))<0)
411 {
412 if (errno==EINTR)return "Server hung up. Press ENTER.";
413 else return "Connection error. Press ENTER.";
414 }
415
416 switch(*packet)
417 {
418 case P_PLAYER_REFUSED:
419 switch(packet[1])
420 {
421 case E_INCOMPATIBLE_VERSION:
422 return "Incompatible client version. Connection refused. Press Enter.";
423
424 default:
425 return "Connection refused. Press ENTER.";
426 }
427
428 case P_PLAYER_ACCEPTED:
429 my_id=get_int(packet+33);
430 if (r<39){send_quit();return "Incompatible server version. Givin' up. Press Enter.";}
431 maj=packet[37];
432 min=packet[38];
433 if (maj!=VERSION_MAJOR||min<MIN_SERVER_VERSION_MINOR)
434 {send_quit();return "Incompatible server version. Givin' up. Press Enter.";}
435 game_start_offset=get_time();
436 game_start_offset-=get_long_long(packet+25);
437 health=100;
438 armor=0;
439 for(a=0;a<ARMS;a++)
440 ammo[a]=0;
441 ammo[0]=weapon[0].basic_ammo;
442 current_weapon=0;
443 weapons=17; /* gun and grenades */
444 hero=new_obj(
445 get_int(packet+1), /* ID */
446 T_PLAYER, /* type */
447 0, /* time to live */
448 get_int16(packet+5), /* sprite */
449 0, /* position */
450 get_int16(packet+23), /* status */
451 get_float(packet+7), /* X */
452 get_float(packet+11), /* Y */
453 get_float(packet+15), /* XSPEED */
454 get_float(packet+19), /* YSPEED */
455 0
456 );
457 break;
458
459 default:
460 return "Connection error. Press ENTER.";
461 }
462 return 0;
463 }
464
465
466 /* send me top X players */
send_info_request(void)467 void send_info_request(void)
468 {
469 unsigned char packet;
470 packet=P_INFO;
471 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
472 }
473
474
475 /* I want to be born again */
send_reenter_game(void)476 void send_reenter_game(void)
477 {
478 unsigned char packet;
479 packet=P_REENTER_GAME;
480 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
481 }
482
483
484 /* send end of game to server */
end_game(void)485 void end_game(void)
486 {
487 unsigned char packet;
488 packet=P_END;
489 send_packet(&packet,1,(struct sockaddr*)(&server),my_id,0);
490 }
491
492
493 /* send chat message */
send_message(char * msg)494 void send_message(char *msg)
495 {
496 static unsigned char packet[MAX_MESSAGE_LENGTH+2];
497 int a;
498
499 a=strlen(msg)+1;
500 packet[0]=P_MESSAGE;
501 memcpy(packet+1,msg,a);
502 send_packet(packet,a+1,(struct sockaddr *)(&server),my_id,0);
503 }
504
505
506 /* send end of game to server */
send_keyboard(void)507 void send_keyboard(void)
508 {
509 unsigned char packet[3];
510 packet[0]=P_KEYBOARD;
511 packet[1]= keyboard_status.right|
512 (keyboard_status.left<<1)|
513 (keyboard_status.jump<<2)|
514 (keyboard_status.creep<<3)|
515 (keyboard_status.speed<<4)|
516 (keyboard_status.fire<<5)|
517 (keyboard_status.down_ladder<<6);
518 packet[2]= keyboard_status.weapon;
519 send_packet(packet,3,(struct sockaddr*)(&server),my_id,0);
520 }
521
522
reset_keyboard(void)523 void reset_keyboard(void)
524 {
525 keyboard_status.left=0;
526 keyboard_status.right=0;
527 keyboard_status.speed=0;
528 keyboard_status.jump=0;
529 keyboard_status.creep=0;
530 keyboard_status.fire=0;
531 keyboard_status.weapon=0;
532 keyboard_status.down_ladder=0;
533 }
534
535 /* recompute object positions */
update_game(void)536 void update_game(void)
537 {
538 struct object_list *p;
539 int w,h;
540 unsigned char stop_x,stop_y,sy;
541 unsigned long_long t;
542 my_double x,y,x1,y1,DELTA_TIME;
543
544 for(p=&objects;p->next;p=p->next)
545 {
546 if (p->next->member.type==T_NOTHING)continue;
547 if ((p->next->member.status)&1024)continue; /* dead player */
548 /* decrement time to live */
549 if (p->next->member.ttl>0)
550 {
551 p->next->member.ttl--;
552 if (!p->next->member.ttl)
553 {
554 if ((p->next->member.type)==T_PLAYER)p->next->member.status&=~16;
555 else
556 {
557 if (p->next->member.type!=T_GRENADE){ /* client's waiting for P_EXPLODE_GRENADE and doesn't delete the grenade yet */
558 p=p->prev;
559 delete_obj(p->next->next->member.id);
560 continue;}
561 }
562 }
563 }
564 /* maintain only objects that you are allowed to maintain */
565 if (!(obj_attr[p->next->member.type].maintainer&1))continue;
566
567
568 /* if not falling slow down x motion */
569 if (!(p->next->member.status&8))p->next->member.xspeed=mul(p->next->member.xspeed,obj_attr[p->next->member.type].slow_down_x);
570
571 /* fall */
572 if (obj_attr[p->next->member.type].fall)
573 {
574 p->next->member.status|=8;
575 p->next->member.yspeed+=FALL_ACCEL;
576 /* but not too fast */
577 if (p->next->member.yspeed>MAX_Y_SPEED)p->next->member.yspeed=MAX_Y_SPEED;
578 }
579
580 get_dimensions(p->next->member.type,p->next->member.status,sprites[p->next->member.sprite].positions,&w,&h);
581 x=p->next->member.x;
582 y=p->next->member.y;
583 t=get_time();
584 DELTA_TIME=float2double(((double)(long_long)(t-p->next->member.last_updated))/MICROSECONDS);
585 update_position(
586 &(p->next->member),
587 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
588 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
589 w,h,&stop_x,&stop_y);
590 p->next->member.last_updated=t;
591
592 /* walk up the stairs */
593 if (stop_x&&p->next->member.type==T_PLAYER&&!(p->next->member.status&256))
594 {
595 x1=p->next->member.x;
596 y1=p->next->member.y;
597 p->next->member.x=x;
598 p->next->member.y=y-int2double(1);
599 update_position(
600 &(p->next->member),
601 p->next->member.x+mul(p->next->member.xspeed,DELTA_TIME),
602 p->next->member.y+mul(p->next->member.yspeed,DELTA_TIME),
603 w,h,0,&sy);
604 if ((p->next->member.xspeed>0&&p->next->member.x<=x1)||(p->next->member.xspeed<0&&p->next->member.x>=x1)) /* restore original values */
605 {
606 p->next->member.x=x1;
607 p->next->member.y=y1;
608 }
609 else
610 {
611 stop_y=sy;
612 stop_x=0;
613 }
614 }
615
616 if (stop_x)p->next->member.xspeed=-mul(p->next->member.xspeed,obj_attr[p->next->member.type].bounce_x);
617 if (my_abs(p->next->member.xspeed)<MIN_X_SPEED)
618 {
619 p->next->member.xspeed=0;
620 p->next->member.status&=~1;
621 }
622
623
624 if (stop_y)
625 {
626 p->next->member.yspeed=mul(p->next->member.yspeed,obj_attr[p->next->member.type].bounce_y);
627 p->next->member.yspeed=-p->next->member.yspeed;
628 if (my_abs(p->next->member.yspeed)<MIN_Y_SPEED)
629 {
630 p->next->member.yspeed=0;
631 if (stop_y==1)p->next->member.status&=~8;
632 }
633 }
634
635 if ((p->next->member.type==T_SHRAPNEL||p->next->member.type==T_BULLET)&&(stop_x||stop_y)) /* bullet and shrapnel die crashing into wall */
636 {
637 p=p->prev; /* deleting object makes a great mess in for cycle, so we must cheat the cycle */
638 delete_obj(p->next->next->member.id);
639 continue;
640 }
641
642 }
643 }
644
645 #define FIRE_SHOOTING weapon[current_weapon].cadence-4+HOLD_GUN_AFTER_SHOOT
646
647 /* hero's next anim position when walking to the right */
_next_anim_right(int pos,int status,int ttl)648 int _next_anim_right(int pos,int status, int ttl)
649 {
650 int start,offset;
651
652 if (pos<=18)start=10; /* normal */
653 else
654 {
655 if (pos<=46)start=38; /* holding gun */
656 else
657 {
658 if (pos<=55)start=47; /* shooting */
659 else start=64; /* creeping */
660 }
661 }
662 offset=pos-start;
663
664 if (status&256)start=64; /* creeping */
665 else
666 {
667 if (status&16)
668 {
669 if (ttl>=FIRE_SHOOTING) start=47; /* shooting */
670 else start=38; /* holding a gun */
671 }
672 else start=10; /* normal */
673 }
674
675 return (status&256)?((offset+1)&7)+start:start+(offset&7)+1;
676 }
677
678
679 /* hero's next anim position when walking to the left */
_next_anim_left(int pos,int status,int ttl)680 int _next_anim_left(int pos,int status, int ttl)
681 {
682 int start,offset;
683
684 if (pos<=8)start=0; /* normal */
685 else
686 {
687 if (pos<=28)start=20; /* holding gun */
688 else
689 {
690 if (pos<=37)start=29; /* shooting */
691 else start=56; /* creeping */
692 }
693 }
694 offset=pos-start;
695
696 if (status&256)start=56; /* creeping */
697 else
698 {
699 if (status&16)
700 {
701 if (ttl>=FIRE_SHOOTING) start=29; /* shooting */
702 else start=20; /* holding a gun */
703 }
704 else start=0; /* normal */
705 }
706
707 return (status&256)?((offset+1)&7)+start:start+(offset&7)+1;
708 }
709
710
711 /* update hero animating position */
update_anim(struct it * obj)712 void update_anim(struct it* obj)
713 {
714 if (!(obj->status&1)) /* not walking */
715 switch((obj->status&6)>>1)
716 {
717 case 0: /* look at me */
718 obj->anim_pos=(obj->status&256)?72:9;
719 break;
720 case 1: /* look left */
721 if (obj->status&16)
722 {
723 if (obj->status&512)
724 {
725 if (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>1)+HOLD_GUN_AFTER_SHOOT))obj->anim_pos=73;
726 else
727 {
728 if (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>2)+HOLD_GUN_AFTER_SHOOT))obj->anim_pos=74;
729 else
730 {
731 if (obj->ttl>=HOLD_GUN_AFTER_SHOOT)obj->anim_pos=75;
732 else obj->anim_pos=0;
733 }
734 }
735 }
736 else
737 {
738 if (obj->ttl>=FIRE_SHOOTING)obj->anim_pos=29;
739 else obj->anim_pos=20;
740 }
741 }
742 else obj->anim_pos=0;
743 if (obj->status&256)obj->anim_pos=56;
744 break;
745 case 2: /* look right */
746 if (obj->status&16)
747 {
748 if (obj->status&512)
749 {
750 if (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>1)+HOLD_GUN_AFTER_SHOOT))obj->anim_pos=76;
751 else
752 {
753 if (obj->ttl>=((weapon[WEAPON_GRENADE].cadence>>2)+HOLD_GUN_AFTER_SHOOT))obj->anim_pos=77;
754 else
755 {
756 if (obj->ttl>=HOLD_GUN_AFTER_SHOOT)obj->anim_pos=78;
757 else obj->anim_pos=10;
758 }
759 }
760 }
761 else
762 {
763 if (obj->ttl>=FIRE_SHOOTING)obj->anim_pos=47;
764 else obj->anim_pos=38;
765 }
766 }
767 else obj->anim_pos=10;
768 if (obj->status&256)obj->anim_pos=64;
769 break;
770 }
771 else /* walking */
772 {
773 switch((obj->status&6)>>1)
774 {
775 case 1: /* walk left */
776 obj->anim_pos=_next_anim_left(obj->anim_pos,obj->status,obj->ttl);
777 break;
778
779 case 2: /* walk right */
780 obj->anim_pos=_next_anim_right(obj->anim_pos,obj->status,obj->ttl);
781 break;
782 }
783 }
784 }
785
786
787 /* draw scene into screenbuffer*/
draw_scene(void)788 void draw_scene(void)
789 {
790 struct object_list *p;
791 unsigned char fore;
792
793 #ifdef TRI_D
794 if (TRI_D_ON)
795 {
796 tri_d=1;
797 show_window(double2int(hero->x)-SCREEN_XOFFSET,double2int(hero->y)-SCREEN_YOFFSET);
798 tri_d=0;
799 }
800 #endif
801
802 show_window(double2int(hero->x)-SCREEN_XOFFSET,double2int(hero->y)-SCREEN_YOFFSET);
803 for (fore=0;fore<=1;fore++)
804 {
805 for(p=&objects;p->next;p=p->next)
806 {
807 if ((obj_attr[p->next->member.type].foreground)!=fore)continue;
808 if (&(p->next->member)==hero)continue;
809 if (p->next->member.type==T_PLAYER)update_anim(&(p->next->member));
810 else {p->next->member.anim_pos++;p->next->member.anim_pos%=sprites[p->next->member.sprite].n_steps;}
811 if (!(p->next->member.status&1024)&&!(p->next->member.status&64)) /* don't draw hidden objects and dead players */
812 {
813 #ifdef TRI_D
814 if(TRI_D_ON)
815 {
816 tri_d=1;
817 put_sprite(
818 double2int(p->next->member.x-hero->x)+fore+SCREEN_XOFFSET,
819 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET,
820 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],
821 1
822 );
823 tri_d=0;
824 }
825 #endif
826
827 put_sprite(
828 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET,
829 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET,
830 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],
831 1
832 );
833 }
834 if (p->next->member.type==T_PLAYER&&p->next->member.status&128) /* hit */
835 {
836 p->next->member.status&=~128;
837 if (!(p->next->member.status&1024)) /* don't draw blood splash to dead players */
838 {
839 #ifdef TRI_D
840 if (TRI_D_ON)
841 {
842 tri_d=1;
843 put_sprite(
844 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+fore+((int)(p->next->member.data)&255),
845 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+(((int)(p->next->member.data)>>8)&255),
846 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((int)p->next->member.data)>>16],
847 1
848 );
849 tri_d=0;
850 }
851 #endif
852
853 put_sprite(
854 double2int(p->next->member.x-hero->x)+SCREEN_XOFFSET+((int)(p->next->member.data)&255),
855 double2int(p->next->member.y-hero->y)+SCREEN_YOFFSET+(((int)(p->next->member.data)>>8)&255),
856 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((int)p->next->member.data)>>16],
857 1
858 );
859 }
860 }
861 }
862 if (obj_attr[T_PLAYER].foreground!=fore)continue;
863 update_anim(hero);
864 if ((hero->status)&1024)continue; /* don't draw dead hero */
865 #ifdef TRI_D
866 if (TRI_D_ON)
867 {
868 tri_d=1;
869 put_sprite(
870 SCREEN_XOFFSET,
871 SCREEN_YOFFSET,
872 sprites[hero->sprite].positions+sprites[hero->sprite].steps[hero->anim_pos],
873 1
874 );
875 tri_d=0;
876 }
877 #endif
878 put_sprite(
879 SCREEN_XOFFSET,
880 SCREEN_YOFFSET,
881 sprites[hero->sprite].positions+sprites[hero->sprite].steps[hero->anim_pos],
882 1
883 );
884 if (hero->status&128) /* hit */
885 {
886 hero->status&=~128;
887 #ifdef TRI_D
888 if (TRI_D_ON)
889 {
890 tri_d=1;
891 put_sprite(
892 SCREEN_XOFFSET+((int)(hero->data)&255),
893 SCREEN_YOFFSET+(((int)(hero->data)>>8)&255),
894 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((int)hero->data)>>16],
895 1
896 );
897 tri_d=0;
898 }
899 #endif
900 put_sprite(
901 SCREEN_XOFFSET+((int)(hero->data)&255),
902 SCREEN_YOFFSET+(((int)(hero->data)>>8)&255),
903 sprites[hit_sprite].positions+sprites[hit_sprite].steps[((int)hero->data)>>16],
904 1
905 );
906 }
907 }
908 }
909
910
change_level(void)911 void change_level(void)
912 {
913 unsigned char *LEVEL;
914 unsigned char txt[256];
915
916 clean_memory();
917 free_sprites(level_sprites_start);
918 reinit_area();
919
920 LEVEL=load_level(level_number);
921 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
922 load_sprites(txt);
923 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
924 load_data(txt);
925 mem_free(LEVEL);
926 }
927
928
929 /* returns number of read bytes */
process_packet(unsigned char * packet,int l)930 int process_packet(unsigned char *packet,int l)
931 {
932 int a,n=l;
933
934 switch(*packet)
935 {
936 case P_CHUNK:
937 for (a=1;a<l&&a<MAX_PACKET_LENGTH;a+=n)
938 n=process_packet(packet+a,l-a);
939 break;
940
941 case P_NEW_OBJ:
942 if (l<28)break; /* invalid packet */
943 n=28;
944 new_obj(
945 get_int(packet+1), /* ID */
946 packet[25], /* type */
947 get_int16(packet+26), /* time to live */
948 get_int16(packet+5), /* sprite */
949 0, /* anim position */
950 get_int16(packet+23), /* status */
951 get_float(packet+7), /* x */
952 get_float(packet+11), /* y */
953 get_float(packet+15), /* xspeed */
954 get_float(packet+19), /* yspeed */
955 0 /* data */
956 );
957 break;
958
959 case P_PLAYER_DELETED:
960 n=1;
961 *error_message=0;
962 return -1;
963
964 case P_DELETE_OBJECT:
965 if (l<5)break; /* invalid packet */
966 delete_obj(get_int(packet+1));
967 n=5;
968 break;
969
970 case P_UPDATE_OBJECT:
971 if (l<26)break; /* invalid packet */
972 {
973 struct object_list *p;
974
975 n=26;
976 p=find_in_table(get_int(packet+1));
977 if (!p)break;
978 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
979 p->member.update_counter=packet[5];
980 p->member.x=get_float(packet+6);
981 p->member.y=get_float(packet+10);
982 p->member.xspeed=get_float(packet+14);
983 p->member.yspeed=get_float(packet+18);
984 p->member.status=get_int16(packet+22);
985 p->member.data=0;
986 p->member.ttl=get_int16(packet+24);
987 /* kdyz tasi, tak se nahodi ttl */
988 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
989 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
990 }
991 break;
992
993 case P_UPDATE_OBJECT_POS:
994 if (l<22)break; /* invalid packet */
995 {
996 struct object_list *p;
997
998 n=22;
999 p=find_in_table(get_int(packet+1));
1000 if (!p)break;
1001 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1002 p->member.update_counter=packet[5];
1003 p->member.x=get_float(packet+6);
1004 p->member.y=get_float(packet+10);
1005 p->member.xspeed=get_float(packet+14);
1006 p->member.yspeed=get_float(packet+18);
1007 }
1008 break;
1009
1010 case P_UPDATE_OBJECT_SPEED:
1011 if (l<14)break; /* invalid packet */
1012 {
1013 struct object_list *p;
1014
1015 n=14;
1016 p=find_in_table(get_int(packet+1));
1017 if (!p)break;
1018 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1019 p->member.update_counter=packet[5];
1020 p->member.xspeed=get_float(packet+6);
1021 p->member.yspeed=get_float(packet+10);
1022 }
1023 break;
1024
1025 case P_UPDATE_OBJECT_COORDS:
1026 if (l<14)break; /* invalid packet */
1027 {
1028 struct object_list *p;
1029
1030 n=14;
1031 p=find_in_table(get_int(packet+1));
1032 if (!p)break;
1033 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1034 p->member.update_counter=packet[5];
1035 p->member.x=get_float(packet+6);
1036 p->member.y=get_float(packet+10);
1037 }
1038 break;
1039
1040 case P_UPDATE_OBJECT_SPEED_STATUS:
1041 if (l<16)break; /* invalid packet */
1042 {
1043 struct object_list *p;
1044
1045 n=16;
1046 p=find_in_table(get_int(packet+1));
1047 if (!p)break;
1048 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1049 p->member.update_counter=packet[5];
1050 p->member.xspeed=get_float(packet+6);
1051 p->member.yspeed=get_float(packet+10);
1052 p->member.status=get_int16(packet+14);
1053 /* kdyz tasi, tak se nahodi ttl */
1054 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
1055 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1056 }
1057 break;
1058
1059 case P_UPDATE_OBJECT_COORDS_STATUS:
1060 if (l<16)break; /* invalid packet */
1061 {
1062 struct object_list *p;
1063
1064 n=16;
1065 p=find_in_table(get_int(packet+1));
1066 if (!p)break;
1067 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1068 p->member.update_counter=packet[5];
1069 p->member.x=get_float(packet+6);
1070 p->member.y=get_float(packet+10);
1071 p->member.status=get_int16(packet+14);
1072 /* kdyz tasi, tak se nahodi ttl */
1073 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
1074 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1075 }
1076 break;
1077
1078 case P_UPDATE_OBJECT_SPEED_STATUS_TTL:
1079 if (l<18)break; /* invalid packet */
1080 {
1081 struct object_list *p;
1082
1083 n=18;
1084 p=find_in_table(get_int(packet+1));
1085 if (!p)break;
1086 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1087 p->member.update_counter=packet[5];
1088 p->member.xspeed=get_float(packet+6);
1089 p->member.yspeed=get_float(packet+10);
1090 p->member.status=get_int16(packet+14);
1091 p->member.ttl=get_int16(packet+16);
1092 /* kdyz tasi, tak se nahodi ttl */
1093 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
1094 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1095 }
1096 break;
1097
1098 case P_UPDATE_OBJECT_COORDS_STATUS_TTL:
1099 if (l<18)break; /* invalid packet */
1100 {
1101 struct object_list *p;
1102
1103 n=18;
1104 p=find_in_table(get_int(packet+1));
1105 if (!p)break;
1106 if(packet[5]-(p->member.update_counter)>127)break; /* throw out old updates */
1107 p->member.update_counter=packet[5];
1108 p->member.x=get_float(packet+6);
1109 p->member.y=get_float(packet+10);
1110 p->member.status=get_int16(packet+14);
1111 p->member.ttl=get_int16(packet+16);
1112 /* kdyz tasi, tak se nahodi ttl */
1113 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
1114 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1115 }
1116 break;
1117
1118 case P_UPDATE_STATUS:
1119 if (l<7)break; /* invalid packet */
1120 {
1121 struct object_list *p;
1122
1123 n=7;
1124 p=find_in_table(get_int(packet+1));
1125 if (!p)break; /* ignore objects we don't have */
1126 p->member.status=get_int16(packet+5);
1127 /* kdyz tasi, tak se nahodi ttl */
1128 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
1129 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1130 }
1131 break;
1132
1133 case P_HIT:
1134 if (l<8)break; /* invalid packet */
1135 {
1136 struct object_list *p;
1137
1138 n=8;
1139 p=find_in_table(get_int(packet+1));
1140 if (!p)break; /* ignore objects we don't have */
1141 p->member.status|=128;
1142 p->member.data=(void*)((packet[5]<<16)+(packet[7]<<8)+(packet[6]));
1143 /* kdyz tasi, tak se nahodi ttl */
1144 if (p->member.type==T_PLAYER&&(p->member.status&32)&&(p->member.status&16))
1145 p->member.ttl=weapon[current_weapon].cadence+HOLD_GUN_AFTER_SHOOT;
1146 }
1147 break;
1148
1149 case P_UPDATE_PLAYER:
1150 if (l<23)break; /* invalid packet */
1151 health=packet[1];
1152 armor=packet[2];
1153 for (a=0;a<ARMS;a++)
1154 ammo[a]=get_int16(packet+3+(a<<1));
1155 frags=get_int(packet+3+ARMS*2);
1156 deaths=get_int(packet+7+ARMS*2);
1157 current_weapon=packet[11+2*ARMS];
1158 weapons=packet[12+2*ARMS];
1159 n=23;
1160 break;
1161
1162 case P_MESSAGE:
1163 if (l<2)break; /* invalid packet */
1164 add_message(packet+1);
1165 n=2+strlen(packet+1);
1166 break;
1167
1168 case P_CHANGE_LEVEL:
1169 {
1170 unsigned char txt[256];
1171 unsigned char *name;
1172 unsigned char *md5;
1173 int a;
1174 char p;
1175
1176 if (l<38)break; /* invalid packet */
1177 a=get_int(packet+1);
1178 if (level_number==a)goto level_changed;
1179 level_number=a;
1180 snprintf(txt,256, "Trying to change level to number %d",level_number);
1181 add_message(txt);
1182 name=load_level(level_number);
1183 if (!name){snprintf(error_message,1024,"Cannot find level number %d. Game terminated. Press ENTER.", level_number);send_quit();return -1;}
1184 snprintf(txt,256,"Changing level to \"%s\"",name);
1185 mem_free(name);
1186 add_message(txt);
1187
1188 md5=md5_level(level_number);
1189 if (strcmp(md5,packet+5)) /* MD5s differ */
1190 {
1191 mem_free(md5);
1192 snprintf(error_message,1024,"Invalid MD5 sum. Can't change level. Game terminated. Press ENTER.");
1193 add_message("Invalid MD5 sum. Can't change level. Exiting...");
1194 send_quit();
1195 return -1;
1196 }
1197 mem_free(md5);
1198
1199 /* OK we can change it */
1200 change_level();
1201 level_changed:
1202
1203 p=P_LEVEL_ACCEPTED;
1204 send_packet(&p,1,(struct sockaddr *)(&server),my_id,0);
1205 n=38;
1206 }
1207 break;
1208
1209 case P_END:
1210 if (l<2)snprintf(error_message,1024,"Game terminated. Press ENTER.");
1211 else snprintf(error_message,1024,"Game terminated by %s. Press ENTER.",packet+1);
1212 return -1;
1213
1214 case P_BELL:
1215 n=1;
1216 c_bell();
1217 break;
1218
1219 case P_INFO:
1220 if (l<=5)break;
1221 active_players=get_int(packet+1);
1222 l=6;
1223 for (a=0;a<packet[5]&&a<TOP_PLAYERS_N;a++)
1224 {
1225 int x;
1226 top_players[a].frags=get_int(packet+l);
1227 top_players[a].deaths=get_int(packet+l+4);
1228 top_players[a].color=packet[l+8];
1229 x=strlen(packet+l+9)+1;
1230 memcpy(top_players[a].name,packet+l+9,x);
1231 l+=x+9;
1232 }
1233 n=l;
1234 break;
1235
1236 case P_EXPLODE_GRENADE:
1237 {
1238 unsigned int i,j;
1239 struct object_list *p;
1240 int b;
1241
1242 if (l<9)break;
1243 n=9;
1244 i=get_int(packet+1);
1245 j=get_int(packet+5);
1246 p=find_in_table(j);
1247 if (!p)break;
1248
1249 for (b=0;b<N_SHRAPNELS_EXPLODE;b++)
1250 {
1251 double angle=(double)b*2*M_PI/N_SHRAPNELS_EXPLODE;
1252 my_double spd=add_int(mul_int(my_and(mul_int(weapon[WEAPON_GRENADE].speed,b+1),15),16),100);
1253
1254 new_obj(
1255 i,
1256 T_SHRAPNEL,
1257 SHRAPNEL_TTL,
1258 shrapnel_sprite[random()%N_SHRAPNELS],
1259 0,
1260 WEAPON_GRENADE,
1261 p->member.x,
1262 p->member.y,
1263 p->member.xspeed+mul(spd,float2double(cos(angle))),
1264 p->member.yspeed+mul(spd,float2double(sin(angle))),
1265 0);
1266 i++;
1267 }
1268 delete_obj(j);
1269
1270 }
1271 break;
1272 }
1273 return n;
1274 }
1275
1276
1277 /* read packet from socket */
read_data(void)1278 int read_data(void)
1279 {
1280 fd_set rfds;
1281 struct timeval tv;
1282 struct sockaddr_in client;
1283 static unsigned char packet[MAX_PACKET_LENGTH];
1284 int a=sizeof(client);
1285 int l;
1286
1287 tv.tv_sec=0;
1288 tv.tv_usec=0;
1289 FD_ZERO(&rfds);
1290 FD_SET(fd,&rfds);
1291 while(select(fd+1,&rfds,0,0,&tv))
1292 {
1293 if ((l=recv_packet(packet,MAX_PACKET_LENGTH,(struct sockaddr*)(&client),&a,1,my_id,0))<0)
1294 return 0; /* something's strange */
1295 if (process_packet(packet,l)<0)return 1;
1296
1297 }
1298 return 0;
1299 }
1300
1301
1302 /* select color for numeric value (red=lack, yellow=edium, green=fill) */
select_color(int value,int max)1303 int select_color(int value,int max)
1304 {
1305 return value>=(max>>1)?10:(value>=(max>>2)?11:9);
1306 }
1307
1308
1309 /* draw board at the bottom of the screen */
draw_board(void)1310 void draw_board(void)
1311 {
1312 int offs=SCREEN_X*(SCREEN_Y-2);
1313 int space=(SCREEN_X-60)/5;
1314 char txt[16];
1315
1316 memset(screen_a+offs,4,SCREEN_X);
1317 memset(screen+offs,'-',SCREEN_X);
1318 memset(screen+offs+SCREEN_X,0,SCREEN_X);
1319 print2screen(0,SCREEN_Y-1,7,"HEALTH");
1320 sprintf(txt,"% 3d%%",health);
1321 print2screen(6,SCREEN_Y-1,select_color(health,100),txt);
1322
1323 print2screen(11+(space>>1),SCREEN_Y-2,4,",");
1324 print2screen(11+(space>>1),SCREEN_Y-1,4,"|");
1325 print2screen(11+space,SCREEN_Y-1,7,"FRAGS");
1326 sprintf(txt,"% 4d",frags);
1327 print2screen(11+space+6,SCREEN_Y-1,11,txt);
1328
1329 print2screen(21+space+(space>>1),SCREEN_Y-2,4,",");
1330 print2screen(21+space+(space>>1),SCREEN_Y-1,4,"|");
1331 print2screen(21+(space<<1),SCREEN_Y-1,7,"DEATHS");
1332 sprintf(txt,"% 4d",deaths);
1333 print2screen(21+(space<<1)+7,SCREEN_Y-1,11,txt);
1334
1335 print2screen(31+(space<<1)+(space>>1),SCREEN_Y-2,4,",");
1336 print2screen(31+(space<<1)+(space>>1),SCREEN_Y-1,4,"|");
1337 sprintf(txt,"%10s",weapon[current_weapon].name);
1338 print2screen(31+3*space,SCREEN_Y-1,11,txt);
1339
1340 print2screen(41+(3*space)+(space>>1),SCREEN_Y-2,4,",");
1341 print2screen(41+(3*space)+(space>>1),SCREEN_Y-1,4,"|");
1342 print2screen(41+(space<<2),SCREEN_Y-1,7,"AMMO");
1343 sprintf(txt,"% 4d",ammo[current_weapon]);
1344 print2screen(41+5+(space<<2),SCREEN_Y-1,select_color(ammo[current_weapon],weapon[current_weapon].max_ammo),txt);
1345
1346 print2screen(49+(space<<2)+(space>>1),SCREEN_Y-2,4,",");
1347 print2screen(49+(space<<2)+(space>>1),SCREEN_Y-1,4,"|");
1348 print2screen(49+5*space,SCREEN_Y-1,7,"ARMOR");
1349 sprintf(txt,"% 4d%%",armor);
1350 print2screen(49+5+5*space,SCREEN_Y-1,select_color(armor,100),txt);
1351 if ((hero->status)&64)print2screen(SCREEN_X-14,SCREEN_Y-2,11,"INVISIBILITY");
1352 if (autorun)print2screen(2,SCREEN_Y-2,15,"AUTORUN");
1353 if (autocreep)print2screen(10,SCREEN_Y-2,15,"AUTOCREEP");
1354 }
1355
1356
1357 /* read string from input, returns everytime, not when string's read */
read_str_online(int y,char * pointer,char * message,int max_len)1358 int read_str_online(int y,char *pointer,char *message, int max_len)
1359 {
1360 int a,b,c,shift=0;
1361
1362 a=strlen(message);
1363 b=strlen(pointer);
1364 c=SCREEN_X*y;
1365
1366 #ifdef TRI_D
1367 if (TRI_D_ON)
1368 {
1369 memcpy(screen2+c,message,a);
1370 memcpy(screen2+c+a,pointer,b);
1371 memset(screen2_a+c,15,a);
1372 memset(screen2_a+c+a,7,b);
1373 memset(screen2_a+c+a+b,0,SCREEN_X-b-a);
1374 }
1375 #endif
1376
1377 memcpy(screen+c,message,a);
1378 memcpy(screen+c+a,pointer,b);
1379 memset(screen_a+c,15,a);
1380 memset(screen_a+c+a,7,b);
1381 memset(screen_a+c+a+b,0,SCREEN_X-b-a);
1382
1383 c_update_kbd();
1384
1385 if (c_was_pressed(K_ESCAPE))
1386 {
1387 pointer[0]=0;
1388 return 2;
1389 }
1390 if (c_was_pressed(K_ENTER))
1391 {
1392 return 1;
1393 }
1394 if (c_pressed(K_BACKSPACE)&&b)
1395 {
1396 b--;
1397 pointer[b]=0;
1398 }
1399 shift=c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT);
1400 for (c=' ';c<128&&b<max_len;c++)
1401 if (c_was_pressed(c))
1402 {
1403 pointer[b]=shift?my_toupper(c):c;
1404 b++;
1405 pointer[b]=0;
1406 }
1407 return 0;
1408 }
1409
1410
1411 /* read number from input, returns everytime, not when number's read */
read_num_online(int y,char * pointer,char * message,int max_len)1412 int read_num_online(int y,char *pointer,char *message, int max_len)
1413 {
1414 int a,b,c;
1415
1416 a=strlen(message);
1417 b=strlen(pointer);
1418 c=SCREEN_X*y;
1419
1420 #ifdef TRI_D
1421 if (TRI_D_ON)
1422 {
1423 memcpy(screen2+c,message,a);
1424 memcpy(screen2+c+a,pointer,b);
1425 memset(screen2_a+c,15,a);
1426 memset(screen2_a+c+a,7,b);
1427 memset(screen2_a+c+a+b,0,SCREEN_X-b-a);
1428 }
1429 #endif
1430
1431 memcpy(screen+c,message,a);
1432 memcpy(screen+c+a,pointer,b);
1433 memset(screen_a+c,15,a);
1434 memset(screen_a+c+a,7,b);
1435 memset(screen_a+c+a+b,0,SCREEN_X-b-a);
1436
1437 c_update_kbd();
1438
1439 if (c_was_pressed(K_ESCAPE))
1440 {
1441 pointer[0]=0;
1442 return 2;
1443 }
1444 if (c_was_pressed(K_ENTER))
1445 {
1446 return 1;
1447 }
1448 if (c_pressed(K_BACKSPACE)&&b)
1449 {
1450 b--;
1451 pointer[b]=0;
1452 }
1453 for (c='0';c<='9'&&b<max_len;c++)
1454 if (c_was_pressed(c))
1455 {
1456 pointer[b]=c;
1457 b++;
1458 pointer[b]=0;
1459 }
1460 return 0;
1461 }
1462
1463
1464 /* load banner.dat */
load_banner(char ** banner)1465 void load_banner(char **banner)
1466 {
1467 FILE *s;
1468 char line[1025];
1469 int a,b;
1470
1471 s=fopen(DATA_PATH BANNER_FILE,"r");
1472 if (!s){shut_down(0);ERROR("Error: Can't load file \""DATA_PATH BANNER_FILE"\".\n");EXIT(1);}
1473 *banner=mem_alloc(1);
1474 **banner=0;
1475 if (!(*banner)){shut_down(0);ERROR("Error: Not enough memory.\n");EXIT(1);}
1476 while (fgets(line,1024,s))
1477 {
1478 if (line[strlen(line)-1]==10)line[strlen(line)-1]=0;
1479 if (line[strlen(line)-1]==13)line[strlen(line)-1]=0; /* crlf shit */
1480 a=strlen(*banner);
1481 b=strlen(line);
1482 *banner=mem_realloc((*banner),a+b+SCREEN_X+1);
1483 memcpy((*banner)+a,line,b);
1484 memset((*banner)+a+b,' ',SCREEN_X);
1485 (*banner)[a+b+SCREEN_X]=0;
1486 }
1487 fclose(s);
1488 }
1489
1490
1491 /* draw initial screen */
menu_screen(char * host,char * name,unsigned short * p,int * color)1492 void menu_screen(char *host,char *name,unsigned short *p,int *color)
1493 {
1494 char txt[8];
1495 int sprite,anim=0,title_anim=0,bulge_anim=0;
1496 unsigned long_long t;
1497 char port[MAX_PORT_LEN+1];
1498 int a=0;
1499 char *m;
1500 char *color_name[15]={"red","green","brown","blue","violet","cyan","gray","black","light red","light green","yellow","light blue","magenta","light cyan","white"};
1501 char *banner;
1502 int l,banner_pos=0;
1503 int help=0;
1504
1505 load_banner(&banner);
1506 l=strlen(banner);
1507 sprintf(port,"%d",*p);
1508 sprintf(txt,"hero%d",*color);
1509 if (find_sprite(txt,&sprite))
1510 {
1511 unsigned char msg[256];
1512 mem_free(banner);
1513 shut_down(0);
1514 snprintf(msg,256,"Error: Can't find sprite \"%s\".\n",txt);
1515 ERROR(msg);
1516 EXIT(1);
1517 }
1518
1519 cycle:
1520 t=get_time();
1521 clear_screen();
1522 #ifdef TRI_D
1523 if (TRI_D_ON)
1524 {
1525 tri_d=1;
1526 put_sprite((SCREEN_X+1-TITLE_WIDTH)>>1,0,sprites[title_sprite].positions+sprites[title_sprite].steps[title_anim],0);
1527 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);
1528 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);
1529 tri_d=0;
1530 }
1531 #endif
1532 put_sprite((SCREEN_X-TITLE_WIDTH)>>1,0,sprites[title_sprite].positions+sprites[title_sprite].steps[title_anim],0);
1533 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);
1534 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);
1535 print2screen(0,TITLE_HEIGHT+4,11,"N:");
1536 print2screen(1,TITLE_HEIGHT+4,2,"AME:");
1537 print2screen(6,TITLE_HEIGHT+4,7,name);
1538 print2screen(0,TITLE_HEIGHT+6,2,"COLOR:");
1539 print2screen(7,TITLE_HEIGHT+6,7,color_name[(*color-1)%15]);
1540 print2screen(0,TITLE_HEIGHT+0,11,"S");
1541 print2screen(1,TITLE_HEIGHT+0,2,"ERVER ADDRESS:");
1542 print2screen(16,TITLE_HEIGHT+0,7,host);
1543 print2screen(0,TITLE_HEIGHT+2,11,"P");
1544 print2screen(1,TITLE_HEIGHT+2,2,"ORT:");
1545 print2screen(6,TITLE_HEIGHT+2,7,port);
1546 print2screen((SCREEN_X-26)>>1,SCREEN_Y-3,7,"Use arrows to change color");
1547 print2screen((SCREEN_X-52)>>1,SCREEN_Y-2,7,"Press ENTER to connect, H for help, ESC or Q to quit");
1548 print2screen(0,SCREEN_Y-1,15,banner+(banner_pos>>1));
1549 banner_pos++;
1550 banner_pos%=l<<1;
1551 anim++;
1552 anim&=15;
1553 title_anim++;
1554 title_anim%=sprites[title_sprite].n_steps;
1555 bulge_anim++;
1556 bulge_anim%=sprites[bulge_sprite].n_steps;
1557 if (*error_message)
1558 {
1559 print2screen((SCREEN_X-strlen(error_message)>>1),SCREEN_Y-1,9,error_message);
1560
1561 #ifdef TRI_D
1562 if (TRI_D_ON)
1563 {
1564 tri_d=1;
1565 blit_screen(1);
1566 tri_d=0;
1567 }
1568
1569 #endif
1570 blit_screen(1);
1571 wait_for_enter();
1572 *error_message=0;
1573 goto cc1;
1574 }
1575 if (help)print_help_window();
1576 switch(a)
1577 {
1578 case 1:
1579 if (read_str_online(SCREEN_Y-1,name,"Enter your name: ",MAX_NAME_LEN))
1580 a=0;
1581 break;
1582
1583 case 3:
1584 if (read_str_online(SCREEN_Y-1,host,"Enter address: ",MAX_HOST_LEN))
1585 a=0;
1586 break;
1587
1588 case 2:
1589 if (read_num_online(SCREEN_Y-1,port,"Enter port: ",MAX_PORT_LEN))
1590 a=0;
1591 break;
1592 }
1593 c_update_kbd();
1594
1595 #ifdef TRI_D
1596 if (TRI_D_ON)
1597 {
1598 tri_d=1;
1599 blit_screen(1);
1600 tri_d=0;
1601 }
1602 #endif
1603
1604 blit_screen(1);
1605 if (!a)
1606 {
1607 if (c_was_pressed('+')||c_was_pressed('=')||c_was_pressed(K_UP)||c_was_pressed(K_RIGHT)||c_was_pressed(K_NUM_PLUS))
1608 {
1609 (*color)++;
1610 if (*color>30)(*color)=1;
1611 sprintf(txt,"hero%d",*color);
1612 if (find_sprite(txt,&sprite))
1613 {shut_down(0);mem_free(banner);fprintf(stderr,"Error: Can't find sprite \"%s\".\n",txt);}
1614 }
1615
1616 if (c_was_pressed('-')||c_was_pressed(K_NUM_MINUS)||c_was_pressed(K_DOWN)||c_was_pressed(K_LEFT))
1617 {
1618 (*color)--;
1619 if (*color<1)(*color)=30;
1620 sprintf(txt,"hero%d",*color);
1621 if (find_sprite(txt,&sprite))
1622 {shut_down(0);mem_free(banner);fprintf(stderr,"Error: Can't find sprite \"%s\".\n",txt);}
1623 }
1624
1625 if (c_was_pressed('h'))help^=1;
1626 if (c_was_pressed(K_ENTER))
1627 {
1628 save_cfg(host,name,*color);
1629 *p=strtol(port,0,10);
1630 if ((m=find_server(host,*p)))
1631 {
1632 print2screen((SCREEN_X-strlen(m)>>1),SCREEN_Y-1,9,m);
1633 #ifdef TRI_D
1634 if (TRI_D_ON)
1635 {
1636 tri_d=1;
1637 blit_screen(1);
1638 tri_d=0;
1639 }
1640 #endif
1641 blit_screen(1);
1642 wait_for_enter();
1643 goto cc1;
1644 }
1645 if ((m=init_socket()))
1646 {
1647 print2screen((SCREEN_X-strlen(m)>>1),SCREEN_Y-1,9,m);
1648 #ifdef TRI_D
1649 if (TRI_D_ON)
1650 {
1651 tri_d=1;
1652 blit_screen(1);
1653 tri_d=0;
1654 }
1655 #endif
1656 blit_screen(1);
1657 wait_for_enter();
1658 goto cc1;
1659 }
1660 if ((m=contact_server(*color,name)))
1661 {
1662 print2screen((SCREEN_X-strlen(m)>>1),SCREEN_Y-1,9,m);
1663 #ifdef TRI_D
1664 if (TRI_D_ON)
1665 {
1666 tri_d=1;
1667 blit_screen(1);
1668 tri_d=0;
1669 }
1670 #endif
1671 blit_screen(1);
1672 wait_for_enter();
1673 goto cc1;
1674 }
1675 mem_free(banner);
1676 return;
1677 }
1678 cc1:
1679 if (c_was_pressed('q')||c_was_pressed(K_ESCAPE))
1680 {
1681 save_cfg(host,name,*color);
1682 mem_free(banner);
1683 shut_down(1);
1684 }
1685
1686 if (c_was_pressed('n'))
1687 a=1;
1688
1689 if (c_was_pressed('a')||c_was_pressed('s'))
1690 a=3;
1691
1692 if (c_was_pressed('p'))
1693 a=2;
1694 }
1695 sleep_until(t+MENU_PERIOD_USEC);
1696 goto cycle;
1697 }
1698
1699
1700 /* handle fatal signal (sigabrt, sigsegv, ...) */
signal_handler(int signum)1701 void signal_handler(int signum)
1702 {
1703
1704 if (connected)send_quit();
1705 shut_down(0);
1706 #ifdef HAVE_PSIGNAL
1707 psignal(signum,"Exiting on signal");
1708 #else
1709 fprintf(stderr, "Exiting on signal: %d\n", signum);
1710 #endif
1711 EXIT(1);
1712 }
1713
1714
1715 /* change size of the screen */
sigwinch_handler(int signum)1716 void sigwinch_handler(int signum)
1717 {
1718 signum=signum;
1719 resize_screen();
1720 #ifdef WIN32
1721 c_shutdown();
1722 c_init(SCREEN_X,SCREEN_Y);
1723 #endif
1724 c_cls();
1725 c_refresh();
1726 #ifndef WIN32
1727 #ifdef SIGWINCH
1728 signal(SIGWINCH,sigwinch_handler);
1729 #endif
1730 #endif
1731 }
1732
1733
1734 /* print command line help */
print_help(void)1735 void print_help(void)
1736 {
1737 printf(
1738 "0verkill client"
1739 #ifdef XWINDOW
1740 " for X windows"
1741 #endif
1742 ".\n"
1743 "(c)2000 Brainsoft\n"
1744 "Usage: 0verkill [-h] [-3] [-s <width>x<height>]"
1745 #ifdef XWINDOW
1746 " [-d <display>] [-f <font name>]"
1747 #endif
1748 "\n"
1749 );
1750 }
1751
1752
parse_dimensions(char * txt)1753 void parse_dimensions(char *txt)
1754 {
1755 char *p;
1756 char *e;
1757 p=txt;
1758 for (p=txt;(*p)&&(*p)!='x';p++);
1759 if (!(*p)){ERROR("Error: Expected dimensions in form WIDTHxHEIGHT.\n");EXIT(1);}
1760 (*p)=0;
1761 p++;
1762 if (!strlen(txt)||!strlen(p)){fprintf(stderr,"Error: Decimal number expected.\n");EXIT(1);}
1763 SCREEN_X=strtoul(txt,&e,10);
1764 if (*e){ERROR("Error: Decimal number expected.\n");EXIT(1);}
1765 SCREEN_Y=strtoul(p,&e,10);
1766 if (*e){ERROR("Error: Decimal number expected.\n");EXIT(1);}
1767 set_size=1;
1768 }
1769
1770
parse_command_line(int argc,char ** argv)1771 void parse_command_line(int argc,char **argv)
1772 {
1773 int a;
1774
1775 while(1)
1776 {
1777 #ifdef TRI_D
1778
1779 #ifdef XWINDOW
1780 a=getopt(argc,argv,"3hl:f:d:s:");
1781 #endif
1782 #ifndef XWINDOW
1783 a=getopt(argc,argv,"3hl:s:");
1784 #endif
1785 #else
1786 #ifdef XWINDOW
1787 a=getopt(argc,argv,"hf:d:s:");
1788 #endif
1789 #ifndef XWINDOW
1790 a=getopt(argc,argv,"hs:");
1791 #endif
1792 #endif
1793 switch(a)
1794 {
1795 case EOF:
1796 return;
1797
1798 case '?':
1799 case ':':
1800 EXIT(1);
1801
1802 case 'h':
1803 print_help();
1804 EXIT(0);
1805
1806 #ifdef TRI_D
1807 case '3':
1808 TRI_D_ON=1;
1809 break;
1810 #endif
1811
1812 case 's':
1813 parse_dimensions(optarg);
1814 break;
1815 #ifdef XWINDOW
1816 case 'd':
1817 x_display_name=optarg;
1818 break;
1819
1820 case 'f':
1821 x_font_name=optarg;
1822 break;
1823 #endif
1824 }
1825 }
1826 }
1827
1828
1829 #define HALL_FAME_WIDTH (MAX_NAME_LEN+17)
1830 #define HALL_FAME_HEIGHT ((active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players)+5)
1831 #define HALL_FAME_X ((SCREEN_X-2-HALL_FAME_WIDTH)>>1)
1832 #define HALL_FAME_Y ((SCREEN_Y-2-HALL_FAME_HEIGHT)>>1)
1833
1834 /* draw window with top players */
print_hall_of_fame(void)1835 void print_hall_of_fame(void)
1836 {
1837 int a;
1838 char txt[32];
1839 unsigned char color;
1840
1841 if (!active_players)return;
1842 sprintf(txt,"TOP %d PLAYERS",TOP_PLAYERS_N);
1843 draw_frame(HALL_FAME_X,HALL_FAME_Y,HALL_FAME_WIDTH,HALL_FAME_HEIGHT,15);
1844 print2screen(HALL_FAME_X+1+((HALL_FAME_WIDTH-strlen(txt))>>1),HALL_FAME_Y+1,11,txt);
1845 print2screen(HALL_FAME_X+2,HALL_FAME_Y+3,15,"NAME");
1846 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+2,HALL_FAME_Y+3,15,"FRAGS");
1847 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+9,HALL_FAME_Y+3,15,"DEATHS");
1848 for (a=0;a<active_players&&a<TOP_PLAYERS_N;a++)
1849 {
1850 color=((top_players[a].color-1)%15)+1;
1851 print2screen(HALL_FAME_X+2,HALL_FAME_Y+4+a,color,top_players[a].name);
1852 sprintf(txt,"% 5d",top_players[a].frags);
1853 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+2,HALL_FAME_Y+4+a,color,txt);
1854 sprintf(txt,"% 5d",top_players[a].deaths);
1855 print2screen(HALL_FAME_X+2+MAX_NAME_LEN+9,HALL_FAME_Y+4+a,color,txt);
1856 }
1857 sprintf(txt,"%d",active_players);
1858 print2screen(HALL_FAME_X+2,HALL_FAME_Y+HALL_FAME_HEIGHT,11,"Players in the game:");
1859 print2screen(HALL_FAME_X+23,HALL_FAME_Y+HALL_FAME_HEIGHT,7,txt);
1860 }
1861
1862
play(void)1863 void play(void)
1864 {
1865 #ifdef PAUSE
1866 int p=0;
1867 #endif
1868 char string[80];
1869 unsigned char chat=0;
1870 unsigned char help=0;
1871 unsigned char hall_fame=0;
1872 unsigned long_long last_time;
1873
1874 last_time=get_time();
1875 while(1)
1876 {
1877 last_time+=CLIENT_PERIOD_USEC;
1878 if (get_time()-last_time>PERIOD_USEC*100)last_time=get_time();
1879 if (read_data())return; /* game terminated */
1880 #ifdef PAUSE
1881 if(!p)clear_screen();
1882 #else
1883 clear_screen();
1884 #endif
1885 update_game();
1886 #ifdef PAUSE
1887 if (!p)draw_scene();
1888 #else
1889 draw_scene();
1890 #endif
1891 update_messages(last_time);
1892 print_messages();
1893 if (chat)
1894 {
1895 switch (read_str_online(SCREEN_Y-3,string,"> ",78))
1896 {
1897 case 2:
1898 chat=0;
1899 break;
1900
1901 case 1:
1902 chat=0;
1903 send_message(string);
1904 break;
1905 }
1906 }
1907 if (help)print_help_window();
1908 if (hall_fame)print_hall_of_fame();
1909 draw_board();
1910
1911 #ifdef TRI_D
1912 if (TRI_D_ON)
1913 {
1914 tri_d=1;
1915 blit_screen(1);
1916 tri_d=0;
1917 }
1918 #endif
1919
1920 blit_screen(1);
1921
1922 creep=0;
1923 if (!chat)c_update_kbd();
1924
1925 #ifdef PAUSE
1926 if (c_was_pressed('p'))p^=1;
1927 #endif
1928 if (!chat&&c_was_pressed('r'))
1929 {
1930 c_cls();
1931 redraw_screen();
1932 }
1933 if (!chat&&c_was_pressed('h'))help^=1;
1934 if (!chat&&c_was_pressed(K_TAB))
1935 {
1936 hall_fame^=1;
1937 if (hall_fame)send_info_request();
1938 }
1939 if (c_was_pressed(K_CAPS_LOCK)||(!chat&&c_was_pressed('a')))autorun^=1;
1940 if (c_was_pressed(K_F10)||(!chat&&c_was_pressed('q')))
1941 {
1942 send_quit();
1943 *error_message=0;
1944 return;
1945 }
1946 if (c_pressed(K_F12))
1947 end_game();
1948
1949 if (!chat && c_was_pressed(K_ENTER))
1950 {
1951 memset(string,0,80);
1952 #ifdef WIN32
1953 c_update_kbd();
1954 c_was_pressed('d');
1955 #endif
1956 chat=1;
1957 }
1958 reset_keyboard();
1959 if (!chat&&c_was_pressed(' '))send_reenter_game();
1960 if (!chat&&c_was_pressed('c'))
1961 autocreep^=1;
1962 if (c_pressed(K_DOWN)||autocreep)
1963 keyboard_status.creep=1;
1964 if (c_pressed(K_UP))
1965 keyboard_status.jump=1;
1966 if (c_pressed(K_LEFT_CTRL)||c_pressed(K_RIGHT_CTRL)||(!chat&&c_pressed('z')))
1967 keyboard_status.fire=1;
1968 if (!chat && c_pressed('d'))
1969 keyboard_status.down_ladder=1;
1970 if (!chat && c_was_pressed('1'))
1971 keyboard_status.weapon=1;
1972 if (!chat && c_was_pressed('2'))
1973 keyboard_status.weapon=2;
1974 if (!chat && c_was_pressed('3'))
1975 keyboard_status.weapon=3;
1976 if (!chat && c_was_pressed('4'))
1977 keyboard_status.weapon=4;
1978 if (!chat && c_was_pressed('5'))
1979 keyboard_status.weapon=5;
1980 if (c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT)||autorun)
1981 keyboard_status.speed=1;
1982 if (c_pressed(K_LEFT))
1983 keyboard_status.left=1;
1984 if (c_pressed(K_RIGHT))
1985 keyboard_status.right=1;
1986
1987 send_keyboard();
1988 sleep_until(last_time+CLIENT_PERIOD_USEC);
1989 }
1990 }
1991
1992 /*----------------------------------------------------------------------------*/
main(int argc,char ** argv)1993 int main(int argc,char **argv)
1994 {
1995 unsigned short port=DEFAULT_PORT;
1996 int color=1;
1997 char host[MAX_HOST_LEN+1];
1998 char name[MAX_NAME_LEN+1];
1999 int a;
2000 unsigned char txt[256];
2001
2002
2003 #ifdef WIN32
2004 WSADATA wd;
2005
2006 WSAStartup(0x101, &wd);
2007 printf("Started WinSock version %X.%02X\n", wd.wVersion/0x100, wd.wVersion&0xFF);
2008 #endif
2009
2010
2011 #ifdef XWINDOW
2012 x_display_name=0;
2013 x_font_name=0;
2014 #endif
2015
2016 last_message=-1;
2017 autorun=0;
2018 autocreep=0;
2019 memset(host,0,MAX_HOST_LEN+1);
2020 memset(name,0,MAX_NAME_LEN+1);
2021 load_cfg(host,name,&color);
2022 last_obj=&objects;
2023 *error_message=0;
2024
2025 parse_command_line(argc,argv);
2026 hash_table_init();
2027 if (!set_size)c_get_size(&SCREEN_X,&SCREEN_Y);
2028 init_sprites();
2029 init_area();
2030 load_sprites(DATA_PATH GAME_SPRITES_FILE);
2031 /* sprites are stored in memory in this order: game sprites (players,
2032 * bullets, corpses, blood, meat...) followed by level sprites
2033 */
2034
2035 level_sprites_start=n_sprites;
2036 if (find_sprite("hit",&hit_sprite)){ERROR("Error: Can't find sprite \"hit\".\n");EXIT(1);}
2037 if (find_sprite("title",&title_sprite)){ERROR("Error: Can't find sprite \"title\".\n");EXIT(1);}
2038 if (find_sprite("bulge",&bulge_sprite)){ERROR("Error: Can't find sprite \"bulge\".\n");EXIT(1);}
2039 for (a=0;a<N_SHRAPNELS;a++)
2040 {
2041 sprintf(txt,"shrapnel%d",a+1);
2042 if (find_sprite(txt,&shrapnel_sprite[a])){fprintf(stderr,"Can't find sprite \"%s\".\n",txt);EXIT(1);}
2043 }
2044
2045 signal(SIGINT,signal_handler);
2046 signal(SIGTERM,signal_handler);
2047 signal(SIGILL,signal_handler);
2048 signal(SIGABRT,signal_handler);
2049 signal(SIGFPE,signal_handler);
2050 signal(SIGSEGV,signal_handler);
2051 #ifndef WIN32
2052 signal(SIGQUIT,signal_handler);
2053 signal(SIGBUS,signal_handler);
2054 #ifdef SIGWINCH
2055 signal(SIGWINCH,sigwinch_handler);
2056 #endif
2057 #endif
2058 c_init(SCREEN_X,SCREEN_Y);
2059 c_cls();
2060 c_cursor(C_HIDE);
2061 c_refresh();
2062 while(1)
2063 {
2064 level_number=-1;
2065 connected=0;
2066 menu_screen(host,name,&port,&color);
2067 connected=1;
2068 play();
2069 clean_memory();
2070 delete_obj(hero->id);
2071 }
2072 }
2073