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