1 /* When compiling with X support don't forget to define XWINDOW symbol */
22 #ifdef HAVE_SYS_SELECT_H
23 #include <sys/select.h>
29 #ifdef TIME_WITH_SYS_TIME
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
83 #define OVERRIDE_FLAG_HOST 0x01
84 #define OVERRIDE_FLAG_NAME 0x02
85 #define OVERRIDE_FLAG_PORT 0x04
86 #define OVERRIDE_FLAG_COLOR 0x08
91 char host
[MAX_HOST_LEN
+1];
92 char name
[MAX_NAME_LEN
+1];
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
;
109 unsigned char autorun
,autocreep
;
112 /* connection with server */
119 struct sockaddr_in server
; /* server address */
122 struct object_list objects
;
123 struct object_list
*last_obj
;
126 /* important sprites */
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 */
138 /* top players table */
141 char name
[MAX_NAME_LEN
+1];
144 }top_players
[TOP_PLAYERS_N
];
146 /* # of active players in the game */
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
;
167 unsigned long_long time
;
170 }msg_line
[N_MESSAGES
];
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
)
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)
212 while (!c_was_pressed(K_ENTER
))
220 /* load configure file from player's home directory */
221 int read_cfg_entry(FILE *stream
, char *retval
, int len
)
224 if (!fgets(retval
,len
+2,stream
))
227 if (retval
[l
-1] == 10)
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
));
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.";
246 int load_cfg(struct config
*cfg
)
253 snprintf(txt
, sizeof(txt
), "%s/%s",getenv("HOME"),CFG_FILE
);
254 stream
=fopen(txt
,"r");
256 snprintf(txt
, sizeof(txt
), "./%s", CFG_FILE
);
257 fopen_s(&stream
, txt
, "r");
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);
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);
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);
275 return load_default_cfg(cfg
, 4);
277 if (a
= read_cfg_entry(stream
, txt
, 4))
278 cfg
->color
= strtol(txt
,0,10);
280 return load_default_cfg(cfg
, 5);
287 /* save configure file to player's home */
288 void save_cfg(struct config
*cfg
)
293 memcpy(&dcfg
, cfg
, sizeof(struct config
));
296 snprintf(txt
, sizeof(txt
), "%s/%s",getenv("HOME"),CFG_FILE
);
298 snprintf(txt
, sizeof(txt
), "./%s",CFG_FILE
);
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
;
313 stream
=fopen(txt
,"w");
315 fopen_s(&stream
, txt
, "w");
319 fprintf(stream
, "%s\n%s\n%d\n%d\n", dcfg
.host
, dcfg
.name
,
320 dcfg
.port
, dcfg
.color
);
325 void scroll_messages(void)
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;
343 void add_message(char *message
, unsigned char flags
)
346 if (last_message
== N_MESSAGES
- 1)
348 last
= last_message
+ 1;
349 msg_line
[last
].time
= get_time() + MESSAGE_TTL
;
352 msg_line
[last
].color
= C_YELLOW
;
355 msg_line
[last
].color
= C_CYAN
;
358 msg_line
[last
].color
= C_GREEN
;
361 msg_line
[last
].color
= C_D_RED
;
364 msg_line
[last
].color
= C_GREY
;
367 msg_line
[last
].color
= C_BLUE
;
370 msg_line
[last
].color
= C_MAGENTA
;
373 msg_line
[last
].color
= C_RED
;
376 msg_line
[last
].color
= MESSAGE_COLOR
;
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);
387 void print_messages(void)
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
)
400 for(a
=0,b
=0;a
<=last_message
;a
++)
401 if (msg_line
[b
].time
<=time
)scroll_messages();
406 /* destroys all objects and messages */
407 void clean_memory(void)
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
);
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;
425 /* shut down the client */
426 void shut_down(int x
)
428 struct object_list
*o
;
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;
447 free_packet_buffer();
448 check_memory_leaks();
453 /* find address of server and fill the server address structure */
454 char * find_server(struct config
*cfg
)
458 h
=gethostbyname(cfg
->host
);
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]));
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";
480 /* send quit request to server */
486 int a
=sizeof(server
);
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
;
506 void server_error(char *msg
, int err
)
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;
528 packet
[0]=P_NEW_PLAYER
;
530 packet
[2]=VERSION_MAJOR
;
531 packet
[3]=VERSION_MINOR
;
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
);
542 if ((r
=recv_packet(packet
,256,0,0,1,0,0))<0)
545 server_error("Server hung up. Press ENTER.", E_CONN
);
548 server_error("Connection error. Press ENTER.", E_CONN
);
555 case P_PLAYER_REFUSED
:
558 case E_INCOMPATIBLE_VERSION
:
559 server_error("Incompatible client version. Connection refused. Press Enter.", E_CONN
);
563 server_error("Another player on this server uses the same name. Press Enter.", E_CONN
);
565 server_error("Connection refused. Press ENTER.", E_CONN
);
569 case P_PLAYER_ACCEPTED
:
570 my_id
=get_int(packet
+35);
573 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN
);
578 if (maj
!=VERSION_MAJOR
||min
<MIN_SERVER_VERSION_MINOR
) {
580 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN
);
583 game_start_offset
=get_time();
584 game_start_offset
-=get_long_long(packet
+27);
589 ammo
[WEAPON_GUN
]=weapon
[WEAPON_GUN
].basic_ammo
;
590 ammo
[WEAPON_CHAINSAW
]=weapon
[WEAPON_CHAINSAW
].basic_ammo
;
592 weapons
=WEAPON_MASK_GUN
|
593 WEAPON_MASK_GRENADE
|
594 WEAPON_MASK_CHAINSAW
|
595 WEAPON_MASK_BLOODRAIN
; /* gun, grenades, chainsaw and blodrain */
597 get_int(packet
+1), /* ID */
599 0, /* time to live */
600 get_int16(packet
+5), /* sprite */
602 get_int(packet
+23), /* status */
603 get_int(packet
+7), /* X */
604 get_int(packet
+11), /* Y */
605 get_int(packet
+15), /* XSPEED */
606 get_int(packet
+19), /* YSPEED */
612 server_error("Connection error. Press ENTER.", E_CONN
);
616 #ifdef HAVE_LIBPTHREAD
626 /* send me top X players */
627 void send_info_request(void)
631 send_packet(&packet
,1,(struct sockaddr
*)(&server
),my_id
,0);
635 /* I want to be born again */
636 void send_reenter_game(void)
639 packet
=P_REENTER_GAME
;
640 send_packet(&packet
,1,(struct sockaddr
*)(&server
),my_id
,0);
644 /* send end of game to server */
649 send_packet(&packet
,1,(struct sockaddr
*)(&server
),my_id
,0);
653 /* send chat message */
654 void send_message(char *msg
, char flags
)
656 static char packet
[MAX_MESSAGE_LENGTH
+ 2];
659 len
= strlen(msg
) + 1;
660 packet
[0] = P_MESSAGE
;
662 memcpy(packet
+ 2, msg
, len
);
663 send_packet(packet
, len
+ 2, (struct sockaddr
*)(&server
), my_id
, 0);
667 /* send end of game to server */
668 void send_keyboard(void)
671 packet
[0]=P_KEYBOARD
;
672 packet
[1]=keyboard_status
.status
;
673 packet
[2]=keyboard_status
.weapon
;
674 send_packet(packet
,3,(struct sockaddr
*)(&server
),my_id
,0);
678 void reset_keyboard(void)
680 keyboard_status
.status
=0;
681 keyboard_status
.weapon
=0;
684 /* recompute object positions */
685 void update_game(void)
687 struct object_list
*p
;
689 unsigned char stop_x
,stop_y
,sy
;
690 unsigned long_long t
;
691 int x
,y
,x1
,y1
,DELTA_TIME
;
693 for(p
=&objects
;p
->next
;p
=p
->next
)
695 if (p
->next
->member
.type
==T_NOTHING
)
697 if (p
->next
->member
.status
& S_DEAD
)
698 continue; /* dead player */
699 /* decrement time to live */
700 if (p
->next
->member
.ttl
>0)
702 p
->next
->member
.ttl
--;
703 if (!p
->next
->member
.ttl
)
705 if ((p
->next
->member
.type
)==T_PLAYER
)
706 p
->next
->member
.status
&= ~S_SHOOTING
;
709 if (p
->next
->member
.type
!=T_GRENADE
&&
710 p
->next
->member
.type
!=T_BFGCELL
){ /* client's waiting for P_EXPLODE_GRENADE and doesn't delete the grenade yet */
712 delete_obj(p
->next
->next
->member
.id
);
717 /* maintain only objects that you are allowed to maintain */
718 if (!(obj_attr
[p
->next
->member
.type
].maintainer
&1))continue;
721 /* if not falling slow down x motion */
722 if (!(p
->next
->member
.status
& S_FALLING
))
723 p
->next
->member
.xspeed
=mul(p
->next
->member
.xspeed
,obj_attr
[p
->next
->member
.type
].slow_down_x
);
726 if (obj_attr
[p
->next
->member
.type
].fall
)
728 p
->next
->member
.status
|= S_FALLING
;
729 p
->next
->member
.yspeed
+=FALL_ACCEL
;
730 /* but not too fast */
731 if (p
->next
->member
.yspeed
>MAX_Y_SPEED
)p
->next
->member
.yspeed
=MAX_Y_SPEED
;
734 get_dimensions(p
->next
->member
.type
,p
->next
->member
.status
,sprites
[p
->next
->member
.sprite
].positions
,&w
,&h
);
738 DELTA_TIME
=float2double(((double)(long_long
)(t
-p
->next
->member
.last_updated
))/MICROSECONDS
);
741 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
742 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
743 w
,h
,&stop_x
,&stop_y
);
744 p
->next
->member
.last_updated
=t
;
746 /* walk up the stairs */
747 if (stop_x
&&p
->next
->member
.type
==T_PLAYER
&&!(p
->next
->member
.status
& S_CREEP
))
749 x1
=p
->next
->member
.x
;
750 y1
=p
->next
->member
.y
;
752 p
->next
->member
.y
=y
-int2double(1);
755 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
756 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
758 if ((p
->next
->member
.xspeed
>0&&p
->next
->member
.x
<=x1
)||(p
->next
->member
.xspeed
<0&&p
->next
->member
.x
>=x1
)) /* restore original values */
760 p
->next
->member
.x
=x1
;
761 p
->next
->member
.y
=y1
;
771 p
->next
->member
.xspeed
=-mul(p
->next
->member
.xspeed
,obj_attr
[p
->next
->member
.type
].bounce_x
);
772 if (my_abs(p
->next
->member
.xspeed
)<MIN_X_SPEED
)
774 p
->next
->member
.xspeed
=0;
775 p
->next
->member
.status
&= ~S_WALKING
;
781 p
->next
->member
.yspeed
=mul(p
->next
->member
.yspeed
,obj_attr
[p
->next
->member
.type
].bounce_y
);
782 p
->next
->member
.yspeed
=-p
->next
->member
.yspeed
;
783 if (my_abs(p
->next
->member
.yspeed
)<MIN_Y_SPEED
)
785 p
->next
->member
.yspeed
=0;
786 if (stop_y
==1)p
->next
->member
.status
&= ~S_FALLING
;
790 if ((p
->next
->member
.type
== T_SHRAPNEL
|| p
->next
->member
.type
== T_BULLET
||
791 p
->next
->member
.type
== T_BFGCELL
|| p
->next
->member
.type
== T_CHAIN
||
792 p
->next
->member
.type
== T_JETFIRE
) &&
793 (stop_x
|| stop_y
)) { /* bullet and shrapnel die crashing into wall */
794 p
=p
->prev
; /* deleting object makes a great mess in for cycle, so we must cheat the cycle */
795 delete_obj(p
->next
->next
->member
.id
);
802 #define FIRE_SHOOTING weapon[current_weapon].cadence-4+HOLD_GUN_AFTER_SHOOT
804 /* hero's next anim position when walking to the right */
805 int _next_anim_right(int pos
,int status
, int ttl
)
810 start
=10; /* normal */
813 if (pos
<=46)start
=(status
& S_CHAINSAW
)?97:38; /* holding gun */
816 if (pos
<=55)start
=(status
& S_CHAINSAW
)?106:47; /* shooting */
817 else start
=64; /* creeping */
822 if (status
& S_CREEP
)
823 start
=64; /* creeping */
826 if (status
& S_SHOOTING
)
828 if (ttl
>=FIRE_SHOOTING
) start
=(status
& S_CHAINSAW
)?106:47; /* shooting */
829 else start
=(status
& S_CHAINSAW
)?97:38; /* holding a gun */
831 else start
=10; /* normal */
834 return (status
& S_CREEP
)?((offset
+1)&7)+start
:start
+(offset
&7)+1;
838 /* hero's next anim position when walking to the left */
839 int _next_anim_left(int pos
,int status
, int ttl
)
843 if (pos
<=8)start
=0; /* normal */
846 if (pos
<=28)start
=(status
& S_CHAINSAW
)?79:20; /* holding gun */
849 if (pos
<=37)start
=(status
& S_CHAINSAW
)?88:29; /* shooting */
850 else start
=56; /* creeping */
855 if (status
& S_CREEP
)
856 start
=56; /* creeping */
859 if (status
& S_SHOOTING
)
861 if (ttl
>=FIRE_SHOOTING
) start
=(status
& S_CHAINSAW
)?88:29; /* shooting */
862 else start
=(status
& S_CHAINSAW
)?79:20; /* holding a gun */
864 else start
=0; /* normal */
867 return (status
& S_CREEP
)?((offset
+1)&7)+start
:start
+(offset
&7)+1;
871 /* update hero animating position */
872 void update_anim(struct it
* obj
)
874 if (!(obj
->status
& S_WALKING
)) /* not walking */
875 switch((obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
)))
877 case 0: /* look at me */
878 obj
->anim_pos
=(obj
->status
& S_CREEP
)?72:9;
880 case S_LOOKLEFT
: /* look left */
881 if (obj
->status
& S_SHOOTING
)
883 if (obj
->status
& S_GRENADE
)
884 obj
->anim_pos
= (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>1)+HOLD_GUN_AFTER_SHOOT
)) ?
885 73 : (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>2)+HOLD_GUN_AFTER_SHOOT
)) ?
886 74 : ((obj
->ttl
>=HOLD_GUN_AFTER_SHOOT
) ? 75 : 0);
887 else if (obj
->status
& S_CHAINSAW
) /* maniak ma motorovku */
888 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 88 : 79;
890 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 29 : 20;
893 if (obj
->status
& S_CREEP
)
896 case S_LOOKRIGHT
: /* look right */
897 if (obj
->status
& S_SHOOTING
)
899 if (obj
->status
& S_GRENADE
)
900 obj
->anim_pos
= (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>1)+HOLD_GUN_AFTER_SHOOT
)) ?
901 76 : (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>2)+HOLD_GUN_AFTER_SHOOT
)) ?
902 77 : ((obj
->ttl
>=HOLD_GUN_AFTER_SHOOT
) ? 78 : 10);
903 else if (obj
->status
& S_CHAINSAW
) /* maniak ma motorovku */
904 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 106 : 97;
906 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 47 : 38;
909 if (obj
->status
& S_CREEP
)
915 switch (obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
))
917 case S_LOOKLEFT
: /* walk left */
918 obj
->anim_pos
=_next_anim_left(obj
->anim_pos
,obj
->status
,obj
->ttl
);
921 case S_LOOKRIGHT
: /* walk right */
922 obj
->anim_pos
=_next_anim_right(obj
->anim_pos
,obj
->status
,obj
->ttl
);
929 /* draw scene into screenbuffer*/
930 void draw_scene(void)
932 struct object_list
*p
;
939 show_window(double2int(hero
->x
)-SCREEN_XOFFSET
,double2int(hero
->y
)-SCREEN_YOFFSET
);
944 show_window(double2int(hero
->x
)-SCREEN_XOFFSET
,double2int(hero
->y
)-SCREEN_YOFFSET
);
945 for (fore
=0;fore
<=1;fore
++)
947 for(p
=&objects
;p
->next
;p
=p
->next
)
949 if ((obj_attr
[p
->next
->member
.type
].foreground
)!=fore
)continue;
950 if (&(p
->next
->member
)==hero
)continue;
951 if (p
->next
->member
.type
==T_PLAYER
)update_anim(&(p
->next
->member
));
952 else {p
->next
->member
.anim_pos
++;p
->next
->member
.anim_pos
%=sprites
[p
->next
->member
.sprite
].n_steps
;}
953 if (p
->next
->member
.status
== WEAPON_CHAINSAW
) continue;
954 if (!(p
->next
->member
.status
& S_DEAD
)&&!(p
->next
->member
.status
& S_INVISIBLE
)) /* don't draw hidden objects and dead players */
961 double2int(p
->next
->member
.x
-hero
->x
)+fore
+SCREEN_XOFFSET
,
962 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
,
963 sprites
[p
->next
->member
.sprite
].positions
+sprites
[p
->next
->member
.sprite
].steps
[p
->next
->member
.anim_pos
],
971 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
,
972 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
,
973 sprites
[p
->next
->member
.sprite
].positions
+sprites
[p
->next
->member
.sprite
].steps
[p
->next
->member
.anim_pos
],
977 if (p
->next
->member
.type
== T_PLAYER
) {
978 if ((p
->next
->member
.status
& S_JETPACK_ON
) && !(p
->next
->member
.status
& S_CREEP
)) {
979 if (p
->next
->member
.status
& S_LOOKRIGHT
)
981 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
-1,
982 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+4,
983 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[1], 1);
984 else if (p
->next
->member
.status
& S_LOOKLEFT
)
986 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+PLAYER_WIDTH
-4,
987 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+4,
988 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[0], 1);
990 if ((gsbi
+= 10) > 1000) {
994 if (p
->next
->member
.status
& S_ONFIRE
) {
995 if (p
->next
->member
.status
& S_CREEP
)
997 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
-5,
998 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
-2,
999 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3 + 3], 1);
1002 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+3,
1003 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
-3,
1004 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3], 1);
1006 if ((p
->next
->member
.status
& S_CHAINSAW
) && (p
->next
->member
.ttl
>= FIRE_SHOOTING
) && !(hero
->status
& S_CREEP
)) {
1007 if (p
->next
->member
.status
& S_LOOKRIGHT
)
1009 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+15,
1010 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+6,
1011 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1012 else if (p
->next
->member
.status
& S_LOOKLEFT
)
1014 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
-8,
1015 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+6,
1016 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1020 if (p
->next
->member
.type
==T_PLAYER
&&p
->next
->member
.status
& S_HIT
) /* hit */
1022 p
->next
->member
.status
&= ~S_HIT
;
1023 if (!(p
->next
->member
.status
& S_DEAD
)) /* don't draw blood splash to dead players */
1030 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+fore
+((long)(p
->next
->member
.data
)&255),
1031 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+(((long)(p
->next
->member
.data
)>>8)&255),
1032 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)p
->next
->member
.data
)>>16],
1040 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+((long)(p
->next
->member
.data
)&255),
1041 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+(((long)(p
->next
->member
.data
)>>8)&255),
1042 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)p
->next
->member
.data
)>>16],
1048 if (obj_attr
[T_PLAYER
].foreground
!=fore
)continue;
1050 if (hero
->status
& S_DEAD
)
1051 continue; /* don't draw dead hero */
1059 sprites
[hero
->sprite
].positions
+sprites
[hero
->sprite
].steps
[hero
->anim_pos
],
1068 sprites
[hero
->sprite
].positions
+sprites
[hero
->sprite
].steps
[hero
->anim_pos
],
1072 if ((hero
->status
& S_JETPACK_ON
) && !(hero
->status
& S_CREEP
)) {
1073 if (hero
->status
& S_LOOKRIGHT
)
1074 put_sprite(SCREEN_XOFFSET
-1, SCREEN_YOFFSET
+4,
1075 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[1], 1);
1076 else if (hero
->status
& S_LOOKLEFT
)
1077 put_sprite(SCREEN_XOFFSET
+PLAYER_WIDTH
-4, SCREEN_YOFFSET
+4,
1078 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[0], 1);
1080 if ((gsbi
+= 10) > 1000) {
1084 if (hero
->status
& S_ONFIRE
) {
1085 if (hero
->status
& S_CREEP
)
1086 put_sprite(SCREEN_XOFFSET
-5, SCREEN_YOFFSET
-2,
1087 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3 + 3], 1);
1089 put_sprite(SCREEN_XOFFSET
+3, SCREEN_YOFFSET
-3,
1090 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3], 1);
1092 if ((hero
->status
& S_CHAINSAW
) && (hero
->ttl
>= FIRE_SHOOTING
) && !(hero
->status
& S_CREEP
)) {
1093 if (hero
->status
& S_LOOKRIGHT
)
1094 put_sprite(SCREEN_XOFFSET
+15, SCREEN_YOFFSET
+6,
1095 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1096 else if (hero
->status
& S_LOOKLEFT
)
1097 put_sprite(SCREEN_XOFFSET
-8, SCREEN_YOFFSET
+6,
1098 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1100 if (hero
->status
& S_HIT
) /* hit */
1102 hero
->status
&= ~S_HIT
;
1108 SCREEN_XOFFSET
+((long)(hero
->data
)&255),
1109 SCREEN_YOFFSET
+(((long)(hero
->data
)>>8)&255),
1110 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)hero
->data
)>>16],
1117 SCREEN_XOFFSET
+((long)(hero
->data
)&255),
1118 SCREEN_YOFFSET
+(((long)(hero
->data
)>>8)&255),
1119 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)hero
->data
)>>16],
1127 void change_level(void)
1133 free_sprites(level_sprites_start
);
1136 LEVEL
=load_level(level_number
);
1137 snprintf(txt
,sizeof(txt
),"%s%s%s",DATA_PATH
,LEVEL
,LEVEL_SPRITES_SUFFIX
);
1139 snprintf(txt
,sizeof(txt
),"%s%s%s",DATA_PATH
,LEVEL
,STATIC_DATA_SUFFIX
);
1145 /* returns number of read bytes */
1146 int process_packet(char *packet
,int l
)
1153 for (a
=1;a
<l
&&a
<MAX_PACKET_LENGTH
;a
+=n
)
1154 n
=process_packet(packet
+a
,l
-a
);
1158 if (l
< (n
=30))break; /* invalid packet */
1160 get_int(packet
+1), /* ID */
1161 packet
[27], /* type */
1162 get_int16(packet
+28), /* time to live */
1163 get_int16(packet
+5), /* sprite */
1164 0, /* anim position */
1165 get_int(packet
+23), /* status */
1166 get_int(packet
+7), /* x */
1167 get_int(packet
+11), /* y */
1168 get_int(packet
+15), /* xspeed */
1169 get_int(packet
+19), /* yspeed */
1174 case P_PLAYER_DELETED
:
1179 case P_DELETE_OBJECT
:
1180 if (l
<5)break; /* invalid packet */
1181 delete_obj(get_int(packet
+1));
1185 case P_UPDATE_OBJECT
:
1186 if (l
< (n
=28))break; /* invalid packet */
1188 struct object_list
*p
;
1190 p
=find_in_table(get_int(packet
+1));
1192 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1193 p
->member
.update_counter
=packet
[5];
1194 p
->member
.x
=get_int(packet
+6);
1195 p
->member
.y
=get_int(packet
+10);
1196 p
->member
.xspeed
=get_int(packet
+14);
1197 p
->member
.yspeed
=get_int(packet
+18);
1198 p
->member
.status
=get_int(packet
+22);
1200 p
->member
.ttl
=get_int16(packet
+26);
1201 /* kdyz tasi, tak se nahodi ttl */
1202 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1203 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1207 case P_UPDATE_OBJECT_POS
:
1208 if (l
<22)break; /* invalid packet */
1210 struct object_list
*p
;
1213 p
=find_in_table(get_int(packet
+1));
1215 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1216 p
->member
.update_counter
=packet
[5];
1217 p
->member
.x
=get_int(packet
+6);
1218 p
->member
.y
=get_int(packet
+10);
1219 p
->member
.xspeed
=get_int(packet
+14);
1220 p
->member
.yspeed
=get_int(packet
+18);
1224 case P_UPDATE_OBJECT_SPEED
:
1225 if (l
<14)break; /* invalid packet */
1227 struct object_list
*p
;
1230 p
=find_in_table(get_int(packet
+1));
1232 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1233 p
->member
.update_counter
=packet
[5];
1234 p
->member
.xspeed
=get_int(packet
+6);
1235 p
->member
.yspeed
=get_int(packet
+10);
1239 case P_UPDATE_OBJECT_COORDS
:
1240 if (l
<14)break; /* invalid packet */
1242 struct object_list
*p
;
1245 p
=find_in_table(get_int(packet
+1));
1247 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1248 p
->member
.update_counter
=packet
[5];
1249 p
->member
.x
=get_int(packet
+6);
1250 p
->member
.y
=get_int(packet
+10);
1254 case P_UPDATE_OBJECT_SPEED_STATUS
:
1255 if (l
< (n
=18))break; /* invalid packet */
1257 struct object_list
*p
;
1259 p
=find_in_table(get_int(packet
+1));
1261 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1262 p
->member
.update_counter
=packet
[5];
1263 p
->member
.xspeed
=get_int(packet
+6);
1264 p
->member
.yspeed
=get_int(packet
+10);
1265 p
->member
.status
=get_int(packet
+14);
1266 /* kdyz tasi, tak se nahodi ttl */
1267 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1268 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1272 case P_UPDATE_OBJECT_COORDS_STATUS
:
1273 if (l
< (n
=18))break; /* invalid packet */
1275 struct object_list
*p
;
1277 p
=find_in_table(get_int(packet
+1));
1279 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1280 p
->member
.update_counter
=packet
[5];
1281 p
->member
.x
=get_int(packet
+6);
1282 p
->member
.y
=get_int(packet
+10);
1283 p
->member
.status
=get_int(packet
+14);
1284 /* kdyz tasi, tak se nahodi ttl */
1285 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1286 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1290 case P_UPDATE_OBJECT_SPEED_STATUS_TTL
:
1291 if (l
< (n
=20))break; /* invalid packet */
1293 struct object_list
*p
;
1295 p
=find_in_table(get_int(packet
+1));
1297 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1298 p
->member
.update_counter
=packet
[5];
1299 p
->member
.xspeed
=get_int(packet
+6);
1300 p
->member
.yspeed
=get_int(packet
+10);
1301 p
->member
.status
=get_int(packet
+14);
1302 p
->member
.ttl
=get_int16(packet
+18);
1303 /* kdyz tasi, tak se nahodi ttl */
1304 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1305 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1309 case P_UPDATE_OBJECT_COORDS_STATUS_TTL
:
1310 if (l
< (n
=20))break; /* invalid packet */
1312 struct object_list
*p
;
1314 p
=find_in_table(get_int(packet
+1));
1316 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1317 p
->member
.update_counter
=packet
[5];
1318 p
->member
.x
=get_int(packet
+6);
1319 p
->member
.y
=get_int(packet
+10);
1320 p
->member
.status
=get_int(packet
+14);
1321 p
->member
.ttl
=get_int16(packet
+18);
1322 /* kdyz tasi, tak se nahodi ttl */
1323 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1324 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1328 case P_UPDATE_STATUS
:
1329 if (l
< (n
=9))break; /* invalid packet */
1331 struct object_list
*p
;
1333 p
=find_in_table(get_int(packet
+1));
1334 if (!p
)break; /* ignore objects we don't have */
1335 p
->member
.status
=get_int(packet
+5);
1336 /* kdyz tasi, tak se nahodi ttl */
1337 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1338 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1343 if (l
<8)break; /* invalid packet */
1345 struct object_list
*p
;
1348 p
=find_in_table(get_int(packet
+1));
1349 if (!p
)break; /* ignore objects we don't have */
1350 p
->member
.status
|=S_HIT
;
1351 p
->member
.data
=(void*)(long)((packet
[5]<<16)+(packet
[7]<<8)+(packet
[6]));
1352 /* kdyz tasi, tak se nahodi ttl */
1353 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1354 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1358 case P_UPDATE_PLAYER
:
1359 if (l
<15+2*ARMS
)break; /* invalid packet */
1362 for (a
=0;a
<ARMS
;a
++)
1363 ammo
[a
]=get_int16(packet
+3+(a
<<1));
1364 frags
=get_int(packet
+3+ARMS
*2);
1365 deaths
=get_int(packet
+7+ARMS
*2);
1366 current_weapon
=get_int16(packet
+11+ARMS
*2);
1367 weapons
=get_int16(packet
+13+ARMS
*2);
1373 break; /* invalid packet */
1374 add_message(packet
+ 2, packet
[1]);
1375 n
= 3 + strlen(packet
+ 2);
1378 case P_CHANGE_LEVEL
:
1386 if (l
<38)break; /* invalid packet */
1387 a
=get_int(packet
+1);
1388 if (level_number
==a
)goto level_changed
;
1390 snprintf(txt
, sizeof(txt
), "Trying to change level to number %d", level_number
);
1391 add_message(txt
, M_INFO
);
1392 name
=load_level(level_number
);
1394 snprintf(error_message
,1024,"Cannot find level "
1395 "number %d. Game terminated. Press ENTER.",
1400 snprintf(txt
,256,"Changing level to \"%s\"",name
);
1402 add_message(txt
, M_INFO
);
1404 md5
=md5_level(level_number
);
1405 if (strcmp((char *)md5
,packet
+5)) /* MD5s differ */
1408 snprintf(error_message
,1024,"Invalid MD5 sum. Can't change level. Game terminated. Press ENTER.");
1409 add_message("Invalid MD5 sum. Can't change level. Exiting...", M_INFO
);
1415 /* OK we can change it */
1420 send_packet(&p
,1,(struct sockaddr
*)(&server
),my_id
,0);
1427 snprintf(error_message
,1024,"Game terminated. Press ENTER.");
1429 snprintf(error_message
,1024,"Game terminated by %s. Press ENTER.",packet
+1);
1439 active_players
=get_int(packet
+1);
1441 for (a
=0;a
<packet
[5]&&a
<TOP_PLAYERS_N
;a
++)
1444 top_players
[a
].frags
=get_int(packet
+l
);
1445 top_players
[a
].deaths
=get_int(packet
+l
+4);
1446 top_players
[a
].color
=packet
[l
+8];
1447 x
=strlen(packet
+l
+9)+1;
1448 memcpy(top_players
[a
].name
,packet
+l
+9,x
);
1454 case P_EXPLODE_GRENADE
:
1456 case P_EXPLODE_BLOODRAIN
:
1459 struct object_list
*p
;
1464 i
=get_int(packet
+1);
1465 j
=get_int(packet
+5);
1469 for (b
=0;b
<N_SHRAPNELS_EXPLODE
;b
++)
1471 double angle
=(double)b
*2*M_PI
/N_SHRAPNELS_EXPLODE
;
1472 int spd
=add_int(mul_int(my_and(mul_int(weapon
[WEAPON_GRENADE
].speed
,b
+1),15),16),100);
1478 (*packet
==P_EXPLODE_GRENADE
)?
1479 shrapnel_sprite
[random()%N_SHRAPNELS
]:
1480 (*packet
==P_EXPLODE_BFG
)?
1481 bfgbit_sprite
[random()%N_SHRAPNELS
]:
1482 bloodrain_sprite
[random()%N_SHRAPNELS
],
1487 p
->member
.xspeed
+mul(spd
,float2double(cos(angle
))),
1488 p
->member
.yspeed
+mul(spd
,float2double(sin(angle
))),
1492 if (*packet
!= P_EXPLODE_BLOODRAIN
)
1502 /* read packet from socket */
1507 struct sockaddr_in client
;
1508 static char packet
[MAX_PACKET_LENGTH
];
1509 int a
=sizeof(client
);
1516 while(select(fd
+1,&rfds
,0,0,&tv
))
1518 if ((l
=recv_packet(packet
,MAX_PACKET_LENGTH
,(struct sockaddr
*)(&client
),&a
,1,my_id
,0))<0)
1519 return 0; /* something's strange */
1520 if (process_packet(packet
,l
)<0)return 1;
1527 /* select color for numeric value (red=lack, yellow=edium, green=fill) */
1528 int select_color(int value
,int max
)
1530 return value
>=(max
>>1)?10:(value
>=(max
>>2)?11:9);
1534 /* draw board at the bottom of the screen */
1535 void draw_board(void)
1537 int offs
=SCREEN_X
*(SCREEN_Y
-2);
1538 int space
=(SCREEN_X
-60)/5;
1542 memset(screen_a
+offs
,4,SCREEN_X
);
1543 memset(screen
+offs
,'-',SCREEN_X
);
1544 memset(screen
+offs
+SCREEN_X
,0,SCREEN_X
);
1545 print2screen(0,SCREEN_Y
-1,7,"HEALTH");
1546 snprintf(txt
, sizeof(txt
), "% 3d%%",health
);
1547 print2screen(6,SCREEN_Y
-1,select_color(health
,100),txt
);
1549 print2screen(11+(space
>>1),SCREEN_Y
-2,4,",");
1550 print2screen(11+(space
>>1),SCREEN_Y
-1,4,"|");
1551 print2screen(11+space
,SCREEN_Y
-1,7,"FRAGS");
1552 snprintf(txt
, sizeof(txt
), "% 4d",frags
);
1553 print2screen(11+space
+6,SCREEN_Y
-1,11,txt
);
1555 print2screen(21+space
+(space
>>1),SCREEN_Y
-2,4,",");
1556 print2screen(21+space
+(space
>>1),SCREEN_Y
-1,4,"|");
1557 print2screen(21+(space
<<1),SCREEN_Y
-1,7,"DEATHS");
1558 snprintf(txt
, sizeof(txt
), "% 4d",deaths
);
1559 print2screen(21+(space
<<1)+7,SCREEN_Y
-1,11,txt
);
1561 print2screen(31+(space
<<1)+(space
>>1),SCREEN_Y
-2,4,",");
1562 print2screen(31+(space
<<1)+(space
>>1),SCREEN_Y
-1,4,"|");
1563 snprintf(txt
, sizeof(txt
), "%10s",weapon
[current_weapon
].name
);
1564 print2screen(31+3*space
,SCREEN_Y
-1,11,txt
);
1566 print2screen(41+(3*space
)+(space
>>1),SCREEN_Y
-2,4,",");
1567 print2screen(41+(3*space
)+(space
>>1),SCREEN_Y
-1,4,"|");
1568 print2screen(41+(space
<<2),SCREEN_Y
-1,7,"AMMO");
1569 snprintf(txt
, sizeof(txt
), "% 4d",ammo
[current_weapon
]);
1570 print2screen(41+5+(space
<<2),SCREEN_Y
-1,select_color(ammo
[current_weapon
],weapon
[current_weapon
].max_ammo
),txt
);
1572 print2screen(49+(space
<<2)+(space
>>1),SCREEN_Y
-2,4,",");
1573 print2screen(49+(space
<<2)+(space
>>1),SCREEN_Y
-1,4,"|");
1574 print2screen(49+5*space
,SCREEN_Y
-1,7,"ARMOR");
1575 snprintf(txt
, sizeof(txt
), "% 4d%%",armor
);
1576 print2screen(49+5+5*space
,SCREEN_Y
-1,select_color(armor
,100),txt
);
1577 if (hero
->status
& S_INVISIBLE
)print2screen(SCREEN_X
-(offset
+= 14),SCREEN_Y
-2,C_YELLOW
,"INVISIBILITY");
1578 if (hero
->status
& S_ILL
)print2screen(SCREEN_X
-(offset
+= 14),SCREEN_Y
-2,C_RED
,"! INFECTED !");
1579 if (hero
->status
& S_ONFIRE
)print2screen(SCREEN_X
-(offset
+= 9),SCREEN_Y
-2,C_RED
,"ON FIRE");
1580 if (autorun
)print2screen(2,SCREEN_Y
-2,15,"AUTORUN");
1581 if (autocreep
)print2screen(10,SCREEN_Y
-2,15,"AUTOCREEP");
1585 /* read string from input, returns everytime, not when string's read */
1586 int read_str_online(int y
,char *pointer
,char *message
, int max_len
)
1597 memcpy(screen2
+c
,message
,a
);
1598 memcpy(screen2
+c
+a
,pointer
,b
);
1599 memset(screen2_a
+c
,15,a
);
1600 memset(screen2_a
+c
+a
,7,b
);
1601 memset(screen2_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1605 memcpy(screen
+c
,message
,a
);
1606 memcpy(screen
+c
+a
,pointer
,b
);
1607 memset(screen_a
+c
,15,a
);
1608 memset(screen_a
+c
+a
,7,b
);
1609 memset(screen_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1613 if (c_was_pressed(K_ESCAPE
))
1618 if (c_was_pressed(K_ENTER
))
1622 if (c_pressed(K_BACKSPACE
)&&b
)
1627 shift
=c_pressed(K_LEFT_SHIFT
)||c_pressed(K_RIGHT_SHIFT
);
1628 for (c
=' ';c
<128&&b
<max_len
;c
++)
1629 if (c_was_pressed(c
))
1631 pointer
[b
]=shift
?my_toupper(c
):c
;
1639 /* read number from input, returns everytime, not when number's read */
1640 int read_num_online(int y
,char *pointer
,char *message
, int max_len
)
1651 memcpy(screen2
+c
,message
,a
);
1652 memcpy(screen2
+c
+a
,pointer
,b
);
1653 memset(screen2_a
+c
,15,a
);
1654 memset(screen2_a
+c
+a
,7,b
);
1655 memset(screen2_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1659 memcpy(screen
+c
,message
,a
);
1660 memcpy(screen
+c
+a
,pointer
,b
);
1661 memset(screen_a
+c
,15,a
);
1662 memset(screen_a
+c
+a
,7,b
);
1663 memset(screen_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1667 if (c_was_pressed(K_ESCAPE
))
1672 if (c_was_pressed(K_ENTER
))
1676 if (c_pressed(K_BACKSPACE
)&&b
)
1681 for (c
='0';c
<='9'&&b
<max_len
;c
++)
1682 if (c_was_pressed(c
))
1692 /* load banner.dat */
1693 void load_banner(char **banner
)
1700 s
=fopen(DATA_PATH BANNER_FILE
,"r");
1702 fopen_s(&s
,DATA_PATH BANNER_FILE
,"r");
1704 if (!s
){shut_down(0);ERROR("Error: Can't load file \""DATA_PATH BANNER_FILE
"\".\n");EXIT(1);}
1705 *banner
=mem_alloc(1);
1707 if (!(*banner
)){shut_down(0);ERROR("Error: Not enough memory.\n");EXIT(1);}
1708 while (fgets(line
,1024,s
))
1710 if (line
[strlen(line
)-1]==10)line
[strlen(line
)-1]=0;
1711 if (line
[strlen(line
)-1]==13)line
[strlen(line
)-1]=0; /* crlf shit */
1714 *banner
=mem_realloc((*banner
),a
+b
+SCREEN_X
+1);
1715 memcpy((*banner
)+a
,line
,b
);
1716 memset((*banner
)+a
+b
,' ',SCREEN_X
);
1717 (*banner
)[a
+b
+SCREEN_X
]=0;
1722 #define ERRBOX_HEIGHT 1
1723 #define ERRBOX_Y ((SCREEN_Y-2-ERRBOX_HEIGHT)>>1)
1725 /* draw error box */
1726 void print_error(char *text
)
1728 int width
= strlen(text
) + 6;
1729 int x
= (SCREEN_X
-2-width
) >> 1;
1731 draw_frame(x
, ERRBOX_Y
, width
, ERRBOX_HEIGHT
, 15);
1732 print2screen(x
+ 2, ERRBOX_Y
+ 1, C_RED
, "/!\\");
1733 print2screen(x
+ 6, ERRBOX_Y
+ 1, C_YELLOW
, text
);
1737 /* draw initial screen */
1738 void menu_screen(struct config
*cfg
)
1741 int sprite
,anim
=0,title_anim
=0,bulge_anim
=0;
1742 unsigned long_long t
;
1743 char port
[MAX_PORT_LEN
+1];
1746 char *color_name
[15]={"red","green","brown","blue","violet","cyan","gray","black","light red","light green","yellow","light blue","magenta","light cyan","white"};
1750 #ifdef HAVE_LIBPTHREAD
1757 load_banner(&banner
);
1759 snprintf(port
, sizeof(port
), "%d",cfg
->port
);
1760 snprintf(txt
, sizeof(txt
), "hero%d",cfg
->color
);
1761 if (find_sprite(txt
,&sprite
))
1766 snprintf(msg
,256,"Error: Can't find sprite \"%s\".\n",txt
);
1778 put_sprite((SCREEN_X
+1-TITLE_WIDTH
)>>1,0,sprites
[title_sprite
].positions
+sprites
[title_sprite
].steps
[title_anim
],0);
1779 put_sprite(SCREEN_XOFFSET
+1+PLAYER_WIDTH
+((SCREEN_X
-SCREEN_XOFFSET
-PLAYER_WIDTH
-BULGE_WIDTH
)>>1),TITLE_HEIGHT
+((SCREEN_Y
-3-BULGE_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[bulge_sprite
].positions
+sprites
[bulge_sprite
].steps
[bulge_anim
],0);
1780 put_sprite(SCREEN_XOFFSET
+1,TITLE_HEIGHT
+((SCREEN_Y
-3-PLAYER_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[sprite
].positions
+sprites
[sprite
].steps
[(anim
<2?48:39)+(anim
&7)],0);
1784 put_sprite((SCREEN_X
-TITLE_WIDTH
)>>1,0,sprites
[title_sprite
].positions
+sprites
[title_sprite
].steps
[title_anim
],0);
1785 put_sprite(SCREEN_XOFFSET
+PLAYER_WIDTH
+((SCREEN_X
-SCREEN_XOFFSET
-PLAYER_WIDTH
-BULGE_WIDTH
)>>1),TITLE_HEIGHT
+((SCREEN_Y
-3-BULGE_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[bulge_sprite
].positions
+sprites
[bulge_sprite
].steps
[bulge_anim
],0);
1786 put_sprite(SCREEN_XOFFSET
,TITLE_HEIGHT
+((SCREEN_Y
-3-PLAYER_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[sprite
].positions
+sprites
[sprite
].steps
[(anim
<2?48:39)+(anim
&7)],0);
1787 print2screen(0,TITLE_HEIGHT
+4,11,"N:");
1788 print2screen(1,TITLE_HEIGHT
+4,2,"AME:");
1789 print2screen(6,TITLE_HEIGHT
+4,7,cfg
->name
);
1790 print2screen(0,TITLE_HEIGHT
+6,2,"COLOR:");
1791 print2screen(7,TITLE_HEIGHT
+6,7,color_name
[(cfg
->color
-1)%15]);
1792 print2screen(0,TITLE_HEIGHT
+0,11,"S");
1793 print2screen(1,TITLE_HEIGHT
+0,2,"ERVER ADDRESS:");
1794 print2screen(16,TITLE_HEIGHT
+0,7,cfg
->host
);
1795 print2screen(0,TITLE_HEIGHT
+2,11,"P");
1796 print2screen(1,TITLE_HEIGHT
+2,2,"ORT:");
1797 print2screen(6,TITLE_HEIGHT
+2,7,port
);
1798 print2screen((SCREEN_X
-26)>>1,SCREEN_Y
-3,7,"Use arrows to change color");
1799 print2screen((SCREEN_X
-52)>>1,SCREEN_Y
-2,7,"Press ENTER to connect, H for help, ESC or Q to quit");
1800 print2screen(0,SCREEN_Y
-1,15,banner
+(banner_pos
>>1));
1806 title_anim
%=sprites
[title_sprite
].n_steps
;
1808 bulge_anim
%=sprites
[bulge_sprite
].n_steps
;
1811 print2screen(((SCREEN_X
-strlen(error_message
))>>1),SCREEN_Y
-1,9,error_message
);
1827 if (help
)print_help_window();
1828 #ifdef HAVE_LIBPTHREAD
1829 if (pt
&& errormsg
.flags
) {
1830 pthread_kill(pt
, 9); /* good bye */
1833 if (!pt
&& errormsg
.flags
== E_CONN_SUCC
) {
1840 print_error(errormsg
.text
);
1845 if (read_str_online(SCREEN_Y
-1,cfg
->name
,"Enter your name: ",MAX_NAME_LEN
)) {
1846 cfg
->override
&= ~OVERRIDE_FLAG_NAME
;
1852 if (read_str_online(SCREEN_Y
-1,cfg
->host
,"Enter address: ",MAX_HOST_LEN
)) {
1853 cfg
->override
&= ~OVERRIDE_FLAG_HOST
;
1859 if (read_num_online(SCREEN_Y
-1,port
,"Enter port: ",MAX_PORT_LEN
)) {
1860 cfg
->override
&= ~OVERRIDE_FLAG_PORT
;
1861 cfg
->port
= strtol(port
, 0, 10);
1880 if ((c_was_pressed('+')||c_was_pressed('=')||c_was_pressed(K_UP
)||c_was_pressed(K_RIGHT
)||c_was_pressed(K_NUM_PLUS
)) && !errormsg
.flags
)
1885 snprintf(txt
, sizeof(txt
), "hero%d",cfg
->color
);
1886 if (find_sprite(txt
,&sprite
))
1887 {shut_down(0);mem_free(banner
);fprintf(stderr
,"Error: Can't find sprite \"%s\".\n",txt
);}
1888 cfg
->override
&= ~OVERRIDE_FLAG_COLOR
;
1891 if ((c_was_pressed('-')||c_was_pressed(K_NUM_MINUS
)||c_was_pressed(K_DOWN
)||c_was_pressed(K_LEFT
)) && !errormsg
.flags
)
1896 snprintf(txt
, sizeof(txt
), "hero%d",cfg
->color
);
1897 if (find_sprite(txt
,&sprite
))
1898 {shut_down(0);mem_free(banner
);fprintf(stderr
,"Error: Can't find sprite \"%s\".\n",txt
);}
1899 cfg
->override
&= ~OVERRIDE_FLAG_COLOR
;
1902 if (c_was_pressed('h') && !errormsg
.flags
)help
^=1;
1903 if (c_was_pressed(K_ENTER
))
1905 if (errormsg
.flags
) {
1906 errormsg
.flags
= E_NONE
;
1910 cfg
->port
=strtol(port
,0,10);
1911 if ((m
=find_server(cfg
)))
1913 print2screen(((SCREEN_X
-strlen(m
))>>1),SCREEN_Y
-1,9,m
);
1926 if ((m
=init_socket()))
1928 print2screen(((SCREEN_X
-strlen(m
))>>1),SCREEN_Y
-1,9,m
);
1941 #ifdef HAVE_LIBPTHREAD
1943 pthread_create(&pt
, NULL
, (void *)contact_server
, cfg
);
1948 if(contact_server(cfg
))
1957 if ((c_was_pressed('q')||c_was_pressed(K_ESCAPE
)) && !errormsg
.flags
)
1964 if (c_was_pressed('n') && !errormsg
.flags
)
1967 if ((c_was_pressed('a')||c_was_pressed('s')) && !errormsg
.flags
)
1970 if (c_was_pressed('p') && !errormsg
.flags
)
1973 sleep_until(t
+MENU_PERIOD_USEC
);
1978 /* handle fatal signal (sigabrt, sigsegv, ...) */
1979 void signal_handler(int signum
)
1982 if (connected
)send_quit();
1985 psignal(signum
,"Exiting on signal");
1987 fprintf(stderr
, "Exiting on signal: %d\n", signum
);
1993 /* change size of the screen */
1994 void sigwinch_handler(int signum
)
2000 c_init(SCREEN_X
,SCREEN_Y
);
2006 signal(SIGWINCH
,sigwinch_handler
);
2012 /* print command line help */
2013 void print_help(void)
2018 x
= " for X windows";
2019 y
= " [-d <display>] [-f <font name>]";
2024 "(c)2000 Brainsoft\n"
2025 "Usage: 0verkill [-h] [-3] [-i <server address>] \n"
2026 "[-c <color>] [-n <player name>] [-p <port>] \n"
2027 "[-s <width>x<height>]%s"
2033 void parse_dimensions(char *txt
)
2038 for (p
=txt
;(*p
)&&(*p
)!='x';p
++);
2039 if (!(*p
)){ERROR("Error: Expected dimensions in form WIDTHxHEIGHT.\n");EXIT(1);}
2042 if (!strlen(txt
)||!strlen(p
)){fprintf(stderr
,"Error: Decimal number expected.\n");EXIT(1);}
2043 SCREEN_X
=strtoul(txt
,&e
,10);
2044 if (*e
){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2045 SCREEN_Y
=strtoul(p
,&e
,10);
2046 if (*e
){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2051 void parse_command_line(struct config
*cfg
)
2060 a
=getopt(cfg
->argc
,cfg
->argv
,"3hl:f:d:s:n:i:p:c:");
2063 a
=getopt(cfg
->argc
,cfg
->argv
,"3hl:s:n:i:p:c:");
2067 a
=getopt(cfg
->argc
,cfg
->argv
,"hf:d:s:n:i:p:c:");
2070 a
=getopt(cfg
->argc
,cfg
->argv
,"hs:n:i:p:c:");
2093 parse_dimensions(optarg
);
2097 x_display_name
=optarg
;
2105 memcpy(cfg
->host
, optarg
, strlen(optarg
) + 1);
2106 cfg
->override
|= OVERRIDE_FLAG_HOST
;
2110 memcpy(cfg
->name
, optarg
, strlen(optarg
) + 1);
2111 cfg
->override
|= OVERRIDE_FLAG_NAME
;
2115 cfg
->port
= strtol(optarg
, 0, 10);
2116 cfg
->override
|= OVERRIDE_FLAG_PORT
;
2120 cfg
->color
= strtol(optarg
, 0, 10);
2121 cfg
->override
|= OVERRIDE_FLAG_COLOR
;
2127 #define HALL_FAME_WIDTH (MAX_NAME_LEN+17)
2128 #define HALL_FAME_HEIGHT ((active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players)+5)
2129 #define HALL_FAME_X ((SCREEN_X-2-HALL_FAME_WIDTH)>>1)
2130 #define HALL_FAME_Y ((SCREEN_Y-2-HALL_FAME_HEIGHT)>>1)
2132 void print_hall_of_fame(void)
2136 unsigned char color
;
2138 if (!active_players
)return;
2139 snprintf(txt
, sizeof(txt
), "TOP %d PLAYERS",TOP_PLAYERS_N
);
2140 draw_frame(HALL_FAME_X
,HALL_FAME_Y
,HALL_FAME_WIDTH
,HALL_FAME_HEIGHT
,15);
2141 print2screen(HALL_FAME_X
+1+((HALL_FAME_WIDTH
-strlen(txt
))>>1),HALL_FAME_Y
+1,11,txt
);
2142 print2screen(HALL_FAME_X
+2,HALL_FAME_Y
+3,15,"NAME");
2143 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+2,HALL_FAME_Y
+3,15,"FRAGS");
2144 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+9,HALL_FAME_Y
+3,15,"DEATHS");
2145 for (a
=0;a
<active_players
&&a
<TOP_PLAYERS_N
;a
++)
2147 color
=((top_players
[a
].color
-1)%15)+1;
2148 print2screen(HALL_FAME_X
+2,HALL_FAME_Y
+4+a
,color
,top_players
[a
].name
);
2149 snprintf(txt
, sizeof(txt
), "% 5d",top_players
[a
].frags
);
2150 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+2,HALL_FAME_Y
+4+a
,color
,txt
);
2151 snprintf(txt
, sizeof(txt
), "% 5d",top_players
[a
].deaths
);
2152 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+9,HALL_FAME_Y
+4+a
,color
,txt
);
2154 snprintf(txt
, sizeof(txt
), "%d",active_players
);
2155 print2screen(HALL_FAME_X
+2,HALL_FAME_Y
+HALL_FAME_HEIGHT
,11,"Players in the game:");
2156 print2screen(HALL_FAME_X
+23,HALL_FAME_Y
+HALL_FAME_HEIGHT
,7,txt
);
2166 unsigned char chat
=0;
2167 unsigned char help
=0;
2168 unsigned char hall_fame
=0;
2169 unsigned long_long last_time
;
2171 last_time
=get_time();
2174 last_time
+=CLIENT_PERIOD_USEC
;
2175 if (get_time()-last_time
>PERIOD_USEC
*100)last_time
=get_time();
2176 if (read_data())return; /* game terminated */
2178 if(!p
)clear_screen();
2184 if (!p
)draw_scene();
2188 update_messages(last_time
);
2192 switch (read_str_online(SCREEN_Y
-3,string
,"> ",78))
2200 send_message(string
, M_CHAT
);
2204 if (help
)print_help_window();
2205 if (hall_fame
)print_hall_of_fame();
2220 if (!chat
)c_update_kbd();
2223 if (c_was_pressed('p'))p
^=1;
2225 if (!chat
&&c_was_pressed('r'))
2230 if (!chat
&&c_was_pressed('h'))help
^=1;
2231 if (!chat
&&c_was_pressed(K_TAB
))
2234 if (hall_fame
)send_info_request();
2236 if (c_was_pressed(K_CAPS_LOCK
)||(!chat
&&c_was_pressed('a')))autorun
^=1;
2237 if (c_was_pressed(K_F10
)||(!chat
&&c_was_pressed('q')))
2243 if (c_pressed(K_F12
))
2246 if (!chat
&& c_was_pressed(K_ENTER
))
2248 memset(string
,0,80);
2256 if (!chat
&&c_was_pressed(' '))send_reenter_game();
2257 if (!chat
&&c_was_pressed('c'))
2259 if (c_pressed(K_DOWN
)||autocreep
)
2260 keyboard_status
.status
|= KBD_CREEP
;
2261 if (c_pressed(K_UP
))
2262 keyboard_status
.status
|= KBD_JUMP
;
2263 if (c_pressed(K_LEFT_CTRL
)||c_pressed(K_RIGHT_CTRL
)||(!chat
&&c_pressed('z')))
2264 keyboard_status
.status
|= KBD_FIRE
;
2265 if (!chat
&& c_pressed('d'))
2266 keyboard_status
.status
|= KBD_DOWN_LADDER
;
2267 if (!chat
&& c_pressed('j'))
2268 keyboard_status
.status
|= KBD_JETPACK
;
2269 if (!chat
&& c_was_pressed('1'))
2270 keyboard_status
.weapon
=1;
2271 if (!chat
&& c_was_pressed('2'))
2272 keyboard_status
.weapon
=2;
2273 if (!chat
&& c_was_pressed('3'))
2274 keyboard_status
.weapon
=3;
2275 if (!chat
&& c_was_pressed('4'))
2276 keyboard_status
.weapon
=4;
2277 if (!chat
&& c_was_pressed('5'))
2278 keyboard_status
.weapon
=5;
2279 if (!chat
&& c_was_pressed('6'))
2280 keyboard_status
.weapon
=6;
2281 if (!chat
&& c_was_pressed('7'))
2282 keyboard_status
.weapon
=7;
2283 if (!chat
&& c_was_pressed('8'))
2284 keyboard_status
.weapon
=8;
2285 if (c_pressed(K_LEFT_SHIFT
)||c_pressed(K_RIGHT_SHIFT
)||autorun
)
2286 keyboard_status
.status
|= KBD_SPEED
;
2287 if (c_pressed(K_LEFT
))
2288 keyboard_status
.status
|= KBD_LEFT
;
2289 if (c_pressed(K_RIGHT
))
2290 keyboard_status
.status
|= KBD_RIGHT
;
2293 sleep_until(last_time
+CLIENT_PERIOD_USEC
);
2297 /*----------------------------------------------------------------------------*/
2298 int main(int argc
,char **argv
)
2302 struct config cfg
= {argc
, argv
, "", "", DEFAULT_PORT
, 1, 0};
2307 WSAStartup(0x101, &wd
);
2308 printf("Started WinSock version %X.%02X\n", wd
.wVersion
/0x100, wd
.wVersion
&0xFF);
2311 chdir_to_data_files();
2320 memset(cfg
.host
,0,MAX_HOST_LEN
+1);
2321 memset(cfg
.name
,0,MAX_NAME_LEN
+1);
2326 parse_command_line(&cfg
);
2328 if (!set_size
)c_get_size(&SCREEN_X
,&SCREEN_Y
);
2332 load_sprites(DATA_PATH GAME_SPRITES_FILE
);
2334 snprintf(txt
,sizeof(txt
),"%s\\data\\sprites.dat",_getcwd(NULL
, 0));
2337 /* sprites are stored in memory in this order: game sprites (players,
2338 * bullets, corpses, blood, meat...) followed by level sprites
2341 level_sprites_start
=n_sprites
;
2342 if (find_sprite("hit",&hit_sprite
)){ERROR("Error: Can't find sprite \"hit\".\n");EXIT(1);}
2343 if (find_sprite("title",&title_sprite
)){ERROR("Error: Can't find sprite \"title\".\n");EXIT(1);}
2344 if (find_sprite("bulge",&bulge_sprite
)){ERROR("Error: Can't find sprite \"bulge\".\n");EXIT(1);}
2345 for (a
=0;a
<N_SHRAPNELS
;a
++)
2347 snprintf(txt
, sizeof(txt
), "shrapnel%d",a
+1);
2348 if (find_sprite(txt
,&shrapnel_sprite
[a
])) {
2349 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2352 snprintf(txt
, sizeof(txt
), "bfgbit%d",a
+1);
2353 if (find_sprite(txt
,&bfgbit_sprite
[a
])) {
2354 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2357 snprintf(txt
, sizeof(txt
), "bloodrain%d",a
+1);
2358 if (find_sprite(txt
,&bloodrain_sprite
[a
])) {
2359 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2363 snprintf(txt
, sizeof(txt
), "jetpack");
2364 if (find_sprite(txt
,&jetpack_sprite
)) {
2365 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2368 snprintf(txt
, sizeof(txt
), "fire");
2369 if (find_sprite(txt
,&fire_sprite
)) {
2370 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2373 snprintf(txt
, sizeof(txt
), "sawchain");
2374 if (find_sprite(txt
,&chain_sprite
)) {
2375 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2379 signal(SIGINT
,signal_handler
);
2380 signal(SIGTERM
,signal_handler
);
2381 signal(SIGILL
,signal_handler
);
2382 signal(SIGABRT
,signal_handler
);
2383 signal(SIGFPE
,signal_handler
);
2384 signal(SIGSEGV
,signal_handler
);
2386 signal(SIGQUIT
,signal_handler
);
2387 signal(SIGBUS
,signal_handler
);
2389 signal(SIGWINCH
,sigwinch_handler
);
2392 c_init(SCREEN_X
,SCREEN_Y
);
2404 delete_obj(hero
->id
);