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