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
);
566 server_error("Connection refused. Press ENTER.", E_CONN
);
570 case P_PLAYER_ACCEPTED
:
571 my_id
=get_int(packet
+35);
574 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN
);
579 if (maj
!=VERSION_MAJOR
||min
<MIN_SERVER_VERSION_MINOR
) {
581 server_error("Incompatible server version. Givin' up. Press Enter.", E_CONN
);
584 game_start_offset
=get_time();
585 game_start_offset
-=get_long_long(packet
+27);
590 ammo
[WEAPON_GUN
]=weapon
[WEAPON_GUN
].basic_ammo
;
591 ammo
[WEAPON_CHAINSAW
]=weapon
[WEAPON_CHAINSAW
].basic_ammo
;
593 weapons
=WEAPON_MASK_GUN
|
594 WEAPON_MASK_GRENADE
|
595 WEAPON_MASK_CHAINSAW
|
596 WEAPON_MASK_BLOODRAIN
; /* gun, grenades, chainsaw and blodrain */
598 get_int(packet
+1), /* ID */
600 0, /* time to live */
601 get_int16(packet
+5), /* sprite */
603 get_int(packet
+23), /* status */
604 get_int(packet
+7), /* X */
605 get_int(packet
+11), /* Y */
606 get_int(packet
+15), /* XSPEED */
607 get_int(packet
+19), /* YSPEED */
613 server_error("Connection error. Press ENTER.", E_CONN
);
617 #ifdef HAVE_LIBPTHREAD
627 /* send me top X players */
628 void send_info_request(void)
632 send_packet(&packet
,1,(struct sockaddr
*)(&server
),my_id
,0);
636 /* I want to be born again */
637 void send_reenter_game(void)
640 packet
=P_REENTER_GAME
;
641 send_packet(&packet
,1,(struct sockaddr
*)(&server
),my_id
,0);
645 /* send end of game to server */
650 send_packet(&packet
,1,(struct sockaddr
*)(&server
),my_id
,0);
654 /* send chat message */
655 void send_message(char *msg
, char flags
)
657 static char packet
[MAX_MESSAGE_LENGTH
+ 2];
660 len
= strlen(msg
) + 1;
661 packet
[0] = P_MESSAGE
;
663 memcpy(packet
+ 2, msg
, len
);
664 send_packet(packet
, len
+ 2, (struct sockaddr
*)(&server
), my_id
, 0);
668 /* send end of game to server */
669 void send_keyboard(void)
672 packet
[0]=P_KEYBOARD
;
673 packet
[1]=keyboard_status
.status
;
674 packet
[2]=keyboard_status
.weapon
;
675 send_packet(packet
,3,(struct sockaddr
*)(&server
),my_id
,0);
679 void reset_keyboard(void)
681 keyboard_status
.status
=0;
682 keyboard_status
.weapon
=0;
685 /* recompute object positions */
686 void update_game(void)
688 struct object_list
*p
;
690 unsigned char stop_x
,stop_y
,sy
;
691 unsigned long_long t
;
692 int x
,y
,x1
,y1
,DELTA_TIME
;
694 for(p
=&objects
;p
->next
;p
=p
->next
)
696 if (p
->next
->member
.type
==T_NOTHING
)
698 if (p
->next
->member
.status
& S_DEAD
)
699 continue; /* dead player */
700 /* decrement time to live */
701 if (p
->next
->member
.ttl
>0)
703 p
->next
->member
.ttl
--;
704 if (!p
->next
->member
.ttl
)
706 if ((p
->next
->member
.type
)==T_PLAYER
)
707 p
->next
->member
.status
&= ~S_SHOOTING
;
710 if (p
->next
->member
.type
!=T_GRENADE
&&
711 p
->next
->member
.type
!=T_BFGCELL
){ /* client's waiting for P_EXPLODE_GRENADE and doesn't delete the grenade yet */
713 delete_obj(p
->next
->next
->member
.id
);
718 /* maintain only objects that you are allowed to maintain */
719 if (!(obj_attr
[p
->next
->member
.type
].maintainer
&1))continue;
722 /* if not falling slow down x motion */
723 if (!(p
->next
->member
.status
& S_FALLING
))
724 p
->next
->member
.xspeed
=mul(p
->next
->member
.xspeed
,obj_attr
[p
->next
->member
.type
].slow_down_x
);
727 if (obj_attr
[p
->next
->member
.type
].fall
)
729 p
->next
->member
.status
|= S_FALLING
;
730 p
->next
->member
.yspeed
+=FALL_ACCEL
;
731 /* but not too fast */
732 if (p
->next
->member
.yspeed
>MAX_Y_SPEED
)p
->next
->member
.yspeed
=MAX_Y_SPEED
;
735 get_dimensions(p
->next
->member
.type
,p
->next
->member
.status
,sprites
[p
->next
->member
.sprite
].positions
,&w
,&h
);
739 DELTA_TIME
=float2double(((double)(long_long
)(t
-p
->next
->member
.last_updated
))/MICROSECONDS
);
742 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
743 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
744 w
,h
,&stop_x
,&stop_y
);
745 p
->next
->member
.last_updated
=t
;
747 /* walk up the stairs */
748 if (stop_x
&&p
->next
->member
.type
==T_PLAYER
&&!(p
->next
->member
.status
& S_CREEP
))
750 x1
=p
->next
->member
.x
;
751 y1
=p
->next
->member
.y
;
753 p
->next
->member
.y
=y
-int2double(1);
756 p
->next
->member
.x
+mul(p
->next
->member
.xspeed
,DELTA_TIME
),
757 p
->next
->member
.y
+mul(p
->next
->member
.yspeed
,DELTA_TIME
),
759 if ((p
->next
->member
.xspeed
>0&&p
->next
->member
.x
<=x1
)||(p
->next
->member
.xspeed
<0&&p
->next
->member
.x
>=x1
)) /* restore original values */
761 p
->next
->member
.x
=x1
;
762 p
->next
->member
.y
=y1
;
772 p
->next
->member
.xspeed
=-mul(p
->next
->member
.xspeed
,obj_attr
[p
->next
->member
.type
].bounce_x
);
773 if (my_abs(p
->next
->member
.xspeed
)<MIN_X_SPEED
)
775 p
->next
->member
.xspeed
=0;
776 p
->next
->member
.status
&= ~S_WALKING
;
782 p
->next
->member
.yspeed
=mul(p
->next
->member
.yspeed
,obj_attr
[p
->next
->member
.type
].bounce_y
);
783 p
->next
->member
.yspeed
=-p
->next
->member
.yspeed
;
784 if (my_abs(p
->next
->member
.yspeed
)<MIN_Y_SPEED
)
786 p
->next
->member
.yspeed
=0;
787 if (stop_y
==1)p
->next
->member
.status
&= ~S_FALLING
;
791 if ((p
->next
->member
.type
== T_SHRAPNEL
|| p
->next
->member
.type
== T_BULLET
||
792 p
->next
->member
.type
== T_BFGCELL
|| p
->next
->member
.type
== T_CHAIN
||
793 p
->next
->member
.type
== T_JETFIRE
) &&
794 (stop_x
|| stop_y
)) { /* bullet and shrapnel die crashing into wall */
795 p
=p
->prev
; /* deleting object makes a great mess in for cycle, so we must cheat the cycle */
796 delete_obj(p
->next
->next
->member
.id
);
803 #define FIRE_SHOOTING weapon[current_weapon].cadence-4+HOLD_GUN_AFTER_SHOOT
805 /* hero's next anim position when walking to the right */
806 int _next_anim_right(int pos
,int status
, int ttl
)
811 start
=10; /* normal */
814 if (pos
<=46)start
=(status
& S_CHAINSAW
)?97:38; /* holding gun */
817 if (pos
<=55)start
=(status
& S_CHAINSAW
)?106:47; /* shooting */
818 else start
=64; /* creeping */
823 if (status
& S_CREEP
)
824 start
=64; /* creeping */
827 if (status
& S_SHOOTING
)
829 if (ttl
>=FIRE_SHOOTING
) start
=(status
& S_CHAINSAW
)?106:47; /* shooting */
830 else start
=(status
& S_CHAINSAW
)?97:38; /* holding a gun */
832 else start
=10; /* normal */
835 return (status
& S_CREEP
)?((offset
+1)&7)+start
:start
+(offset
&7)+1;
839 /* hero's next anim position when walking to the left */
840 int _next_anim_left(int pos
,int status
, int ttl
)
844 if (pos
<=8)start
=0; /* normal */
847 if (pos
<=28)start
=(status
& S_CHAINSAW
)?79:20; /* holding gun */
850 if (pos
<=37)start
=(status
& S_CHAINSAW
)?88:29; /* shooting */
851 else start
=56; /* creeping */
856 if (status
& S_CREEP
)
857 start
=56; /* creeping */
860 if (status
& S_SHOOTING
)
862 if (ttl
>=FIRE_SHOOTING
) start
=(status
& S_CHAINSAW
)?88:29; /* shooting */
863 else start
=(status
& S_CHAINSAW
)?79:20; /* holding a gun */
865 else start
=0; /* normal */
868 return (status
& S_CREEP
)?((offset
+1)&7)+start
:start
+(offset
&7)+1;
872 /* update hero animating position */
873 void update_anim(struct it
* obj
)
875 if (!(obj
->status
& S_WALKING
)) /* not walking */
876 switch((obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
)))
878 case 0: /* look at me */
879 obj
->anim_pos
=(obj
->status
& S_CREEP
)?72:9;
881 case S_LOOKLEFT
: /* look left */
882 if (obj
->status
& S_SHOOTING
)
884 if (obj
->status
& S_GRENADE
)
885 obj
->anim_pos
= (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>1)+HOLD_GUN_AFTER_SHOOT
)) ?
886 73 : (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>2)+HOLD_GUN_AFTER_SHOOT
)) ?
887 74 : ((obj
->ttl
>=HOLD_GUN_AFTER_SHOOT
) ? 75 : 0);
888 else if (obj
->status
& S_CHAINSAW
) /* maniak ma motorovku */
889 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 88 : 79;
891 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 29 : 20;
894 if (obj
->status
& S_CREEP
)
897 case S_LOOKRIGHT
: /* look right */
898 if (obj
->status
& S_SHOOTING
)
900 if (obj
->status
& S_GRENADE
)
901 obj
->anim_pos
= (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>1)+HOLD_GUN_AFTER_SHOOT
)) ?
902 76 : (obj
->ttl
>=((weapon
[WEAPON_GRENADE
].cadence
>>2)+HOLD_GUN_AFTER_SHOOT
)) ?
903 77 : ((obj
->ttl
>=HOLD_GUN_AFTER_SHOOT
) ? 78 : 10);
904 else if (obj
->status
& S_CHAINSAW
) /* maniak ma motorovku */
905 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 106 : 97;
907 obj
->anim_pos
=(obj
->ttl
>=FIRE_SHOOTING
) ? 47 : 38;
910 if (obj
->status
& S_CREEP
)
916 switch (obj
->status
& (S_LOOKLEFT
| S_LOOKRIGHT
))
918 case S_LOOKLEFT
: /* walk left */
919 obj
->anim_pos
=_next_anim_left(obj
->anim_pos
,obj
->status
,obj
->ttl
);
922 case S_LOOKRIGHT
: /* walk right */
923 obj
->anim_pos
=_next_anim_right(obj
->anim_pos
,obj
->status
,obj
->ttl
);
930 /* draw scene into screenbuffer*/
931 void draw_scene(void)
933 struct object_list
*p
;
940 show_window(double2int(hero
->x
)-SCREEN_XOFFSET
,double2int(hero
->y
)-SCREEN_YOFFSET
);
945 show_window(double2int(hero
->x
)-SCREEN_XOFFSET
,double2int(hero
->y
)-SCREEN_YOFFSET
);
946 for (fore
=0;fore
<=1;fore
++)
948 for(p
=&objects
;p
->next
;p
=p
->next
)
950 if ((obj_attr
[p
->next
->member
.type
].foreground
)!=fore
)continue;
951 if (&(p
->next
->member
)==hero
)continue;
952 if (p
->next
->member
.type
==T_PLAYER
)update_anim(&(p
->next
->member
));
953 else {p
->next
->member
.anim_pos
++;p
->next
->member
.anim_pos
%=sprites
[p
->next
->member
.sprite
].n_steps
;}
954 if (p
->next
->member
.status
== WEAPON_CHAINSAW
) continue;
955 if (!(p
->next
->member
.status
& S_DEAD
)&&!(p
->next
->member
.status
& S_INVISIBLE
)) /* don't draw hidden objects and dead players */
962 double2int(p
->next
->member
.x
-hero
->x
)+fore
+SCREEN_XOFFSET
,
963 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
,
964 sprites
[p
->next
->member
.sprite
].positions
+sprites
[p
->next
->member
.sprite
].steps
[p
->next
->member
.anim_pos
],
972 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
,
973 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
,
974 sprites
[p
->next
->member
.sprite
].positions
+sprites
[p
->next
->member
.sprite
].steps
[p
->next
->member
.anim_pos
],
978 if (p
->next
->member
.type
== T_PLAYER
) {
979 if ((p
->next
->member
.status
& S_JETPACK_ON
) && !(p
->next
->member
.status
& S_CREEP
)) {
980 if (p
->next
->member
.status
& S_LOOKRIGHT
)
982 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
-1,
983 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+4,
984 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[1], 1);
985 else if (p
->next
->member
.status
& S_LOOKLEFT
)
987 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+PLAYER_WIDTH
-4,
988 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+4,
989 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[0], 1);
991 if ((gsbi
+= 10) > 1000) {
995 if (p
->next
->member
.status
& S_ONFIRE
) {
996 if (p
->next
->member
.status
& S_CREEP
)
998 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
-5,
999 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
-2,
1000 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3 + 3], 1);
1003 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+3,
1004 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
-3,
1005 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3], 1);
1007 if ((p
->next
->member
.status
& S_CHAINSAW
) && (p
->next
->member
.ttl
>= FIRE_SHOOTING
) && !(hero
->status
& S_CREEP
)) {
1008 if (p
->next
->member
.status
& S_LOOKRIGHT
)
1010 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+15,
1011 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+6,
1012 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1013 else if (p
->next
->member
.status
& S_LOOKLEFT
)
1015 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
-8,
1016 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+6,
1017 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1021 if (p
->next
->member
.type
==T_PLAYER
&&p
->next
->member
.status
& S_HIT
) /* hit */
1023 p
->next
->member
.status
&= ~S_HIT
;
1024 if (!(p
->next
->member
.status
& S_DEAD
)) /* don't draw blood splash to dead players */
1031 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+fore
+((long)(p
->next
->member
.data
)&255),
1032 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+(((long)(p
->next
->member
.data
)>>8)&255),
1033 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)p
->next
->member
.data
)>>16],
1041 double2int(p
->next
->member
.x
-hero
->x
)+SCREEN_XOFFSET
+((long)(p
->next
->member
.data
)&255),
1042 double2int(p
->next
->member
.y
-hero
->y
)+SCREEN_YOFFSET
+(((long)(p
->next
->member
.data
)>>8)&255),
1043 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)p
->next
->member
.data
)>>16],
1049 if (obj_attr
[T_PLAYER
].foreground
!=fore
)continue;
1051 if (hero
->status
& S_DEAD
)
1052 continue; /* don't draw dead hero */
1060 sprites
[hero
->sprite
].positions
+sprites
[hero
->sprite
].steps
[hero
->anim_pos
],
1069 sprites
[hero
->sprite
].positions
+sprites
[hero
->sprite
].steps
[hero
->anim_pos
],
1073 if ((hero
->status
& S_JETPACK_ON
) && !(hero
->status
& S_CREEP
)) {
1074 if (hero
->status
& S_LOOKRIGHT
)
1075 put_sprite(SCREEN_XOFFSET
-1, SCREEN_YOFFSET
+4,
1076 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[1], 1);
1077 else if (hero
->status
& S_LOOKLEFT
)
1078 put_sprite(SCREEN_XOFFSET
+PLAYER_WIDTH
-4, SCREEN_YOFFSET
+4,
1079 sprites
[jetpack_sprite
].positions
+sprites
[jetpack_sprite
].steps
[0], 1);
1081 if ((gsbi
+= 10) > 1000) {
1085 if (hero
->status
& S_ONFIRE
) {
1086 if (hero
->status
& S_CREEP
)
1087 put_sprite(SCREEN_XOFFSET
-5, SCREEN_YOFFSET
-2,
1088 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3 + 3], 1);
1090 put_sprite(SCREEN_XOFFSET
+3, SCREEN_YOFFSET
-3,
1091 sprites
[fire_sprite
].positions
+sprites
[fire_sprite
].steps
[gsbi
% 3], 1);
1093 if ((hero
->status
& S_CHAINSAW
) && (hero
->ttl
>= FIRE_SHOOTING
) && !(hero
->status
& S_CREEP
)) {
1094 if (hero
->status
& S_LOOKRIGHT
)
1095 put_sprite(SCREEN_XOFFSET
+15, SCREEN_YOFFSET
+6,
1096 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1097 else if (hero
->status
& S_LOOKLEFT
)
1098 put_sprite(SCREEN_XOFFSET
-8, SCREEN_YOFFSET
+6,
1099 sprites
[chain_sprite
].positions
+sprites
[chain_sprite
].steps
[(gsbi
/ 10) % 2], 1);
1101 if (hero
->status
& S_HIT
) /* hit */
1103 hero
->status
&= ~S_HIT
;
1109 SCREEN_XOFFSET
+((long)(hero
->data
)&255),
1110 SCREEN_YOFFSET
+(((long)(hero
->data
)>>8)&255),
1111 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)hero
->data
)>>16],
1118 SCREEN_XOFFSET
+((long)(hero
->data
)&255),
1119 SCREEN_YOFFSET
+(((long)(hero
->data
)>>8)&255),
1120 sprites
[hit_sprite
].positions
+sprites
[hit_sprite
].steps
[((long)hero
->data
)>>16],
1128 void change_level(void)
1134 free_sprites(level_sprites_start
);
1137 LEVEL
=load_level(level_number
);
1138 snprintf(txt
,sizeof(txt
),"%s%s%s",DATA_PATH
,LEVEL
,LEVEL_SPRITES_SUFFIX
);
1140 snprintf(txt
,sizeof(txt
),"%s%s%s",DATA_PATH
,LEVEL
,STATIC_DATA_SUFFIX
);
1146 /* returns number of read bytes */
1147 int process_packet(char *packet
,int l
)
1154 for (a
=1;a
<l
&&a
<MAX_PACKET_LENGTH
;a
+=n
)
1155 n
=process_packet(packet
+a
,l
-a
);
1159 if (l
< (n
=30))break; /* invalid packet */
1161 get_int(packet
+1), /* ID */
1162 packet
[27], /* type */
1163 get_int16(packet
+28), /* time to live */
1164 get_int16(packet
+5), /* sprite */
1165 0, /* anim position */
1166 get_int(packet
+23), /* status */
1167 get_int(packet
+7), /* x */
1168 get_int(packet
+11), /* y */
1169 get_int(packet
+15), /* xspeed */
1170 get_int(packet
+19), /* yspeed */
1175 case P_PLAYER_DELETED
:
1180 case P_DELETE_OBJECT
:
1181 if (l
<5)break; /* invalid packet */
1182 delete_obj(get_int(packet
+1));
1186 case P_UPDATE_OBJECT
:
1187 if (l
< (n
=28))break; /* invalid packet */
1189 struct object_list
*p
;
1191 p
=find_in_table(get_int(packet
+1));
1193 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1194 p
->member
.update_counter
=packet
[5];
1195 p
->member
.x
=get_int(packet
+6);
1196 p
->member
.y
=get_int(packet
+10);
1197 p
->member
.xspeed
=get_int(packet
+14);
1198 p
->member
.yspeed
=get_int(packet
+18);
1199 p
->member
.status
=get_int(packet
+22);
1201 p
->member
.ttl
=get_int16(packet
+26);
1202 /* kdyz tasi, tak se nahodi ttl */
1203 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1204 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1208 case P_UPDATE_OBJECT_POS
:
1209 if (l
<22)break; /* invalid packet */
1211 struct object_list
*p
;
1214 p
=find_in_table(get_int(packet
+1));
1216 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1217 p
->member
.update_counter
=packet
[5];
1218 p
->member
.x
=get_int(packet
+6);
1219 p
->member
.y
=get_int(packet
+10);
1220 p
->member
.xspeed
=get_int(packet
+14);
1221 p
->member
.yspeed
=get_int(packet
+18);
1225 case P_UPDATE_OBJECT_SPEED
:
1226 if (l
<14)break; /* invalid packet */
1228 struct object_list
*p
;
1231 p
=find_in_table(get_int(packet
+1));
1233 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1234 p
->member
.update_counter
=packet
[5];
1235 p
->member
.xspeed
=get_int(packet
+6);
1236 p
->member
.yspeed
=get_int(packet
+10);
1240 case P_UPDATE_OBJECT_COORDS
:
1241 if (l
<14)break; /* invalid packet */
1243 struct object_list
*p
;
1246 p
=find_in_table(get_int(packet
+1));
1248 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1249 p
->member
.update_counter
=packet
[5];
1250 p
->member
.x
=get_int(packet
+6);
1251 p
->member
.y
=get_int(packet
+10);
1255 case P_UPDATE_OBJECT_SPEED_STATUS
:
1256 if (l
< (n
=18))break; /* invalid packet */
1258 struct object_list
*p
;
1260 p
=find_in_table(get_int(packet
+1));
1262 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1263 p
->member
.update_counter
=packet
[5];
1264 p
->member
.xspeed
=get_int(packet
+6);
1265 p
->member
.yspeed
=get_int(packet
+10);
1266 p
->member
.status
=get_int(packet
+14);
1267 /* kdyz tasi, tak se nahodi ttl */
1268 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1269 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1273 case P_UPDATE_OBJECT_COORDS_STATUS
:
1274 if (l
< (n
=18))break; /* invalid packet */
1276 struct object_list
*p
;
1278 p
=find_in_table(get_int(packet
+1));
1280 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1281 p
->member
.update_counter
=packet
[5];
1282 p
->member
.x
=get_int(packet
+6);
1283 p
->member
.y
=get_int(packet
+10);
1284 p
->member
.status
=get_int(packet
+14);
1285 /* kdyz tasi, tak se nahodi ttl */
1286 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1287 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1291 case P_UPDATE_OBJECT_SPEED_STATUS_TTL
:
1292 if (l
< (n
=20))break; /* invalid packet */
1294 struct object_list
*p
;
1296 p
=find_in_table(get_int(packet
+1));
1298 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1299 p
->member
.update_counter
=packet
[5];
1300 p
->member
.xspeed
=get_int(packet
+6);
1301 p
->member
.yspeed
=get_int(packet
+10);
1302 p
->member
.status
=get_int(packet
+14);
1303 p
->member
.ttl
=get_int16(packet
+18);
1304 /* kdyz tasi, tak se nahodi ttl */
1305 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1306 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1310 case P_UPDATE_OBJECT_COORDS_STATUS_TTL
:
1311 if (l
< (n
=20))break; /* invalid packet */
1313 struct object_list
*p
;
1315 p
=find_in_table(get_int(packet
+1));
1317 if(packet
[5]-(p
->member
.update_counter
)>127)break; /* throw out old updates */
1318 p
->member
.update_counter
=packet
[5];
1319 p
->member
.x
=get_int(packet
+6);
1320 p
->member
.y
=get_int(packet
+10);
1321 p
->member
.status
=get_int(packet
+14);
1322 p
->member
.ttl
=get_int16(packet
+18);
1323 /* kdyz tasi, tak se nahodi ttl */
1324 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1325 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1329 case P_UPDATE_STATUS
:
1330 if (l
< (n
=9))break; /* invalid packet */
1332 struct object_list
*p
;
1334 p
=find_in_table(get_int(packet
+1));
1335 if (!p
)break; /* ignore objects we don't have */
1336 p
->member
.status
=get_int(packet
+5);
1337 /* kdyz tasi, tak se nahodi ttl */
1338 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1339 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1344 if (l
<8)break; /* invalid packet */
1346 struct object_list
*p
;
1349 p
=find_in_table(get_int(packet
+1));
1350 if (!p
)break; /* ignore objects we don't have */
1351 p
->member
.status
|=S_HIT
;
1352 p
->member
.data
=(void*)(long)((packet
[5]<<16)+(packet
[7]<<8)+(packet
[6]));
1353 /* kdyz tasi, tak se nahodi ttl */
1354 if (p
->member
.type
==T_PLAYER
&&(p
->member
.status
& S_HOLDING
)&&(p
->member
.status
& S_SHOOTING
))
1355 p
->member
.ttl
=weapon
[current_weapon
].cadence
+HOLD_GUN_AFTER_SHOOT
;
1359 case P_UPDATE_PLAYER
:
1360 if (l
<15+2*ARMS
)break; /* invalid packet */
1363 for (a
=0;a
<ARMS
;a
++)
1364 ammo
[a
]=get_int16(packet
+3+(a
<<1));
1365 frags
=get_int(packet
+3+ARMS
*2);
1366 deaths
=get_int(packet
+7+ARMS
*2);
1367 current_weapon
=get_int16(packet
+11+ARMS
*2);
1368 weapons
=get_int16(packet
+13+ARMS
*2);
1374 break; /* invalid packet */
1375 add_message(packet
+ 2, packet
[1]);
1376 n
= 3 + strlen(packet
+ 2);
1379 case P_CHANGE_LEVEL
:
1387 if (l
<38)break; /* invalid packet */
1388 a
=get_int(packet
+1);
1389 if (level_number
==a
)goto level_changed
;
1391 snprintf(txt
, sizeof(txt
), "Trying to change level to number %d", level_number
);
1392 add_message(txt
, M_INFO
);
1393 name
=load_level(level_number
);
1395 snprintf(error_message
,1024,"Cannot find level "
1396 "number %d. Game terminated. Press ENTER.",
1401 snprintf(txt
,256,"Changing level to \"%s\"",name
);
1403 add_message(txt
, M_INFO
);
1405 md5
=md5_level(level_number
);
1406 if (strcmp((char *)md5
,packet
+5)) /* MD5s differ */
1409 snprintf(error_message
,1024,"Invalid MD5 sum. Can't change level. Game terminated. Press ENTER.");
1410 add_message("Invalid MD5 sum. Can't change level. Exiting...", M_INFO
);
1416 /* OK we can change it */
1421 send_packet(&p
,1,(struct sockaddr
*)(&server
),my_id
,0);
1428 snprintf(error_message
,1024,"Game terminated. Press ENTER.");
1430 snprintf(error_message
,1024,"Game terminated by %s. Press ENTER.",packet
+1);
1440 active_players
=get_int(packet
+1);
1442 for (a
=0;a
<packet
[5]&&a
<TOP_PLAYERS_N
;a
++)
1445 top_players
[a
].frags
=get_int(packet
+l
);
1446 top_players
[a
].deaths
=get_int(packet
+l
+4);
1447 top_players
[a
].color
=packet
[l
+8];
1448 x
=strlen(packet
+l
+9)+1;
1449 memcpy(top_players
[a
].name
,packet
+l
+9,x
);
1455 case P_EXPLODE_GRENADE
:
1457 case P_EXPLODE_BLOODRAIN
:
1460 struct object_list
*p
;
1465 i
=get_int(packet
+1);
1466 j
=get_int(packet
+5);
1470 for (b
=0;b
<N_SHRAPNELS_EXPLODE
;b
++)
1472 double angle
=(double)b
*2*M_PI
/N_SHRAPNELS_EXPLODE
;
1473 int spd
=add_int(mul_int(my_and(mul_int(weapon
[WEAPON_GRENADE
].speed
,b
+1),15),16),100);
1479 (*packet
==P_EXPLODE_GRENADE
)?
1480 shrapnel_sprite
[random()%N_SHRAPNELS
]:
1481 (*packet
==P_EXPLODE_BFG
)?
1482 bfgbit_sprite
[random()%N_SHRAPNELS
]:
1483 bloodrain_sprite
[random()%N_SHRAPNELS
],
1488 p
->member
.xspeed
+mul(spd
,float2double(cos(angle
))),
1489 p
->member
.yspeed
+mul(spd
,float2double(sin(angle
))),
1493 if (*packet
!= P_EXPLODE_BLOODRAIN
)
1503 /* read packet from socket */
1508 struct sockaddr_in client
;
1509 static char packet
[MAX_PACKET_LENGTH
];
1510 int a
=sizeof(client
);
1517 while(select(fd
+1,&rfds
,0,0,&tv
))
1519 if ((l
=recv_packet(packet
,MAX_PACKET_LENGTH
,(struct sockaddr
*)(&client
),&a
,1,my_id
,0))<0)
1520 return 0; /* something's strange */
1521 if (process_packet(packet
,l
)<0)return 1;
1528 /* select color for numeric value (red=lack, yellow=edium, green=fill) */
1529 int select_color(int value
,int max
)
1531 return value
>=(max
>>1)?10:(value
>=(max
>>2)?11:9);
1535 /* draw board at the bottom of the screen */
1536 void draw_board(void)
1538 int offs
=SCREEN_X
*(SCREEN_Y
-2);
1539 int space
=(SCREEN_X
-60)/5;
1543 memset(screen_a
+offs
,4,SCREEN_X
);
1544 memset(screen
+offs
,'-',SCREEN_X
);
1545 memset(screen
+offs
+SCREEN_X
,0,SCREEN_X
);
1546 print2screen(0,SCREEN_Y
-1,7,"HEALTH");
1547 snprintf(txt
, sizeof(txt
), "% 3d%%",health
);
1548 print2screen(6,SCREEN_Y
-1,select_color(health
,100),txt
);
1550 print2screen(11+(space
>>1),SCREEN_Y
-2,4,",");
1551 print2screen(11+(space
>>1),SCREEN_Y
-1,4,"|");
1552 print2screen(11+space
,SCREEN_Y
-1,7,"FRAGS");
1553 snprintf(txt
, sizeof(txt
), "% 4d",frags
);
1554 print2screen(11+space
+6,SCREEN_Y
-1,11,txt
);
1556 print2screen(21+space
+(space
>>1),SCREEN_Y
-2,4,",");
1557 print2screen(21+space
+(space
>>1),SCREEN_Y
-1,4,"|");
1558 print2screen(21+(space
<<1),SCREEN_Y
-1,7,"DEATHS");
1559 snprintf(txt
, sizeof(txt
), "% 4d",deaths
);
1560 print2screen(21+(space
<<1)+7,SCREEN_Y
-1,11,txt
);
1562 print2screen(31+(space
<<1)+(space
>>1),SCREEN_Y
-2,4,",");
1563 print2screen(31+(space
<<1)+(space
>>1),SCREEN_Y
-1,4,"|");
1564 snprintf(txt
, sizeof(txt
), "%10s",weapon
[current_weapon
].name
);
1565 print2screen(31+3*space
,SCREEN_Y
-1,11,txt
);
1567 print2screen(41+(3*space
)+(space
>>1),SCREEN_Y
-2,4,",");
1568 print2screen(41+(3*space
)+(space
>>1),SCREEN_Y
-1,4,"|");
1569 print2screen(41+(space
<<2),SCREEN_Y
-1,7,"AMMO");
1570 snprintf(txt
, sizeof(txt
), "% 4d",ammo
[current_weapon
]);
1571 print2screen(41+5+(space
<<2),SCREEN_Y
-1,select_color(ammo
[current_weapon
],weapon
[current_weapon
].max_ammo
),txt
);
1573 print2screen(49+(space
<<2)+(space
>>1),SCREEN_Y
-2,4,",");
1574 print2screen(49+(space
<<2)+(space
>>1),SCREEN_Y
-1,4,"|");
1575 print2screen(49+5*space
,SCREEN_Y
-1,7,"ARMOR");
1576 snprintf(txt
, sizeof(txt
), "% 4d%%",armor
);
1577 print2screen(49+5+5*space
,SCREEN_Y
-1,select_color(armor
,100),txt
);
1578 if (hero
->status
& S_INVISIBLE
)print2screen(SCREEN_X
-(offset
+= 14),SCREEN_Y
-2,C_YELLOW
,"INVISIBILITY");
1579 if (hero
->status
& S_ILL
)print2screen(SCREEN_X
-(offset
+= 14),SCREEN_Y
-2,C_RED
,"! INFECTED !");
1580 if (hero
->status
& S_ONFIRE
)print2screen(SCREEN_X
-(offset
+= 9),SCREEN_Y
-2,C_RED
,"ON FIRE");
1581 if (autorun
)print2screen(2,SCREEN_Y
-2,15,"AUTORUN");
1582 if (autocreep
)print2screen(10,SCREEN_Y
-2,15,"AUTOCREEP");
1586 /* read string from input, returns everytime, not when string's read */
1587 int read_str_online(int y
,char *pointer
,char *message
, int max_len
)
1598 memcpy(screen2
+c
,message
,a
);
1599 memcpy(screen2
+c
+a
,pointer
,b
);
1600 memset(screen2_a
+c
,15,a
);
1601 memset(screen2_a
+c
+a
,7,b
);
1602 memset(screen2_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1606 memcpy(screen
+c
,message
,a
);
1607 memcpy(screen
+c
+a
,pointer
,b
);
1608 memset(screen_a
+c
,15,a
);
1609 memset(screen_a
+c
+a
,7,b
);
1610 memset(screen_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1614 if (c_was_pressed(K_ESCAPE
))
1619 if (c_was_pressed(K_ENTER
))
1623 if (c_pressed(K_BACKSPACE
)&&b
)
1628 shift
=c_pressed(K_LEFT_SHIFT
)||c_pressed(K_RIGHT_SHIFT
);
1629 for (c
=' ';c
<128&&b
<max_len
;c
++)
1630 if (c_was_pressed(c
))
1632 pointer
[b
]=shift
?my_toupper(c
):c
;
1640 /* read number from input, returns everytime, not when number's read */
1641 int read_num_online(int y
,char *pointer
,char *message
, int max_len
)
1652 memcpy(screen2
+c
,message
,a
);
1653 memcpy(screen2
+c
+a
,pointer
,b
);
1654 memset(screen2_a
+c
,15,a
);
1655 memset(screen2_a
+c
+a
,7,b
);
1656 memset(screen2_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1660 memcpy(screen
+c
,message
,a
);
1661 memcpy(screen
+c
+a
,pointer
,b
);
1662 memset(screen_a
+c
,15,a
);
1663 memset(screen_a
+c
+a
,7,b
);
1664 memset(screen_a
+c
+a
+b
,0,SCREEN_X
-b
-a
);
1668 if (c_was_pressed(K_ESCAPE
))
1673 if (c_was_pressed(K_ENTER
))
1677 if (c_pressed(K_BACKSPACE
)&&b
)
1682 for (c
='0';c
<='9'&&b
<max_len
;c
++)
1683 if (c_was_pressed(c
))
1693 /* load banner.dat */
1694 void load_banner(char **banner
)
1701 s
=fopen(DATA_PATH BANNER_FILE
,"r");
1703 fopen_s(&s
,DATA_PATH BANNER_FILE
,"r");
1705 if (!s
){shut_down(0);ERROR("Error: Can't load file \""DATA_PATH BANNER_FILE
"\".\n");EXIT(1);}
1706 *banner
=mem_alloc(1);
1708 if (!(*banner
)){shut_down(0);ERROR("Error: Not enough memory.\n");EXIT(1);}
1709 while (fgets(line
,1024,s
))
1711 if (line
[strlen(line
)-1]==10)line
[strlen(line
)-1]=0;
1712 if (line
[strlen(line
)-1]==13)line
[strlen(line
)-1]=0; /* crlf shit */
1715 *banner
=mem_realloc((*banner
),a
+b
+SCREEN_X
+1);
1716 memcpy((*banner
)+a
,line
,b
);
1717 memset((*banner
)+a
+b
,' ',SCREEN_X
);
1718 (*banner
)[a
+b
+SCREEN_X
]=0;
1723 #define ERRBOX_HEIGHT 1
1724 #define ERRBOX_Y ((SCREEN_Y-2-ERRBOX_HEIGHT)>>1)
1726 /* draw error box */
1727 void print_error(char *text
)
1729 int width
= strlen(text
) + 6;
1730 int x
= (SCREEN_X
-2-width
) >> 1;
1732 draw_frame(x
, ERRBOX_Y
, width
, ERRBOX_HEIGHT
, 15);
1733 print2screen(x
+ 2, ERRBOX_Y
+ 1, C_RED
, "/!\\");
1734 print2screen(x
+ 6, ERRBOX_Y
+ 1, C_YELLOW
, text
);
1738 /* draw initial screen */
1739 void menu_screen(struct config
*cfg
)
1742 int sprite
,anim
=0,title_anim
=0,bulge_anim
=0;
1743 unsigned long_long t
;
1744 char port
[MAX_PORT_LEN
+1];
1747 char *color_name
[15]={"red","green","brown","blue","violet","cyan","gray","black","light red","light green","yellow","light blue","magenta","light cyan","white"};
1751 #ifdef HAVE_LIBPTHREAD
1758 load_banner(&banner
);
1760 snprintf(port
, sizeof(port
), "%d",cfg
->port
);
1761 snprintf(txt
, sizeof(txt
), "hero%d",cfg
->color
);
1762 if (find_sprite(txt
,&sprite
))
1767 snprintf(msg
,256,"Error: Can't find sprite \"%s\".\n",txt
);
1779 put_sprite((SCREEN_X
+1-TITLE_WIDTH
)>>1,0,sprites
[title_sprite
].positions
+sprites
[title_sprite
].steps
[title_anim
],0);
1780 put_sprite(SCREEN_XOFFSET
+1+PLAYER_WIDTH
+((SCREEN_X
-SCREEN_XOFFSET
-PLAYER_WIDTH
-BULGE_WIDTH
)>>1),TITLE_HEIGHT
+((SCREEN_Y
-3-BULGE_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[bulge_sprite
].positions
+sprites
[bulge_sprite
].steps
[bulge_anim
],0);
1781 put_sprite(SCREEN_XOFFSET
+1,TITLE_HEIGHT
+((SCREEN_Y
-3-PLAYER_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[sprite
].positions
+sprites
[sprite
].steps
[(anim
<2?48:39)+(anim
&7)],0);
1785 put_sprite((SCREEN_X
-TITLE_WIDTH
)>>1,0,sprites
[title_sprite
].positions
+sprites
[title_sprite
].steps
[title_anim
],0);
1786 put_sprite(SCREEN_XOFFSET
+PLAYER_WIDTH
+((SCREEN_X
-SCREEN_XOFFSET
-PLAYER_WIDTH
-BULGE_WIDTH
)>>1),TITLE_HEIGHT
+((SCREEN_Y
-3-BULGE_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[bulge_sprite
].positions
+sprites
[bulge_sprite
].steps
[bulge_anim
],0);
1787 put_sprite(SCREEN_XOFFSET
,TITLE_HEIGHT
+((SCREEN_Y
-3-PLAYER_HEIGHT
-TITLE_HEIGHT
)>>1),sprites
[sprite
].positions
+sprites
[sprite
].steps
[(anim
<2?48:39)+(anim
&7)],0);
1788 print2screen(0,TITLE_HEIGHT
+4,11,"N");
1789 print2screen(1,TITLE_HEIGHT
+4,2,"AME:");
1790 print2screen(6,TITLE_HEIGHT
+4,7,cfg
->name
);
1791 print2screen(0,TITLE_HEIGHT
+6,2,"COLOR:");
1792 print2screen(7,TITLE_HEIGHT
+6,7,color_name
[(cfg
->color
-1)%15]);
1793 print2screen(0,TITLE_HEIGHT
+0,11,"S");
1794 print2screen(1,TITLE_HEIGHT
+0,2,"ERVER ADDRESS:");
1795 print2screen(16,TITLE_HEIGHT
+0,7,cfg
->host
);
1796 print2screen(0,TITLE_HEIGHT
+2,11,"P");
1797 print2screen(1,TITLE_HEIGHT
+2,2,"ORT:");
1798 print2screen(6,TITLE_HEIGHT
+2,7,port
);
1799 print2screen((SCREEN_X
-26)>>1,SCREEN_Y
-3,7,"Use arrows to change color");
1800 print2screen((SCREEN_X
-52)>>1,SCREEN_Y
-2,7,"Press ENTER to connect, H for help, ESC or Q to quit");
1801 print2screen(0,SCREEN_Y
-1,15,banner
+(banner_pos
>>1));
1807 title_anim
%=sprites
[title_sprite
].n_steps
;
1809 bulge_anim
%=sprites
[bulge_sprite
].n_steps
;
1812 print2screen(((SCREEN_X
-strlen(error_message
))>>1),SCREEN_Y
-1,9,error_message
);
1828 if (help
)print_help_window();
1829 #ifdef HAVE_LIBPTHREAD
1830 if (pt
&& errormsg
.flags
) {
1831 pthread_kill(pt
, 9); /* good bye */
1834 if (!pt
&& errormsg
.flags
== E_CONN_SUCC
) {
1841 print_error(errormsg
.text
);
1846 if (read_str_online(SCREEN_Y
-1,cfg
->name
,"Enter your name: ",MAX_NAME_LEN
)) {
1847 cfg
->override
&= ~OVERRIDE_FLAG_NAME
;
1853 if (read_str_online(SCREEN_Y
-1,cfg
->host
,"Enter address: ",MAX_HOST_LEN
)) {
1854 cfg
->override
&= ~OVERRIDE_FLAG_HOST
;
1860 if (read_num_online(SCREEN_Y
-1,port
,"Enter port: ",MAX_PORT_LEN
)) {
1861 cfg
->override
&= ~OVERRIDE_FLAG_PORT
;
1862 cfg
->port
= strtol(port
, 0, 10);
1881 if ((c_was_pressed('+')||c_was_pressed('=')||c_was_pressed(K_UP
)||c_was_pressed(K_RIGHT
)||c_was_pressed(K_NUM_PLUS
)) && !errormsg
.flags
)
1886 snprintf(txt
, sizeof(txt
), "hero%d",cfg
->color
);
1887 if (find_sprite(txt
,&sprite
))
1888 {shut_down(0);mem_free(banner
);fprintf(stderr
,"Error: Can't find sprite \"%s\".\n",txt
);}
1889 cfg
->override
&= ~OVERRIDE_FLAG_COLOR
;
1892 if ((c_was_pressed('-')||c_was_pressed(K_NUM_MINUS
)||c_was_pressed(K_DOWN
)||c_was_pressed(K_LEFT
)) && !errormsg
.flags
)
1897 snprintf(txt
, sizeof(txt
), "hero%d",cfg
->color
);
1898 if (find_sprite(txt
,&sprite
))
1899 {shut_down(0);mem_free(banner
);fprintf(stderr
,"Error: Can't find sprite \"%s\".\n",txt
);}
1900 cfg
->override
&= ~OVERRIDE_FLAG_COLOR
;
1903 if (c_was_pressed('h') && !errormsg
.flags
)help
^=1;
1904 if (c_was_pressed(K_ENTER
))
1906 if (errormsg
.flags
) {
1907 errormsg
.flags
= E_NONE
;
1911 cfg
->port
=strtol(port
,0,10);
1912 if ((m
=find_server(cfg
)))
1914 print2screen(((SCREEN_X
-strlen(m
))>>1),SCREEN_Y
-1,9,m
);
1927 if ((m
=init_socket()))
1929 print2screen(((SCREEN_X
-strlen(m
))>>1),SCREEN_Y
-1,9,m
);
1942 #ifdef HAVE_LIBPTHREAD
1944 pthread_create(&pt
, NULL
, (void *)contact_server
, cfg
);
1949 if(contact_server(cfg
))
1958 if ((c_was_pressed('q')||c_was_pressed(K_ESCAPE
)) && !errormsg
.flags
)
1965 if (c_was_pressed('n') && !errormsg
.flags
)
1968 if ((c_was_pressed('a')||c_was_pressed('s')) && !errormsg
.flags
)
1971 if (c_was_pressed('p') && !errormsg
.flags
)
1974 sleep_until(t
+MENU_PERIOD_USEC
);
1979 /* handle fatal signal (sigabrt, sigsegv, ...) */
1980 void signal_handler(int signum
)
1983 if (connected
)send_quit();
1986 psignal(signum
,"Exiting on signal");
1988 fprintf(stderr
, "Exiting on signal: %d\n", signum
);
1994 /* change size of the screen */
1995 void sigwinch_handler(int signum
)
2001 c_init(SCREEN_X
,SCREEN_Y
);
2007 signal(SIGWINCH
,sigwinch_handler
);
2013 /* print command line help */
2014 void print_help(void)
2019 x
= " for X windows";
2020 y
= " [-d <display>] [-f <font name>]";
2025 "(c)2000 Brainsoft\n"
2026 "Usage: 0verkill [-h] [-3] [-i <server address>] \n"
2027 "[-c <color>] [-n <player name>] [-p <port>] \n"
2028 "[-s <width>x<height>]%s"
2034 void parse_dimensions(char *txt
)
2039 for (p
=txt
;(*p
)&&(*p
)!='x';p
++);
2040 if (!(*p
)){ERROR("Error: Expected dimensions in form WIDTHxHEIGHT.\n");EXIT(1);}
2043 if (!strlen(txt
)||!strlen(p
)){fprintf(stderr
,"Error: Decimal number expected.\n");EXIT(1);}
2044 SCREEN_X
=strtoul(txt
,&e
,10);
2045 if (*e
){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2046 SCREEN_Y
=strtoul(p
,&e
,10);
2047 if (*e
){ERROR("Error: Decimal number expected.\n");EXIT(1);}
2052 void parse_command_line(struct config
*cfg
)
2061 a
=getopt(cfg
->argc
,cfg
->argv
,"3hl:f:d:s:n:i:p:c:");
2064 a
=getopt(cfg
->argc
,cfg
->argv
,"3hl:s:n:i:p:c:");
2068 a
=getopt(cfg
->argc
,cfg
->argv
,"hf:d:s:n:i:p:c:");
2071 a
=getopt(cfg
->argc
,cfg
->argv
,"hs:n:i:p:c:");
2094 parse_dimensions(optarg
);
2098 x_display_name
=optarg
;
2106 memcpy(cfg
->host
, optarg
, strlen(optarg
) + 1);
2107 cfg
->override
|= OVERRIDE_FLAG_HOST
;
2111 memcpy(cfg
->name
, optarg
, strlen(optarg
) + 1);
2112 cfg
->override
|= OVERRIDE_FLAG_NAME
;
2116 cfg
->port
= strtol(optarg
, 0, 10);
2117 cfg
->override
|= OVERRIDE_FLAG_PORT
;
2121 cfg
->color
= strtol(optarg
, 0, 10);
2122 cfg
->override
|= OVERRIDE_FLAG_COLOR
;
2128 #define HALL_FAME_WIDTH (MAX_NAME_LEN+17)
2129 #define HALL_FAME_HEIGHT ((active_players>TOP_PLAYERS_N?TOP_PLAYERS_N:active_players)+5)
2130 #define HALL_FAME_X ((SCREEN_X-2-HALL_FAME_WIDTH)>>1)
2131 #define HALL_FAME_Y ((SCREEN_Y-2-HALL_FAME_HEIGHT)>>1)
2133 void print_hall_of_fame(void)
2137 unsigned char color
;
2139 if (!active_players
)return;
2140 snprintf(txt
, sizeof(txt
), "TOP %d PLAYERS",TOP_PLAYERS_N
);
2141 draw_frame(HALL_FAME_X
,HALL_FAME_Y
,HALL_FAME_WIDTH
,HALL_FAME_HEIGHT
,15);
2142 print2screen(HALL_FAME_X
+1+((HALL_FAME_WIDTH
-strlen(txt
))>>1),HALL_FAME_Y
+1,11,txt
);
2143 print2screen(HALL_FAME_X
+2,HALL_FAME_Y
+3,15,"NAME");
2144 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+2,HALL_FAME_Y
+3,15,"FRAGS");
2145 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+9,HALL_FAME_Y
+3,15,"DEATHS");
2146 for (a
=0;a
<active_players
&&a
<TOP_PLAYERS_N
;a
++)
2148 color
=((top_players
[a
].color
-1)%15)+1;
2149 print2screen(HALL_FAME_X
+2,HALL_FAME_Y
+4+a
,color
,top_players
[a
].name
);
2150 snprintf(txt
, sizeof(txt
), "% 5d",top_players
[a
].frags
);
2151 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+2,HALL_FAME_Y
+4+a
,color
,txt
);
2152 snprintf(txt
, sizeof(txt
), "% 5d",top_players
[a
].deaths
);
2153 print2screen(HALL_FAME_X
+2+MAX_NAME_LEN
+9,HALL_FAME_Y
+4+a
,color
,txt
);
2155 snprintf(txt
, sizeof(txt
), "%d",active_players
);
2156 print2screen(HALL_FAME_X
+2,HALL_FAME_Y
+HALL_FAME_HEIGHT
,11,"Players in the game:");
2157 print2screen(HALL_FAME_X
+23,HALL_FAME_Y
+HALL_FAME_HEIGHT
,7,txt
);
2167 unsigned char chat
=0;
2168 unsigned char help
=0;
2169 unsigned char hall_fame
=0;
2170 unsigned long_long last_time
;
2172 last_time
=get_time();
2175 last_time
+=CLIENT_PERIOD_USEC
;
2176 if (get_time()-last_time
>PERIOD_USEC
*100)last_time
=get_time();
2177 if (read_data())return; /* game terminated */
2179 if(!p
)clear_screen();
2185 if (!p
)draw_scene();
2189 update_messages(last_time
);
2193 switch (read_str_online(SCREEN_Y
-3,string
,"> ",78))
2201 send_message(string
, M_CHAT
);
2205 if (help
)print_help_window();
2206 if (hall_fame
)print_hall_of_fame();
2221 if (!chat
)c_update_kbd();
2224 if (c_was_pressed('p'))p
^=1;
2226 if (!chat
&&c_was_pressed('r'))
2231 if (!chat
&&c_was_pressed('h'))help
^=1;
2232 if (!chat
&&c_was_pressed(K_TAB
))
2235 if (hall_fame
)send_info_request();
2237 if (c_was_pressed(K_CAPS_LOCK
)||(!chat
&&c_was_pressed('a')))autorun
^=1;
2238 if (c_was_pressed(K_F10
)||(!chat
&&c_was_pressed('q')))
2244 if (c_pressed(K_F12
))
2247 if (!chat
&& c_was_pressed(K_ENTER
))
2249 memset(string
,0,80);
2257 if (!chat
&&c_was_pressed(' '))send_reenter_game();
2258 if (!chat
&&c_was_pressed('c'))
2260 if (c_pressed(K_DOWN
)||autocreep
)
2261 keyboard_status
.status
|= KBD_CREEP
;
2262 if (c_pressed(K_UP
))
2263 keyboard_status
.status
|= KBD_JUMP
;
2264 if (c_pressed(K_LEFT_CTRL
)||c_pressed(K_RIGHT_CTRL
)||(!chat
&&c_pressed('z')))
2265 keyboard_status
.status
|= KBD_FIRE
;
2266 if (!chat
&& c_pressed('d'))
2267 keyboard_status
.status
|= KBD_DOWN_LADDER
;
2268 if (!chat
&& c_pressed('j'))
2269 keyboard_status
.status
|= KBD_JETPACK
;
2270 if (!chat
&& c_was_pressed('1'))
2271 keyboard_status
.weapon
=1;
2272 if (!chat
&& c_was_pressed('2'))
2273 keyboard_status
.weapon
=2;
2274 if (!chat
&& c_was_pressed('3'))
2275 keyboard_status
.weapon
=3;
2276 if (!chat
&& c_was_pressed('4'))
2277 keyboard_status
.weapon
=4;
2278 if (!chat
&& c_was_pressed('5'))
2279 keyboard_status
.weapon
=5;
2280 if (!chat
&& c_was_pressed('6'))
2281 keyboard_status
.weapon
=6;
2282 if (!chat
&& c_was_pressed('7'))
2283 keyboard_status
.weapon
=7;
2284 if (!chat
&& c_was_pressed('8'))
2285 keyboard_status
.weapon
=8;
2286 if (c_pressed(K_LEFT_SHIFT
)||c_pressed(K_RIGHT_SHIFT
)||autorun
)
2287 keyboard_status
.status
|= KBD_SPEED
;
2288 if (c_pressed(K_LEFT
))
2289 keyboard_status
.status
|= KBD_LEFT
;
2290 if (c_pressed(K_RIGHT
))
2291 keyboard_status
.status
|= KBD_RIGHT
;
2294 sleep_until(last_time
+CLIENT_PERIOD_USEC
);
2298 /*----------------------------------------------------------------------------*/
2299 int main(int argc
,char **argv
)
2303 struct config cfg
= {argc
, argv
, "", "", DEFAULT_PORT
, 1, 0};
2308 WSAStartup(0x101, &wd
);
2309 printf("Started WinSock version %X.%02X\n", wd
.wVersion
/0x100, wd
.wVersion
&0xFF);
2312 chdir_to_data_files();
2321 memset(cfg
.host
,0,MAX_HOST_LEN
+1);
2322 memset(cfg
.name
,0,MAX_NAME_LEN
+1);
2327 parse_command_line(&cfg
);
2329 if (!set_size
)c_get_size(&SCREEN_X
,&SCREEN_Y
);
2333 load_sprites(DATA_PATH GAME_SPRITES_FILE
);
2335 snprintf(txt
,sizeof(txt
),"%s\\data\\sprites.dat",_getcwd(NULL
, 0));
2338 /* sprites are stored in memory in this order: game sprites (players,
2339 * bullets, corpses, blood, meat...) followed by level sprites
2342 level_sprites_start
=n_sprites
;
2343 if (find_sprite("hit",&hit_sprite
)){ERROR("Error: Can't find sprite \"hit\".\n");EXIT(1);}
2344 if (find_sprite("title",&title_sprite
)){ERROR("Error: Can't find sprite \"title\".\n");EXIT(1);}
2345 if (find_sprite("bulge",&bulge_sprite
)){ERROR("Error: Can't find sprite \"bulge\".\n");EXIT(1);}
2346 for (a
=0;a
<N_SHRAPNELS
;a
++)
2348 snprintf(txt
, sizeof(txt
), "shrapnel%d",a
+1);
2349 if (find_sprite(txt
,&shrapnel_sprite
[a
])) {
2350 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2353 snprintf(txt
, sizeof(txt
), "bfgbit%d",a
+1);
2354 if (find_sprite(txt
,&bfgbit_sprite
[a
])) {
2355 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2358 snprintf(txt
, sizeof(txt
), "bloodrain%d",a
+1);
2359 if (find_sprite(txt
,&bloodrain_sprite
[a
])) {
2360 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2364 snprintf(txt
, sizeof(txt
), "jetpack");
2365 if (find_sprite(txt
,&jetpack_sprite
)) {
2366 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2369 snprintf(txt
, sizeof(txt
), "fire");
2370 if (find_sprite(txt
,&fire_sprite
)) {
2371 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2374 snprintf(txt
, sizeof(txt
), "sawchain");
2375 if (find_sprite(txt
,&chain_sprite
)) {
2376 fprintf(stderr
,"Can't find sprite \"%s\".\n",txt
);
2380 signal(SIGINT
,signal_handler
);
2381 signal(SIGTERM
,signal_handler
);
2382 signal(SIGILL
,signal_handler
);
2383 signal(SIGABRT
,signal_handler
);
2384 signal(SIGFPE
,signal_handler
);
2385 signal(SIGSEGV
,signal_handler
);
2387 signal(SIGQUIT
,signal_handler
);
2388 signal(SIGBUS
,signal_handler
);
2390 signal(SIGWINCH
,sigwinch_handler
);
2393 c_init(SCREEN_X
,SCREEN_Y
);
2405 delete_obj(hero
->id
);