]> icculus.org git repositories - btb/d2x.git/blob - main/bmread.c
added Visual C project for opengl, buncha macro fixes and stuff
[btb/d2x.git] / main / bmread.c
1 /* $Id: bmread.c,v 1.5 2003-10-10 09:36:34 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Routines to parse bitmaps.tbl
18  *
19  * Old Log:
20  * Revision 2.4  1995/03/28  18:05:29  john
21  * Fixed it so you don't have to delete pig after changing bitmaps.tbl
22  *
23  * Revision 2.3  1995/03/07  16:52:03  john
24  * Fixed robots not moving without edtiro bug.
25  *
26  * Revision 2.2  1995/03/06  16:10:20  mike
27  * Fix compile errors if building without editor.
28  *
29  * Revision 2.1  1995/03/02  14:55:40  john
30  * Fixed bug with EDITOR never defined.
31  *
32  * Revision 2.0  1995/02/27  11:33:10  john
33  * New version 2.0, which has no anonymous unions, builds with
34  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
35  *
36  * Revision 1.1  1995/02/25  14:02:36  john
37  * Initial revision
38  *
39  *
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include <conf.h>
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <string.h>
50 #include <ctype.h>
51
52 #include "pstypes.h"
53 #include "inferno.h"
54 #include "gr.h"
55 #include "bm.h"
56 #include "gamepal.h"
57 #include "u_mem.h"
58 #include "mono.h"
59 #include "error.h"
60 #include "object.h"
61 #include "vclip.h"
62 #include "effects.h"
63 #include "polyobj.h"
64 #include "wall.h"
65 #include "textures.h"
66 #include "game.h"
67 #ifdef NETWORK
68 #include "multi.h"
69 #endif
70
71 #include "iff.h"
72 #include "cfile.h"
73
74 #include "hostage.h"
75 #include "powerup.h"
76 #include "laser.h"
77 #include "sounds.h"
78 #include "piggy.h"
79 #include "aistruct.h"
80 #include "robot.h"
81 #include "weapon.h"
82 #include "gauges.h"
83 #include "player.h"
84 #include "endlevel.h"
85 #include "cntrlcen.h"
86 #include "compbit.h"
87 #include "args.h"
88
89
90 #include "editor/texpage.h"
91
92 #define BM_NONE                 -1
93 #define BM_COCKPIT               0
94 #define BM_TEXTURES              2
95 #define BM_UNUSED                        3
96 #define BM_VCLIP                         4
97 #define BM_EFFECTS          5
98 #define BM_ECLIP                         6
99 #define BM_WEAPON                        7
100 #define BM_DEMO                  8
101 #define BM_ROBOTEX          9
102 #define BM_WALL_ANIMS   12
103 #define BM_WCLIP                        13
104 #define BM_ROBOT                        14
105 #define BM_GAUGES                       20
106 #define BM_GAUGES_HIRES 21
107
108 #define MAX_BITMAPS_PER_BRUSH 30
109
110 extern player_ship only_player_ship;            // In bm.c
111
112 short           N_ObjBitmaps=0;
113 short           N_ObjBitmapPtrs=0;
114 static int                      Num_robot_ais = 0;
115 int     TmapList[MAX_TEXTURES];
116 char    Powerup_names[MAX_POWERUP_TYPES][POWERUP_NAME_LENGTH];
117 char    Robot_names[MAX_ROBOT_TYPES][ROBOT_NAME_LENGTH];
118
119 //---------------- Internal variables ---------------------------
120 static int                      Registered_only = 0;            //      Gets set by ! in column 1.
121 static int                      SuperX = -1;
122 static int                      Installed=0;
123 static char             *arg;
124 static short            tmap_count = 0;
125 static short            texture_count = 0;
126 static short            clip_count = 0;
127 static short            clip_num;
128 static short            sound_num;
129 static short            frames;
130 static float            time;
131 static int                      hit_sound = -1;
132 static sbyte            bm_flag = BM_NONE;
133 static int                      abm_flag = 0;
134 static int                      rod_flag = 0;
135 static short            wall_open_sound, wall_close_sound,wall_explodes,wall_blastable, wall_hidden;
136 float           vlighting=0;
137 static int                      obj_eclip;
138 static char             *dest_bm;               //clip number to play when destroyed
139 static int                      dest_vclip;             //what vclip to play when exploding
140 static int                      dest_eclip;             //what eclip to play when exploding
141 static fix                      dest_size;              //3d size of explosion
142 static int                      crit_clip;              //clip number to play when destroyed
143 static int                      crit_flag;              //flag if this is a destroyed eclip
144 static int                      tmap1_flag;             //flag if this is used as tmap_num (not tmap_num2)
145 static int                      num_sounds=0;
146
147 int     linenum;                //line int table currently being parsed
148
149 //------------------- Useful macros and variables ---------------
150 #define REMOVE_EOL(s)           remove_char((s),'\n')
151 #define REMOVE_COMMENTS(s)      remove_char((s),';')
152 #define REMOVE_DOTS(s)          remove_char((s),'.')
153
154 #define IFTOK(str) if (!strcmp(arg, str))
155 char *space = { " \t" };        
156 //--unused-- char *equal = { "=" };
157 char *equal_space = { " \t=" };
158
159
160 //      For the sake of LINT, defining prototypes to module's functions
161 void bm_read_alias(void);
162 void bm_read_marker(void);
163 void bm_read_robot_ai(void);
164 void bm_read_powerup(int unused_flag);
165 void bm_read_hostage(void);
166 void bm_read_robot(void);
167 void bm_read_weapon(int unused_flag);
168 void bm_read_reactor(void);
169 void bm_read_exitmodel(void);
170 void bm_read_player_ship(void);
171 void bm_read_some_file(void);
172 void bm_read_sound(void);
173 void bm_write_extra_robots(void);
174 void clear_to_end_of_line(void);
175 void verify_textures(void);
176
177
178 //----------------------------------------------------------------------
179 void remove_char( char * s, char c )
180 {
181         char *p;
182         p = strchr(s,c);
183         if (p) *p = '\0';
184 }
185
186 //---------------------------------------------------------------
187 int compute_average_pixel(grs_bitmap *new)
188 {
189         int     row, column, color;
190         char    *pptr;
191         int     total_red, total_green, total_blue;
192
193         pptr = (char *)new->bm_data;
194
195         total_red = 0;
196         total_green = 0;
197         total_blue = 0;
198
199         for (row=0; row<new->bm_h; row++)
200                 for (column=0; column<new->bm_w; column++) {
201                         color = *pptr++;
202                         total_red += gr_palette[color*3];
203                         total_green += gr_palette[color*3+1];
204                         total_blue += gr_palette[color*3+2];
205                 }
206
207         total_red /= (new->bm_h * new->bm_w);
208         total_green /= (new->bm_h * new->bm_w);
209         total_blue /= (new->bm_h * new->bm_w);
210
211         return BM_XRGB(total_red/2, total_green/2, total_blue/2);
212 }
213
214 //---------------------------------------------------------------
215 // Loads a bitmap from either the piggy file, a r64 file, or a
216 // whatever extension is passed.
217
218 bitmap_index bm_load_sub( char * filename )
219 {
220         bitmap_index bitmap_num;
221         grs_bitmap * new;
222         ubyte newpal[256*3];
223         int iff_error;          //reference parm to avoid warning message
224         char fname[20];
225
226         bitmap_num.index = 0;
227
228 #ifdef SHAREWARE
229         if (Registered_only) {
230                 //mprintf( 0, "Skipping registered-only bitmap '%s'\n", filename );
231                 return bitmap_num;
232         }
233 #endif
234
235         _splitpath(  filename, NULL, NULL, fname, NULL );
236
237         bitmap_num=piggy_find_bitmap( fname );
238         if (bitmap_num.index)   {
239                 //mprintf(( 0, "Found bitmap '%s' in pig!\n", fname ));
240                 return bitmap_num;
241         }
242
243         MALLOC( new, grs_bitmap, 1 );
244         iff_error = iff_read_bitmap(filename,new,BM_LINEAR,newpal);
245         new->bm_handle=0;
246         if (iff_error != IFF_NO_ERROR)          {
247                 mprintf((1, "File %s - IFF error: %s",filename,iff_errormsg(iff_error)));
248                 Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum);
249         }
250
251         if ( iff_has_transparency )
252                 gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX );
253         else
254                 gr_remap_bitmap_good( new, newpal, -1, SuperX );
255
256         new->avg_color = compute_average_pixel(new);
257
258         // -- mprintf((0, "N" ));
259         bitmap_num = piggy_register_bitmap( new, fname, 0 );
260         d_free( new );
261         return bitmap_num;
262 }
263
264 extern grs_bitmap bogus_bitmap;
265 extern ubyte bogus_bitmap_initialized;
266 extern digi_sound bogus_sound;
267
268 void ab_load( char * filename, bitmap_index bmp[], int *nframes )
269 {
270         grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH];
271         bitmap_index bi;
272         int i;
273         int iff_error;          //reference parm to avoid warning message
274         ubyte newpal[768];
275         char fname[20];
276         char tempname[20];
277
278 #ifdef SHAREWARE
279         if (Registered_only) {
280                 Assert( bogus_bitmap_initialized != 0 );
281                 mprintf(( 0, "Skipping registered-only animation '%s'\n", filename ));
282                 bmp[0].index = 0;               //index of bogus bitmap==0 (I think)            //&bogus_bitmap;
283                 *nframes = 1;
284                 return;
285         }
286 #endif
287
288
289         _splitpath( filename, NULL, NULL, fname, NULL );
290         
291         for (i=0; i<MAX_BITMAPS_PER_BRUSH; i++ )        {
292                 sprintf( tempname, "%s#%d", fname, i );
293                 bi = piggy_find_bitmap( tempname );
294                 if ( !bi.index )        
295                         break;
296                 bmp[i] = bi;
297                 //mprintf(( 0, "Found animation frame %d, %s, in piggy file\n", i, tempname ));
298         }
299
300         if (i) {
301                 *nframes = i;
302                 return;
303         }
304
305 //      Note that last argument passes an address to the array newpal (which is a pointer).
306 //      type mismatch found using lint, will substitute this line with an adjusted
307 //      one.  If fatal error, then it can be easily changed.
308 //      iff_error = iff_read_animbrush(filename,bm,MAX_BITMAPS_PER_BRUSH,nframes,&newpal);
309    iff_error = iff_read_animbrush(filename,bm,MAX_BITMAPS_PER_BRUSH,nframes,newpal);
310         if (iff_error != IFF_NO_ERROR)  {
311                 mprintf((1,"File %s - IFF error: %s",filename,iff_errormsg(iff_error)));
312                 Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum);
313         }
314
315         for (i=0;i< *nframes; i++)      {
316                 bitmap_index new_bmp;
317                 sprintf( tempname, "%s#%d", fname, i );
318                 if ( iff_has_transparency )
319                         gr_remap_bitmap_good( bm[i], newpal, iff_transparent_color, SuperX );
320                 else
321                         gr_remap_bitmap_good( bm[i], newpal, -1, SuperX );
322
323                 bm[i]->avg_color = compute_average_pixel(bm[i]);
324
325                 new_bmp = piggy_register_bitmap( bm[i], tempname, 0 );
326                 d_free( bm[i] );
327                 bmp[i] = new_bmp;
328                 if (!i)
329                         mprintf((0, "Registering %s in piggy file.", tempname ));
330                 else
331                         mprintf((0, "."));
332         }
333         mprintf((0, "\n"));
334 }
335
336 int ds_load( char * filename )  {
337         int i;
338         CFILE * cfp;
339         digi_sound new;
340         char fname[20];
341         char rawname[100];
342
343 #ifdef SHAREWARE
344         if (Registered_only) {
345                 //mprintf( 0, "Skipping registered-only sound '%s'\n", filename );
346                 return 0;       //don't know what I should return here          //&bogus_sound;
347         }
348 #endif
349
350         _splitpath(  filename, NULL, NULL, fname, NULL );
351         _makepath( rawname, NULL, NULL,fname, (digi_sample_rate==SAMPLE_RATE_22K)?".R22":".RAW" );
352
353         i=piggy_find_sound( fname );
354         if (i!=255)     {
355                 return i;
356         }
357
358         cfp = cfopen( rawname, "rb" );
359
360         if (cfp!=NULL) {
361                 new.length      = cfilelength( cfp );
362                 MALLOC( new.data, ubyte, new.length );
363                 cfread( new.data, 1, new.length, cfp );
364                 cfclose(cfp);
365                 // -- mprintf( (0, "S" ));
366                 // -- mprintf( (0, "<%s>", rawname ));
367         } else {
368                 mprintf( (1, "Warning: Couldn't find '%s'\n", filename ));
369                 return 255;
370         }
371         i = piggy_register_sound( &new, fname, 0 );
372         return i;
373 }
374
375 //parse a float
376 float get_float()
377 {
378         char *xarg;
379
380         xarg = strtok( NULL, space );
381         return atof( xarg );
382 }
383
384 //parse an int
385 int get_int()
386 {
387         char *xarg;
388
389         xarg = strtok( NULL, space );
390         return atoi( xarg );
391 }
392
393 // rotates a byte left one bit, preserving the bit falling off the right
394 //void
395 //rotate_left(char *c)
396 //{
397 //      int found;
398 //
399 //      found = 0;
400 //      if (*c & 0x80)
401 //              found = 1;
402 //      *c = *c << 1;
403 //      if (found)
404 //              *c |= 0x01;
405 //}
406
407 //loads a texture and returns the texture num
408 int get_texture(char *name)
409 {
410         char short_name[FILENAME_LEN];
411         int i;
412
413         strcpy(short_name,name);
414         REMOVE_DOTS(short_name);
415         for (i=0;i<texture_count;i++)
416                 if (!stricmp(TmapInfo[i].filename,short_name))
417                         break;
418         if (i==texture_count) {
419                 Textures[texture_count] = bm_load_sub(name);
420                 strcpy( TmapInfo[texture_count].filename, short_name);
421                 texture_count++;
422                 Assert(texture_count < MAX_TEXTURES);
423                 NumTextures = texture_count;
424         }
425
426         return i;
427 }
428
429 #define LINEBUF_SIZE 600
430
431 #define DEFAULT_PIG_PALETTE     "groupa.256"
432
433 //-----------------------------------------------------------------
434 // Initializes all bitmaps from BITMAPS.TBL file.
435 // This is called when the editor is IN.
436 // If no editor, bm_init() is called.
437 int bm_init_use_tbl()
438 {
439         CFILE   * InfoFile;
440         char    inputline[LINEBUF_SIZE];
441         int     i, have_bin_tbl;
442
443         gr_use_palette_table(DEFAULT_PIG_PALETTE);
444
445         load_palette(DEFAULT_PIG_PALETTE,-2,0);         //special: tell palette code which pig is loaded
446
447         init_polygon_models();
448
449         ObjType[0] = OL_PLAYER;
450         ObjId[0] = 0;
451         Num_total_object_types = 1;
452
453         for (i=0; i<MAX_SOUNDS; i++ )   {
454                 Sounds[i] = 255;
455                 AltSounds[i] = 255;
456         }
457
458         for (i=0; i<MAX_TEXTURES; i++ ) {
459                 TmapInfo[i].eclip_num = -1;
460                 TmapInfo[i].flags = 0;
461                 TmapInfo[i].slide_u = TmapInfo[i].slide_v = 0;
462                 TmapInfo[i].destroyed = -1;
463         }
464
465         for (i=0;i<MAX_REACTORS;i++)
466                 Reactors[i].model_num = -1;
467
468         Num_effects = 0;
469         for (i=0; i<MAX_EFFECTS; i++ ) {
470                 //Effects[i].bm_ptr = (grs_bitmap **) -1;
471                 Effects[i].changing_wall_texture = -1;
472                 Effects[i].changing_object_texture = -1;
473                 Effects[i].segnum = -1;
474                 Effects[i].vc.num_frames = -1;          //another mark of being unused
475         }
476
477         for (i=0;i<MAX_POLYGON_MODELS;i++)
478                 Dying_modelnums[i] = Dead_modelnums[i] = -1;
479
480         Num_vclips = 0;
481         for (i=0; i<VCLIP_MAXNUM; i++ ) {
482                 Vclip[i].num_frames = -1;
483                 Vclip[i].flags = 0;
484         }
485
486         for (i=0; i<MAX_WALL_ANIMS; i++ )
487                 WallAnims[i].num_frames = -1;
488         Num_wall_anims = 0;
489
490         setbuf(stdout, NULL);   // unbuffered output via printf
491
492         if (Installed)
493                 return 1;
494
495         Installed = 1;
496
497         piggy_init();           //don't care about error, since no pig is ok for editor
498
499 //      if ( FindArg( "-nobm" ) )       {
500 //              piggy_read_sounds();
501 //              return 0;
502 //      }
503
504         // Open BITMAPS.TBL for reading.
505         have_bin_tbl = 0;
506         InfoFile = cfopen( "BITMAPS.TBL", "rb" );
507         if (InfoFile == NULL) {
508                 InfoFile = cfopen("BITMAPS.BIN", "rb");
509                 if (InfoFile == NULL)
510                         Error("Missing BITMAPS.TBL and BITMAPS.BIN file\n");
511                 have_bin_tbl = 1;
512         }
513         linenum = 0;
514         
515         cfseek( InfoFile, 0L, SEEK_SET);
516
517         while (cfgets(inputline, LINEBUF_SIZE, InfoFile)) {
518                 int l;
519                 char *temp_ptr;
520
521                 linenum++;
522
523                 if (inputline[0]==' ' || inputline[0]=='\t') {
524                         char *t;
525                         for (t=inputline;*t && *t!='\n';t++)
526                                 if (! (*t==' ' || *t=='\t')) {
527                                         mprintf((1,"Suspicious: line %d of BITMAPS.TBL starts with whitespace\n",linenum));
528                                         break;
529                                 }
530                 }
531
532                 if (have_bin_tbl) {                             // is this a binary tbl file
533                         for (i = 0; i < strlen(inputline) - 1; i++) {
534                                 encode_rotate_left(&(inputline[i]));
535                                 inputline[i] = inputline[i] ^ BITMAP_TBL_XOR;
536                                 encode_rotate_left(&(inputline[i]));
537                         }
538                 } else {
539                         while (inputline[(l=strlen(inputline))-2]=='\\') {
540                                 if (!isspace(inputline[l-3])) {         //if not space before backslash...
541                                         inputline[l-2] = ' ';                           //add one
542                                         l++;
543                                 }
544                                 cfgets(inputline+l-2,LINEBUF_SIZE-(l-2), InfoFile);
545                                 linenum++;
546                         }
547                 }
548
549                 REMOVE_EOL(inputline);
550                 if (strchr(inputline, ';')!=NULL) REMOVE_COMMENTS(inputline);
551
552                 if (strlen(inputline) == LINEBUF_SIZE-1)
553                         Error("Possible line truncation in BITMAPS.TBL on line %d\n",linenum);
554
555                 SuperX = -1;
556
557                 if ( (temp_ptr=strstr( inputline, "superx=" )) )        {
558                         SuperX = atoi( &temp_ptr[7] );
559                         Assert(SuperX == 254);
560                                 //the superx color isn't kept around, so the new piggy regeneration
561                                 //code doesn't know what it is, so it assumes that it's 254, so
562                                 //this code requires that it be 254
563                                                                                 
564                 }
565
566                 arg = strtok( inputline, space );
567                 if (arg[0] == '@') {
568                         arg++;
569                         Registered_only = 1;
570                 } else
571                         Registered_only = 0;
572
573                 while (arg != NULL )
574                         {
575                         // Check all possible flags and defines.
576                         if (*arg == '$') bm_flag = BM_NONE; // reset to no flags as default.
577
578                         IFTOK("$COCKPIT")                       bm_flag = BM_COCKPIT;
579                         else IFTOK("$GAUGES")           {bm_flag = BM_GAUGES;   clip_count = 0;}
580                         else IFTOK("$GAUGES_HIRES"){bm_flag = BM_GAUGES_HIRES; clip_count = 0;}
581                         else IFTOK("$SOUND")            bm_read_sound();
582                         else IFTOK("$DOOR_ANIMS")       bm_flag = BM_WALL_ANIMS;
583                         else IFTOK("$WALL_ANIMS")       bm_flag = BM_WALL_ANIMS;
584                         else IFTOK("$TEXTURES")         bm_flag = BM_TEXTURES;
585                         else IFTOK("$VCLIP")                    {bm_flag = BM_VCLIP;            vlighting = 0;  clip_count = 0;}
586                         else IFTOK("$ECLIP")                    {bm_flag = BM_ECLIP;            vlighting = 0;  clip_count = 0; obj_eclip=0; dest_bm=NULL; dest_vclip=-1; dest_eclip=-1; dest_size=-1; crit_clip=-1; crit_flag=0; sound_num=-1;}
587                         else IFTOK("$WCLIP")                    {bm_flag = BM_WCLIP;            vlighting = 0;  clip_count = 0; wall_explodes = wall_blastable = 0; wall_open_sound=wall_close_sound=-1; tmap1_flag=0; wall_hidden=0;}
588
589                         else IFTOK("$EFFECTS")          {bm_flag = BM_EFFECTS;  clip_num = 0;}
590                         else IFTOK("$ALIAS")                    bm_read_alias();
591
592                         #ifdef EDITOR
593                         else IFTOK("!METALS_FLAG")              TextureMetals = texture_count;
594                         else IFTOK("!LIGHTS_FLAG")              TextureLights = texture_count;
595                         else IFTOK("!EFFECTS_FLAG")     TextureEffects = texture_count;
596                         #endif
597
598                         else IFTOK("lighting")                  TmapInfo[texture_count-1].lighting = fl2f(get_float());
599                         else IFTOK("damage")                    TmapInfo[texture_count-1].damage = fl2f(get_float());
600                         else IFTOK("volatile")                  TmapInfo[texture_count-1].flags |= TMI_VOLATILE;
601                         else IFTOK("goal_blue")                 TmapInfo[texture_count-1].flags |= TMI_GOAL_BLUE;
602                         else IFTOK("goal_red")                  TmapInfo[texture_count-1].flags |= TMI_GOAL_RED;
603                         else IFTOK("water")                             TmapInfo[texture_count-1].flags |= TMI_WATER;
604                         else IFTOK("force_field")               TmapInfo[texture_count-1].flags |= TMI_FORCE_FIELD;
605                         else IFTOK("slide")                             {TmapInfo[texture_count-1].slide_u = fl2f(get_float())>>8; TmapInfo[texture_count-1].slide_v = fl2f(get_float())>>8;}
606                         else IFTOK("destroyed")                 {int t=texture_count-1; TmapInfo[t].destroyed = get_texture(strtok( NULL, space ));}
607                         //else IFTOK("Num_effects")             Num_effects = get_int();
608                         else IFTOK("Num_wall_anims")    Num_wall_anims = get_int();
609                         else IFTOK("clip_num")                  clip_num = get_int();
610                         else IFTOK("dest_bm")                   dest_bm = strtok( NULL, space );
611                         else IFTOK("dest_vclip")                dest_vclip = get_int();
612                         else IFTOK("dest_eclip")                dest_eclip = get_int();
613                         else IFTOK("dest_size")                 dest_size = fl2f(get_float());
614                         else IFTOK("crit_clip")                 crit_clip = get_int();
615                         else IFTOK("crit_flag")                 crit_flag = get_int();
616                         else IFTOK("sound_num")                 sound_num = get_int();
617                         else IFTOK("frames")                    frames = get_int();
618                         else IFTOK("time")                              time = get_float();
619                         else IFTOK("obj_eclip")                 obj_eclip = get_int();
620                         else IFTOK("hit_sound")                 hit_sound = get_int();
621                         else IFTOK("abm_flag")                  abm_flag = get_int();
622                         else IFTOK("tmap1_flag")                tmap1_flag = get_int();
623                         else IFTOK("vlighting")                 vlighting = get_float();
624                         else IFTOK("rod_flag")                  rod_flag = get_int();
625                         else IFTOK("superx")                    get_int();
626                         else IFTOK("open_sound")                wall_open_sound = get_int();
627                         else IFTOK("close_sound")               wall_close_sound = get_int();
628                         else IFTOK("explodes")                  wall_explodes = get_int();
629                         else IFTOK("blastable")                 wall_blastable = get_int();
630                         else IFTOK("hidden")                            wall_hidden = get_int();
631                         else IFTOK("$ROBOT_AI")                 bm_read_robot_ai();
632
633                         else IFTOK("$POWERUP")                  {bm_read_powerup(0);            continue;}
634                         else IFTOK("$POWERUP_UNUSED")   {bm_read_powerup(1);            continue;}
635                         else IFTOK("$HOSTAGE")                  {bm_read_hostage();             continue;}
636                         else IFTOK("$ROBOT")                            {bm_read_robot();                       continue;}
637                         else IFTOK("$WEAPON")                   {bm_read_weapon(0);             continue;}
638                         else IFTOK("$WEAPON_UNUSED")    {bm_read_weapon(1);             continue;}
639                         else IFTOK("$REACTOR")                  {bm_read_reactor();             continue;}
640                         else IFTOK("$MARKER")                   {bm_read_marker();              continue;}
641                         else IFTOK("$PLAYER_SHIP")              {bm_read_player_ship(); continue;}
642                         else IFTOK("$EXIT") {
643                                 #ifdef SHAREWARE
644                                         bm_read_exitmodel();    
645                                 #else
646                                         clear_to_end_of_line();
647                                 #endif
648                                 continue;
649                         }
650                         else    {               //not a special token, must be a bitmap!
651
652                                 // Remove any illegal/unwanted spaces and tabs at this point.
653                                 while ((*arg=='\t') || (*arg==' ')) arg++;
654                                 if (*arg == '\0') { break; }    
655
656                                 //check for '=' in token, indicating error
657                                 if (strchr(arg,'='))
658                                         Error("Unknown token <'%s'> on line %d of BITMAPS.TBL",arg,linenum);
659
660                                 // Otherwise, 'arg' is apparently a bitmap filename.
661                                 // Load bitmap and process it below:
662                                 bm_read_some_file();
663
664                         }
665
666                         arg = strtok( NULL, equal_space );
667                         continue;
668       }
669         }
670
671         NumTextures = texture_count;
672         Num_tmaps = tmap_count;
673
674         Textures[NumTextures++].index = 0;              //entry for bogus tmap
675
676         cfclose( InfoFile );
677
678         atexit(bm_close);
679
680         Assert(N_robot_types == Num_robot_ais);         //should be one ai info per robot
681
682         #ifdef SHAREWARE
683         init_endlevel();                //this is here so endlevel bitmaps go into pig
684         #endif
685
686         verify_textures();
687
688         //check for refereced but unused clip count
689         for (i=0; i<MAX_EFFECTS; i++ )
690                 if (    (
691                                   (Effects[i].changing_wall_texture!=-1) ||
692                                   (Effects[i].changing_object_texture!=-1)
693              )
694                          && (Effects[i].vc.num_frames==-1) )
695                         Error("EClip %d referenced (by polygon object?), but not defined",i);
696
697         #ifndef NDEBUG
698         {
699                 int used;
700                 for (i=used=0; i<num_sounds; i++ )
701                         if (Sounds[i] != 255)
702                                 used++;
703                 mprintf((0,"Sound slots used: %d of %d, highest index %d\n",used,MAX_SOUNDS,num_sounds));
704
705                 //make sure all alt sounds refer to valid main sounds
706                 for (i=used=0; i<num_sounds; i++ ) {
707                         int alt = AltSounds[i];
708                         Assert(alt==0 || alt==-1 || Sounds[alt]!=255);
709                 }
710         }
711         #endif
712
713         piggy_read_sounds();
714
715         #ifdef EDITOR
716         piggy_dump_all();
717         #endif
718
719         gr_use_palette_table(DEFAULT_PALETTE);
720
721         return 0;
722 }
723
724 void verify_textures()
725 {
726         grs_bitmap * bmp;
727         int i,j;
728         j=0;
729         for (i=0; i<Num_tmaps; i++ )    {
730                 bmp = &GameBitmaps[Textures[i].index];
731                 if ( (bmp->bm_w!=64)||(bmp->bm_h!=64)||(bmp->bm_rowsize!=64) )  {
732                         mprintf( (1, "ERROR: Texture '%s' isn't 64x64 !\n", TmapInfo[i].filename ));
733                         j++;
734                 }
735         }
736         if (j)
737                 Error("%d textures were not 64x64.  See mono screen for list.",j);
738
739         for (i=0;i<Num_effects;i++)
740                 if (Effects[i].changing_object_texture != -1)
741                         if (GameBitmaps[ObjBitmaps[Effects[i].changing_object_texture].index].bm_w!=64 || GameBitmaps[ObjBitmaps[Effects[i].changing_object_texture].index].bm_h!=64)
742                                 Error("Effect %d is used on object, but is not 64x64",i);
743
744 }
745
746 void bm_read_alias()
747 {
748         char *t;
749
750         Assert(Num_aliases < MAX_ALIASES);
751
752         t = strtok( NULL, space );  strncpy(alias_list[Num_aliases].alias_name,t,sizeof(alias_list[Num_aliases].alias_name));
753         t = strtok( NULL, space );  strncpy(alias_list[Num_aliases].file_name,t,sizeof(alias_list[Num_aliases].file_name));
754
755         Num_aliases++;
756 }
757
758 //--unused-- void dump_all_transparent_textures()
759 //--unused-- {
760 //--unused--    FILE * fp;
761 //--unused--    int i,j,k;
762 //--unused--    ubyte * p;
763 //--unused--    fp = fopen( "XPARENT.LST", "wt" );
764 //--unused--    for (i=0; i<Num_tmaps; i++ )    {
765 //--unused--            k = 0;
766 //--unused--            p = Textures[i]->bm_data;
767 //--unused--            for (j=0; j<64*64; j++ )
768 //--unused--                    if ( (*p++)==255 ) k++;
769 //--unused--            if ( k )        {
770 //--unused--                    fprintf( fp, "'%s' has %d transparent pixels\n", TmapInfo[i].filename, k );
771 //--unused--            }                               
772 //--unused--    }
773 //--unused--    fclose(fp);     
774 //--unused-- }
775
776
777 void bm_close()
778 {
779         if (Installed)
780         {
781                 Installed=0;
782         }
783 }
784
785 void set_lighting_flag(sbyte *bp)
786 {
787         if (vlighting < 0)
788                 *bp |= BM_FLAG_NO_LIGHTING;
789         else
790                 *bp &= (0xff ^ BM_FLAG_NO_LIGHTING);
791 }
792
793 void set_texture_name(char *name)
794 {
795         strcpy ( TmapInfo[texture_count].filename, name );
796         REMOVE_DOTS(TmapInfo[texture_count].filename);
797 }
798
799 void bm_read_eclip()
800 {
801         bitmap_index bitmap;
802         int dest_bm_num = 0;
803
804         Assert(clip_num < MAX_EFFECTS);
805
806         if (clip_num+1 > Num_effects)
807                 Num_effects = clip_num+1;
808
809         Effects[clip_num].flags = 0;
810
811         //load the dest bitmap first, so that after this routine, the last-loaded
812         //texture will be the monitor, so that lighting parameter will be applied
813         //to the correct texture
814         if (dest_bm) {                  //deal with bitmap for blown up clip
815                 char short_name[FILENAME_LEN];
816                 int i;
817                 strcpy(short_name,dest_bm);
818                 REMOVE_DOTS(short_name);
819                 for (i=0;i<texture_count;i++)
820                         if (!stricmp(TmapInfo[i].filename,short_name))
821                                 break;
822                 if (i==texture_count) {
823                         Textures[texture_count] = bm_load_sub(dest_bm);
824                         strcpy( TmapInfo[texture_count].filename, short_name);
825                         texture_count++;
826                         Assert(texture_count < MAX_TEXTURES);
827                         NumTextures = texture_count;
828                 }
829                 else if (Textures[i].index == 0)                //was found, but registered out
830                         Textures[i] = bm_load_sub(dest_bm);
831                 dest_bm_num = i;
832         }
833
834         if (!abm_flag)  {
835                 bitmap = bm_load_sub(arg);
836
837                 Effects[clip_num].vc.play_time = fl2f(time);
838                 Effects[clip_num].vc.num_frames = frames;
839                 Effects[clip_num].vc.frame_time = fl2f(time)/frames;
840
841                 Assert(clip_count < frames);
842                 Effects[clip_num].vc.frames[clip_count] = bitmap;
843                 set_lighting_flag(&GameBitmaps[bitmap.index].bm_flags);
844
845                 Assert(!obj_eclip);             //obj eclips for non-abm files not supported!
846                 Assert(crit_flag==0);
847
848                 if (clip_count == 0) {
849                         Effects[clip_num].changing_wall_texture = texture_count;
850                         Assert(tmap_count < MAX_TEXTURES);
851                         TmapList[tmap_count++] = texture_count;
852                         Textures[texture_count] = bitmap;
853                         set_texture_name(arg);
854                         Assert(texture_count < MAX_TEXTURES);
855                         texture_count++;
856                         TmapInfo[texture_count].eclip_num = clip_num;
857                         NumTextures = texture_count;
858                 }
859
860                 clip_count++;
861
862         } else {
863                 bitmap_index bm[MAX_BITMAPS_PER_BRUSH];
864                 abm_flag = 0;
865
866                 ab_load( arg, bm, &Effects[clip_num].vc.num_frames );
867
868                 //printf("EC%d.", clip_num);
869                 Effects[clip_num].vc.play_time = fl2f(time);
870                 Effects[clip_num].vc.frame_time = Effects[clip_num].vc.play_time/Effects[clip_num].vc.num_frames;
871
872                 clip_count = 0; 
873                 set_lighting_flag( &GameBitmaps[bm[clip_count].index].bm_flags);
874                 Effects[clip_num].vc.frames[clip_count] = bm[clip_count];
875
876                 if (!obj_eclip && !crit_flag) {
877                         Effects[clip_num].changing_wall_texture = texture_count;
878                         Assert(tmap_count < MAX_TEXTURES);
879                         TmapList[tmap_count++] = texture_count;
880                         Textures[texture_count] = bm[clip_count];
881                         set_texture_name( arg );
882                         Assert(texture_count < MAX_TEXTURES);
883                         TmapInfo[texture_count].eclip_num = clip_num;
884                         texture_count++;
885                         NumTextures = texture_count;
886                 }
887
888                 if (obj_eclip) {
889
890                         if (Effects[clip_num].changing_object_texture == -1) {          //first time referenced
891                                 Effects[clip_num].changing_object_texture = N_ObjBitmaps;               // XChange ObjectBitmaps
892                                 N_ObjBitmaps++;
893                         }
894
895                         ObjBitmaps[Effects[clip_num].changing_object_texture] = Effects[clip_num].vc.frames[0];
896                 }
897
898                 //if for an object, Effects_bm_ptrs set in object load
899
900                 for(clip_count=1;clip_count < Effects[clip_num].vc.num_frames; clip_count++) {
901                         set_lighting_flag( &GameBitmaps[bm[clip_count].index].bm_flags);
902                         Effects[clip_num].vc.frames[clip_count] = bm[clip_count];
903                 }
904
905         }
906
907         Effects[clip_num].crit_clip = crit_clip;
908         Effects[clip_num].sound_num = sound_num;
909
910         if (dest_bm) {                  //deal with bitmap for blown up clip
911
912                 Effects[clip_num].dest_bm_num = dest_bm_num;
913
914                 if (dest_vclip==-1)
915                         Error("Desctuction vclip missing on line %d",linenum);
916                 if (dest_size==-1)
917                         Error("Desctuction vclip missing on line %d",linenum);
918
919                 Effects[clip_num].dest_vclip = dest_vclip;
920                 Effects[clip_num].dest_size = dest_size;
921
922                 Effects[clip_num].dest_eclip = dest_eclip;
923         }
924         else {
925                 Effects[clip_num].dest_bm_num = -1;
926                 Effects[clip_num].dest_eclip = -1;
927         }
928
929         if (crit_flag)
930                 Effects[clip_num].flags |= EF_CRITICAL;
931 }
932
933
934 void bm_read_gauges()
935 {
936         bitmap_index bitmap;
937         int i, num_abm_frames;
938
939         if (!abm_flag)  {
940                 bitmap = bm_load_sub(arg);
941                 Assert(clip_count < MAX_GAUGE_BMS);
942                 Gauges[clip_count] = bitmap;
943                 clip_count++;
944         } else {
945                 bitmap_index bm[MAX_BITMAPS_PER_BRUSH];
946                 abm_flag = 0;
947                 ab_load( arg, bm, &num_abm_frames );
948                 for (i=clip_count; i<clip_count+num_abm_frames; i++) {
949                         Assert(i < MAX_GAUGE_BMS);
950                         Gauges[i] = bm[i-clip_count];
951                 }
952                 clip_count += num_abm_frames;
953         }
954 }
955
956 void bm_read_gauges_hires()
957 {
958         bitmap_index bitmap;
959         int i, num_abm_frames;
960
961         if (!abm_flag)  {
962                 bitmap = bm_load_sub(arg);
963                 Assert(clip_count < MAX_GAUGE_BMS);
964                 Gauges_hires[clip_count] = bitmap;
965                 clip_count++;
966         } else {
967                 bitmap_index bm[MAX_BITMAPS_PER_BRUSH];
968                 abm_flag = 0;
969                 ab_load( arg, bm, &num_abm_frames );
970                 for (i=clip_count; i<clip_count+num_abm_frames; i++) {
971                         Assert(i < MAX_GAUGE_BMS);
972                         Gauges_hires[i] = bm[i-clip_count];
973                 }
974                 clip_count += num_abm_frames;
975         }
976 }
977
978 void bm_read_wclip()
979 {
980         bitmap_index bitmap;
981         Assert(clip_num < MAX_WALL_ANIMS);
982
983         WallAnims[clip_num].flags = 0;
984
985         if (wall_explodes)      WallAnims[clip_num].flags |= WCF_EXPLODES;
986         if (wall_blastable)     WallAnims[clip_num].flags |= WCF_BLASTABLE;
987         if (wall_hidden)                WallAnims[clip_num].flags |= WCF_HIDDEN;
988         if (tmap1_flag)         WallAnims[clip_num].flags |= WCF_TMAP1;
989
990         if (!abm_flag)  {
991                 bitmap = bm_load_sub(arg);
992                 if ( (WallAnims[clip_num].num_frames>-1) && (clip_count==0) )
993                         Error( "Wall Clip %d is already used!", clip_num );
994                 WallAnims[clip_num].play_time = fl2f(time);
995                 WallAnims[clip_num].num_frames = frames;
996                 //WallAnims[clip_num].frame_time = fl2f(time)/frames;
997                 Assert(clip_count < frames);
998                 WallAnims[clip_num].frames[clip_count++] = texture_count;
999                 WallAnims[clip_num].open_sound = wall_open_sound;
1000                 WallAnims[clip_num].close_sound = wall_close_sound;
1001                 Textures[texture_count] = bitmap;
1002                 set_lighting_flag(&GameBitmaps[bitmap.index].bm_flags);
1003                 set_texture_name( arg );
1004                 Assert(texture_count < MAX_TEXTURES);
1005                 texture_count++;
1006                 NumTextures = texture_count;
1007                 if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1;
1008         } else {
1009                 bitmap_index bm[MAX_BITMAPS_PER_BRUSH];
1010                 int nframes;
1011                 if ( (WallAnims[clip_num].num_frames>-1)  )
1012                         Error( "AB_Wall clip %d is already used!", clip_num );
1013                 abm_flag = 0;
1014                 ab_load( arg, bm, &nframes );
1015                 WallAnims[clip_num].num_frames = nframes;
1016                 //printf("WC");
1017                 WallAnims[clip_num].play_time = fl2f(time);
1018                 //WallAnims[clip_num].frame_time = fl2f(time)/nframes;
1019                 WallAnims[clip_num].open_sound = wall_open_sound;
1020                 WallAnims[clip_num].close_sound = wall_close_sound;
1021
1022                 WallAnims[clip_num].close_sound = wall_close_sound;
1023                 strcpy(WallAnims[clip_num].filename, arg);
1024                 REMOVE_DOTS(WallAnims[clip_num].filename);      
1025
1026                 if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1;
1027
1028                 set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags);
1029
1030                 for (clip_count=0;clip_count < WallAnims[clip_num].num_frames; clip_count++)    {
1031                         //printf("%d", clip_count);
1032                         Textures[texture_count] = bm[clip_count];
1033                         set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags);
1034                         WallAnims[clip_num].frames[clip_count] = texture_count;
1035                         REMOVE_DOTS(arg);
1036                         sprintf( TmapInfo[texture_count].filename, "%s#%d", arg, clip_count);
1037                         Assert(texture_count < MAX_TEXTURES);
1038                         texture_count++;
1039                         NumTextures = texture_count;
1040                 }
1041         }
1042 }
1043
1044 void bm_read_vclip()
1045 {
1046         bitmap_index bi;
1047         Assert(clip_num < VCLIP_MAXNUM);
1048
1049         if (clip_num >= Num_vclips)
1050                 Num_vclips = clip_num+1;
1051
1052         if (!abm_flag)  {
1053                 if ( (Vclip[clip_num].num_frames>-1) && (clip_count==0)  )
1054                         Error( "Vclip %d is already used!", clip_num );
1055                 bi = bm_load_sub(arg);
1056                 Vclip[clip_num].play_time = fl2f(time);
1057                 Vclip[clip_num].num_frames = frames;
1058                 Vclip[clip_num].frame_time = fl2f(time)/frames;
1059                 Vclip[clip_num].light_value = fl2f(vlighting);
1060                 Vclip[clip_num].sound_num = sound_num;
1061                 set_lighting_flag(&GameBitmaps[bi.index].bm_flags);
1062                 Assert(clip_count < frames);
1063                 Vclip[clip_num].frames[clip_count++] = bi;
1064                 if (rod_flag) {
1065                         rod_flag=0;
1066                         Vclip[clip_num].flags |= VF_ROD;
1067                 }                       
1068
1069         } else  {
1070                 bitmap_index bm[MAX_BITMAPS_PER_BRUSH];
1071                 abm_flag = 0;
1072                 if ( (Vclip[clip_num].num_frames>-1)  )
1073                         Error( "AB_Vclip %d is already used!", clip_num );
1074                 ab_load( arg, bm, &Vclip[clip_num].num_frames );
1075
1076                 if (rod_flag) {
1077                         //int i;
1078                         rod_flag=0;
1079                         Vclip[clip_num].flags |= VF_ROD;
1080                 }                       
1081                 //printf("VC");
1082                 Vclip[clip_num].play_time = fl2f(time);
1083                 Vclip[clip_num].frame_time = fl2f(time)/Vclip[clip_num].num_frames;
1084                 Vclip[clip_num].light_value = fl2f(vlighting);
1085                 Vclip[clip_num].sound_num = sound_num;
1086                 set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags);
1087
1088                 for (clip_count=0;clip_count < Vclip[clip_num].num_frames; clip_count++) {
1089                         //printf("%d", clip_count);
1090                         set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags);
1091                         Vclip[clip_num].frames[clip_count] = bm[clip_count];
1092                 }
1093         }
1094 }
1095
1096 // ------------------------------------------------------------------------------
1097 void get4fix(fix *fixp)
1098 {
1099         char    *curtext;
1100         int     i;
1101
1102         for (i=0; i<NDL; i++) {
1103                 curtext = strtok(NULL, space);
1104                 fixp[i] = fl2f(atof(curtext));
1105         }
1106 }
1107
1108 // ------------------------------------------------------------------------------
1109 void get4byte(sbyte *bytep)
1110 {
1111         char    *curtext;
1112         int     i;
1113
1114         for (i=0; i<NDL; i++) {
1115                 curtext = strtok(NULL, space);
1116                 bytep[i] = atoi(curtext);
1117         }
1118 }
1119
1120 // ------------------------------------------------------------------------------
1121 //      Convert field of view from an angle in 0..360 to cosine.
1122 void adjust_field_of_view(fix *fovp)
1123 {
1124         int             i;
1125         fixang  tt;
1126         float           ff;
1127         fix             temp;
1128
1129         for (i=0; i<NDL; i++) {
1130                 ff = - f2fl(fovp[i]);
1131                 if (ff > 179) {
1132                         mprintf((1, "Warning: Bogus field of view (%7.3f).  Must be in 0..179.\n", ff));
1133                         ff = 179;
1134                 }
1135                 ff = ff/360;
1136                 tt = fl2f(ff);
1137                 fix_sincos(tt, &temp, &fovp[i]);
1138         }
1139 }
1140
1141 void clear_to_end_of_line(void)
1142 {
1143         arg = strtok( NULL, space );
1144         while (arg != NULL)
1145                 arg = strtok( NULL, space );
1146 }
1147
1148 void bm_read_sound()
1149 {
1150         int sound_num;
1151         int alt_sound_num;
1152
1153         sound_num = get_int();
1154         alt_sound_num = get_int();
1155
1156         if ( sound_num>=MAX_SOUNDS )
1157                 Error( "Too many sound files.\n" );
1158
1159         if (sound_num >= num_sounds)
1160                 num_sounds = sound_num+1;
1161
1162         if (Sounds[sound_num] != 255)
1163                 Error("Sound num %d already used, bitmaps.tbl, line %d\n",sound_num,linenum);
1164
1165         arg = strtok(NULL, space);
1166
1167         Sounds[sound_num] = ds_load(arg);
1168
1169         if ( alt_sound_num == 0 )
1170                 AltSounds[sound_num] = sound_num;
1171         else if (alt_sound_num < 0 )
1172                 AltSounds[sound_num] = 255;
1173         else
1174                 AltSounds[sound_num] = alt_sound_num;
1175
1176         if (Sounds[sound_num] == 255)
1177                 Error("Can't load soundfile <%s>",arg);
1178 }
1179
1180 // ------------------------------------------------------------------------------
1181 void bm_read_robot_ai() 
1182 {
1183         char                    *robotnum_text;
1184         int                     robotnum;
1185         robot_info      *robptr;
1186
1187         robotnum_text = strtok(NULL, space);
1188         robotnum = atoi(robotnum_text);
1189         Assert(robotnum < MAX_ROBOT_TYPES);
1190         robptr = &Robot_info[robotnum];
1191
1192         Assert(robotnum == Num_robot_ais);              //make sure valid number
1193
1194 #ifdef SHAREWARE
1195         if (Registered_only) {
1196                 Num_robot_ais++;
1197                 clear_to_end_of_line();
1198                 return;
1199         }
1200 #endif
1201
1202         Num_robot_ais++;
1203
1204         get4fix(robptr->field_of_view);
1205         get4fix(robptr->firing_wait);
1206         get4fix(robptr->firing_wait2);
1207         get4byte(robptr->rapidfire_count);
1208         get4fix(robptr->turn_time);
1209 //      get4fix(robptr->fire_power);
1210 //      get4fix(robptr->shield);
1211         get4fix(robptr->max_speed);
1212         get4fix(robptr->circle_distance);
1213         get4byte(robptr->evade_speed);
1214
1215         robptr->always_0xabcd   = 0xabcd;
1216
1217         adjust_field_of_view(robptr->field_of_view);
1218
1219 }
1220
1221 //      ----------------------------------------------------------------------------------------------
1222 //this will load a bitmap for a polygon models.  it puts the bitmap into
1223 //the array ObjBitmaps[], and also deals with animating bitmaps
1224 //returns a pointer to the bitmap
1225 grs_bitmap *load_polymodel_bitmap(char *name)
1226 {
1227         Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS);
1228
1229 //      Assert( N_ObjBitmaps == N_ObjBitmapPtrs );
1230
1231         if (name[0] == '%') {           //an animating bitmap!
1232                 int eclip_num;
1233
1234                 eclip_num = atoi(name+1);
1235
1236                 if (Effects[eclip_num].changing_object_texture == -1) {         //first time referenced
1237                         Effects[eclip_num].changing_object_texture = N_ObjBitmaps;
1238                         ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps;
1239                         N_ObjBitmaps++;
1240                 } else {
1241                         ObjBitmapPtrs[N_ObjBitmapPtrs++] = Effects[eclip_num].changing_object_texture;
1242                 }
1243                 Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS);
1244                 Assert(N_ObjBitmapPtrs < MAX_OBJ_BITMAPS);
1245                 return NULL;
1246         }
1247         else    {
1248                 ObjBitmaps[N_ObjBitmaps] = bm_load_sub(name);
1249                 if (GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_w!=64 || GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_h!=64)
1250                         Error("Bitmap <%s> is not 64x64",name);
1251                 ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps;
1252                 N_ObjBitmaps++;
1253                 Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS);
1254                 Assert(N_ObjBitmapPtrs < MAX_OBJ_BITMAPS);
1255                 return &GameBitmaps[ObjBitmaps[N_ObjBitmaps-1].index];
1256         }
1257 }
1258
1259 #define MAX_MODEL_VARIANTS      4
1260
1261 // ------------------------------------------------------------------------------
1262 void bm_read_robot()    
1263 {
1264         char                    *model_name[MAX_MODEL_VARIANTS];
1265         int                     n_models,i;
1266         int                     first_bitmap_num[MAX_MODEL_VARIANTS];
1267         char                    *equal_ptr;
1268         int                     exp1_vclip_num=-1;
1269         int                     exp1_sound_num=-1;
1270         int                     exp2_vclip_num=-1;
1271         int                     exp2_sound_num=-1;
1272         fix                     lighting = F1_0/2;              // Default
1273         fix                     strength = F1_0*10;             // Default strength
1274         fix                     mass = f1_0*4;
1275         fix                     drag = f1_0/2;
1276         short           weapon_type = 0, weapon_type2 = -1;
1277         int                     g,s;
1278         char                    name[ROBOT_NAME_LENGTH];
1279         int                     contains_count=0, contains_id=0, contains_prob=0, contains_type=0, behavior=AIB_NORMAL;
1280         int                     companion = 0, smart_blobs=0, energy_blobs=0, badass=0, energy_drain=0, kamikaze=0, thief=0, pursuit=0, lightcast=0, death_roll=0;
1281         fix                     glow=0, aim=F1_0;
1282         int                     deathroll_sound = SOUND_BOSS_SHARE_DIE; //default
1283         int                     score_value=1000;
1284         int                     cloak_type=0;           //      Default = this robot does not cloak
1285         int                     attack_type=0;          //      Default = this robot attacks by firing (1=lunge)
1286         int                     boss_flag=0;                            //      Default = robot is not a boss.
1287         int                     see_sound = ROBOT_SEE_SOUND_DEFAULT;
1288         int                     attack_sound = ROBOT_ATTACK_SOUND_DEFAULT;
1289         int                     claw_sound = ROBOT_CLAW_SOUND_DEFAULT;
1290         int                     taunt_sound = ROBOT_SEE_SOUND_DEFAULT;
1291         ubyte flags=0;
1292
1293         Assert(N_robot_types < MAX_ROBOT_TYPES);
1294
1295 #ifdef SHAREWARE
1296         if (Registered_only) {
1297                 Robot_info[N_robot_types].model_num = -1;
1298                 N_robot_types++;
1299                 Assert(N_robot_types < MAX_ROBOT_TYPES);
1300                 Num_total_object_types++;
1301                 Assert(Num_total_object_types < MAX_OBJTYPE);
1302                 clear_to_end_of_line();
1303                 return;
1304         }
1305 #endif
1306
1307         model_name[0] = strtok( NULL, space );
1308         first_bitmap_num[0] = N_ObjBitmapPtrs;
1309         n_models = 1;
1310
1311         // Process bitmaps
1312         bm_flag=BM_ROBOT;
1313         arg = strtok( NULL, space );
1314         while (arg!=NULL)       {
1315                 equal_ptr = strchr( arg, '=' );
1316                 if ( equal_ptr )        {
1317                         *equal_ptr='\0';
1318                         equal_ptr++;
1319                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1320                         if (!stricmp( arg, "exp1_vclip" ))      {
1321                                 exp1_vclip_num = atoi(equal_ptr);
1322                         } else if (!stricmp( arg, "exp2_vclip" ))       {
1323                                 exp2_vclip_num = atoi(equal_ptr);
1324                         } else if (!stricmp( arg, "exp1_sound" ))       {
1325                                 exp1_sound_num = atoi(equal_ptr);
1326                         } else if (!stricmp( arg, "exp2_sound" ))       {
1327                                 exp2_sound_num = atoi(equal_ptr);
1328                         } else if (!stricmp( arg, "lighting" )) {
1329                                 lighting = fl2f(atof(equal_ptr));
1330                                 if ( (lighting < 0) || (lighting > F1_0 )) {
1331                                         mprintf( (1, "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)));
1332                                         Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting));
1333                                 }
1334                         } else if (!stricmp( arg, "weapon_type" )) {
1335                                 weapon_type = atoi(equal_ptr);
1336                         } else if (!stricmp( arg, "weapon_type2" )) {
1337                                 weapon_type2 = atoi(equal_ptr);
1338                         } else if (!stricmp( arg, "strength" )) {
1339                                 strength = i2f(atoi(equal_ptr));
1340                         } else if (!stricmp( arg, "mass" )) {
1341                                 mass = fl2f(atof(equal_ptr));
1342                         } else if (!stricmp( arg, "drag" )) {
1343                                 drag = fl2f(atof(equal_ptr));
1344                         } else if (!stricmp( arg, "contains_id" )) {
1345                                 contains_id = atoi(equal_ptr);
1346                         } else if (!stricmp( arg, "contains_type" )) {
1347                                 contains_type = atoi(equal_ptr);
1348                         } else if (!stricmp( arg, "contains_count" )) {
1349                                 contains_count = atoi(equal_ptr);
1350                         } else if (!stricmp( arg, "companion" )) {
1351                                 companion = atoi(equal_ptr);
1352                         } else if (!stricmp( arg, "badass" )) {
1353                                 badass = atoi(equal_ptr);
1354                         } else if (!stricmp( arg, "lightcast" )) {
1355                                 lightcast = atoi(equal_ptr);
1356                         } else if (!stricmp( arg, "glow" )) {
1357                                 glow = fl2f(atof(equal_ptr));
1358                         } else if (!stricmp( arg, "death_roll" )) {
1359                                 death_roll = atoi(equal_ptr);
1360                         } else if (!stricmp( arg, "deathroll_sound" )) {
1361                                 deathroll_sound = atoi(equal_ptr);
1362                         } else if (!stricmp( arg, "thief" )) {
1363                                 thief = atoi(equal_ptr);
1364                         } else if (!stricmp( arg, "kamikaze" )) {
1365                                 kamikaze = atoi(equal_ptr);
1366                         } else if (!stricmp( arg, "pursuit" )) {
1367                                 pursuit = atoi(equal_ptr);
1368                         } else if (!stricmp( arg, "smart_blobs" )) {
1369                                 smart_blobs = atoi(equal_ptr);
1370                         } else if (!stricmp( arg, "energy_blobs" )) {
1371                                 energy_blobs = atoi(equal_ptr);
1372                         } else if (!stricmp( arg, "energy_drain" )) {
1373                                 energy_drain = atoi(equal_ptr);
1374                         } else if (!stricmp( arg, "contains_prob" )) {
1375                                 contains_prob = atoi(equal_ptr);
1376                         } else if (!stricmp( arg, "cloak_type" )) {
1377                                 cloak_type = atoi(equal_ptr);
1378                         } else if (!stricmp( arg, "attack_type" )) {
1379                                 attack_type = atoi(equal_ptr);
1380                         } else if (!stricmp( arg, "boss" )) {
1381                                 boss_flag = atoi(equal_ptr);
1382                         } else if (!stricmp( arg, "score_value" )) {
1383                                 score_value = atoi(equal_ptr);
1384                         } else if (!stricmp( arg, "see_sound" )) {
1385                                 see_sound = atoi(equal_ptr);
1386                         } else if (!stricmp( arg, "attack_sound" )) {
1387                                 attack_sound = atoi(equal_ptr);
1388                         } else if (!stricmp( arg, "claw_sound" )) {
1389                                 claw_sound = atoi(equal_ptr);
1390                         } else if (!stricmp( arg, "taunt_sound" )) {
1391                                 taunt_sound = atoi(equal_ptr);
1392                         } else if (!stricmp( arg, "aim" )) {
1393                                 aim = fl2f(atof(equal_ptr));
1394                         } else if (!stricmp( arg, "big_radius" )) {
1395                                 if (atoi(equal_ptr))
1396                                         flags |= RIF_BIG_RADIUS;
1397                         } else if (!stricmp( arg, "behavior" )) {
1398                                 if (!stricmp(equal_ptr, "STILL"))
1399                                         behavior = AIB_STILL;
1400                                 else if (!stricmp(equal_ptr, "NORMAL"))
1401                                         behavior = AIB_NORMAL;
1402                                 else if (!stricmp(equal_ptr, "BEHIND"))
1403                                         behavior = AIB_BEHIND;
1404                                 else if (!stricmp(equal_ptr, "RUN_FROM"))
1405                                         behavior = AIB_RUN_FROM;
1406                                 else if (!stricmp(equal_ptr, "SNIPE"))
1407                                         behavior = AIB_SNIPE;
1408                                 else if (!stricmp(equal_ptr, "STATION"))
1409                                         behavior = AIB_STATION;
1410                                 else if (!stricmp(equal_ptr, "FOLLOW"))
1411                                         behavior = AIB_FOLLOW;
1412                                 else
1413                                         Int3(); //      Error.  Illegal behavior type for current robot.
1414                         } else if (!stricmp( arg, "name" )) {
1415                                 Assert(strlen(equal_ptr) < ROBOT_NAME_LENGTH);  //      Oops, name too long.
1416                                 strcpy(name, &equal_ptr[1]);
1417                                 name[strlen(name)-1] = 0;
1418                         } else if (!stricmp( arg, "simple_model" )) {
1419                                 model_name[n_models] = equal_ptr;
1420                                 first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1421                                 n_models++;
1422                                 Assert(n_models < MAX_MODEL_VARIANTS);
1423                         } else {
1424                                 Int3();
1425                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
1426                         }               
1427                 } else {                        // Must be a texture specification...
1428                         load_polymodel_bitmap(arg);
1429                 }
1430                 arg = strtok( NULL, space );
1431         }
1432
1433         //clear out anim info
1434         for (g=0;g<MAX_GUNS+1;g++)
1435                 for (s=0;s<N_ANIM_STATES;s++)
1436                         Robot_info[N_robot_types].anim_states[g][s].n_joints = 0;       //inialize to zero
1437
1438         first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1439
1440         for (i=0;i<n_models;i++) {
1441                 int n_textures;
1442                 int model_num,last_model_num=0;
1443
1444                 n_textures = first_bitmap_num[i+1] - first_bitmap_num[i];
1445
1446                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],(i==0)?&Robot_info[N_robot_types]:NULL);
1447
1448                 if (i==0)
1449                         Robot_info[N_robot_types].model_num = model_num;
1450                 else
1451                         Polygon_models[last_model_num].simpler_model = model_num+1;
1452
1453                 last_model_num = model_num;
1454         }
1455
1456         if ((glow > i2f(15)) || (glow < 0) || (glow != 0 && glow < 0x1000)) {
1457                 mprintf((0,"Invalid glow value %x for robot %d\n",glow,N_robot_types));
1458                 Int3();
1459         }
1460
1461         ObjType[Num_total_object_types] = OL_ROBOT;
1462         ObjId[Num_total_object_types] = N_robot_types;
1463
1464         Robot_info[N_robot_types].exp1_vclip_num = exp1_vclip_num;
1465         Robot_info[N_robot_types].exp2_vclip_num = exp2_vclip_num;
1466         Robot_info[N_robot_types].exp1_sound_num = exp1_sound_num;
1467         Robot_info[N_robot_types].exp2_sound_num = exp2_sound_num;
1468         Robot_info[N_robot_types].lighting = lighting;
1469         Robot_info[N_robot_types].weapon_type = weapon_type;
1470         Robot_info[N_robot_types].weapon_type2 = weapon_type2;
1471         Robot_info[N_robot_types].strength = strength;
1472         Robot_info[N_robot_types].mass = mass;
1473         Robot_info[N_robot_types].drag = drag;
1474         Robot_info[N_robot_types].cloak_type = cloak_type;
1475         Robot_info[N_robot_types].attack_type = attack_type;
1476         Robot_info[N_robot_types].boss_flag = boss_flag;
1477
1478         Robot_info[N_robot_types].contains_id = contains_id;
1479         Robot_info[N_robot_types].contains_count = contains_count;
1480         Robot_info[N_robot_types].contains_prob = contains_prob;
1481         Robot_info[N_robot_types].companion = companion;
1482         Robot_info[N_robot_types].badass = badass;
1483         Robot_info[N_robot_types].lightcast = lightcast;
1484         Robot_info[N_robot_types].glow = (glow>>12);            //convert to 4:4
1485         Robot_info[N_robot_types].death_roll = death_roll;
1486         Robot_info[N_robot_types].deathroll_sound = deathroll_sound;
1487         Robot_info[N_robot_types].thief = thief;
1488         Robot_info[N_robot_types].flags = flags;
1489         Robot_info[N_robot_types].kamikaze = kamikaze;
1490         Robot_info[N_robot_types].pursuit = pursuit;
1491         Robot_info[N_robot_types].smart_blobs = smart_blobs;
1492         Robot_info[N_robot_types].energy_blobs = energy_blobs;
1493         Robot_info[N_robot_types].energy_drain = energy_drain;
1494         Robot_info[N_robot_types].score_value = score_value;
1495         Robot_info[N_robot_types].see_sound = see_sound;
1496         Robot_info[N_robot_types].attack_sound = attack_sound;
1497         Robot_info[N_robot_types].claw_sound = claw_sound;
1498         Robot_info[N_robot_types].taunt_sound = taunt_sound;
1499         Robot_info[N_robot_types].behavior = behavior;          //      Default behavior for this robot, if coming out of matcen.
1500         Robot_info[N_robot_types].aim = min(f2i(aim*255), 255);         //      how well this robot type can aim.  255=perfect
1501
1502         if (contains_type)
1503                 Robot_info[N_robot_types].contains_type = OBJ_ROBOT;
1504         else
1505                 Robot_info[N_robot_types].contains_type = OBJ_POWERUP;
1506
1507         strcpy(Robot_names[N_robot_types], name);
1508
1509         N_robot_types++;
1510         Num_total_object_types++;
1511
1512         Assert(N_robot_types < MAX_ROBOT_TYPES);
1513         Assert(Num_total_object_types < MAX_OBJTYPE);
1514
1515         bm_flag = BM_NONE;
1516 }
1517
1518 //read a reactor model
1519 void bm_read_reactor()
1520 {
1521         char *model_name, *model_name_dead=NULL;
1522         int first_bitmap_num, first_bitmap_num_dead=0, n_normal_bitmaps;
1523         char *equal_ptr;
1524         short model_num;
1525         short explosion_vclip_num = -1;
1526         short explosion_sound_num = SOUND_ROBOT_DESTROYED;
1527         fix     lighting = F1_0/2;              // Default
1528         int type=-1;
1529         fix strength=0;
1530
1531         Assert(Num_reactors < MAX_REACTORS);
1532
1533 #ifdef SHAREWARE
1534         if (Registered_only) {
1535                 Num_reactors++;
1536                 clear_to_end_of_line();
1537                 return;
1538         }
1539 #endif
1540
1541         model_name = strtok( NULL, space );
1542
1543         // Process bitmaps
1544         bm_flag = BM_NONE;
1545         arg = strtok( NULL, space );
1546         first_bitmap_num = N_ObjBitmapPtrs;
1547
1548         type = OL_CONTROL_CENTER;
1549
1550         while (arg!=NULL)       {
1551
1552                 equal_ptr = strchr( arg, '=' );
1553
1554                 if ( equal_ptr )        {
1555                         *equal_ptr='\0';
1556                         equal_ptr++;
1557
1558                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1559
1560                         //@@if (!stricmp(arg,"type")) {
1561                         //@@    if (!stricmp(equal_ptr,"controlcen"))
1562                         //@@            type = OL_CONTROL_CENTER;
1563                         //@@    else if (!stricmp(equal_ptr,"clutter"))
1564                         //@@            type = OL_CLUTTER;
1565                         //@@}
1566
1567                         if (!stricmp( arg, "exp_vclip" ))       {
1568                                 explosion_vclip_num = atoi(equal_ptr);
1569                         } else if (!stricmp( arg, "dead_pof" )) {
1570                                 model_name_dead = equal_ptr;
1571                                 first_bitmap_num_dead=N_ObjBitmapPtrs;
1572                         } else if (!stricmp( arg, "exp_sound" ))        {
1573                                 explosion_sound_num = atoi(equal_ptr);
1574                         } else if (!stricmp( arg, "lighting" )) {
1575                                 lighting = fl2f(atof(equal_ptr));
1576                                 if ( (lighting < 0) || (lighting > F1_0 )) {
1577                                         mprintf( (1, "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)));
1578                                         Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting));
1579                                 }
1580                         } else if (!stricmp( arg, "strength" )) {
1581                                 strength = fl2f(atof(equal_ptr));
1582                         } else {
1583                                 Int3();
1584                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
1585                         }               
1586                 } else {                        // Must be a texture specification...
1587                         load_polymodel_bitmap(arg);
1588                 }
1589                 arg = strtok( NULL, space );
1590         }
1591
1592         if ( model_name_dead )
1593                 n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num;
1594         else
1595                 n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num;
1596
1597         model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL);
1598
1599         if ( model_name_dead )
1600                 Dead_modelnums[model_num]  = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL);
1601         else
1602                 Dead_modelnums[model_num] = -1;
1603
1604         if (type == -1)
1605                 Error("No object type specfied for object in BITMAPS.TBL on line %d\n",linenum);
1606
1607         Reactors[Num_reactors].model_num = model_num;
1608         Reactors[Num_reactors].n_guns = read_model_guns(model_name,Reactors[Num_reactors].gun_points,Reactors[Num_reactors].gun_dirs,NULL);
1609
1610         ObjType[Num_total_object_types] = type;
1611         ObjId[Num_total_object_types] = Num_reactors;
1612         ObjStrength[Num_total_object_types] = strength;
1613         
1614         //printf( "Object type %d is a control center\n", Num_total_object_types );
1615         Num_total_object_types++;
1616         Assert(Num_total_object_types < MAX_OBJTYPE);
1617
1618         Num_reactors++;
1619 }
1620
1621 //read the marker object
1622 void bm_read_marker()
1623 {
1624         char *model_name;
1625         int first_bitmap_num, n_normal_bitmaps;
1626         char *equal_ptr;
1627
1628         model_name = strtok( NULL, space );
1629
1630         // Process bitmaps
1631         bm_flag = BM_NONE;
1632         arg = strtok( NULL, space );
1633         first_bitmap_num = N_ObjBitmapPtrs;
1634
1635         while (arg!=NULL)       {
1636
1637                 equal_ptr = strchr( arg, '=' );
1638
1639                 if ( equal_ptr )        {
1640                         *equal_ptr='\0';
1641                         equal_ptr++;
1642
1643                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1644                         mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
1645                         Int3();
1646
1647                 } else {                        // Must be a texture specification...
1648                         load_polymodel_bitmap(arg);
1649                 }
1650                 arg = strtok( NULL, space );
1651         }
1652
1653         n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num;
1654
1655         Marker_model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL);
1656 }
1657
1658 #ifdef SHAREWARE
1659 //read the exit model
1660 void bm_read_exitmodel()
1661 {
1662         char *model_name, *model_name_dead=NULL;
1663         int first_bitmap_num, first_bitmap_num_dead, n_normal_bitmaps;
1664         char *equal_ptr;
1665         short model_num;
1666
1667         model_name = strtok( NULL, space );
1668
1669         // Process bitmaps
1670         bm_flag = BM_NONE;
1671         arg = strtok( NULL, space );
1672         first_bitmap_num = N_ObjBitmapPtrs;
1673
1674         while (arg!=NULL)       {
1675
1676                 equal_ptr = strchr( arg, '=' );
1677
1678                 if ( equal_ptr )        {
1679                         *equal_ptr='\0';
1680                         equal_ptr++;
1681
1682                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1683
1684                         if (!stricmp( arg, "dead_pof" ))        {
1685                                 model_name_dead = equal_ptr;
1686                                 first_bitmap_num_dead=N_ObjBitmapPtrs;
1687                         } else {
1688                                 Int3();
1689                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
1690                         }               
1691                 } else {                        // Must be a texture specification...
1692                         load_polymodel_bitmap(arg);
1693                 }
1694                 arg = strtok( NULL, space );
1695         }
1696
1697         if ( model_name_dead )
1698                 n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num;
1699         else
1700                 n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num;
1701
1702         model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL);
1703
1704         if ( model_name_dead )
1705                 Dead_modelnums[model_num]  = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL);
1706         else
1707                 Dead_modelnums[model_num] = -1;
1708
1709 //@@    ObjType[Num_total_object_types] = type;
1710 //@@    ObjId[Num_total_object_types] = model_num;
1711 //@@    ObjStrength[Num_total_object_types] = strength;
1712 //@@    
1713 //@@    //printf( "Object type %d is a control center\n", Num_total_object_types );
1714 //@@    Num_total_object_types++;
1715 //@@    Assert(Num_total_object_types < MAX_OBJTYPE);
1716
1717         exit_modelnum = model_num;
1718         destroyed_exit_modelnum = Dead_modelnums[model_num];
1719
1720 }
1721 #endif
1722
1723 void bm_read_player_ship()
1724 {
1725         char    *model_name_dying=NULL;
1726         char    *model_name[MAX_MODEL_VARIANTS];
1727         int     n_models=0,i;
1728         int     first_bitmap_num[MAX_MODEL_VARIANTS];
1729         char *equal_ptr;
1730         robot_info ri;
1731         int last_multi_bitmap_num=-1;
1732
1733         // Process bitmaps
1734         bm_flag = BM_NONE;
1735
1736         arg = strtok( NULL, space );
1737
1738         Player_ship->mass = Player_ship->drag = 0;      //stupid defaults
1739         Player_ship->expl_vclip_num = -1;
1740
1741         while (arg!=NULL)       {
1742
1743                 equal_ptr = strchr( arg, '=' );
1744
1745                 if ( equal_ptr )        {
1746
1747                         *equal_ptr='\0';
1748                         equal_ptr++;
1749
1750                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
1751
1752                         if (!stricmp( arg, "model" )) {
1753                                 Assert(n_models==0);
1754                                 model_name[0] = equal_ptr;
1755                                 first_bitmap_num[0] = N_ObjBitmapPtrs;
1756                                 n_models = 1;
1757                         } else if (!stricmp( arg, "simple_model" )) {
1758                                 model_name[n_models] = equal_ptr;
1759                                 first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1760                                 n_models++;
1761                                 Assert(n_models < MAX_MODEL_VARIANTS);
1762
1763                                 if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1)
1764                                         last_multi_bitmap_num=N_ObjBitmapPtrs;
1765                         }
1766                         else if (!stricmp( arg, "mass" ))
1767                                 Player_ship->mass = fl2f(atof(equal_ptr));
1768                         else if (!stricmp( arg, "drag" ))
1769                                 Player_ship->drag = fl2f(atof(equal_ptr));
1770 //                      else if (!stricmp( arg, "low_thrust" ))
1771 //                              Player_ship->low_thrust = fl2f(atof(equal_ptr));
1772                         else if (!stricmp( arg, "max_thrust" ))
1773                                 Player_ship->max_thrust = fl2f(atof(equal_ptr));
1774                         else if (!stricmp( arg, "reverse_thrust" ))
1775                                 Player_ship->reverse_thrust = fl2f(atof(equal_ptr));
1776                         else if (!stricmp( arg, "brakes" ))
1777                                 Player_ship->brakes = fl2f(atof(equal_ptr));
1778                         else if (!stricmp( arg, "wiggle" ))
1779                                 Player_ship->wiggle = fl2f(atof(equal_ptr));
1780                         else if (!stricmp( arg, "max_rotthrust" ))
1781                                 Player_ship->max_rotthrust = fl2f(atof(equal_ptr));
1782                         else if (!stricmp( arg, "dying_pof" ))
1783                                 model_name_dying = equal_ptr;
1784                         else if (!stricmp( arg, "expl_vclip_num" ))
1785                                 Player_ship->expl_vclip_num=atoi(equal_ptr);
1786                         else {
1787                                 Int3();
1788                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
1789                         }               
1790                 }
1791                 else if (!stricmp( arg, "multi_textures" )) {
1792
1793                         First_multi_bitmap_num = N_ObjBitmapPtrs;
1794                         first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1795
1796                 }
1797                 else                    // Must be a texture specification...
1798
1799                         load_polymodel_bitmap(arg);
1800
1801                 arg = strtok( NULL, space );
1802         }
1803
1804         Assert(model_name != NULL);
1805
1806         if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1)
1807                 last_multi_bitmap_num=N_ObjBitmapPtrs;
1808
1809         if (First_multi_bitmap_num==-1)
1810                 first_bitmap_num[n_models] = N_ObjBitmapPtrs;
1811
1812 #ifdef NETWORK
1813         Assert(last_multi_bitmap_num-First_multi_bitmap_num == (MAX_NUM_NET_PLAYERS-1)*2);
1814 #endif
1815
1816         for (i=0;i<n_models;i++) {
1817                 int n_textures;
1818                 int model_num,last_model_num=0;
1819
1820                 n_textures = first_bitmap_num[i+1] - first_bitmap_num[i];
1821
1822                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],(i==0)?&ri:NULL);
1823
1824                 if (i==0)
1825                         Player_ship->model_num = model_num;
1826                 else
1827                         Polygon_models[last_model_num].simpler_model = model_num+1;
1828
1829                 last_model_num = model_num;
1830         }
1831
1832         if ( model_name_dying ) {
1833                 Assert(n_models);
1834                 Dying_modelnums[Player_ship->model_num]  = load_polygon_model(model_name_dying,first_bitmap_num[1]-first_bitmap_num[0],first_bitmap_num[0],NULL);
1835         }
1836
1837         Assert(ri.n_guns == N_PLAYER_GUNS);
1838
1839         //calc player gun positions
1840
1841         {
1842                 polymodel *pm;
1843                 robot_info *r;
1844                 vms_vector pnt;
1845                 int mn;                         //submodel number
1846                 int gun_num;
1847         
1848                 r = &ri;
1849                 pm = &Polygon_models[Player_ship->model_num];
1850
1851                 for (gun_num=0;gun_num<r->n_guns;gun_num++) {
1852
1853                         pnt = r->gun_points[gun_num];
1854                         mn = r->gun_submodels[gun_num];
1855                 
1856                         //instance up the tree for this gun
1857                         while (mn != 0) {
1858                                 vm_vec_add2(&pnt,&pm->submodel_offsets[mn]);
1859                                 mn = pm->submodel_parents[mn];
1860                         }
1861
1862                         Player_ship->gun_points[gun_num] = pnt;
1863                 
1864                 }
1865         }
1866
1867
1868 }
1869
1870 void bm_read_some_file()
1871 {
1872
1873         switch (bm_flag) {
1874         case BM_NONE:
1875                 Error("Trying to read bitmap <%s> with bm_flag==BM_NONE on line %d of BITMAPS.TBL",arg,linenum);
1876                 break;
1877         case BM_COCKPIT:        {
1878                 bitmap_index bitmap;
1879                 bitmap = bm_load_sub(arg);
1880                 Assert( Num_cockpits < N_COCKPIT_BITMAPS );
1881                 cockpit_bitmap[Num_cockpits++] = bitmap;
1882                 //bm_flag = BM_NONE;
1883                 return;
1884                 }
1885                 break;
1886         case BM_GAUGES:
1887                 bm_read_gauges();
1888                 return;
1889                 break;
1890         case BM_GAUGES_HIRES:
1891                 bm_read_gauges_hires();
1892                 return;
1893                 break;
1894         case BM_WEAPON:
1895                 bm_read_weapon(0);
1896                 return;
1897                 break;
1898         case BM_VCLIP:
1899                 bm_read_vclip();
1900                 return;
1901                 break;                                  
1902         case BM_ECLIP:
1903                 bm_read_eclip();
1904                 return;
1905                 break;
1906         case BM_TEXTURES:                       {
1907                 bitmap_index bitmap;
1908                 bitmap = bm_load_sub(arg);
1909                 Assert(tmap_count < MAX_TEXTURES);
1910                 TmapList[tmap_count++] = texture_count;
1911                 Textures[texture_count] = bitmap;
1912                 set_texture_name( arg );
1913                 Assert(texture_count < MAX_TEXTURES);
1914                 texture_count++;
1915                 NumTextures = texture_count;
1916                 return;
1917                 }
1918                 break;
1919         case BM_WCLIP:
1920                 bm_read_wclip();
1921                 return;
1922                 break;
1923         }
1924
1925         Error("Trying to read bitmap <%s> with unknown bm_flag <%x> on line %d of BITMAPS.TBL",arg,bm_flag,linenum);
1926 }
1927
1928 // ------------------------------------------------------------------------------
1929 //      If unused_flag is set, then this is just a placeholder.  Don't actually reference vclips or load bbms.
1930 void bm_read_weapon(int unused_flag)
1931 {
1932         int     i,n;
1933         int     n_models=0;
1934         char    *equal_ptr;
1935         char    *pof_file_inner=NULL;
1936         char    *model_name[MAX_MODEL_VARIANTS];
1937         int     first_bitmap_num[MAX_MODEL_VARIANTS];
1938         int     lighted;                                        //flag for whether is a texture is lighted
1939
1940         Assert(N_weapon_types < MAX_WEAPON_TYPES);
1941
1942         n = N_weapon_types;
1943         N_weapon_types++;
1944         Assert(N_weapon_types <= MAX_WEAPON_TYPES);
1945
1946         if (unused_flag) {
1947                 clear_to_end_of_line();
1948                 return;
1949         }
1950
1951 #ifdef SHAREWARE
1952         if (Registered_only) {
1953                 clear_to_end_of_line();
1954                 return;
1955         }
1956 #endif
1957
1958         // Initialize weapon array
1959         Weapon_info[n].render_type = WEAPON_RENDER_NONE;                // 0=laser, 1=blob, 2=object
1960         Weapon_info[n].bitmap.index = 0;
1961         Weapon_info[n].model_num = -1;
1962         Weapon_info[n].model_num_inner = -1;
1963         Weapon_info[n].blob_size = 0x1000;                                                                      // size of blob
1964         Weapon_info[n].flash_vclip = -1;
1965         Weapon_info[n].flash_sound = SOUND_LASER_FIRED;
1966         Weapon_info[n].flash_size = 0;
1967         Weapon_info[n].robot_hit_vclip = -1;
1968         Weapon_info[n].robot_hit_sound = -1;
1969         Weapon_info[n].wall_hit_vclip = -1;
1970         Weapon_info[n].wall_hit_sound = -1;
1971         Weapon_info[n].impact_size = 0;
1972         for (i=0; i<NDL; i++) {
1973                 Weapon_info[n].strength[i] = F1_0;
1974                 Weapon_info[n].speed[i] = F1_0*10;
1975         }
1976         Weapon_info[n].mass = F1_0;
1977         Weapon_info[n].thrust = 0;
1978         Weapon_info[n].drag = 0;
1979         Weapon_info[n].persistent = 0;
1980
1981         Weapon_info[n].energy_usage = 0;                                        //      How much fuel is consumed to fire this weapon.
1982         Weapon_info[n].ammo_usage = 0;                                  //      How many units of ammunition it uses.
1983         Weapon_info[n].fire_wait = F1_0/4;                              //      Time until this weapon can be fired again.
1984         Weapon_info[n].fire_count = 1;                                  //      Number of bursts fired from EACH GUN per firing.  For weapons which fire from both sides, 3*fire_count shots will be fired.
1985         Weapon_info[n].damage_radius = 0;                               //      Radius of damage for missiles, not lasers.  Does damage to objects within this radius of hit point.
1986 //--01/19/95, mk--      Weapon_info[n].damage_force = 0;                                        //      Force (movement) due to explosion
1987         Weapon_info[n].destroyable = 1;                                 //      Weapons default to destroyable
1988         Weapon_info[n].matter = 0;                                                      //      Weapons default to not being constructed of matter (they are energy!)
1989         Weapon_info[n].bounce = 0;                                                      //      Weapons default to not bouncing off walls
1990
1991         Weapon_info[n].flags = 0;
1992
1993         Weapon_info[n].lifetime = WEAPON_DEFAULT_LIFETIME;                                      //      Number of bursts fired from EACH GUN per firing.  For weapons which fire from both sides, 3*fire_count shots will be fired.
1994
1995         Weapon_info[n].po_len_to_width_ratio = F1_0*10;
1996
1997         Weapon_info[n].picture.index = 0;
1998         Weapon_info[n].hires_picture.index = 0;
1999         Weapon_info[n].homing_flag = 0;
2000
2001         Weapon_info[n].flash = 0;
2002         Weapon_info[n].multi_damage_scale = F1_0;
2003         Weapon_info[n].afterburner_size = 0;
2004         Weapon_info[n].children = -1;
2005
2006         // Process arguments
2007         arg = strtok( NULL, space );
2008
2009         lighted = 1;                    //assume first texture is lighted
2010
2011         Weapon_info[n].speedvar = 128;
2012
2013         while (arg!=NULL)       {
2014                 equal_ptr = strchr( arg, '=' );
2015                 if ( equal_ptr )        {
2016                         *equal_ptr='\0';
2017                         equal_ptr++;
2018                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
2019                         if (!stricmp( arg, "laser_bmp" ))       {
2020                                 // Load bitmap with name equal_ptr
2021
2022                                 Weapon_info[n].bitmap = bm_load_sub(equal_ptr);         //load_polymodel_bitmap(equal_ptr);
2023                                 Weapon_info[n].render_type = WEAPON_RENDER_LASER;
2024
2025                         } else if (!stricmp( arg, "blob_bmp" )) {
2026                                 // Load bitmap with name equal_ptr
2027
2028                                 Weapon_info[n].bitmap = bm_load_sub(equal_ptr);         //load_polymodel_bitmap(equal_ptr);
2029                                 Weapon_info[n].render_type = WEAPON_RENDER_BLOB;
2030
2031                         } else if (!stricmp( arg, "weapon_vclip" ))     {
2032                                 // Set vclip to play for this weapon.
2033                                 Weapon_info[n].bitmap.index = 0;
2034                                 Weapon_info[n].render_type = WEAPON_RENDER_VCLIP;
2035                                 Weapon_info[n].weapon_vclip = atoi(equal_ptr);
2036
2037                         } else if (!stricmp( arg, "none_bmp" )) {
2038                                 Weapon_info[n].bitmap = bm_load_sub(equal_ptr);
2039                                 Weapon_info[n].render_type = WEAPON_RENDER_NONE;
2040
2041                         } else if (!stricmp( arg, "weapon_pof" ))       {
2042                                 // Load pof file
2043                                 Assert(n_models==0);
2044                                 model_name[0] = equal_ptr;
2045                                 first_bitmap_num[0] = N_ObjBitmapPtrs;
2046                                 n_models=1;
2047                         } else if (!stricmp( arg, "simple_model" )) {
2048                                 model_name[n_models] = equal_ptr;
2049                                 first_bitmap_num[n_models] = N_ObjBitmapPtrs;
2050                                 n_models++;
2051                                 Assert(n_models < MAX_MODEL_VARIANTS);
2052                         } else if (!stricmp( arg, "weapon_pof_inner" )) {
2053                                 // Load pof file
2054                                 pof_file_inner = equal_ptr;
2055                         } else if (!stricmp( arg, "strength" )) {
2056                                 for (i=0; i<NDL-1; i++) {
2057                                         Weapon_info[n].strength[i] = fl2f(atof(equal_ptr));
2058                                         equal_ptr = strtok(NULL, space);
2059                                 }
2060                                 Weapon_info[n].strength[i] = i2f(atoi(equal_ptr));
2061                         } else if (!stricmp( arg, "mass" )) {
2062                                 Weapon_info[n].mass = fl2f(atof(equal_ptr));
2063                         } else if (!stricmp( arg, "drag" )) {
2064                                 Weapon_info[n].drag = fl2f(atof(equal_ptr));
2065                         } else if (!stricmp( arg, "thrust" )) {
2066                                 Weapon_info[n].thrust = fl2f(atof(equal_ptr));
2067                         } else if (!stricmp( arg, "matter" )) {
2068                                 Weapon_info[n].matter = atoi(equal_ptr);
2069                         } else if (!stricmp( arg, "bounce" )) {
2070                                 Weapon_info[n].bounce = atoi(equal_ptr);
2071                         } else if (!stricmp( arg, "speed" )) {
2072                                 for (i=0; i<NDL-1; i++) {
2073                                         Weapon_info[n].speed[i] = i2f(atoi(equal_ptr));
2074                                         equal_ptr = strtok(NULL, space);
2075                                 }
2076                                 Weapon_info[n].speed[i] = i2f(atoi(equal_ptr));
2077                         } else if (!stricmp( arg, "speedvar" )) {
2078                                 Weapon_info[n].speedvar = (atoi(equal_ptr) * 128) / 100;
2079                         } else if (!stricmp( arg, "flash_vclip" ))      {
2080                                 Weapon_info[n].flash_vclip = atoi(equal_ptr);
2081                         } else if (!stricmp( arg, "flash_sound" ))      {
2082                                 Weapon_info[n].flash_sound = atoi(equal_ptr);
2083                         } else if (!stricmp( arg, "flash_size" ))       {
2084                                 Weapon_info[n].flash_size = fl2f(atof(equal_ptr));
2085                         } else if (!stricmp( arg, "blob_size" ))        {
2086                                 Weapon_info[n].blob_size = fl2f(atof(equal_ptr));
2087                         } else if (!stricmp( arg, "robot_hit_vclip" ))  {
2088                                 Weapon_info[n].robot_hit_vclip = atoi(equal_ptr);
2089                         } else if (!stricmp( arg, "robot_hit_sound" ))  {
2090                                 Weapon_info[n].robot_hit_sound = atoi(equal_ptr);
2091                         } else if (!stricmp( arg, "wall_hit_vclip" ))   {
2092                                 Weapon_info[n].wall_hit_vclip = atoi(equal_ptr);
2093                         } else if (!stricmp( arg, "wall_hit_sound" ))   {
2094                                 Weapon_info[n].wall_hit_sound = atoi(equal_ptr);
2095                         } else if (!stricmp( arg, "impact_size" ))      {
2096                                 Weapon_info[n].impact_size = fl2f(atof(equal_ptr));
2097                         } else if (!stricmp( arg, "lighted" ))  {
2098                                 lighted = atoi(equal_ptr);
2099                         } else if (!stricmp( arg, "lw_ratio" )) {
2100                                 Weapon_info[n].po_len_to_width_ratio = fl2f(atof(equal_ptr));
2101                         } else if (!stricmp( arg, "lightcast" ))        {
2102                                 Weapon_info[n].light = fl2f(atof(equal_ptr));
2103                         } else if (!stricmp( arg, "persistent" ))       {
2104                                 Weapon_info[n].persistent = atoi(equal_ptr);
2105                         } else if (!stricmp(arg, "energy_usage" )) {
2106                                 Weapon_info[n].energy_usage = fl2f(atof(equal_ptr));
2107                         } else if (!stricmp(arg, "ammo_usage" )) {
2108                                 Weapon_info[n].ammo_usage = atoi(equal_ptr);
2109                         } else if (!stricmp(arg, "fire_wait" )) {
2110                                 Weapon_info[n].fire_wait = fl2f(atof(equal_ptr));
2111                         } else if (!stricmp(arg, "fire_count" )) {
2112                                 Weapon_info[n].fire_count = atoi(equal_ptr);
2113                         } else if (!stricmp(arg, "damage_radius" )) {
2114                                 Weapon_info[n].damage_radius = fl2f(atof(equal_ptr));
2115 //--01/19/95, mk--                      } else if (!stricmp(arg, "damage_force" )) {
2116 //--01/19/95, mk--                              Weapon_info[n].damage_force = fl2f(atof(equal_ptr));
2117                         } else if (!stricmp(arg, "lifetime" )) {
2118                                 Weapon_info[n].lifetime = fl2f(atof(equal_ptr));
2119                         } else if (!stricmp(arg, "destroyable" )) {
2120                                 Weapon_info[n].destroyable = atoi(equal_ptr);
2121                         } else if (!stricmp(arg, "picture" )) {
2122                                 Weapon_info[n].picture = bm_load_sub(equal_ptr);
2123                         } else if (!stricmp(arg, "hires_picture" )) {
2124                                 Weapon_info[n].hires_picture = bm_load_sub(equal_ptr);
2125                         } else if (!stricmp(arg, "homing" )) {
2126                                 Weapon_info[n].homing_flag = !!atoi(equal_ptr);
2127                         } else if (!stricmp(arg, "flash" )) {
2128                                 Weapon_info[n].flash = atoi(equal_ptr);
2129                         } else if (!stricmp(arg, "multi_damage_scale" )) {
2130                                 Weapon_info[n].multi_damage_scale = fl2f(atof(equal_ptr));
2131                         } else if (!stricmp(arg, "afterburner_size" )) {
2132                                 Weapon_info[n].afterburner_size = f2i(16*fl2f(atof(equal_ptr)));
2133                         } else if (!stricmp(arg, "children" )) {
2134                                 Weapon_info[n].children = atoi(equal_ptr);
2135                         } else if (!stricmp(arg, "placable" )) {
2136                                 if (atoi(equal_ptr)) {
2137                                         Weapon_info[n].flags |= WIF_PLACABLE;
2138
2139                                         Assert(Num_total_object_types < MAX_OBJTYPE);
2140                                         ObjType[Num_total_object_types] = OL_WEAPON;
2141                                         ObjId[Num_total_object_types] = n;
2142                                         Num_total_object_types++;
2143                                 }
2144                         } else {
2145                                 Int3();
2146                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
2147                         }               
2148                 } else {                        // Must be a texture specification...
2149                         grs_bitmap *bm;
2150
2151                         bm = load_polymodel_bitmap(arg);
2152                         if (! lighted)
2153                                 bm->bm_flags |= BM_FLAG_NO_LIGHTING;
2154
2155                         lighted = 1;                    //default for next bitmap is lighted
2156                 }
2157                 arg = strtok( NULL, space );
2158         }
2159
2160         first_bitmap_num[n_models] = N_ObjBitmapPtrs;
2161
2162         for (i=0;i<n_models;i++) {
2163                 int n_textures;
2164                 int model_num,last_model_num=0;
2165
2166                 n_textures = first_bitmap_num[i+1] - first_bitmap_num[i];
2167
2168                 model_num = load_polygon_model(model_name[i],n_textures,first_bitmap_num[i],NULL);
2169
2170                 if (i==0) {
2171                         Weapon_info[n].render_type = WEAPON_RENDER_POLYMODEL;
2172                         Weapon_info[n].model_num = model_num;
2173                 }
2174                 else
2175                         Polygon_models[last_model_num].simpler_model = model_num+1;
2176
2177                 last_model_num = model_num;
2178         }
2179
2180         if ( pof_file_inner )   {
2181                 Assert(n_models);
2182                 Weapon_info[n].model_num_inner = load_polygon_model(pof_file_inner,first_bitmap_num[1]-first_bitmap_num[0],first_bitmap_num[0],NULL);
2183         }
2184
2185         if ((Weapon_info[n].ammo_usage == 0) && (Weapon_info[n].energy_usage == 0))
2186                 mprintf((1, "Warning: Weapon %i has ammo and energy usage of 0.\n", n));
2187
2188 // -- render type of none is now legal --       Assert( Weapon_info[n].render_type != WEAPON_RENDER_NONE );
2189 }
2190
2191
2192
2193
2194
2195 // ------------------------------------------------------------------------------
2196 #define DEFAULT_POWERUP_SIZE i2f(3)
2197
2198 void bm_read_powerup(int unused_flag)
2199 {
2200         int n;
2201         char    *equal_ptr;
2202
2203         Assert(N_powerup_types < MAX_POWERUP_TYPES);
2204
2205         n = N_powerup_types;
2206         N_powerup_types++;
2207
2208         if (unused_flag) {
2209                 clear_to_end_of_line();
2210                 return;
2211         }
2212
2213         // Initialize powerup array
2214         Powerup_info[n].light = F1_0/3;         //      Default lighting value.
2215         Powerup_info[n].vclip_num = -1;
2216         Powerup_info[n].hit_sound = -1;
2217         Powerup_info[n].size = DEFAULT_POWERUP_SIZE;
2218         Powerup_names[n][0] = 0;
2219
2220         // Process arguments
2221         arg = strtok( NULL, space );
2222
2223         while (arg!=NULL)       {
2224                 equal_ptr = strchr( arg, '=' );
2225                 if ( equal_ptr )        {
2226                         *equal_ptr='\0';
2227                         equal_ptr++;
2228                         // if we have john=cool, arg is 'john' and equal_ptr is 'cool'
2229                         if (!stricmp( arg, "vclip_num" ))       {
2230                                 Powerup_info[n].vclip_num = atoi(equal_ptr);
2231                         } else if (!stricmp( arg, "light" ))    {
2232                                 Powerup_info[n].light = fl2f(atof(equal_ptr));
2233                         } else if (!stricmp( arg, "hit_sound" ))        {
2234                                 Powerup_info[n].hit_sound = atoi(equal_ptr);
2235                         } else if (!stricmp( arg, "name" )) {
2236                                 Assert(strlen(equal_ptr) < POWERUP_NAME_LENGTH);        //      Oops, name too long.
2237                                 strcpy(Powerup_names[n], &equal_ptr[1]);
2238                                 Powerup_names[n][strlen(Powerup_names[n])-1] = 0;
2239                         } else if (!stricmp( arg, "size" ))     {
2240                                 Powerup_info[n].size = fl2f(atof(equal_ptr));
2241                         } else {
2242                                 Int3();
2243                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
2244                         }               
2245                 } else {                        // Must be a texture specification...
2246                         Int3();
2247                         mprintf( (1, "Invalid argument, %s in bitmaps.tbl\n", arg ));
2248                 }
2249                 arg = strtok( NULL, space );
2250         }
2251
2252         ObjType[Num_total_object_types] = OL_POWERUP;
2253         ObjId[Num_total_object_types] = n;
2254         //printf( "Object type %d is a powerup\n", Num_total_object_types );
2255         Num_total_object_types++;
2256         Assert(Num_total_object_types < MAX_OBJTYPE);
2257
2258 }
2259
2260 void bm_read_hostage()
2261 {
2262         int n;
2263         char    *equal_ptr;
2264
2265         Assert(N_hostage_types < MAX_HOSTAGE_TYPES);
2266
2267         n = N_hostage_types;
2268         N_hostage_types++;
2269
2270         // Process arguments
2271         arg = strtok( NULL, space );
2272
2273         while (arg!=NULL)       {
2274                 equal_ptr = strchr( arg, '=' );
2275                 if ( equal_ptr )        {
2276                         *equal_ptr='\0';
2277                         equal_ptr++;
2278
2279                         if (!stricmp( arg, "vclip_num" ))
2280
2281                                 Hostage_vclip_num[n] = atoi(equal_ptr);
2282
2283                         else {
2284                                 Int3();
2285                                 mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr ));
2286                         }
2287
2288                 } else {
2289                         Int3();
2290                         mprintf( (1, "Invalid argument, %s in bitmaps.tbl at line %d\n", arg, linenum ));
2291                 }
2292                 arg = strtok( NULL, space );
2293         }
2294
2295         ObjType[Num_total_object_types] = OL_HOSTAGE;
2296         ObjId[Num_total_object_types] = n;
2297         //printf( "Object type %d is a hostage\n", Num_total_object_types );
2298         Num_total_object_types++;
2299         Assert(Num_total_object_types < MAX_OBJTYPE);
2300
2301 }
2302
2303 //these values are the number of each item in the release of d2
2304 //extra items added after the release get written in an additional hamfile
2305 #define N_D2_ROBOT_TYPES                66
2306 #define N_D2_ROBOT_JOINTS               1145
2307 #define N_D2_POLYGON_MODELS     166
2308 #define N_D2_OBJBITMAPS                 422
2309 #define N_D2_OBJBITMAPPTRS              502
2310 #define N_D2_WEAPON_TYPES               62
2311
2312 void bm_write_all(FILE *fp)
2313 {
2314         int i,t;
2315         FILE *tfile;
2316         int s=0;
2317
2318 tfile = fopen("hamfile.lst","wt");
2319
2320         t = NumTextures-1;      //don't save bogus texture
2321         fwrite( &t, sizeof(int), 1, fp );
2322         fwrite( Textures, sizeof(bitmap_index), t, fp );
2323         for (i=0;i<t;i++)
2324                 fwrite( &TmapInfo[i], sizeof(*TmapInfo)-sizeof(TmapInfo->filename)-sizeof(TmapInfo->pad2), 1, fp );
2325
2326 fprintf(tfile,"NumTextures = %d, Textures array = %d, TmapInfo array = %d\n",NumTextures,sizeof(bitmap_index)*NumTextures,sizeof(tmap_info)*NumTextures);
2327
2328         t = MAX_SOUNDS;
2329         fwrite( &t, sizeof(int), 1, fp );
2330         fwrite( Sounds, sizeof(ubyte), t, fp );
2331         fwrite( AltSounds, sizeof(ubyte), t, fp );
2332
2333 fprintf(tfile,"Num Sounds = %d, Sounds array = %d, AltSounds array = %d\n",t,t,t);
2334
2335         fwrite( &Num_vclips, sizeof(int), 1, fp );
2336         fwrite( Vclip, sizeof(vclip), Num_vclips, fp );
2337
2338 fprintf(tfile,"Num_vclips = %d, Vclip array = %d\n",Num_vclips,sizeof(vclip)*Num_vclips);
2339
2340         fwrite( &Num_effects, sizeof(int), 1, fp );
2341         fwrite( Effects, sizeof(eclip), Num_effects, fp );
2342
2343 fprintf(tfile,"Num_effects = %d, Effects array = %d\n",Num_effects,sizeof(eclip)*Num_effects);
2344
2345         fwrite( &Num_wall_anims, sizeof(int), 1, fp );
2346         fwrite( WallAnims, sizeof(wclip), Num_wall_anims, fp );
2347
2348 fprintf(tfile,"Num_wall_anims = %d, WallAnims array = %d\n",Num_wall_anims,sizeof(wclip)*Num_wall_anims);
2349
2350         t = N_D2_ROBOT_TYPES;
2351         fwrite( &t, sizeof(int), 1, fp );
2352         fwrite( Robot_info, sizeof(robot_info), t, fp );
2353
2354 fprintf(tfile,"N_robot_types = %d, Robot_info array = %d\n",t,sizeof(robot_info)*N_robot_types);
2355
2356         t = N_D2_ROBOT_JOINTS;
2357         fwrite( &t, sizeof(int), 1, fp );
2358         fwrite( Robot_joints, sizeof(jointpos), t, fp );
2359
2360 fprintf(tfile,"N_robot_joints = %d, Robot_joints array = %d\n",t,sizeof(jointpos)*N_robot_joints);
2361
2362         t = N_D2_WEAPON_TYPES;
2363         fwrite( &t, sizeof(int), 1, fp );
2364         fwrite( Weapon_info, sizeof(weapon_info), t, fp );
2365
2366 fprintf(tfile,"N_weapon_types = %d, Weapon_info array = %d\n",N_weapon_types,sizeof(weapon_info)*N_weapon_types);
2367
2368         fwrite( &N_powerup_types, sizeof(int), 1, fp );
2369         fwrite( Powerup_info, sizeof(powerup_type_info), N_powerup_types, fp );
2370         
2371 fprintf(tfile,"N_powerup_types = %d, Powerup_info array = %d\n",N_powerup_types,sizeof(powerup_info)*N_powerup_types);
2372
2373         t = N_D2_POLYGON_MODELS;
2374         fwrite( &t, sizeof(int), 1, fp );
2375         fwrite( Polygon_models, sizeof(polymodel), t, fp );
2376
2377 fprintf(tfile,"N_polygon_models = %d, Polygon_models array = %d\n",t,sizeof(polymodel)*t);
2378
2379         for (i=0; i<t; i++ )    {
2380                 g3_uninit_polygon_model(Polygon_models[i].model_data);  //get RGB colors
2381                 fwrite( Polygon_models[i].model_data, sizeof(ubyte), Polygon_models[i].model_data_size, fp );
2382 fprintf(tfile,"  Model %d, data size = %d\n",i,Polygon_models[i].model_data_size); s+=Polygon_models[i].model_data_size;
2383                 g3_init_polygon_model(Polygon_models[i].model_data);    //map colors again
2384         }
2385 fprintf(tfile,"Total model size = %d\n",s);
2386
2387         fwrite( Dying_modelnums, sizeof(int), t, fp );
2388         fwrite( Dead_modelnums, sizeof(int), t, fp );
2389
2390 fprintf(tfile,"Dying_modelnums array = %d, Dead_modelnums array = %d\n",sizeof(int)*t,sizeof(int)*t);
2391
2392         t = MAX_GAUGE_BMS;
2393         fwrite( &t, sizeof(int), 1, fp );
2394         fwrite( Gauges, sizeof(bitmap_index), t, fp );
2395         fwrite( Gauges_hires, sizeof(bitmap_index), t, fp );
2396
2397 fprintf(tfile,"Num gauge bitmaps = %d, Gauges array = %d, Gauges_hires array = %d\n",t,sizeof(bitmap_index)*t,sizeof(bitmap_index)*t);
2398
2399         t = MAX_OBJ_BITMAPS;
2400         fwrite( &t, sizeof(int), 1, fp );
2401         fwrite( ObjBitmaps, sizeof(bitmap_index), t, fp );
2402         fwrite( ObjBitmapPtrs, sizeof(ushort), t, fp );
2403
2404 fprintf(tfile,"Num obj bitmaps = %d, ObjBitmaps array = %d, ObjBitmapPtrs array = %d\n",t,sizeof(bitmap_index)*t,sizeof(ushort)*t);
2405
2406         fwrite( &only_player_ship, sizeof(player_ship), 1, fp );
2407
2408 fprintf(tfile,"player_ship size = %d\n",sizeof(player_ship));
2409
2410         fwrite( &Num_cockpits, sizeof(int), 1, fp );
2411         fwrite( cockpit_bitmap, sizeof(bitmap_index), Num_cockpits, fp );
2412
2413 fprintf(tfile,"Num_cockpits = %d, cockpit_bitmaps array = %d\n",Num_cockpits,sizeof(bitmap_index)*Num_cockpits);
2414
2415 //@@    fwrite( &Num_total_object_types, sizeof(int), 1, fp );
2416 //@@    fwrite( ObjType, sizeof(sbyte), Num_total_object_types, fp );
2417 //@@    fwrite( ObjId, sizeof(sbyte), Num_total_object_types, fp );
2418 //@@    fwrite( ObjStrength, sizeof(fix), Num_total_object_types, fp );
2419
2420 fprintf(tfile,"Num_total_object_types = %d, ObjType array = %d, ObjId array = %d, ObjStrength array = %d\n",Num_total_object_types,Num_total_object_types,Num_total_object_types,sizeof(fix)*Num_total_object_types);
2421
2422         fwrite( &First_multi_bitmap_num, sizeof(int), 1, fp );
2423
2424         fwrite( &Num_reactors, sizeof(Num_reactors), 1, fp );
2425         fwrite( Reactors, sizeof(*Reactors), Num_reactors, fp);
2426
2427 fprintf(tfile,"Num_reactors = %d, Reactors array = %d\n",Num_reactors,sizeof(*Reactors)*Num_reactors);
2428
2429         fwrite( &Marker_model_num, sizeof(Marker_model_num), 1, fp);
2430
2431         //@@fwrite( &N_controlcen_guns, sizeof(int), 1, fp );
2432         //@@fwrite( controlcen_gun_points, sizeof(vms_vector), N_controlcen_guns, fp );
2433         //@@fwrite( controlcen_gun_dirs, sizeof(vms_vector), N_controlcen_guns, fp );
2434
2435         #ifdef SHAREWARE
2436         fwrite( &exit_modelnum, sizeof(int), 1, fp );
2437         fwrite( &destroyed_exit_modelnum, sizeof(int), 1, fp );
2438         #endif
2439
2440 fclose(tfile);
2441
2442         bm_write_extra_robots();
2443 }
2444
2445 void bm_write_extra_robots()
2446 {
2447         FILE *fp;
2448         u_int32_t t;
2449         int i;
2450
2451         fp = fopen("robots.ham","wb");
2452
2453         t = 0x5848414d; /* 'XHAM' */
2454         fwrite( &t, sizeof(int), 1, fp );
2455         t = 1;  //version
2456         fwrite( &t, sizeof(int), 1, fp );
2457
2458         //write weapon info
2459         t = N_weapon_types - N_D2_WEAPON_TYPES;
2460         fwrite( &t, sizeof(int), 1, fp );
2461         fwrite( &Weapon_info[N_D2_WEAPON_TYPES], sizeof(weapon_info), t, fp );
2462
2463         //now write robot info
2464
2465         t = N_robot_types - N_D2_ROBOT_TYPES;
2466         fwrite( &t, sizeof(int), 1, fp );
2467         fwrite( &Robot_info[N_D2_ROBOT_TYPES], sizeof(robot_info), t, fp );
2468
2469         t = N_robot_joints - N_D2_ROBOT_JOINTS;
2470         fwrite( &t, sizeof(int), 1, fp );
2471         fwrite( &Robot_joints[N_D2_ROBOT_JOINTS], sizeof(jointpos), t, fp );
2472
2473         t = N_polygon_models - N_D2_POLYGON_MODELS;
2474         fwrite( &t, sizeof(int), 1, fp );
2475         fwrite( &Polygon_models[N_D2_POLYGON_MODELS], sizeof(polymodel), t, fp );
2476
2477         for (i=N_D2_POLYGON_MODELS; i<N_polygon_models; i++ )   {
2478                 g3_uninit_polygon_model(Polygon_models[i].model_data);  //get RGB colors
2479                 fwrite( Polygon_models[i].model_data, sizeof(ubyte), Polygon_models[i].model_data_size, fp );
2480                 g3_init_polygon_model(Polygon_models[i].model_data);    //map colors again
2481         }
2482
2483         fwrite( &Dying_modelnums[N_D2_POLYGON_MODELS], sizeof(int), t, fp );
2484         fwrite( &Dead_modelnums[N_D2_POLYGON_MODELS], sizeof(int), t, fp );
2485
2486         t = N_ObjBitmaps - N_D2_OBJBITMAPS;
2487         fwrite( &t, sizeof(int), 1, fp );
2488         fwrite( &ObjBitmaps[N_D2_OBJBITMAPS], sizeof(bitmap_index), t, fp );
2489
2490         t = N_ObjBitmapPtrs - N_D2_OBJBITMAPPTRS;
2491         fwrite( &t, sizeof(int), 1, fp );
2492         fwrite( &ObjBitmapPtrs[N_D2_OBJBITMAPPTRS], sizeof(ushort), t, fp );
2493
2494         fwrite( ObjBitmapPtrs, sizeof(ushort), t, fp );
2495
2496         fclose(fp);
2497 }