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