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