/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #ifdef RCS char bmread_rcsid[] = "$Id: bmread.c,v 1.1.1.1 2001-01-19 03:30:01 bradleyb Exp $"; #endif #include #ifdef EDITOR #include #include #include #include #include #include "pstypes.h" #include "inferno.h" #include "gr.h" #include "bm.h" #include "gamepal.h" #include "mem.h" #include "mono.h" #include "error.h" #include "object.h" #include "vclip.h" #include "effects.h" #include "polyobj.h" #include "wall.h" #include "textures.h" #include "game.h" #include "multi.h" #include "iff.h" #include "cfile.h" #include "hostage.h" #include "powerup.h" #include "laser.h" #include "sounds.h" #include "piggy.h" #include "aistruct.h" #include "robot.h" #include "weapon.h" #include "gauges.h" #include "player.h" #include "endlevel.h" #include "cntrlcen.h" #include "compbit.h" #include "args.h" #include "editor\texpage.h" #define BM_NONE -1 #define BM_COCKPIT 0 #define BM_TEXTURES 2 #define BM_UNUSED 3 #define BM_VCLIP 4 #define BM_EFFECTS 5 #define BM_ECLIP 6 #define BM_WEAPON 7 #define BM_DEMO 8 #define BM_ROBOTEX 9 #define BM_WALL_ANIMS 12 #define BM_WCLIP 13 #define BM_ROBOT 14 #define BM_GAUGES 20 #define BM_GAUGES_HIRES 21 #define MAX_BITMAPS_PER_BRUSH 30 extern player_ship only_player_ship; // In bm.c short N_ObjBitmaps=0; short N_ObjBitmapPtrs=0; static int Num_robot_ais = 0; int TmapList[MAX_TEXTURES]; char Powerup_names[MAX_POWERUP_TYPES][POWERUP_NAME_LENGTH]; char Robot_names[MAX_ROBOT_TYPES][ROBOT_NAME_LENGTH]; //---------------- Internal variables --------------------------- static int Registered_only = 0; // Gets set by ! in column 1. static int SuperX = -1; static int Installed=0; static char *arg; static short tmap_count = 0; static short texture_count = 0; static short clip_count = 0; static short clip_num; static short sound_num; static short frames; static float time; static int hit_sound = -1; static byte bm_flag = BM_NONE; static int abm_flag = 0; static int rod_flag = 0; static short wall_open_sound, wall_close_sound,wall_explodes,wall_blastable, wall_hidden; float vlighting=0; static int obj_eclip; static char *dest_bm; //clip number to play when destroyed static int dest_vclip; //what vclip to play when exploding static int dest_eclip; //what eclip to play when exploding static fix dest_size; //3d size of explosion static int crit_clip; //clip number to play when destroyed static int crit_flag; //flag if this is a destroyed eclip static int tmap1_flag; //flag if this is used as tmap_num (not tmap_num2) static int num_sounds=0; int linenum; //line int table currently being parsed //------------------- Useful macros and variables --------------- #define REMOVE_EOL(s) remove_char((s),'\n') #define REMOVE_COMMENTS(s) remove_char((s),';') #define REMOVE_DOTS(s) remove_char((s),'.') #define IFTOK(str) if (!strcmp(arg, str)) char *space = { " \t" }; //--unused-- char *equal = { "=" }; char *equal_space = { " \t=" }; // For the sake of LINT, defining prototypes to module's functions void bm_read_robot_ai(void); void bm_read_powerup(int unused_flag); void bm_read_hostage(void); void bm_read_robot(void); void bm_read_weapon(int unused_flag); void bm_read_reactor(void); void bm_read_exitmodel(void); void bm_read_player_ship(void); void bm_read_some_file(void); void bm_read_sound(void); void verify_textures(void); //---------------------------------------------------------------------- void remove_char( char * s, char c ) { char *p; p = strchr(s,c); if (p) *p = '\0'; } //--------------------------------------------------------------- int compute_average_pixel(grs_bitmap *new) { int row, column, color; char *pptr; int total_red, total_green, total_blue; pptr = (char *)new->bm_data; total_red = 0; total_green = 0; total_blue = 0; for (row=0; rowbm_h; row++) for (column=0; columnbm_w; column++) { color = *pptr++; total_red += gr_palette[color*3]; total_green += gr_palette[color*3+1]; total_blue += gr_palette[color*3+2]; } total_red /= (new->bm_h * new->bm_w); total_green /= (new->bm_h * new->bm_w); total_blue /= (new->bm_h * new->bm_w); return BM_XRGB(total_red/2, total_green/2, total_blue/2); } //--------------------------------------------------------------- // Loads a bitmap from either the piggy file, a r64 file, or a // whatever extension is passed. bitmap_index bm_load_sub( char * filename ) { bitmap_index bitmap_num; grs_bitmap * new; ubyte newpal[256*3]; int iff_error; //reference parm to avoid warning message char fname[20]; bitmap_num.index = 0; #ifdef SHAREWARE if (Registered_only) { //mprintf( 0, "Skipping registered-only bitmap '%s'\n", filename ); return bitmap_num; } #endif _splitpath( filename, NULL, NULL, fname, NULL ); bitmap_num=piggy_find_bitmap( fname ); if (bitmap_num.index) { //mprintf(( 0, "Found bitmap '%s' in pig!\n", fname )); return bitmap_num; } MALLOC( new, grs_bitmap, 1 ); iff_error = iff_read_bitmap(filename,new,BM_LINEAR,newpal); new->bm_handle=0; if (iff_error != IFF_NO_ERROR) { mprintf((1, "File %s - IFF error: %s",filename,iff_errormsg(iff_error))); Error("File <%s> - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum); } if ( iff_has_transparency ) gr_remap_bitmap_good( new, newpal, iff_transparent_color, SuperX ); else gr_remap_bitmap_good( new, newpal, -1, SuperX ); new->avg_color = compute_average_pixel(new); // -- mprintf((0, "N" )); bitmap_num = piggy_register_bitmap( new, fname, 0 ); d_free( new ); return bitmap_num; } extern grs_bitmap bogus_bitmap; extern ubyte bogus_bitmap_initialized; extern digi_sound bogus_sound; void ab_load( char * filename, bitmap_index bmp[], int *nframes ) { grs_bitmap * bm[MAX_BITMAPS_PER_BRUSH]; bitmap_index bi; int i; int iff_error; //reference parm to avoid warning message ubyte newpal[768]; char fname[20]; char tempname[20]; #ifdef SHAREWARE if (Registered_only) { Assert( bogus_bitmap_initialized != 0 ); mprintf(( 0, "Skipping registered-only animation '%s'\n", filename )); bmp[0].index = 0; //index of bogus bitmap==0 (I think) //&bogus_bitmap; *nframes = 1; return; } #endif _splitpath( filename, NULL, NULL, fname, NULL ); for (i=0; i - IFF error: %s, line %d",filename,iff_errormsg(iff_error),linenum); } for (i=0;i< *nframes; i++) { bitmap_index new_bmp; sprintf( tempname, "%s#%d", fname, i ); if ( iff_has_transparency ) gr_remap_bitmap_good( bm[i], newpal, iff_transparent_color, SuperX ); else gr_remap_bitmap_good( bm[i], newpal, -1, SuperX ); bm[i]->avg_color = compute_average_pixel(bm[i]); new_bmp = piggy_register_bitmap( bm[i], tempname, 0 ); d_free( bm[i] ); bmp[i] = new_bmp; if (!i) mprintf((0, "Registering %s in piggy file.", tempname )); else mprintf((0, ".")); } mprintf((0, "\n")); } int ds_load( char * filename ) { int i; CFILE * cfp; digi_sound new; char fname[20]; char rawname[100]; #ifdef SHAREWARE if (Registered_only) { //mprintf( 0, "Skipping registered-only sound '%s'\n", filename ); return 0; //don't know what I should return here //&bogus_sound; } #endif _splitpath( filename, NULL, NULL, fname, NULL ); _makepath( rawname, NULL, NULL,fname, (digi_sample_rate==SAMPLE_RATE_22K)?".R22":".RAW" ); i=piggy_find_sound( fname ); if (i!=255) { return i; } cfp = cfopen( rawname, "rb" ); if (cfp!=NULL) { new.length = cfilelength( cfp ); MALLOC( new.data, ubyte, new.length ); cfread( new.data, 1, new.length, cfp ); cfclose(cfp); // -- mprintf( (0, "S" )); // -- mprintf( (0, "<%s>", rawname )); } else { mprintf( (1, "Warning: Couldn't find '%s'\n", filename )); return 255; } i = piggy_register_sound( &new, fname, 0 ); return i; } //parse a float float get_float() { char *xarg; xarg = strtok( NULL, space ); return atof( xarg ); } //parse an int int get_int() { char *xarg; xarg = strtok( NULL, space ); return atoi( xarg ); } // rotates a byte left one bit, preserving the bit falling off the right //void //rotate_left(char *c) //{ // int found; // // found = 0; // if (*c & 0x80) // found = 1; // *c = *c << 1; // if (found) // *c |= 0x01; //} //loads a texture and returns the texture num int get_texture(char *name) { char short_name[FILENAME_LEN]; int i; strcpy(short_name,name); REMOVE_DOTS(short_name); for (i=0;i>8; TmapInfo[texture_count-1].slide_v = fl2f(get_float())>>8;} else IFTOK("destroyed") {int t=texture_count-1; TmapInfo[t].destroyed = get_texture(strtok( NULL, space ));} //else IFTOK("Num_effects") Num_effects = get_int(); else IFTOK("Num_wall_anims") Num_wall_anims = get_int(); else IFTOK("clip_num") clip_num = get_int(); else IFTOK("dest_bm") dest_bm = strtok( NULL, space ); else IFTOK("dest_vclip") dest_vclip = get_int(); else IFTOK("dest_eclip") dest_eclip = get_int(); else IFTOK("dest_size") dest_size = fl2f(get_float()); else IFTOK("crit_clip") crit_clip = get_int(); else IFTOK("crit_flag") crit_flag = get_int(); else IFTOK("sound_num") sound_num = get_int(); else IFTOK("frames") frames = get_int(); else IFTOK("time") time = get_float(); else IFTOK("obj_eclip") obj_eclip = get_int(); else IFTOK("hit_sound") hit_sound = get_int(); else IFTOK("abm_flag") abm_flag = get_int(); else IFTOK("tmap1_flag") tmap1_flag = get_int(); else IFTOK("vlighting") vlighting = get_float(); else IFTOK("rod_flag") rod_flag = get_int(); else IFTOK("superx") get_int(); else IFTOK("open_sound") wall_open_sound = get_int(); else IFTOK("close_sound") wall_close_sound = get_int(); else IFTOK("explodes") wall_explodes = get_int(); else IFTOK("blastable") wall_blastable = get_int(); else IFTOK("hidden") wall_hidden = get_int(); else IFTOK("$ROBOT_AI") bm_read_robot_ai(); else IFTOK("$POWERUP") {bm_read_powerup(0); continue;} else IFTOK("$POWERUP_UNUSED") {bm_read_powerup(1); continue;} else IFTOK("$HOSTAGE") {bm_read_hostage(); continue;} else IFTOK("$ROBOT") {bm_read_robot(); continue;} else IFTOK("$WEAPON") {bm_read_weapon(0); continue;} else IFTOK("$WEAPON_UNUSED") {bm_read_weapon(1); continue;} else IFTOK("$REACTOR") {bm_read_reactor(); continue;} else IFTOK("$MARKER") {bm_read_marker(); continue;} else IFTOK("$PLAYER_SHIP") {bm_read_player_ship(); continue;} else IFTOK("$EXIT") { #ifdef SHAREWARE bm_read_exitmodel(); #else clear_to_end_of_line(); #endif continue; } else { //not a special token, must be a bitmap! // Remove any illegal/unwanted spaces and tabs at this point. while ((*arg=='\t') || (*arg==' ')) arg++; if (*arg == '\0') { break; } //check for '=' in token, indicating error if (strchr(arg,'=')) Error("Unknown token <'%s'> on line %d of BITMAPS.TBL",arg,linenum); // Otherwise, 'arg' is apparently a bitmap filename. // Load bitmap and process it below: bm_read_some_file(); } arg = strtok( NULL, equal_space ); continue; } } NumTextures = texture_count; Num_tmaps = tmap_count; Textures[NumTextures++].index = 0; //entry for bogus tmap cfclose( InfoFile ); atexit(bm_close); Assert(N_robot_types == Num_robot_ais); //should be one ai info per robot #ifdef SHAREWARE init_endlevel(); //this is here so endlevel bitmaps go into pig #endif verify_textures(); //check for refereced but unused clip count for (i=0; ibm_w!=64)||(bmp->bm_h!=64)||(bmp->bm_rowsize!=64) ) { mprintf( (1, "ERROR: Texture '%s' isn't 64x64 !\n", TmapInfo[i].filename )); j++; } } if (j) Error("%d textures were not 64x64. See mono screen for list.",j); for (i=0;ibm_data; //--unused-- for (j=0; j<64*64; j++ ) //--unused-- if ( (*p++)==255 ) k++; //--unused-- if ( k ) { //--unused-- fprintf( fp, "'%s' has %d transparent pixels\n", TmapInfo[i].filename, k ); //--unused-- } //--unused-- } //--unused-- fclose(fp); //--unused-- } void bm_close() { if (Installed) { Installed=0; } } void set_lighting_flag(byte *bp) { if (vlighting < 0) *bp |= BM_FLAG_NO_LIGHTING; else *bp &= (0xff ^ BM_FLAG_NO_LIGHTING); } void set_texture_name(char *name) { strcpy ( TmapInfo[texture_count].filename, name ); REMOVE_DOTS(TmapInfo[texture_count].filename); } void bm_read_eclip() { bitmap_index bitmap; int dest_bm_num; Assert(clip_num < MAX_EFFECTS); if (clip_num+1 > Num_effects) Num_effects = clip_num+1; Effects[clip_num].flags = 0; //load the dest bitmap first, so that after this routine, the last-loaded //texture will be the monitor, so that lighting parameter will be applied //to the correct texture if (dest_bm) { //deal with bitmap for blown up clip char short_name[FILENAME_LEN]; int i; strcpy(short_name,dest_bm); REMOVE_DOTS(short_name); for (i=0;i-1) && (clip_count==0) ) Error( "Wall Clip %d is already used!", clip_num ); WallAnims[clip_num].play_time = fl2f(time); WallAnims[clip_num].num_frames = frames; //WallAnims[clip_num].frame_time = fl2f(time)/frames; Assert(clip_count < frames); WallAnims[clip_num].frames[clip_count++] = texture_count; WallAnims[clip_num].open_sound = wall_open_sound; WallAnims[clip_num].close_sound = wall_close_sound; Textures[texture_count] = bitmap; set_lighting_flag(&GameBitmaps[bitmap.index].bm_flags); set_texture_name( arg ); Assert(texture_count < MAX_TEXTURES); texture_count++; NumTextures = texture_count; if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1; } else { bitmap_index bm[MAX_BITMAPS_PER_BRUSH]; int nframes; if ( (WallAnims[clip_num].num_frames>-1) ) Error( "AB_Wall clip %d is already used!", clip_num ); abm_flag = 0; ab_load( arg, bm, &nframes ); WallAnims[clip_num].num_frames = nframes; //printf("WC"); WallAnims[clip_num].play_time = fl2f(time); //WallAnims[clip_num].frame_time = fl2f(time)/nframes; WallAnims[clip_num].open_sound = wall_open_sound; WallAnims[clip_num].close_sound = wall_close_sound; WallAnims[clip_num].close_sound = wall_close_sound; strcpy(WallAnims[clip_num].filename, arg); REMOVE_DOTS(WallAnims[clip_num].filename); if (clip_num >= Num_wall_anims) Num_wall_anims = clip_num+1; set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); for (clip_count=0;clip_count < WallAnims[clip_num].num_frames; clip_count++) { //printf("%d", clip_count); Textures[texture_count] = bm[clip_count]; set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); WallAnims[clip_num].frames[clip_count] = texture_count; REMOVE_DOTS(arg); sprintf( TmapInfo[texture_count].filename, "%s#%d", arg, clip_count); Assert(texture_count < MAX_TEXTURES); texture_count++; NumTextures = texture_count; } } } void bm_read_vclip() { bitmap_index bi; Assert(clip_num < VCLIP_MAXNUM); if (clip_num >= Num_vclips) Num_vclips = clip_num+1; if (!abm_flag) { if ( (Vclip[clip_num].num_frames>-1) && (clip_count==0) ) Error( "Vclip %d is already used!", clip_num ); bi = bm_load_sub(arg); Vclip[clip_num].play_time = fl2f(time); Vclip[clip_num].num_frames = frames; Vclip[clip_num].frame_time = fl2f(time)/frames; Vclip[clip_num].light_value = fl2f(vlighting); Vclip[clip_num].sound_num = sound_num; set_lighting_flag(&GameBitmaps[bi.index].bm_flags); Assert(clip_count < frames); Vclip[clip_num].frames[clip_count++] = bi; if (rod_flag) { rod_flag=0; Vclip[clip_num].flags |= VF_ROD; } } else { bitmap_index bm[MAX_BITMAPS_PER_BRUSH]; abm_flag = 0; if ( (Vclip[clip_num].num_frames>-1) ) Error( "AB_Vclip %d is already used!", clip_num ); ab_load( arg, bm, &Vclip[clip_num].num_frames ); if (rod_flag) { //int i; rod_flag=0; Vclip[clip_num].flags |= VF_ROD; } //printf("VC"); Vclip[clip_num].play_time = fl2f(time); Vclip[clip_num].frame_time = fl2f(time)/Vclip[clip_num].num_frames; Vclip[clip_num].light_value = fl2f(vlighting); Vclip[clip_num].sound_num = sound_num; set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); for (clip_count=0;clip_count < Vclip[clip_num].num_frames; clip_count++) { //printf("%d", clip_count); set_lighting_flag(&GameBitmaps[bm[clip_count].index].bm_flags); Vclip[clip_num].frames[clip_count] = bm[clip_count]; } } } // ------------------------------------------------------------------------------ void get4fix(fix *fixp) { char *curtext; int i; for (i=0; i 179) { mprintf((1, "Warning: Bogus field of view (%7.3f). Must be in 0..179.\n", ff)); ff = 179; } ff = ff/360; tt = fl2f(ff); fix_sincos(tt, &temp, &fovp[i]); } } void clear_to_end_of_line(void) { arg = strtok( NULL, space ); while (arg != NULL) arg = strtok( NULL, space ); } void bm_read_sound() { int sound_num; int alt_sound_num; sound_num = get_int(); alt_sound_num = get_int(); if ( sound_num>=MAX_SOUNDS ) Error( "Too many sound files.\n" ); if (sound_num >= num_sounds) num_sounds = sound_num+1; if (Sounds[sound_num] != 255) Error("Sound num %d already used, bitmaps.tbl, line %d\n",sound_num,linenum); arg = strtok(NULL, space); Sounds[sound_num] = ds_load(arg); if ( alt_sound_num == 0 ) AltSounds[sound_num] = sound_num; else if (alt_sound_num < 0 ) AltSounds[sound_num] = 255; else AltSounds[sound_num] = alt_sound_num; if (Sounds[sound_num] == 255) Error("Can't load soundfile <%s>",arg); } // ------------------------------------------------------------------------------ void bm_read_robot_ai() { char *robotnum_text; int robotnum; robot_info *robptr; robotnum_text = strtok(NULL, space); robotnum = atoi(robotnum_text); Assert(robotnum < MAX_ROBOT_TYPES); robptr = &Robot_info[robotnum]; Assert(robotnum == Num_robot_ais); //make sure valid number #ifdef SHAREWARE if (Registered_only) { Num_robot_ais++; clear_to_end_of_line(); return; } #endif Num_robot_ais++; get4fix(robptr->field_of_view); get4fix(robptr->firing_wait); get4fix(robptr->firing_wait2); get4byte(robptr->rapidfire_count); get4fix(robptr->turn_time); // get4fix(robptr->fire_power); // get4fix(robptr->shield); get4fix(robptr->max_speed); get4fix(robptr->circle_distance); get4byte(robptr->evade_speed); robptr->always_0xabcd = 0xabcd; adjust_field_of_view(robptr->field_of_view); } // ---------------------------------------------------------------------------------------------- //this will load a bitmap for a polygon models. it puts the bitmap into //the array ObjBitmaps[], and also deals with animating bitmaps //returns a pointer to the bitmap grs_bitmap *load_polymodel_bitmap(char *name) { Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS); // Assert( N_ObjBitmaps == N_ObjBitmapPtrs ); if (name[0] == '%') { //an animating bitmap! int eclip_num; eclip_num = atoi(name+1); if (Effects[eclip_num].changing_object_texture == -1) { //first time referenced Effects[eclip_num].changing_object_texture = N_ObjBitmaps; ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps; N_ObjBitmaps++; } else { ObjBitmapPtrs[N_ObjBitmapPtrs++] = Effects[eclip_num].changing_object_texture; } Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS); Assert(N_ObjBitmapPtrs < MAX_OBJ_BITMAPS); return NULL; } else { ObjBitmaps[N_ObjBitmaps] = bm_load_sub(name); if (GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_w!=64 || GameBitmaps[ObjBitmaps[N_ObjBitmaps].index].bm_h!=64) Error("Bitmap <%s> is not 64x64",name); ObjBitmapPtrs[N_ObjBitmapPtrs++] = N_ObjBitmaps; N_ObjBitmaps++; Assert(N_ObjBitmaps < MAX_OBJ_BITMAPS); Assert(N_ObjBitmapPtrs < MAX_OBJ_BITMAPS); return &GameBitmaps[ObjBitmaps[N_ObjBitmaps-1].index]; } } #define MAX_MODEL_VARIANTS 4 // ------------------------------------------------------------------------------ void bm_read_robot() { char *model_name[MAX_MODEL_VARIANTS]; int n_models,i; int first_bitmap_num[MAX_MODEL_VARIANTS]; char *equal_ptr; int exp1_vclip_num=-1; int exp1_sound_num=-1; int exp2_vclip_num=-1; int exp2_sound_num=-1; fix lighting = F1_0/2; // Default fix strength = F1_0*10; // Default strength fix mass = f1_0*4; fix drag = f1_0/2; short weapon_type = 0, weapon_type2 = -1; int g,s; char name[ROBOT_NAME_LENGTH]; int contains_count=0, contains_id=0, contains_prob=0, contains_type=0, behavior=AIB_NORMAL; 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; fix glow=0, aim=F1_0; int deathroll_sound = SOUND_BOSS_SHARE_DIE; //default int score_value=1000; int cloak_type=0; // Default = this robot does not cloak int attack_type=0; // Default = this robot attacks by firing (1=lunge) int boss_flag=0; // Default = robot is not a boss. int see_sound = ROBOT_SEE_SOUND_DEFAULT; int attack_sound = ROBOT_ATTACK_SOUND_DEFAULT; int claw_sound = ROBOT_CLAW_SOUND_DEFAULT; int taunt_sound = ROBOT_SEE_SOUND_DEFAULT; ubyte flags=0; Assert(N_robot_types < MAX_ROBOT_TYPES); #ifdef SHAREWARE if (Registered_only) { Robot_info[N_robot_types].model_num = -1; N_robot_types++; Assert(N_robot_types < MAX_ROBOT_TYPES); Num_total_object_types++; Assert(Num_total_object_types < MAX_OBJTYPE); clear_to_end_of_line(); return; } #endif model_name[0] = strtok( NULL, space ); first_bitmap_num[0] = N_ObjBitmapPtrs; n_models = 1; // Process bitmaps bm_flag=BM_ROBOT; arg = strtok( NULL, space ); while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' if (!stricmp( arg, "exp1_vclip" )) { exp1_vclip_num = atoi(equal_ptr); } else if (!stricmp( arg, "exp2_vclip" )) { exp2_vclip_num = atoi(equal_ptr); } else if (!stricmp( arg, "exp1_sound" )) { exp1_sound_num = atoi(equal_ptr); } else if (!stricmp( arg, "exp2_sound" )) { exp2_sound_num = atoi(equal_ptr); } else if (!stricmp( arg, "lighting" )) { lighting = fl2f(atof(equal_ptr)); if ( (lighting < 0) || (lighting > F1_0 )) { mprintf( (1, "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting))); Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)); } } else if (!stricmp( arg, "weapon_type" )) { weapon_type = atoi(equal_ptr); } else if (!stricmp( arg, "weapon_type2" )) { weapon_type2 = atoi(equal_ptr); } else if (!stricmp( arg, "strength" )) { strength = i2f(atoi(equal_ptr)); } else if (!stricmp( arg, "mass" )) { mass = fl2f(atof(equal_ptr)); } else if (!stricmp( arg, "drag" )) { drag = fl2f(atof(equal_ptr)); } else if (!stricmp( arg, "contains_id" )) { contains_id = atoi(equal_ptr); } else if (!stricmp( arg, "contains_type" )) { contains_type = atoi(equal_ptr); } else if (!stricmp( arg, "contains_count" )) { contains_count = atoi(equal_ptr); } else if (!stricmp( arg, "companion" )) { companion = atoi(equal_ptr); } else if (!stricmp( arg, "badass" )) { badass = atoi(equal_ptr); } else if (!stricmp( arg, "lightcast" )) { lightcast = atoi(equal_ptr); } else if (!stricmp( arg, "glow" )) { glow = fl2f(atof(equal_ptr)); } else if (!stricmp( arg, "death_roll" )) { death_roll = atoi(equal_ptr); } else if (!stricmp( arg, "deathroll_sound" )) { deathroll_sound = atoi(equal_ptr); } else if (!stricmp( arg, "thief" )) { thief = atoi(equal_ptr); } else if (!stricmp( arg, "kamikaze" )) { kamikaze = atoi(equal_ptr); } else if (!stricmp( arg, "pursuit" )) { pursuit = atoi(equal_ptr); } else if (!stricmp( arg, "smart_blobs" )) { smart_blobs = atoi(equal_ptr); } else if (!stricmp( arg, "energy_blobs" )) { energy_blobs = atoi(equal_ptr); } else if (!stricmp( arg, "energy_drain" )) { energy_drain = atoi(equal_ptr); } else if (!stricmp( arg, "contains_prob" )) { contains_prob = atoi(equal_ptr); } else if (!stricmp( arg, "cloak_type" )) { cloak_type = atoi(equal_ptr); } else if (!stricmp( arg, "attack_type" )) { attack_type = atoi(equal_ptr); } else if (!stricmp( arg, "boss" )) { boss_flag = atoi(equal_ptr); } else if (!stricmp( arg, "score_value" )) { score_value = atoi(equal_ptr); } else if (!stricmp( arg, "see_sound" )) { see_sound = atoi(equal_ptr); } else if (!stricmp( arg, "attack_sound" )) { attack_sound = atoi(equal_ptr); } else if (!stricmp( arg, "claw_sound" )) { claw_sound = atoi(equal_ptr); } else if (!stricmp( arg, "taunt_sound" )) { taunt_sound = atoi(equal_ptr); } else if (!stricmp( arg, "aim" )) { aim = fl2f(atof(equal_ptr)); } else if (!stricmp( arg, "big_radius" )) { if (atoi(equal_ptr)) flags |= RIF_BIG_RADIUS; } else if (!stricmp( arg, "behavior" )) { if (!stricmp(equal_ptr, "STILL")) behavior = AIB_STILL; else if (!stricmp(equal_ptr, "NORMAL")) behavior = AIB_NORMAL; else if (!stricmp(equal_ptr, "BEHIND")) behavior = AIB_BEHIND; else if (!stricmp(equal_ptr, "RUN_FROM")) behavior = AIB_RUN_FROM; else if (!stricmp(equal_ptr, "SNIPE")) behavior = AIB_SNIPE; else if (!stricmp(equal_ptr, "STATION")) behavior = AIB_STATION; else if (!stricmp(equal_ptr, "FOLLOW")) behavior = AIB_FOLLOW; else Int3(); // Error. Illegal behavior type for current robot. } else if (!stricmp( arg, "name" )) { Assert(strlen(equal_ptr) < ROBOT_NAME_LENGTH); // Oops, name too long. strcpy(name, &equal_ptr[1]); name[strlen(name)-1] = 0; } else if (!stricmp( arg, "simple_model" )) { model_name[n_models] = equal_ptr; first_bitmap_num[n_models] = N_ObjBitmapPtrs; n_models++; Assert(n_models < MAX_MODEL_VARIANTS); } else { Int3(); mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr )); } } else { // Must be a texture specification... load_polymodel_bitmap(arg); } arg = strtok( NULL, space ); } //clear out anim info for (g=0;g i2f(15)) || (glow < 0) || (glow != 0 && glow < 0x1000)) { mprintf((0,"Invalid glow value %x for robot %d\n",glow,N_robot_types)); Int3(); } ObjType[Num_total_object_types] = OL_ROBOT; ObjId[Num_total_object_types] = N_robot_types; Robot_info[N_robot_types].exp1_vclip_num = exp1_vclip_num; Robot_info[N_robot_types].exp2_vclip_num = exp2_vclip_num; Robot_info[N_robot_types].exp1_sound_num = exp1_sound_num; Robot_info[N_robot_types].exp2_sound_num = exp2_sound_num; Robot_info[N_robot_types].lighting = lighting; Robot_info[N_robot_types].weapon_type = weapon_type; Robot_info[N_robot_types].weapon_type2 = weapon_type2; Robot_info[N_robot_types].strength = strength; Robot_info[N_robot_types].mass = mass; Robot_info[N_robot_types].drag = drag; Robot_info[N_robot_types].cloak_type = cloak_type; Robot_info[N_robot_types].attack_type = attack_type; Robot_info[N_robot_types].boss_flag = boss_flag; Robot_info[N_robot_types].contains_id = contains_id; Robot_info[N_robot_types].contains_count = contains_count; Robot_info[N_robot_types].contains_prob = contains_prob; Robot_info[N_robot_types].companion = companion; Robot_info[N_robot_types].badass = badass; Robot_info[N_robot_types].lightcast = lightcast; Robot_info[N_robot_types].glow = (glow>>12); //convert to 4:4 Robot_info[N_robot_types].death_roll = death_roll; Robot_info[N_robot_types].deathroll_sound = deathroll_sound; Robot_info[N_robot_types].thief = thief; Robot_info[N_robot_types].flags = flags; Robot_info[N_robot_types].kamikaze = kamikaze; Robot_info[N_robot_types].pursuit = pursuit; Robot_info[N_robot_types].smart_blobs = smart_blobs; Robot_info[N_robot_types].energy_blobs = energy_blobs; Robot_info[N_robot_types].energy_drain = energy_drain; Robot_info[N_robot_types].score_value = score_value; Robot_info[N_robot_types].see_sound = see_sound; Robot_info[N_robot_types].attack_sound = attack_sound; Robot_info[N_robot_types].claw_sound = claw_sound; Robot_info[N_robot_types].taunt_sound = taunt_sound; Robot_info[N_robot_types].behavior = behavior; // Default behavior for this robot, if coming out of matcen. Robot_info[N_robot_types].aim = min(f2i(aim*255), 255); // how well this robot type can aim. 255=perfect if (contains_type) Robot_info[N_robot_types].contains_type = OBJ_ROBOT; else Robot_info[N_robot_types].contains_type = OBJ_POWERUP; strcpy(Robot_names[N_robot_types], name); N_robot_types++; Num_total_object_types++; Assert(N_robot_types < MAX_ROBOT_TYPES); Assert(Num_total_object_types < MAX_OBJTYPE); bm_flag = BM_NONE; } //read a reactor model void bm_read_reactor() { char *model_name, *model_name_dead=NULL; int first_bitmap_num, first_bitmap_num_dead, n_normal_bitmaps; char *equal_ptr; short model_num; short explosion_vclip_num = -1; short explosion_sound_num = SOUND_ROBOT_DESTROYED; fix lighting = F1_0/2; // Default int type=-1; fix strength=0; Assert(Num_reactors < MAX_REACTORS); #ifdef SHAREWARE if (Registered_only) { Num_reactors++; clear_to_end_of_line(); return; } #endif model_name = strtok( NULL, space ); // Process bitmaps bm_flag = BM_NONE; arg = strtok( NULL, space ); first_bitmap_num = N_ObjBitmapPtrs; type = OL_CONTROL_CENTER; while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' //@@if (!stricmp(arg,"type")) { //@@ if (!stricmp(equal_ptr,"controlcen")) //@@ type = OL_CONTROL_CENTER; //@@ else if (!stricmp(equal_ptr,"clutter")) //@@ type = OL_CLUTTER; //@@} if (!stricmp( arg, "exp_vclip" )) { explosion_vclip_num = atoi(equal_ptr); } else if (!stricmp( arg, "dead_pof" )) { model_name_dead = equal_ptr; first_bitmap_num_dead=N_ObjBitmapPtrs; } else if (!stricmp( arg, "exp_sound" )) { explosion_sound_num = atoi(equal_ptr); } else if (!stricmp( arg, "lighting" )) { lighting = fl2f(atof(equal_ptr)); if ( (lighting < 0) || (lighting > F1_0 )) { mprintf( (1, "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting))); Error( "In bitmaps.tbl, lighting value of %.2f is out of range 0..1.\n", f2fl(lighting)); } } else if (!stricmp( arg, "strength" )) { strength = fl2f(atof(equal_ptr)); } else { Int3(); mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr )); } } else { // Must be a texture specification... load_polymodel_bitmap(arg); } arg = strtok( NULL, space ); } if ( model_name_dead ) n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num; else n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); if ( model_name_dead ) Dead_modelnums[model_num] = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL); else Dead_modelnums[model_num] = -1; if (type == -1) Error("No object type specfied for object in BITMAPS.TBL on line %d\n",linenum); Reactors[Num_reactors].model_num = model_num; Reactors[Num_reactors].n_guns = read_model_guns(model_name,Reactors[Num_reactors].gun_points,Reactors[Num_reactors].gun_dirs,NULL); ObjType[Num_total_object_types] = type; ObjId[Num_total_object_types] = Num_reactors; ObjStrength[Num_total_object_types] = strength; //printf( "Object type %d is a control center\n", Num_total_object_types ); Num_total_object_types++; Assert(Num_total_object_types < MAX_OBJTYPE); Num_reactors++; } //read the marker object void bm_read_marker() { char *model_name; int first_bitmap_num, n_normal_bitmaps; char *equal_ptr; model_name = strtok( NULL, space ); // Process bitmaps bm_flag = BM_NONE; arg = strtok( NULL, space ); first_bitmap_num = N_ObjBitmapPtrs; while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr )); Int3(); } else { // Must be a texture specification... load_polymodel_bitmap(arg); } arg = strtok( NULL, space ); } n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; Marker_model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); } #ifdef SHAREWARE //read the exit model void bm_read_exitmodel() { char *model_name, *model_name_dead=NULL; int first_bitmap_num, first_bitmap_num_dead, n_normal_bitmaps; char *equal_ptr; short model_num; model_name = strtok( NULL, space ); // Process bitmaps bm_flag = BM_NONE; arg = strtok( NULL, space ); first_bitmap_num = N_ObjBitmapPtrs; while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' if (!stricmp( arg, "dead_pof" )) { model_name_dead = equal_ptr; first_bitmap_num_dead=N_ObjBitmapPtrs; } else { Int3(); mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr )); } } else { // Must be a texture specification... load_polymodel_bitmap(arg); } arg = strtok( NULL, space ); } if ( model_name_dead ) n_normal_bitmaps = first_bitmap_num_dead-first_bitmap_num; else n_normal_bitmaps = N_ObjBitmapPtrs-first_bitmap_num; model_num = load_polygon_model(model_name,n_normal_bitmaps,first_bitmap_num,NULL); if ( model_name_dead ) Dead_modelnums[model_num] = load_polygon_model(model_name_dead,N_ObjBitmapPtrs-first_bitmap_num_dead,first_bitmap_num_dead,NULL); else Dead_modelnums[model_num] = -1; //@@ ObjType[Num_total_object_types] = type; //@@ ObjId[Num_total_object_types] = model_num; //@@ ObjStrength[Num_total_object_types] = strength; //@@ //@@ //printf( "Object type %d is a control center\n", Num_total_object_types ); //@@ Num_total_object_types++; //@@ Assert(Num_total_object_types < MAX_OBJTYPE); exit_modelnum = model_num; destroyed_exit_modelnum = Dead_modelnums[model_num]; } #endif void bm_read_player_ship() { char *model_name_dying=NULL; char *model_name[MAX_MODEL_VARIANTS]; int n_models=0,i; int first_bitmap_num[MAX_MODEL_VARIANTS]; char *equal_ptr; robot_info ri; int last_multi_bitmap_num=-1; // Process bitmaps bm_flag = BM_NONE; arg = strtok( NULL, space ); Player_ship->mass = Player_ship->drag = 0; //stupid defaults Player_ship->expl_vclip_num = -1; while (arg!=NULL) { equal_ptr = strchr( arg, '=' ); if ( equal_ptr ) { *equal_ptr='\0'; equal_ptr++; // if we have john=cool, arg is 'john' and equal_ptr is 'cool' if (!stricmp( arg, "model" )) { Assert(n_models==0); model_name[0] = equal_ptr; first_bitmap_num[0] = N_ObjBitmapPtrs; n_models = 1; } else if (!stricmp( arg, "simple_model" )) { model_name[n_models] = equal_ptr; first_bitmap_num[n_models] = N_ObjBitmapPtrs; n_models++; Assert(n_models < MAX_MODEL_VARIANTS); if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1) last_multi_bitmap_num=N_ObjBitmapPtrs; } else if (!stricmp( arg, "mass" )) Player_ship->mass = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "drag" )) Player_ship->drag = fl2f(atof(equal_ptr)); // else if (!stricmp( arg, "low_thrust" )) // Player_ship->low_thrust = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "max_thrust" )) Player_ship->max_thrust = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "reverse_thrust" )) Player_ship->reverse_thrust = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "brakes" )) Player_ship->brakes = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "wiggle" )) Player_ship->wiggle = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "max_rotthrust" )) Player_ship->max_rotthrust = fl2f(atof(equal_ptr)); else if (!stricmp( arg, "dying_pof" )) model_name_dying = equal_ptr; else if (!stricmp( arg, "expl_vclip_num" )) Player_ship->expl_vclip_num=atoi(equal_ptr); else { Int3(); mprintf( (1, "Invalid parameter, %s=%s in bitmaps.tbl\n", arg, equal_ptr )); } } else if (!stricmp( arg, "multi_textures" )) { First_multi_bitmap_num = N_ObjBitmapPtrs; first_bitmap_num[n_models] = N_ObjBitmapPtrs; } else // Must be a texture specification... load_polymodel_bitmap(arg); arg = strtok( NULL, space ); } Assert(model_name != NULL); if (First_multi_bitmap_num!=-1 && last_multi_bitmap_num==-1) last_multi_bitmap_num=N_ObjBitmapPtrs; if (First_multi_bitmap_num==-1) first_bitmap_num[n_models] = N_ObjBitmapPtrs; Assert(last_multi_bitmap_num-First_multi_bitmap_num == (MAX_NUM_NET_PLAYERS-1)*2); for (i=0;imodel_num = model_num; else Polygon_models[last_model_num].simpler_model = model_num+1; last_model_num = model_num; } if ( model_name_dying ) { Assert(n_models); 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); } Assert(ri.n_guns == N_PLAYER_GUNS); //calc player gun positions { polymodel *pm; robot_info *r; vms_vector pnt; int mn; //submodel number int gun_num; r = &ri; pm = &Polygon_models[Player_ship->model_num]; for (gun_num=0;gun_numn_guns;gun_num++) { pnt = r->gun_points[gun_num]; mn = r->gun_submodels[gun_num]; //instance up the tree for this gun while (mn != 0) { vm_vec_add2(&pnt,&pm->submodel_offsets[mn]); mn = pm->submodel_parents[mn]; } Player_ship->gun_points[gun_num] = pnt; } } } void bm_read_some_file() { switch (bm_flag) { case BM_NONE: Error("Trying to read bitmap <%s> with bm_flag==BM_NONE on line %d of BITMAPS.TBL",arg,linenum); break; case BM_COCKPIT: { bitmap_index bitmap; bitmap = bm_load_sub(arg); Assert( Num_cockpits < N_COCKPIT_BITMAPS ); cockpit_bitmap[Num_cockpits++] = bitmap; //bm_flag = BM_NONE; return; } break; case BM_GAUGES: bm_read_gauges(); return; break; case BM_GAUGES_HIRES: bm_read_gauges_hires(); return; break; case BM_WEAPON: bm_read_weapon(0); return; break; case BM_VCLIP: bm_read_vclip(); return; break; case BM_ECLIP: bm_read_eclip(); return; break; case BM_TEXTURES: { bitmap_index bitmap; bitmap = bm_load_sub(arg); Assert(tmap_count < MAX_TEXTURES); TmapList[tmap_count++] = texture_count; Textures[texture_count] = bitmap; set_texture_name( arg ); Assert(texture_count < MAX_TEXTURES); texture_count++; NumTextures = texture_count; return; } break; case BM_WCLIP: bm_read_wclip(); return; break; } Error("Trying to read bitmap <%s> with unknown bm_flag <%x> on line %d of BITMAPS.TBL",arg,bm_flag,linenum); } // ------------------------------------------------------------------------------ // If unused_flag is set, then this is just a placeholder. Don't actually reference vclips or load bbms. void bm_read_weapon(int unused_flag) { int i,n; int n_models=0; char *equal_ptr; char *pof_file_inner=NULL; char *model_name[MAX_MODEL_VARIANTS]; int first_bitmap_num[MAX_MODEL_VARIANTS]; int lighted; //flag for whether is a texture is lighted Assert(N_weapon_types < MAX_WEAPON_TYPES); n = N_weapon_types; N_weapon_types++; Assert(N_weapon_types <= MAX_WEAPON_TYPES); if (unused_flag) { clear_to_end_of_line(); return; } #ifdef SHAREWARE if (Registered_only) { clear_to_end_of_line(); return; } #endif // Initialize weapon array Weapon_info[n].render_type = WEAPON_RENDER_NONE; // 0=laser, 1=blob, 2=object Weapon_info[n].bitmap.index = 0; Weapon_info[n].model_num = -1; Weapon_info[n].model_num_inner = -1; Weapon_info[n].blob_size = 0x1000; // size of blob Weapon_info[n].flash_vclip = -1; Weapon_info[n].flash_sound = SOUND_LASER_FIRED; Weapon_info[n].flash_size = 0; Weapon_info[n].robot_hit_vclip = -1; Weapon_info[n].robot_hit_sound = -1; Weapon_info[n].wall_hit_vclip = -1; Weapon_info[n].wall_hit_sound = -1; Weapon_info[n].impact_size = 0; for (i=0; ibm_flags |= BM_FLAG_NO_LIGHTING; lighted = 1; //default for next bitmap is lighted } arg = strtok( NULL, space ); } first_bitmap_num[n_models] = N_ObjBitmapPtrs; for (i=0;ifilename)-sizeof(TmapInfo->pad2), 1, fp ); fprintf(tfile,"NumTextures = %d, Textures array = %d, TmapInfo array = %d\n",NumTextures,sizeof(bitmap_index)*NumTextures,sizeof(tmap_info)*NumTextures); t = MAX_SOUNDS; fwrite( &t, sizeof(int), 1, fp ); fwrite( Sounds, sizeof(ubyte), t, fp ); fwrite( AltSounds, sizeof(ubyte), t, fp ); fprintf(tfile,"Num Sounds = %d, Sounds array = %d, AltSounds array = %d\n",t,t,t); fwrite( &Num_vclips, sizeof(int), 1, fp ); fwrite( Vclip, sizeof(vclip), Num_vclips, fp ); fprintf(tfile,"Num_vclips = %d, Vclip array = %d\n",Num_vclips,sizeof(vclip)*Num_vclips); fwrite( &Num_effects, sizeof(int), 1, fp ); fwrite( Effects, sizeof(eclip), Num_effects, fp ); fprintf(tfile,"Num_effects = %d, Effects array = %d\n",Num_effects,sizeof(eclip)*Num_effects); fwrite( &Num_wall_anims, sizeof(int), 1, fp ); fwrite( WallAnims, sizeof(wclip), Num_wall_anims, fp ); fprintf(tfile,"Num_wall_anims = %d, WallAnims array = %d\n",Num_wall_anims,sizeof(wclip)*Num_wall_anims); t = N_D2_ROBOT_TYPES; fwrite( &t, sizeof(int), 1, fp ); fwrite( Robot_info, sizeof(robot_info), t, fp ); fprintf(tfile,"N_robot_types = %d, Robot_info array = %d\n",t,sizeof(robot_info)*N_robot_types); t = N_D2_ROBOT_JOINTS; fwrite( &t, sizeof(int), 1, fp ); fwrite( Robot_joints, sizeof(jointpos), t, fp ); fprintf(tfile,"N_robot_joints = %d, Robot_joints array = %d\n",t,sizeof(jointpos)*N_robot_joints); t = N_D2_WEAPON_TYPES; fwrite( &t, sizeof(int), 1, fp ); fwrite( Weapon_info, sizeof(weapon_info), t, fp ); fprintf(tfile,"N_weapon_types = %d, Weapon_info array = %d\n",N_weapon_types,sizeof(weapon_info)*N_weapon_types); fwrite( &N_powerup_types, sizeof(int), 1, fp ); fwrite( Powerup_info, sizeof(powerup_type_info), N_powerup_types, fp ); fprintf(tfile,"N_powerup_types = %d, Powerup_info array = %d\n",N_powerup_types,sizeof(powerup_info)*N_powerup_types); t = N_D2_POLYGON_MODELS; fwrite( &t, sizeof(int), 1, fp ); fwrite( Polygon_models, sizeof(polymodel), t, fp ); fprintf(tfile,"N_polygon_models = %d, Polygon_models array = %d\n",t,sizeof(polymodel)*t); for (i=0; i