29 /* static map of the level */
36 unsigned char *area_a
;
39 struct sprite
*sprites
=DUMMY
;
40 char **sprite_names
=DUMMY
;
41 int n_sprites
; /* number of sprites */
43 struct object_list
*last_obj
;
50 /* object attributes */
51 struct obj_attr_type obj_attr
[N_TYPES
]=
53 /* fall, bounce x, bounce y, slow down x, maintainer, foreground */
54 {1,0,0,PLAYER_SLOW_DOWN_X
,BOTH_UPDATE
,0}, /* player */
55 {0,0,0,int2double(1),BOTH
,0}, /* bullet */
56 {1,0,float2double(.25),PLAYER_SLOW_DOWN_X
,BOTH
,0}, /* corpse */
57 {1,0,0,0,NOBODY
,0}, /* medikit */
58 {1,0,0,0,NOBODY
,0}, /* shotgun */
59 {1,0,0,0,NOBODY
,0}, /* uzi */
60 {1,0,0,0,NOBODY
,0}, /* rifle */
61 {1,float2double(.8),float2double(.5),float2double(.8),CLIENT
,0}, /* shell */
62 {1,0,0,0,NOBODY
,0}, /* ammo for gun */
63 {1,0,0,0,NOBODY
,0}, /* ammo for shotgun */
64 {1,0,0,0,NOBODY
,0}, /* ammo for uzi */
65 {1,0,0,0,NOBODY
,0}, /* ammo for rifle */
66 {0,0,0,0,NOBODY
,0}, /* nothing */
67 {1,float2double(.4),float2double(.4),float2double(.3),CLIENT
,0}, /* mess */
68 {1,float2double(.5),float2double(.5),float2double(.9),BOTH
/*_UPDATE*/,0}, /* grenade */
69 {1,0,0,0,NOBODY
,0}, /* grenade ammo */
70 {1,0,0,int2double(1),BOTH
,0}, /* grenade shrapnel */
71 {1,0,0,0,NOBODY
,0}, /* armor */
72 {1,0,0,0,NOBODY
,0}, /* invisibility */
73 {1,0,0,0,NOBODY
,0}, /* noise */
74 {0,0,0,0,NOBODY
,1}, /* nothing in foreground */
75 {0,0,0,0,NOBODY
,1}, /* killing object */
76 {1,0,0,0,NOBODY
,0}, /* teleport */
77 {1,0,0,0,NOBODY
,0}, /* BFG */
78 {0,0,0,int2double(1),BOTH
,0}, /* BFG cell */
79 {0,0,0,int2double(1),BOTH
,0}, /* chainsaw chain */
83 /* weapon attributes */
84 struct weapon_type weapon
[ARMS
]=
86 /* name, cadence, ttl, bullet speed, impact, lethalness, armor damage, basic ammo, additional ammo, max ammo, shell xspeed, shell yspeed */
87 {"Browning",16,50,float2double(3*36),float2double(.3*36),20,2,13,12,48,float2double((double).3*36),-float2double(1*36)},
88 {"Shotgun",25,50,float2double(3*36),float2double(.5*36),10,5,6,12,30,float2double((double).3*36),-float2double((double)1.2*36)},
89 {"Uzi",3,50,float2double(4*36),float2double(.25*36),15,4,50,50,150,float2double((double).9*36),-float2double((double)1.5*36)},
90 {"Rifle",40,70,float2double(6*36),float2double(.4*36),50,20,1,15,15,0,0},
91 {"Grenades",15,60,float2double((double)3.73*36),0,75,40,0,6,24,float2double(3*36),-float2double((double)1.5*36)}, /* shell speed=grenade throwing speed, bullet speed=shrapnel speed */
92 {"BFG",200,80,float2double(2*36),float2double(1*36),100,100,10,10,10,float2double((double).1*36),-float2double((double)1.5*36)},
93 {"Chainsaw",1,5,float2double(1.8*36),0,10,10,1,1,1,0,0},
94 {"Bloodrain",15,0,float2double((double)3.73*36),0,75,40,1,1,1,0,0},
98 /* initialize playing area */
99 /* must be run before loading data */
102 area
=mem_alloc(AREA_X
*AREA_Y
);
103 if (!area
){ERROR("Error: Not enough memory!\n");EXIT(1);}
104 area_a
=mem_alloc(AREA_X
*AREA_Y
);
105 if (!area_a
){ERROR("Error: Not enough memory!\n");EXIT(1);}
106 memset(area
,' ',AREA_X
*AREA_Y
);
107 memset(area_a
,0,AREA_X
*AREA_Y
);
117 /* reinitializes playing area */
118 /* must be called before loading new level */
119 void reinit_area(void)
121 memset(area
,' ',AREA_X
*AREA_Y
);
122 memset(area_a
,0,AREA_X
*AREA_Y
);
125 /* skip white space */
126 /* ancillary function */
127 void _skip_ws(char **txt
)
129 for (;(**txt
)==' '||(**txt
)==9||(**txt
)==10;(*txt
)++);
133 /* find sprite according to its name */
134 /* returns 1 on error */
135 /* it's slow but not called in speed critical parts of the program */
136 int find_sprite(char *name
,int *num
)
138 for ((*num
)=0;(*num
)<n_sprites
;(*num
)++)
139 if (!strcmp(sprite_names
[*num
],name
))return 0;
144 /* convert type character (from data files) into type */
145 int _convert_type(unsigned char c
)
149 case 'b': return TYPE_BACKGROUND
;
150 case 'w': return TYPE_WALL
;
151 case 'j': return TYPE_JUMP
;
152 case 'f': return TYPE_FOREGROUND
;
153 case 'i': return TYPE_JUMP_FOREGROUND
;
155 /* dynamic objects, they use great letter */
156 case 'M': return T_MEDIKIT
;
157 case 'A': return T_ARMOR
;
158 case 'N': return T_NOTHING
;
159 case 'F': return T_NOTHING_FORE
;
160 case 'K': return T_KILL
;
161 case 'S': return T_SHOTGUN
;
162 case 'Z': return T_BFG
;
163 case 'U': return T_UZI
;
164 case 'R': return T_RIFLE
;
165 case '1': return T_AMMO_GUN
;
166 case '2': return T_AMMO_SHOTGUN
;
167 case '3': return T_AMMO_UZI
;
168 case '4': return T_AMMO_RIFLE
;
169 case '5': return T_AMMO_GRENADE
;
170 case 'I': return T_INVISIBILITY
;
171 case 'T': return T_TELEPORT
;
172 case 'X': return T_BIOSKULL
;
173 case 'x': return T_BIOMED
;
174 case 'r': return T_BLOODRAIN
;
175 case 'J': return T_JETPACK
;
176 case 'P': return T_PS
;
179 case 'B': return TYPE_BIRTHPLACE
;
186 /* load static data */
187 void load_data(char * filename
)
190 static char line
[1024];
196 if (!(stream
=fopen(filename
,"rb")))
198 if (!fopen_s(&stream
,filename
,"rb"))
202 snprintf(msg
,256,"Can't open file \"%s\"!\n",filename
);
206 while(fgets(line
,1024,stream
))
210 for (name
=p
;(*p
)!=' '&&(*p
)!=9&&(*p
)!=10&&(*p
);p
++);
214 if ((t
=_convert_type(*p
))<0)
217 snprintf(msg
,256,"Unknown object type '%c'.\n",*p
);
226 if (find_sprite(name
,&n
))
229 snprintf(msg
,256,"Unknown bitmap name \"%s\"!\n",name
);
233 _put_sprite(AREA_X
,AREA_Y
,area
,area_a
,x
,y
,sprites
[n
].positions
,t
,0);
240 void load_sprites(char * filename
)
248 if(!(stream
=fopen(filename
,"rb")))
252 if((err
= fopen_s(&stream
,filename
,"rb")) != 0)
256 snprintf(msg
,256,"Can't open file \"%s\"!\n",filename
);
260 while(fgets(line
,1024,stream
))
264 for (q
=p
;(*p
)!=' '&&(*p
)!=9&&(*p
)!=10&&(*p
);p
++);
269 sprite_names
=(char **)mem_realloc(sprite_names
,n_sprites
*sizeof(unsigned char*));
270 if (!sprite_names
){ERROR("Memory allocation error!\n");EXIT(1);}
271 sprites
=(struct sprite
*)mem_realloc(sprites
,n_sprites
*sizeof(struct sprite
));
272 if (!sprites
){ERROR("Memory allocation error!\n");EXIT(1);}
273 sprite_names
[n_sprites
-1]=(char *)mem_alloc(l
+1);
274 if (!sprite_names
[n_sprites
-1]){ERROR("Memory allocation error!\n");EXIT(1);}
275 memcpy(sprite_names
[n_sprites
-1],q
,l
+1);
277 for (q
=p
;(*p
)!=' '&&(*p
)!=9&&(*p
)!=10&&(*p
);p
++)
281 snprintf(r
, sizeof(r
), "%s\\%s", _getcwd(NULL
, 0), q
)
285 load_sprite(q
,sprites
+(n_sprites
-1));
291 void free_sprites(int start_num
)
295 for (a
=start_num
;a
<n_sprites
;a
++)
297 mem_free(sprite_names
[a
]);
298 free_sprite(sprites
+a
);
301 sprite_names
=(char **)mem_realloc(sprite_names
,n_sprites
*sizeof(unsigned char*));
302 if (!sprite_names
){ERROR("Memory allocation error!\n");EXIT(1);}
303 sprites
=mem_realloc(sprites
,n_sprites
*sizeof(struct sprite
));
304 if (!sprites
){ERROR("Memory allocation error!\n");EXIT(1);}
308 /* returns allocated string with level name or NULL on error */
309 /* level_num is a line number in the LEVEL_FILE */
310 char *load_level(int level_num
)
318 if(!(f
=fopen(DATA_PATH LEVEL_FILE
,"r")))
321 snprintf(txt
,sizeof(txt
),"%s\\data\\level.dat",_getcwd(NULL
, 0));
322 if((err
= fopen_s(&f
, txt
, "r")) != 0)
326 for (a
=0;a
<=level_num
;)
328 if (!(fgets(txt
,1024,f
)))return NULL
;
330 /* remove trailing CR and/or LF */
331 if (txt
[strlen(txt
)-1]==10)txt
[strlen(txt
)-1]=0;
332 if (txt
[strlen(txt
)-1]==13)txt
[strlen(txt
)-1]=0;
340 retval
=mem_alloc(1+a
*sizeof(unsigned char));
341 if (!retval
)return NULL
;
342 memcpy(retval
,txt
,a
+1); /* including trailing zero */
343 if (!strlen(retval
)){mem_free(retval
);return NULL
;}
348 /* create a new object and fill with data and add to hash table */
362 last_obj
->next
=mem_alloc(sizeof(struct object_list
));
363 if (!last_obj
->next
)return 0;
364 last_obj
->next
->prev
=last_obj
;
365 last_obj
=last_obj
->next
;
367 last_obj
->member
.x
=x
;
368 last_obj
->member
.y
=y
;
369 last_obj
->member
.xspeed
=xspeed
;
370 last_obj
->member
.yspeed
=yspeed
;
371 last_obj
->member
.type
=type
;
372 last_obj
->member
.ttl
=ttl
;
373 last_obj
->member
.sprite
=sprite
;
374 last_obj
->member
.anim_pos
=pos
;
375 last_obj
->member
.data
=data
;
376 last_obj
->member
.id
=id
;
377 last_obj
->member
.status
=status
;
378 last_obj
->member
.update_counter
=0;
379 last_obj
->member
.last_updated
=get_time();
380 add_to_table(last_obj
);
381 return &(last_obj
->member
);
385 /* completely delete object from the list */
386 void delete_obj(unsigned long id
)
388 struct object_list
*q
;
389 if (!(q
=remove_from_table(id
)))return; /* packets can come more than once, so we must ignore deleting deleted object */
390 q
->prev
->next
=q
->next
;
391 if (!q
->next
) last_obj
=q
->prev
; /* q is last object in list */
392 else q
->next
->prev
=q
->prev
;
396 void put_long_long(char *p
,unsigned long_long num
, int *offset
)
398 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
399 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
400 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
401 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
402 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
403 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
404 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
405 p
[(*offset
)++]=(char)(num
& 0xff);
409 void put_int(char *p
,int num
, int *offset
)
411 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
412 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
413 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
414 p
[(*offset
)++]=(char)(num
& 0xff);
420 return ((p
[0]&0xff) | ((p
[1]&0xff)<<8) |
421 ((p
[2]&0xff)<<16) | ((p
[3]&0xff)<<24));
425 void put_int16(char *p
, short num
, int *offset
)
427 p
[(*offset
)++]=(char)(num
& 0xff);num
>>=8;
428 p
[(*offset
)++]=(char)(num
& 0xff);
432 int get_int16(char *p
)
434 return ((p
[0]&0xff) | ((p
[1]&0xff)<<8));
438 unsigned long_long
get_long_long(char *p
)
440 #define ULL unsigned long_long
454 /* test if vertical line from yh to yl can move from old_x to new_x axis */
455 /* returns farthest possible x axis */
456 /* flag is filled with 1 if objects is stopped */
457 int can_go_x(int old_x
,int new_x
,int yh
, int yl
,unsigned char *flag
)
468 for (x
=double2int(old_x
)+1;x
<=round_up(new_x
);x
++) /* go to the right */
470 if (x
>AREA_X
-1) return int2double(AREA_X
-1);
472 if ((area_a
[x
+y
*AREA_X
]&240)==TYPE_WALL
)
473 return int2double(x
-1);
476 for (x
=round_up(old_x
)-1;x
>=double2int(new_x
);x
--) /* go to the left */
480 if ((area_a
[x
+y
*AREA_X
]&240)==TYPE_WALL
) return int2double(x
+1);
487 /* test if horizontal line from xl to xr can move from old_y to new_y axis */
488 /* returns farthest possible y axis */
489 /* flag is filled with 1 if objects is stopped */
490 /* down ladder: 1=fall through ladders etc., 0=stand on ladders */
491 int can_go_y(int old_y
, int new_y
,int xl
, int xr
,unsigned char *flag
,unsigned char down_ladder
)
495 if (old_y
==new_y
){if(flag
)*flag
=0;return new_y
;}
498 for (y
=double2int(old_y
)+1;y
<=round_up(new_y
);y
++) /* go down */
500 if (y
>AREA_Y
-1) return int2double(AREA_Y
-1);
502 if ((area_a
[x
+y
*AREA_X
]&240)==TYPE_WALL
||(!down_ladder
&&((area_a
[x
+y
*AREA_X
]&240)==TYPE_JUMP
||(area_a
[x
+y
*AREA_X
]&240)==TYPE_JUMP_FOREGROUND
))) return int2double(y
-1);
507 for (y
=round_up(old_y
)-1;y
>=double2int(new_y
);y
--) /* go up */
511 if ((area_a
[x
+y
*AREA_X
]&240)==TYPE_WALL
) return int2double(y
+1);
519 /* automatically computes dimensions of unknown type, if anim positions is given */
520 /* object must be rectangular */
526 get_dimensions(int type
,int status
,struct pos
*s
,int *w
,int *h
)
531 if (status
& S_CREEP
)
555 if (!s
){*h
=0;return;}
557 if (*h
)*w
=s
->lines
[0].len
;
563 /* updates object's position */
564 void update_position(struct it
* obj
,int new_x
,int new_y
,int width
, int height
,unsigned char *fx
,unsigned char *fy
)
566 unsigned char down_ladder
=0;
568 /* player is climbing ladder down */
569 if (obj
->type
== T_PLAYER
&& obj
->status
& S_CLIMB_DOWN
)
573 obj
->x
=sub_int(can_go_x(add_int(obj
->x
,width
-1),add_int(new_x
,width
-1),double2int(obj
->y
),round_up(obj
->y
)+height
-1,fx
),width
-1);
575 obj
->x
=can_go_x(obj
->x
,new_x
,double2int(obj
->y
),round_up(obj
->y
)+height
-1,fx
);
578 obj
->y
=sub_int(can_go_y(add_int(obj
->y
,height
-1),add_int(new_y
,height
-1),double2int(obj
->x
),round_up(obj
->x
)+width
-1,fy
,down_ladder
),height
-1);
580 obj
->y
=can_go_y(obj
->y
,new_y
,double2int(obj
->x
),round_up(obj
->x
)+width
-1,fy
,down_ladder
);
584 unsigned char *__add_md5(char *filename
, int *len
, unsigned char**result
)
590 q
=MD5File(filename
,NULL
);
592 if (!(*result
))*result
=DUMMY
;
593 p
=mem_realloc((*result
),(*len
)+a
+1);
594 if (!result
)return NULL
;
596 memcpy((*result
)+(*len
),q
,a
+1);
602 /* computes md5 sum from the level
603 * level_num is the line number in level.dat file
604 * returns allocated string with the MD5 sum or NULL (on error)
606 char* md5_level(int level_num
)
608 unsigned char *result
=0;
613 q
=load_level(level_num
);
616 if (!__add_md5(DATA_PATH LEVEL_FILE
,&len
,&result
)){mem_free(result
);return NULL
;}
618 snprintf(p
,2048,"%s%s%s",DATA_PATH
,q
,LEVEL_SPRITES_SUFFIX
);
619 if (!__add_md5(p
,&len
,&result
)){mem_free(result
);return NULL
;}
621 snprintf(p
,2048,"%s%s%s",DATA_PATH
,q
,STATIC_DATA_SUFFIX
);
622 if (!__add_md5(p
,&len
,&result
)){mem_free(result
);return NULL
;}
624 snprintf(p
,2048,"%s%s%s",DATA_PATH
,q
,DYNAMIC_DATA_SUFFIX
);
625 if (!__add_md5(p
,&len
,&result
)){mem_free(result
);return NULL
;}
627 snprintf(p
,2048,"%s%s%s",DATA_PATH
,q
,LEVEL_SPRITES_SUFFIX
);
634 if(!(f
=fopen(p
,"r")))
636 if(!fopen_s(&f
, p
, "r"))
642 while (fgets(p
,2048,f
))
644 if (p
[strlen(p
)-1]==13)p
[strlen(p
)-1]=0;
645 if (p
[strlen(p
)-1]==10)p
[strlen(p
)-1]=0;
649 for (;(*q
)&&(*q
)!=' '&&(*q
)!=9&&(*q
)!=10&&(*q
)!=13;q
++);
651 if (!strlen(q
))continue;
652 if (!__add_md5(q
,&len
,&result
)){mem_free(result
);return NULL
;}
657 q
=MD5Data(result
,len
,NULL
);
662 /* returns 1 if the file is readable */
663 static int r_access(const char *filename
)
666 return !access(filename
, R_OK
);
670 if(f
= fopen(filename
, "r"))
672 if(fopen_s(&f
, filename
, "r"))
682 /* changes the current dir to where the data files can be found */
683 void chdir_to_data_files(void)
685 if (!r_access(DATA_PATH BANNER_FILE
))