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