/* 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-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Functions to load & save player games * */ #include #include #include #include #include #include "dxxerror.h" #include "gameseq.h" #include "player.h" #include "playsave.h" #include "joy.h" #include "digi.h" #include "newmenu.h" #include "palette.h" #include "menu.h" #include "config.h" #include "text.h" #include "state.h" #include "u_mem.h" #include "strutil.h" #include "strio.h" #include "vers_id.h" #include "byteswap.h" #include "physfsx.h" #include "newdemo.h" #include "gauges.h" #include "args.h" //version 5 -> 6: added new highest level information //version 6 -> 7: stripped out the old saved_game array. //version 7 -> 8: readded the old saved_game array since this is needed // for shareware saved games //the shareware is level 4 #define SAVE_FILE_ID 0x44504c52 /* 'DPLR' */ #define SAVED_GAME_VERSION 8 //increment this every time saved_game struct changes #define COMPATIBLE_SAVED_GAME_VERSION 4 #define COMPATIBLE_PLAYER_STRUCT_VERSION 16 static void plyr_read_stats(); struct player_config PlayerCfg; saved_game_sw saved_games[N_SAVE_SLOTS]; int new_player_config() { int i=0; for (i=0;i='a'){ neg=1;/*I=p[0]-'a';*/ }else{ neg=0;/*I=p[0]-'A';*/ } i=0;*v=0; p++; while (p[i*2] && p[i*2+1] && p[i*2]!=' '){ c=(p[i*2]-33)+((p[i*2+1]-33)<<4); c^=effcode[i+neg]; *v+=c << (i*8); i++; } if (neg) *v *= -1; if (!p[i*2]) return NULL; return p+(i*2); } static void plyr_read_stats_v(int *k, int *d) { char filename[PATH_MAX]; int k1=-1,k2=0,d1=-1,d2=0; PHYSFS_file *f; *k=0;*d=0;//in case the file doesn't exist. memset(filename, '\0', PATH_MAX); snprintf(filename,PATH_MAX,GameArg.SysUsePlayersDir?"Players/%s.eff":"%s.eff",Players[Player_num].callsign); f = PHYSFSX_openReadBuffered(filename); if(f) { char line[256],*word; if(!PHYSFS_eof(f)) { PHYSFSX_fgets(line,50,f); word=splitword(line,':'); if(!strcmp(word,"kills")) *k=atoi(line); d_free(word); } if(!PHYSFS_eof(f)) { PHYSFSX_fgets(line,50,f); word=splitword(line,':'); if(!strcmp(word,"deaths")) *d=atoi(line); d_free(word); } if(!PHYSFS_eof(f)) { PHYSFSX_fgets(line,50,f); word=splitword(line,':'); if(!strcmp(word,"key") && strlen(line)>10){ unsigned char *p; if (line[0]=='0' && line[1]=='1'){ if ((p=decode_stat((unsigned char*)line+3,&k1,effcode1))&& (p=decode_stat(p+1,&k2,effcode2))&& (p=decode_stat(p+1,&d1,effcode3))){ decode_stat(p+1,&d2,effcode4); } } } d_free(word); } if (k1!=k2 || k1!=*k || d1!=d2 || d1!=*d) { *k=0;*d=0; } } if(f) PHYSFS_close(f); } static void plyr_read_stats() { plyr_read_stats_v(&PlayerCfg.NetlifeKills,&PlayerCfg.NetlifeKilled); } void plyr_save_stats() { int kills = PlayerCfg.NetlifeKills,deaths = PlayerCfg.NetlifeKilled, neg, i; char filename[PATH_MAX]; unsigned char buf[16],buf2[16],a; PHYSFS_file *f; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir?"Players/%s.eff":"%s.eff", Players[Player_num].callsign); f = PHYSFSX_openWriteBuffered(filename); if(!f) return; //broken! PHYSFSX_printf(f,"kills:%i\n",kills); PHYSFSX_printf(f,"deaths:%i\n",deaths); PHYSFSX_printf(f,"key:01 "); if (kills<0) { neg=1; kills*=-1; } else neg=0; for (i=0;kills;i++) { a=(kills & 0xFF) ^ effcode1[i+neg]; buf[i*2]=(a&0xF)+33; buf[i*2+1]=(a>>4)+33; a=(kills & 0xFF) ^ effcode2[i+neg]; buf2[i*2]=(a&0xF)+33; buf2[i*2+1]=(a>>4)+33; kills>>=8; } buf[i*2]=0; buf2[i*2]=0; if (neg) i+='a'; else i+='A'; PHYSFSX_printf(f,"%c%s %c%s ",i,buf,i,buf2); if (deaths<0) { neg=1; deaths*=-1; }else neg=0; for (i=0;deaths;i++) { a=(deaths & 0xFF) ^ effcode3[i+neg]; buf[i*2]=(a&0xF)+33; buf[i*2+1]=(a>>4)+33; a=(deaths & 0xFF) ^ effcode4[i+neg]; buf2[i*2]=(a&0xF)+33; buf2[i*2+1]=(a>>4)+33; deaths>>=8; } buf[i*2]=0; buf2[i*2]=0; if (neg) i+='a'; else i+='A'; PHYSFSX_printf(f,"%c%s %c%s\n",i,buf,i,buf2); PHYSFS_close(f); } static int write_player_dxx(const char *filename) { PHYSFS_file *fout; int rc=0; char tempfile[PATH_MAX]; strcpy(tempfile,filename); tempfile[strlen(tempfile)-4]=0; strcat(tempfile,".pl$"); fout=PHYSFSX_openWriteBuffered(tempfile); if (!fout && GameArg.SysUsePlayersDir) { PHYSFS_mkdir("Players/"); //try making directory fout=PHYSFSX_openWriteBuffered(tempfile); } if(fout) { PHYSFSX_printf(fout,"[D1X Options]\n"); PHYSFSX_printf(fout,"[weapon reorder]\n"); PHYSFSX_printf(fout,"primary=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",PlayerCfg.PrimaryOrder[0], PlayerCfg.PrimaryOrder[1], PlayerCfg.PrimaryOrder[2],PlayerCfg.PrimaryOrder[3], PlayerCfg.PrimaryOrder[4], PlayerCfg.PrimaryOrder[5]); PHYSFSX_printf(fout,"secondary=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",PlayerCfg.SecondaryOrder[0], PlayerCfg.SecondaryOrder[1], PlayerCfg.SecondaryOrder[2],PlayerCfg.SecondaryOrder[3], PlayerCfg.SecondaryOrder[4], PlayerCfg.SecondaryOrder[5]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[keyboard]\n"); PHYSFSX_printf(fout,"sensitivity0=%d\n",PlayerCfg.KeyboardSens[0]); PHYSFSX_printf(fout,"sensitivity1=%d\n",PlayerCfg.KeyboardSens[1]); PHYSFSX_printf(fout,"sensitivity2=%d\n",PlayerCfg.KeyboardSens[2]); PHYSFSX_printf(fout,"sensitivity3=%d\n",PlayerCfg.KeyboardSens[3]); PHYSFSX_printf(fout,"sensitivity4=%d\n",PlayerCfg.KeyboardSens[4]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[joystick]\n"); PHYSFSX_printf(fout,"sensitivity0=%d\n",PlayerCfg.JoystickSens[0]); PHYSFSX_printf(fout,"sensitivity1=%d\n",PlayerCfg.JoystickSens[1]); PHYSFSX_printf(fout,"sensitivity2=%d\n",PlayerCfg.JoystickSens[2]); PHYSFSX_printf(fout,"sensitivity3=%d\n",PlayerCfg.JoystickSens[3]); PHYSFSX_printf(fout,"sensitivity4=%d\n",PlayerCfg.JoystickSens[4]); PHYSFSX_printf(fout,"sensitivity5=%d\n",PlayerCfg.JoystickSens[5]); PHYSFSX_printf(fout,"deadzone0=%d\n",PlayerCfg.JoystickDead[0]); PHYSFSX_printf(fout,"deadzone1=%d\n",PlayerCfg.JoystickDead[1]); PHYSFSX_printf(fout,"deadzone2=%d\n",PlayerCfg.JoystickDead[2]); PHYSFSX_printf(fout,"deadzone3=%d\n",PlayerCfg.JoystickDead[3]); PHYSFSX_printf(fout,"deadzone4=%d\n",PlayerCfg.JoystickDead[4]); PHYSFSX_printf(fout,"deadzone5=%d\n",PlayerCfg.JoystickDead[5]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[mouse]\n"); PHYSFSX_printf(fout,"flightsim=%d\n",PlayerCfg.MouseFlightSim); PHYSFSX_printf(fout,"sensitivity0=%d\n",PlayerCfg.MouseSens[0]); PHYSFSX_printf(fout,"sensitivity1=%d\n",PlayerCfg.MouseSens[1]); PHYSFSX_printf(fout,"sensitivity2=%d\n",PlayerCfg.MouseSens[2]); PHYSFSX_printf(fout,"sensitivity3=%d\n",PlayerCfg.MouseSens[3]); PHYSFSX_printf(fout,"sensitivity4=%d\n",PlayerCfg.MouseSens[4]); PHYSFSX_printf(fout,"sensitivity5=%d\n",PlayerCfg.MouseSens[5]); PHYSFSX_printf(fout,"fsdead=%d\n",PlayerCfg.MouseFSDead); PHYSFSX_printf(fout,"fsindi=%d\n",PlayerCfg.MouseFSIndicator); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[weapon keys v2]\n"); PHYSFSX_printf(fout,"1=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[0],PlayerCfg.KeySettingsRebirth[1],PlayerCfg.KeySettingsRebirth[2]); PHYSFSX_printf(fout,"2=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[3],PlayerCfg.KeySettingsRebirth[4],PlayerCfg.KeySettingsRebirth[5]); PHYSFSX_printf(fout,"3=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[6],PlayerCfg.KeySettingsRebirth[7],PlayerCfg.KeySettingsRebirth[8]); PHYSFSX_printf(fout,"4=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[9],PlayerCfg.KeySettingsRebirth[10],PlayerCfg.KeySettingsRebirth[11]); PHYSFSX_printf(fout,"5=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[12],PlayerCfg.KeySettingsRebirth[13],PlayerCfg.KeySettingsRebirth[14]); PHYSFSX_printf(fout,"6=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[15],PlayerCfg.KeySettingsRebirth[16],PlayerCfg.KeySettingsRebirth[17]); PHYSFSX_printf(fout,"7=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[18],PlayerCfg.KeySettingsRebirth[19],PlayerCfg.KeySettingsRebirth[20]); PHYSFSX_printf(fout,"8=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[21],PlayerCfg.KeySettingsRebirth[22],PlayerCfg.KeySettingsRebirth[23]); PHYSFSX_printf(fout,"9=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[24],PlayerCfg.KeySettingsRebirth[25],PlayerCfg.KeySettingsRebirth[26]); PHYSFSX_printf(fout,"0=0x%x,0x%x,0x%x\n",PlayerCfg.KeySettingsRebirth[27],PlayerCfg.KeySettingsRebirth[28],PlayerCfg.KeySettingsRebirth[29]); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[cockpit]\n"); PHYSFSX_printf(fout,"mode=%i\n",PlayerCfg.CockpitMode[0]); PHYSFSX_printf(fout,"hud=%i\n",PlayerCfg.HudMode); PHYSFSX_printf(fout,"rettype=%i\n",PlayerCfg.ReticleType); PHYSFSX_printf(fout,"retrgba=%i,%i,%i,%i\n",PlayerCfg.ReticleRGBA[0],PlayerCfg.ReticleRGBA[1],PlayerCfg.ReticleRGBA[2],PlayerCfg.ReticleRGBA[3]); PHYSFSX_printf(fout,"retsize=%i\n",PlayerCfg.ReticleSize); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[toggles]\n"); PHYSFSX_printf(fout,"persistentdebris=%i\n",PlayerCfg.PersistentDebris); PHYSFSX_printf(fout,"prshot=%i\n",PlayerCfg.PRShot); PHYSFSX_printf(fout,"noredundancy=%i\n",PlayerCfg.NoRedundancy); PHYSFSX_printf(fout,"multimessages=%i\n",PlayerCfg.MultiMessages); PHYSFSX_printf(fout,"norankings=%i\n",PlayerCfg.NoRankings); PHYSFSX_printf(fout,"bombgauge=%i\n",PlayerCfg.BombGauge); PHYSFSX_printf(fout,"automapfreeflight=%i\n",PlayerCfg.AutomapFreeFlight); PHYSFSX_printf(fout,"nofireautoselect=%i\n",PlayerCfg.NoFireAutoselect); PHYSFSX_printf(fout,"cycleautoselectonly=%i\n",PlayerCfg.CycleAutoselectOnly); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[graphics]\n"); PHYSFSX_printf(fout,"alphaeffects=%i\n",PlayerCfg.AlphaEffects); PHYSFSX_printf(fout,"dynlightcolor=%i\n",PlayerCfg.DynLightColor); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[plx version]\n"); PHYSFSX_printf(fout,"plx version=%s\n", VERSION); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[end]\n"); PHYSFS_close(fout); if(rc==0) { PHYSFS_delete(filename); rc = PHYSFSX_rename(tempfile,filename); } return rc; } else return errno; } //read in the player's saved games. returns errno (0 == no error) int read_player_file() { char filename[PATH_MAX]; PHYSFS_file *file; int player_file_size, shareware_file = -1, id = 0; short saved_game_version, player_struct_version; Assert(Player_num>=0 && Player_num PlayerCfg.HighestLevels[i].LevelNum) PlayerCfg.HighestLevels[i].LevelNum = levelnum; write_player_file(); } //gets the player's highest level from the file for this mission int get_highest_level(void) { int i; int highest_saturn_level = 0; read_player_file(); #ifndef SATURN if (strlen(Current_mission_filename)==0 ) { for (i=0;i i ) i = highest_saturn_level; return i; } //write out player's saved games. returns errno (0 == no error) int write_player_file() { char filename[PATH_MAX]; PHYSFS_file *file; int errno_ret, i; if ( Newdemo_state == ND_STATE_PLAYBACK ) return -1; errno_ret = WriteConfigFile(); memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.plx" : "%.8s.plx", Players[Player_num].callsign); write_player_dxx(filename); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.plr" : "%.8s.plr", Players[Player_num].callsign); file = PHYSFSX_openWriteBuffered(filename); if (!file) return errno; PHYSFS_writeULE32(file, SAVE_FILE_ID); PHYSFS_writeULE16(file, SAVED_GAME_VERSION); PHYSFS_writeULE16(file, PLAYER_STRUCT_VERSION); PHYSFS_writeSLE32(file, PlayerCfg.NHighestLevels); PHYSFS_writeSLE32(file, PlayerCfg.DefaultDifficulty); PHYSFS_writeSLE32(file, PlayerCfg.AutoLeveling); errno_ret = EZERO; //write higest level info if ((PHYSFS_write( file, PlayerCfg.HighestLevels, sizeof(hli), PlayerCfg.NHighestLevels) != PlayerCfg.NHighestLevels)) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } if (PHYSFS_write( file, saved_games,sizeof(saved_games),1) != 1) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } if ((PHYSFS_write( file, PlayerCfg.NetworkMessageMacro, MAX_MESSAGE_LEN, 4) != 4)) { errno_ret = errno; PHYSFS_close(file); return errno_ret; } //write kconfig info { if (PHYSFS_write(file, PlayerCfg.KeySettings[0], sizeof(PlayerCfg.KeySettings[0]), 1) != 1) errno_ret=errno; if (PHYSFS_write(file, PlayerCfg.KeySettings[1], sizeof(PlayerCfg.KeySettings[1]), 1) != 1) errno_ret=errno; for (i = 0; i < MAX_CONTROLS*3; i++) if (PHYSFS_write(file, "0", sizeof(ubyte), 1) != 1) // Skip obsolete Flightstick/Thrustmaster/Gravis map fields errno_ret=errno; if (PHYSFS_write(file, PlayerCfg.KeySettings[2], sizeof(PlayerCfg.KeySettings[2]), 1) != 1) errno_ret=errno; for (i = 0; i < MAX_CONTROLS; i++) if (PHYSFS_write(file, "0", sizeof(ubyte), 1) != 1) // Skip obsolete Cyberman map field errno_ret=errno; if(errno_ret == EZERO) { ubyte old_avg_joy_sensitivity = 8; if (PHYSFS_write( file, &PlayerCfg.ControlType, sizeof(ubyte), 1 )!=1) errno_ret=errno; else if (PHYSFS_write( file, &old_avg_joy_sensitivity, sizeof(ubyte), 1 )!=1) errno_ret=errno; } } if (!PHYSFS_close(file)) errno_ret = errno; if (errno_ret != EZERO) { PHYSFS_delete(filename); //delete bogus file nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s",TXT_ERROR_WRITING_PLR, strerror(errno_ret)); } return errno_ret; } // read stored values from ngp file to netgame_info void read_netgame_profile(netgame_info *ng) { char filename[PATH_MAX], line[50], *token, *ptr; const char *value; PHYSFS_file *file; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.ngp" : "%.8s.ngp", Players[Player_num].callsign); if (!PHYSFSX_exists(filename,0)) return; file = PHYSFSX_openReadBuffered(filename); if (!file) return; // NOTE that we do not set any defaults here or even initialize netgame_info. For flexibility, leave that to the function calling this. while (!PHYSFS_eof(file)) { memset(line, 0, 50); PHYSFSX_gets(file, line); ptr = &(line[0]); while (isspace(*ptr)) ptr++; if (*ptr != '\0') { token = strtok(ptr, "="); value = strtok(NULL, "="); if (!value) value = ""; if (!strcmp(token, "game_name")) { char * p; strncpy( ng->game_name, value, NETGAME_NAME_LEN+1 ); p = strchr( ng->game_name, '\n'); if ( p ) *p = 0; } else if (!strcmp(token, "gamemode")) ng->gamemode = strtol(value, NULL, 10); else if (!strcmp(token, "RefusePlayers")) ng->RefusePlayers = strtol(value, NULL, 10); else if (!strcmp(token, "difficulty")) ng->difficulty = strtol(value, NULL, 10); else if (!strcmp(token, "game_flags")) { packed_game_flags p; p.value = strtol(value, NULL, 10); ng->game_flag = unpack_game_flags(&p); } else if (!strcmp(token, "AllowedItems")) ng->AllowedItems = strtol(value, NULL, 10); else if (!strcmp(token, "ShowEnemyNames")) ng->ShowEnemyNames = strtol(value, NULL, 10); else if (!strcmp(token, "BrightPlayers")) ng->BrightPlayers = strtol(value, NULL, 10); else if (!strcmp(token, "InvulAppear")) ng->InvulAppear = strtol(value, NULL, 10); else if (!strcmp(token, "KillGoal")) ng->KillGoal = strtol(value, NULL, 10); else if (!strcmp(token, "PlayTimeAllowed")) ng->PlayTimeAllowed = strtol(value, NULL, 10); else if (!strcmp(token, "control_invul_time")) ng->control_invul_time = strtol(value, NULL, 10); else if (!strcmp(token, "PacketsPerSec")) ng->PacketsPerSec = strtol(value, NULL, 10); else if (!strcmp(token, "ShortPackets")) ng->ShortPackets = strtol(value, NULL, 10); else if (!strcmp(token, "NoFriendlyFire")) ng->NoFriendlyFire = strtol(value, NULL, 10); #ifdef USE_TRACKER else if (!strcmp(token, "Tracker")) ng->Tracker = strtol(value, NULL, 10); #endif } } PHYSFS_close(file); } // write values from netgame_info to ngp file void write_netgame_profile(netgame_info *ng) { char filename[PATH_MAX]; PHYSFS_file *file; memset(filename, '\0', PATH_MAX); snprintf(filename, PATH_MAX, GameArg.SysUsePlayersDir? "Players/%.8s.ngp" : "%.8s.ngp", Players[Player_num].callsign); file = PHYSFSX_openWriteBuffered(filename); if (!file) return; PHYSFSX_printf(file, "game_name=%s\n", ng->game_name); PHYSFSX_printf(file, "gamemode=%i\n", ng->gamemode); PHYSFSX_printf(file, "RefusePlayers=%i\n", ng->RefusePlayers); PHYSFSX_printf(file, "difficulty=%i\n", ng->difficulty); PHYSFSX_printf(file, "game_flags=%i\n", pack_game_flags(&ng->game_flag).value); PHYSFSX_printf(file, "AllowedItems=%i\n", ng->AllowedItems); PHYSFSX_printf(file, "ShowEnemyNames=%i\n", ng->ShowEnemyNames); PHYSFSX_printf(file, "BrightPlayers=%i\n", ng->BrightPlayers); PHYSFSX_printf(file, "InvulAppear=%i\n", ng->InvulAppear); PHYSFSX_printf(file, "KillGoal=%i\n", ng->KillGoal); PHYSFSX_printf(file, "PlayTimeAllowed=%i\n", ng->PlayTimeAllowed); PHYSFSX_printf(file, "control_invul_time=%i\n", ng->control_invul_time); PHYSFSX_printf(file, "PacketsPerSec=%i\n", ng->PacketsPerSec); PHYSFSX_printf(file, "ShortPackets=%i\n", ng->ShortPackets); PHYSFSX_printf(file, "NoFriendlyFire=%i\n", ng->NoFriendlyFire); #ifdef USE_TRACKER PHYSFSX_printf(file, "Tracker=%i\n", ng->Tracker); #else PHYSFSX_printf(file, "Tracker=0\n"); #endif PHYSFSX_printf(file, "ngp version=%s\n",VERSION); PHYSFS_close(file); }