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