1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 #ifndef WIN32
6 #include "config.h"
7 #endif
8
9 #include "data.h"
10 #include "cfg.h"
11 #include "hash.h"
12 #include "time.h"
13 #include "md5.h"
14 #include "error.h"
15
16
17 #ifdef TRI_D
18 int tri_d=0;
19 int TRI_D_ON=0;
20 #endif
21
22
23 /* static map of the level */
24 unsigned char *area;
25
26 /* attributes:
27 lower 4 bits=color
28 higher 4 bits=type
29 */
30 unsigned char *area_a;
31
32
33 struct sprite *sprites=DUMMY;
34 unsigned char **sprite_names=DUMMY;
35 int n_sprites; /* number of sprites */
36
37 struct object_list *last_obj;
38
39 #define NOBODY 0
40 #define CLIENT 1
41 #define BOTH 3
42 #define BOTH_UPDATE 7
43
44 /* object attributes */
45 struct obj_attr_type obj_attr[N_TYPES]=
46 {
47 /* fall, bounce x, bounce y, slow down x, maintainer, foreground */
48 {1,0,0,PLAYER_SLOW_DOWN_X,BOTH_UPDATE,0}, /* player */
49 {0,0,0,int2double(1),BOTH,0}, /* bullet */
50 {1,0,float2double(.25),PLAYER_SLOW_DOWN_X,BOTH,0}, /* corpse */
51 {1,0,0,0,NOBODY,0}, /* medikit */
52 {1,0,0,0,NOBODY,0}, /* shotgun */
53 {1,0,0,0,NOBODY,0}, /* uzi */
54 {1,0,0,0,NOBODY,0}, /* rifle */
55 {1,float2double(.8),float2double(.5),float2double(.8),CLIENT,0}, /* shell */
56 {1,0,0,0,NOBODY,0}, /* ammo for gun */
57 {1,0,0,0,NOBODY,0}, /* ammo for shotgun */
58 {1,0,0,0,NOBODY,0}, /* ammo for uzi */
59 {1,0,0,0,NOBODY,0}, /* ammo for rifle */
60 {0,0,0,0,NOBODY,0}, /* nothing */
61 {1,float2double(.4),float2double(.4),float2double(.3),CLIENT,0}, /* mess */
62 {1,float2double(.5),float2double(.5),float2double(.9),BOTH/*_UPDATE*/,0}, /* grenade */
63 {1,0,0,0,NOBODY,0}, /* grenade ammo */
64 {1,0,0,int2double(1),BOTH,0}, /* grenade shrapnel */
65 {1,0,0,0,NOBODY,0}, /* armor */
66 {1,0,0,0,NOBODY,0}, /* invisibility */
67 {1,0,0,0,NOBODY,0}, /* noise */
68 {0,0,0,0,NOBODY,1}, /* nothing in foreground */
69 {0,0,0,0,NOBODY,1}, /* killing object */
70 };
71
72
73 /* weapon attributes */
74 struct weapon_type weapon[ARMS]=
75 {
76 /* name, cadence, ttl, bullet speed, impact, lethalness, armor damage, basic ammo, additional ammo, max ammo, shell xspeed, shell yspeed */
77 {"Browning",16,50,float2double(3*36),float2double(.3*36),20,2,13,12,48,float2double((double).3*36),-float2double(1*36)},
78 {"Shotgun",25,50,float2double(3*36),float2double(.5*36),10,5,6,12,30,float2double((double).3*36),-float2double((double)1.2*36)},
79 {"Uzi",3,50,float2double(4*36),float2double(.25*36),15,4,50,50,150,float2double((double).9*36),-float2double((double)1.5*36)},
80 {"Rifle",40,70,float2double(6*36),float2double(.4*36),50,20,1,15,15,0,0},
81 {"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 */
82 };
83
84
85 /* initialize playing area */
86 /* must be run before loading data */
init_area(void)87 void init_area(void)
88 {
89 area=mem_alloc(AREA_X*AREA_Y);
90 if (!area){ERROR("Error: Not enough memory!\n");EXIT(1);}
91 area_a=mem_alloc(AREA_X*AREA_Y);
92 if (!area_a){ERROR("Error: Not enough memory!\n");EXIT(1);}
93 memset(area,' ',AREA_X*AREA_Y);
94 memset(area_a,0,AREA_X*AREA_Y);
95 }
96
free_area(void)97 void free_area(void)
98 {
99 mem_free(area);
100 mem_free(area_a);
101 }
102
103
104 /* reinitializes playing area */
105 /* must be called before loading new level */
reinit_area(void)106 void reinit_area(void)
107 {
108 memset(area,' ',AREA_X*AREA_Y);
109 memset(area_a,0,AREA_X*AREA_Y);
110 }
111
112 /* skip white space */
113 /* ancillary function */
_skip_ws(char ** txt)114 void _skip_ws(char **txt)
115 {
116 for (;(**txt)==' '||(**txt)==9||(**txt)==10;(*txt)++);
117 }
118
119
120 /* find sprite according to its name */
121 /* returns 1 on error */
122 /* it's slow but not called in speed critical parts of the program */
find_sprite(unsigned char * name,int * num)123 int find_sprite(unsigned char *name,int *num)
124 {
125 for ((*num)=0;(*num)<n_sprites;(*num)++)
126 if (!strcmp(sprite_names[*num],name))return 0;
127 return 1;
128 }
129
130
131 /* convert type character (from data files) into type */
_convert_type(unsigned char c)132 int _convert_type(unsigned char c)
133 {
134 switch(c)
135 {
136
137 /* static objects */
138 case 'b': return TYPE_BACKGROUND;
139
140 case 'w': return TYPE_WALL;
141
142 case 'j': return TYPE_JUMP;
143
144 case 'f': return TYPE_FOREGROUND;
145
146 case 'i': return TYPE_JUMP_FOREGROUND;
147
148 /* dynamic objects, they use great letter */
149
150 case 'M': return T_MEDIKIT;
151
152 case 'A': return T_ARMOR;
153
154 case 'N': return T_NOTHING;
155
156 case 'F': return T_NOTHING_FORE;
157
158 case 'K': return T_KILL;
159
160 case 'S': return T_SHOTGUN;
161
162 case 'U': return T_UZI;
163
164 case 'R': return T_RIFLE;
165
166 case '1': return T_AMMO_GUN;
167
168 case '2': return T_AMMO_SHOTGUN;
169
170 case '3': return T_AMMO_UZI;
171
172 case '4': return T_AMMO_RIFLE;
173
174 case '5': return T_AMMO_GRENADE;
175
176 case 'I': return T_INVISIBILITY;
177
178 /* birthplace */
179 case 'B': return TYPE_BIRTHPLACE;
180
181 default:
182 return -1;
183 }
184 }
185
186
187 /* load static data */
load_data(unsigned char * filename)188 void load_data(unsigned char * filename)
189 {
190 FILE * stream;
191 static char line[1024];
192 char *p,*q,*name;
193 int n,x,y;
194 int t;
195
196 if (!(stream=fopen(filename,"rb")))
197 {
198 char msg[256];
199 snprintf(msg,256,"Can't open file \"%s\"!\n",filename);
200 ERROR(msg);
201 EXIT(1);
202 }
203 while(fgets(line,1024,stream))
204 {
205 p=line;
206 _skip_ws(&p);
207 for (name=p;(*p)!=' '&&(*p)!=9&&(*p)!=10&&(*p);p++);
208 if (!(*p))continue;
209 *p=0;p++;
210 _skip_ws(&p);
211 if ((t=_convert_type(*p))<0)
212 {
213 char msg[256];
214 snprintf(msg,256,"Unknown object type '%c'.\n",*p);
215 ERROR(msg);
216 EXIT(1);
217 }
218 p++;
219 _skip_ws(&p);
220 x=strtol(p,&q,0);
221 _skip_ws(&q);
222 y=strtol(q,&p,0);
223 if (find_sprite(name,&n))
224 {
225 char msg[256];
226 snprintf(msg,256,"Unknown bitmap name \"%s\"!\n",name);
227 ERROR(msg);
228 EXIT(1);
229 }
230 _put_sprite(AREA_X,AREA_Y,area,area_a,x,y,sprites[n].positions,t,0);
231 }
232 fclose(stream);
233 }
234
235
236 /* load sprites */
load_sprites(unsigned char * filename)237 void load_sprites(unsigned char * filename)
238 {
239 FILE *stream;
240 static char line[1024];
241 char *p,*q;
242 int l;
243
244 stream=fopen(filename,"rb");
245 if (!stream)
246 {
247 char msg[256];
248 snprintf(msg,256,"Can't open file \"%s\"!\n",filename);
249 ERROR(msg);
250 EXIT(1);
251 }
252 while(fgets(line,1024,stream))
253 {
254 p=line;
255 _skip_ws(&p);
256 for (q=p;(*p)!=' '&&(*p)!=9&&(*p)!=10&&(*p);p++);
257 if (!(*p))continue;
258 *p=0;p++;
259 l=strlen(q);
260 n_sprites++;
261 sprite_names=(unsigned char **)mem_realloc(sprite_names,n_sprites*sizeof(unsigned char*));
262 if (!sprite_names){ERROR("Memory allocation error!\n");EXIT(1);}
263 sprites=(struct sprite *)mem_realloc(sprites,n_sprites*sizeof(struct sprite));
264 if (!sprites){ERROR("Memory allocation error!\n");EXIT(1);}
265 sprite_names[n_sprites-1]=(char *)mem_alloc(l+1);
266 if (!sprite_names[n_sprites-1]){ERROR("Memory allocation error!\n");EXIT(1);}
267 memcpy(sprite_names[n_sprites-1],q,l+1);
268 _skip_ws(&p);
269 for (q=p;(*p)!=' '&&(*p)!=9&&(*p)!=10&&(*p);p++);
270 *p=0;p++;
271 load_sprite(q,sprites+(n_sprites-1));
272 }
273 fclose(stream);
274 }
275
276
free_sprites(int start_num)277 void free_sprites(int start_num)
278 {
279 int a;
280
281 for (a=start_num;a<n_sprites;a++)
282 {
283 mem_free(sprite_names[a]);
284 free_sprite(sprites+a);
285 }
286 n_sprites=start_num;
287 sprite_names=(unsigned char **)mem_realloc(sprite_names,n_sprites*sizeof(unsigned char*));
288 if (!sprite_names){ERROR("Memory allocation error!\n");EXIT(1);}
289 sprites=mem_realloc(sprites,n_sprites*sizeof(struct sprite));
290 if (!sprites){ERROR("Memory allocation error!\n");EXIT(1);}
291 }
292
293
294 /* returns allocated string with level name or NULL on error */
295 /* level_num is a line number in the LEVEL_FILE */
load_level(int level_num)296 unsigned char *load_level(int level_num)
297 {
298 unsigned char txt[1024];
299 unsigned char *retval;
300 int a;
301 FILE *f;
302
303 f=fopen(DATA_PATH LEVEL_FILE,"r");
304 if (!f)return NULL;
305
306 for (a=0;a<=level_num;)
307 {
308 if (!(fgets(txt,1024,f)))return NULL;
309
310 /* remove trailing CR and/or LF */
311 if (txt[strlen(txt)-1]==10)txt[strlen(txt)-1]=0;
312 if (txt[strlen(txt)-1]==13)txt[strlen(txt)-1]=0;
313
314 if (strlen(txt))a++;
315 }
316
317 fclose(f);
318
319 a=strlen(txt);
320 retval=mem_alloc(1+a*sizeof(unsigned char));
321 if (!retval)return NULL;
322 memcpy(retval,txt,a+1); /* including trailing zero */
323 if (!strlen(retval)){mem_free(retval);return NULL;}
324 return retval;
325
326 }
327
328 /* create a new object and fill with data and add to hash table */
new_obj(unsigned int id,unsigned char type,int ttl,int sprite,unsigned char pos,int status,my_double x,my_double y,my_double xspeed,my_double yspeed,void * data)329 struct it * new_obj(
330 unsigned int id,
331 unsigned char type,
332 int ttl,
333 int sprite,
334 unsigned char pos,
335 int status,
336 my_double x,
337 my_double y,
338 my_double xspeed,
339 my_double yspeed,
340 void * data)
341 {
342 last_obj->next=mem_alloc(sizeof(struct object_list));
343 if (!last_obj->next)return 0;
344 last_obj->next->prev=last_obj;
345 last_obj=last_obj->next;
346 last_obj->next=0;
347 last_obj->member.x=x;
348 last_obj->member.y=y;
349 last_obj->member.xspeed=xspeed;
350 last_obj->member.yspeed=yspeed;
351 last_obj->member.type=type;
352 last_obj->member.ttl=ttl;
353 last_obj->member.sprite=sprite;
354 last_obj->member.anim_pos=pos;
355 last_obj->member.data=data;
356 last_obj->member.id=id;
357 last_obj->member.status=status;
358 last_obj->member.update_counter=0;
359 last_obj->member.last_updated=get_time();
360 add_to_table(last_obj);
361 return &(last_obj->member);
362 }
363
364
365 /* completely delete object from the list */
delete_obj(unsigned long id)366 void delete_obj(unsigned long id)
367 {
368 struct object_list *q;
369 if (!(q=remove_from_table(id)))return; /* packets can come more than once, so we must ignore deleting deleted object */
370 q->prev->next=q->next;
371 if (!q->next) last_obj=q->prev; /* q is last object in list */
372 else q->next->prev=q->prev;
373 mem_free(q);
374 }
375
376
put_long_long(unsigned char * p,unsigned long_long num)377 void put_long_long(unsigned char *p,unsigned long_long num)
378 {
379 p[0]=num&255;num>>=8;
380 p[1]=num&255;num>>=8;
381 p[2]=num&255;num>>=8;
382 p[3]=num&255;num>>=8;
383 p[4]=num&255;num>>=8;
384 p[5]=num&255;num>>=8;
385 p[6]=num&255;num>>=8;
386 p[7]=num&255;
387 }
388
389
put_int(unsigned char * p,int num)390 void put_int(unsigned char *p,int num)
391 {
392 p[0]=num&255;num>>=8;
393 p[1]=num&255;num>>=8;
394 p[2]=num&255;num>>=8;
395 p[3]=num&255;
396 }
397
398
get_int(unsigned char * p)399 int get_int(unsigned char *p)
400 {
401 return (int)p[0]+
402 ((int)(p[1])<<8)+
403 ((int)(p[2])<<16)+
404 ((int)(p[3])<<24);
405 }
406
407
put_int16(unsigned char * p,int num)408 void put_int16(unsigned char *p,int num)
409 {
410 p[0]=num&255;num>>=8;
411 p[1]=num&255;
412 }
413
414
get_int16(unsigned char * p)415 int get_int16(unsigned char *p)
416 {
417 return (int)p[0]+((int)(p[1])<<8);
418 }
419
420
get_float(unsigned char * p)421 my_double get_float(unsigned char *p)
422 {
423 int a;
424 a= (int)p[0]+
425 ((int)(p[1])<<8)+
426 ((int)(p[2])<<16)+
427 ((int)(p[3])<<24);
428 return a;
429 }
430
431
put_float(unsigned char * p,my_double num)432 void put_float(unsigned char *p,my_double num)
433 {
434 p[0]=num&255;num>>=8;
435 p[1]=num&255;num>>=8;
436 p[2]=num&255;num>>=8;
437 p[3]=num&255;
438 }
439
440
get_long_long(unsigned char * p)441 unsigned long_long get_long_long(unsigned char *p)
442 {
443 #define ULL unsigned long_long
444 return (ULL)p[0]+
445 ((ULL)(p[1])<<8)+
446 ((ULL)(p[2])<<16)+
447 ((ULL)(p[3])<<24)+
448 ((ULL)(p[4])<<32)+
449 ((ULL)(p[5])<<40)+
450 ((ULL)(p[6])<<48)+
451 ((ULL)(p[7])<<56);
452 #undef ULL
453 }
454
455
456
457 /* test if vertical line from yh to yl can move from old_x to new_x axis */
458 /* returns farthest possible x axis */
459 /* flag is filled with 1 if objects is stopped */
can_go_x(my_double old_x,my_double new_x,int yh,int yl,unsigned char * flag)460 my_double can_go_x(my_double old_x,my_double new_x,int yh, int yl,unsigned char *flag)
461 {
462 int x,y;
463 if (yh<0) yh=0;
464 if (old_x==new_x+.5)
465 {
466 if(flag)*flag=0;
467 return new_x;
468 }
469 if(flag)*flag=1;
470 if (old_x<new_x)
471 for (x=double2int(old_x)+1;x<=round_up(new_x);x++) /* go to the right */
472 {
473 if (x>AREA_X-1) return int2double(AREA_X-1);
474 for (y=yh;y<=yl;y++)
475 if ((area_a[x+y*AREA_X]&240)==TYPE_WALL)
476 return int2double(x-1);
477 }
478 else
479 for (x=round_up(old_x)-1;x>=double2int(new_x);x--) /* go to the left */
480 {
481 if (x<0) return 0;
482 for (y=yh;y<=yl;y++)
483 if ((area_a[x+y*AREA_X]&240)==TYPE_WALL) return int2double(x+1);
484 }
485 if(flag)*flag=0;
486 return new_x;
487 }
488
489
490 /* test if horizontal line from xl to xr can move from old_y to new_y axis */
491 /* returns farthest possible y axis */
492 /* flag is filled with 1 if objects is stopped */
493 /* down ladder: 1=fall through ladders etc., 0=stand on ladders */
can_go_y(my_double old_y,my_double new_y,int xl,int xr,unsigned char * flag,unsigned char down_ladder)494 my_double can_go_y(my_double old_y, my_double new_y,int xl, int xr,unsigned char *flag,unsigned char down_ladder)
495 {
496 int x,y;
497 if (xl<0) xl=0;
498 if (old_y==new_y){if(flag)*flag=0;return new_y;}
499 if(flag)*flag=1;
500 if (old_y<new_y)
501 for (y=double2int(old_y)+1;y<=round_up(new_y);y++) /* go down */
502 {
503 if (y>AREA_Y-1) return int2double(AREA_Y-1);
504 for (x=xl;x<=xr;x++)
505 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);
506 }
507 else
508 {
509 if (flag)*flag=2;
510 for (y=round_up(old_y)-1;y>=double2int(new_y);y--) /* go up */
511 {
512 if (y<0) return 0;
513 for (x=xl;x<=xr;x++)
514 if ((area_a[x+y*AREA_X]&240)==TYPE_WALL) return int2double(y+1);
515 }
516 }
517 if(flag)*flag=0;
518 return new_y;
519 }
520
521
522 /* automatically computes dimensions of unknown type, if anim positions is given */
523 /* object must be rectangular */
524 #ifdef HAVE_INLINE
525 inline void
526 #else
527 void
528 #endif
get_dimensions(int type,int status,struct pos * s,int * w,int * h)529 get_dimensions(int type,int status,struct pos *s,int *w,int *h)
530 {
531 switch(type)
532 {
533 case T_PLAYER:
534 if (status&256)
535 {
536 *w=CREEP_WIDTH;
537 *h=CREEP_HEIGHT;
538 }
539 else
540 {
541 *w=PLAYER_WIDTH;
542 *h=PLAYER_HEIGHT;
543 }
544 return;
545
546 case T_SHOTGUN:
547 *w=22;
548 *h=3;
549 return;
550
551 case T_UZI:
552 *w=12;
553 *h=3;
554 return;
555
556 default:
557 *w=0;
558 if (!s){*h=0;return;}
559 *h=s->n;
560 if (*h)*w=s->lines[0].len;
561 }
562 }
563
564
565
566 /* updates object's position */
update_position(struct it * obj,my_double new_x,my_double new_y,int width,int height,unsigned char * fx,unsigned char * fy)567 void update_position(struct it* obj,my_double new_x,my_double new_y,int width, int height,unsigned char *fx,unsigned char *fy)
568 {
569 unsigned char down_ladder=0;
570
571 /* player is climbing ladder down */
572 if (obj->type==T_PLAYER&&obj->status&2048) down_ladder=1;
573
574 if (obj->xspeed>0)
575 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);
576 else
577 obj->x=can_go_x(obj->x,new_x,double2int(obj->y),round_up(obj->y)+height-1,fx);
578
579 if (obj->yspeed>0)
580 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);
581 else
582 obj->y=can_go_y(obj->y,new_y,double2int(obj->x),round_up(obj->x)+width-1,fy,down_ladder);
583 }
584
585
__add_md5(unsigned char * filename,int * len,unsigned char ** result)586 unsigned char *__add_md5(unsigned char *filename, int *len, unsigned char**result)
587 {
588 unsigned char *p,*q;
589 int a;
590
591 q=MD5File(filename,NULL);
592 a=strlen(q);
593 if (!(*result))*result=DUMMY;
594 p=mem_realloc((*result),(*len)+a+1);
595 if (!result)return NULL;
596 (*result)=p;
597 memcpy((*result)+(*len),q,a+1);
598 mem_free(q);
599 (*len)+=a;
600 return (*result);
601 }
602
603 /* computes md5 sum from the level
604 * level_num is the line number in level.dat file
605 * returns allocated string with the MD5 sum or NULL (on error)
606 */
md5_level(int level_num)607 unsigned char* md5_level(int level_num)
608 {
609 unsigned char *result=0;
610 char *q;
611 int len=0;
612 unsigned char p[2048];
613
614 q=load_level(level_num);
615 if (!q)return NULL;
616
617 if (!__add_md5(DATA_PATH LEVEL_FILE,&len,&result)){mem_free(result);return NULL;}
618
619 snprintf(p,2048,"%s%s%s",DATA_PATH,q,LEVEL_SPRITES_SUFFIX);
620 if (!__add_md5(p,&len,&result)){mem_free(result);return NULL;}
621
622 snprintf(p,2048,"%s%s%s",DATA_PATH,q,STATIC_DATA_SUFFIX);
623 if (!__add_md5(p,&len,&result)){mem_free(result);return NULL;}
624
625 snprintf(p,2048,"%s%s%s",DATA_PATH,q,DYNAMIC_DATA_SUFFIX);
626 if (!__add_md5(p,&len,&result)){mem_free(result);return NULL;}
627
628 snprintf(p,2048,"%s%s%s",DATA_PATH,q,LEVEL_SPRITES_SUFFIX);
629 mem_free(q);
630
631 {
632 FILE *f;
633
634 f=fopen(p,"r");
635 if (!f){mem_free(result);return NULL;}
636 while (fgets(p,2048,f))
637 {
638 if (p[strlen(p)-1]==13)p[strlen(p)-1]=0;
639 if (p[strlen(p)-1]==10)p[strlen(p)-1]=0;
640
641 q=p;
642 _skip_ws(&q);
643 for (;(*q)&&(*q)!=' '&&(*q)!=9&&(*q)!=10&&(*q)!=13;q++);
644 _skip_ws(&q);
645 if (!strlen(q))continue;
646 if (!__add_md5(q,&len,&result)){mem_free(result);return NULL;}
647 }
648 fclose(f);
649 }
650
651 q=MD5Data(result,len,NULL);
652 mem_free(result);
653 return q;
654 }
655