Descent3/manage/manage.cpp

3426 lines
91 KiB
C++
Raw Normal View History

2024-04-16 03:43:29 +00:00
/*
* $Logfile: /DescentIII/Main/manage/manage.cpp $
* $Revision: 103 $
* $Date: 10/10/01 11:32a $
* $Author: Matt $
*
* Jason should put something here
*
* $Log: /DescentIII/Main/manage/manage.cpp $
*
* 103 10/10/01 11:32a Matt
* Added system to check for errors when reading in add-on data.
*
* 102 10/08/01 1:50p Matt
* Added a case for gamefile pagetype to avoid int3
*
* 101 4/19/00 5:07p Matt
* From Duane for 1.4
* Added checks, asserts, and fixes for bad return values
*
* 100 3/20/00 12:27p Matt
* Merge of Duane's post-1.3 changes.
* Mac pilot directory stuff.
*
* 99 10/26/99 3:30p Jeff
* handle extra.gam addon tablefile
*
* 98 10/20/99 6:27p Jeff
* sped up addon page popping (by saving page offsets)
*
* 97 10/19/99 9:14p Chris
* Fixed a memory free bug
*
* 96 8/11/99 5:32p Jeff
* changes to fix addon tablefile support so it works correctly
*
* 95 7/28/99 2:29p Kevin
* Added macintosh DLL extentions (msl)
*
* 94 5/14/99 12:45p Matt
* Removed yet more static data
*
* 93 5/14/99 12:33p Matt
* Fixed another case of too much local data for the Mac.
*
* 92 5/13/99 8:36p Matt
* Made some local variables global to get around the 32K local variable
* limit on the Mac.
*
* 91 5/12/99 3:01p Matt
* Declared one texpage structure statically for all the functions that
* need it, because the Mac limits local data to 32K.
*
* 90 4/30/99 8:53p Matt
* Added a "voice" directory for gamefiles.
*
* 89 4/22/99 3:26p Jason
* added transferring of pagelocks
*
* 88 4/20/99 12:06a Jeff
* added so files to data/scripts search path
*
* 87 4/15/99 5:21p Jason
* sped up table file loading
*
* 86 4/14/99 10:46a Kevin
* Removed OutrageMessageBox from release builds
*
* 85 4/14/99 1:33a Jeff
* fixed case mismatched #includes
*
* 84 4/12/99 3:05p Jason
* changes for 256 textures
*
* 83 3/05/99 10:42a Jason
* more deletion of pagelocls
*
* 82 3/04/99 1:46p Jason
* fixed some manage problems
*
* 81 2/27/99 5:15p Jason
* fixed search path bug
*
* 80 2/17/99 12:11p Jason
* added music directory to searchable list
*
* 79 2/16/99 11:35a Samir
* added art directory.
*
* 78 2/10/99 3:47p Jason
* before doing a backup, makes sure that the tablefile version is the
* same on the net and on the local machine
*
* 77 1/29/99 6:29p Jason
* first pass at adding bumpmaps
*
* 76 1/21/99 11:16p Jeff
* pulled out some structs and defines from header files and moved them
* into seperate header files so that multiplayer dlls don't require major
* game headers, just those new headers. Side effect is a shorter build
* time. Also cleaned up some header file #includes that weren't needed.
* This affected polymodel.h, object.h, player.h, vecmat.h, room.h,
* manage.h and multi.h
*
* 75 1/13/99 2:49p Jeff
* added .msg to the search path for data\scripts
*
* 74 1/13/99 7:08a Jeff
* put some #ifdef's around some window's specific code (really only used
* in the editor, but EDITOR is never defined when building manage) so it
* builds in linux
*
* 73 12/30/98 6:52p Matt
* Fixed compile warnings
*
* 72 12/29/98 4:30p Jason
* added add-on data functionality
*
* 71 12/13/98 7:51p Jeff
* only check the script directory for cpp,dll and def files
*
* 70 12/11/98 5:50p Jeff
* implemented and added changes regarding Level&Scripting manage system
* and compiler interface
*
* 69 11/28/98 2:19p Jason
* fixed stupid filecopy bug
*
* 68 11/18/98 11:02a Jason
* temp fix for table problems
*
* 67 11/16/98 3:49p Jason
* changes for manage system
*
* 66 11/16/98 2:43p Jason
* better file checking for old files
*
* 65 11/13/98 12:30p Jason
* fixed reordered pages bug
*
* 64 11/13/98 12:30p Jason
* changes for weapons
*
* 63 11/06/98 6:00p Josh
* fixed dumb bug
*
* 62 11/06/98 5:28p Josh
* FROM JASON:upped tracklock limit
*
* 61 11/06/98 12:35p Jason
* more speedups for manage system
*
* 60 11/05/98 7:55p Jason
* changes for new manage system
*
* 59 11/04/98 11:02a Jason
* added levels and briefing directories to new "old files" update method
*
* 58 11/02/98 6:35p Jason
* changes for filter
*
* 57 11/02/98 6:02p Jason
* made yes network updates much faster
*
* 56 10/15/98 8:48a Matt
* Changed some errors to use Error() instead of OutrageMessageBox()
*
* 55 10/14/98 5:15p Jason
* added version checking to the table file
*
* 54 10/12/98 11:38p Jeff
* wrapped all the Object_info[].description whenever freed...trying to
* find an obscure bug. Added icon_name to manage page of Generic
*
* 53 10/12/98 10:31a Jason
* don't seach data directories if release
*
* 52 10/09/98 4:39p Jason
* fixed local table file message
*
* 51 10/09/98 2:27p Jason
* reorganized table file system
*
* 50 10/09/98 2:40a Jason
* fixed table file issues with demo
*
* 49 10/08/98 10:03p Jason
* more filtered table file stuff
*
* 48 10/08/98 7:05p Jason
* added file filter support
*
* 47 9/28/98 6:53p Kevin
* localized some multiplayer menus
*
* 46 9/25/98 4:37p Jason
* fixed dedicated server printing out progress messages
*
* 45 9/25/98 2:53p Jason
* added progress bar
*
* 44 9/25/98 12:24p Samir
* fixed bugs for release version.
*
* 43 9/24/98 6:22p Jason
* fixed RELEASE version asking to update network files
*
* 42 9/18/98 3:58p Jason
* change weapon reordering to do countermeasure weapons after generics
*
* 41 9/15/98 4:31p Jason
* added more functionality for the dedicated server
*
* 40 9/14/98 6:28p Jason
* first pass at getting dedicated server working
*
* 39 8/25/98 3:42p Jason
* fixed generic object problems
*
* 38 8/25/98 3:25p Jason
* turned off fast load trick
*
* 37 8/17/98 4:00p Jason
* Added mprintf
*
* 36 8/15/98 5:17p Matt
* Added new Base_directory variable. Got rid of D3_LOCAL check and
* 'local directory' registry variable.
*
* 35 8/13/98 6:34p Jason
* made table file loading much faster
*
* 34 8/10/98 1:49p Samir
* added music directory.
*
* 33 8/03/98 6:44p Jason
* set custom graphics in the search path
*
* 32 7/27/98 6:25p Jeff
* added creation of custom directories
*
* 31 6/23/98 2:43p Matt
* Changed calls to OutrageMessageBox() & Debug_MessageBox() to deal with
* int return value (instead of bool).
*
* 30 6/12/98 1:06p Jason
* added smart loading from local table file
*
* 29 5/04/98 5:00p Keneta
* FROM JASON:Fixed copyfile bug
*
* 28 5/04/98 4:42p Jason
* even better error checking
*
* 26 5/04/98 4:24p Jason
* upped MAX_TRIES
*
* 25 5/04/98 4:18p Jason
* added assert to prevent table file problems
*
* 24 3/31/98 3:49p Jason
* added memory lib
*
* 23 3/19/98 3:51p Samir
* added misc data directory.
*
* 22 2/23/98 2:00p Jason
* Pop up a message box when table file couldn't be opened
*
* 21 2/06/98 12:15p Jason
* upped max times program will try to delete the table file before
* bailing
*
* 20 2/04/98 11:47a Jason
* added dynamic description field to generic pages
*
* 19 1/26/98 11:32a Jason
* upped the number of times the system will try to delete a table file
*
* 18 1/22/98 2:49p Samir
* Added D3 Local Dir to the search path.
*
* 17 1/15/98 6:22p Jason
* added safety checks so the network won't copy over a primitive you have
* held locally
*
* 16 1/15/98 4:54p Mark
* FROM JASON:Do switcheroo a few times before giving up
*
* 15 12/22/97 3:50p Chris
*
* 14 11/17/97 4:16p Jason
* added briefings directory
*
* 13 9/09/97 4:07p Matt
* Added mprintf()
*
* 12 9/04/97 2:53p Samir
* Added gamefile and generic page strings to PageNames array.
*
* 11 8/12/97 12:47p Matt
* Only copy pagefile from net if different from local copy.
* When loading pages, print different char for each type
* Show how long it took to load the pagefile
*
* 10 8/11/97 1:54p Matt
* Ripped out robot & powerup pages, and added generic page
*
* 9 8/08/97 5:17p Jason
* made it so that when you update from the network it doesn't halt other
* users
*
* 8 8/08/97 3:44p Jason
* added code to support new generic page
*
* 7 8/08/97 1:57p Matt
* Took out error message now handled by mng_MakeLocker()
*
* 6 7/29/97 12:07p Jason
* added gamefile page for auto retrieval of non-standard page types
*
* 50 6/27/97 3:11p Jason
* added room directories
*
*
* 49 6/11/97 1:07p Samir
* The removal of gameos and replaced with oeApplication, oeDatabase
*
* 48 6/10/97 5:08p Jason
* added reorderpages menu item
*
* 47 6/05/97 2:52p Jason
* added megacell functions
*
* 46 5/30/97 11:41a Jason
* made a better error message if someone already has the table file
* locked upon startup
*
* 45 5/22/97 3:08p Jason
* added the ReorderPage function
*
* 44 5/16/97 3:53p Jason
* added filepage dialog
*
* 43 5/15/97 5:56 PM Jeremy
* made initlocaltable files check if the file exists by using cfexist
* rather than trying to open the file and checking the error code
*
* 42 5/14/97 6:38p Jason
* fixed a plethora of potential problems by locking the table file when
* someone is starting up.
*
* 41 5/14/97 6:44 PM Jeremy
* fixed a bug where local dir backup directory was not being set
* correctly in init local table files
*
* 40 5/13/97 3:41p Jason
* made all manage code work with the new device independant database
*
* 39 5/08/97 12:41p Jason
* made manage system work with device dependant path names
*
* 38 4/29/97 5:07p Samir
* Added levels directory to search path
*
* 37 4/25/97 6:16p Jason
* added switcheroo function
*
* 36 4/01/97 2:13p Jason
* changes for sound page functionality
*
* 35 3/31/97 4:35p Jason
* added player ship and weapon pages
*
* 34 3/25/97 3:10p Jason
* added robots and robot page functionality
*
* 33 3/17/97 4:27p Jason
* added sounds directory to path list
*
* 32 3/14/97 7:18p Matt
* Added missing include
*
* 31 3/14/97 6:13 PM Jeremy
* changed calls to windows "MessageBox" to OutrageMessageBox, changed
* call of GetUserName to os_database->get_user_name, #included descent.h
* in order to refer to the OS_database object, unincluded <windows.h> and
* <direct.h>
*
* 30 3/13/97 7:39p Matt
* Changed code to use getenv() (ANSI-standard) instead of
* GetEnvironmentVariable()
*
* 29 3/13/97 12:34p Matt
* Changed code to not leave directory changed after checking for presence
* of a directory.
*
* 28 3/13/97 11:37a Samir
* Changed os file functions to ddio file functions
*
* 27 3/10/97 2:23p Jason
* added auto creation of models directory
*
* 26 3/07/97 1:02p Jason
* Now uses Samir's OS specific directory functions
*
* 25 3/05/97 3:10p Jason
* added more door functionality
*
* 24 3/05/97 12:16p Jason
* added code to support our new 3d doors
*
* 23 3/03/97 6:21p Matt
* Changed cfile functions to use D3 naming convention
*
* $NoKeywords: $
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#if defined(WIN32)
#include <windows.h>
#elif defined(__LINUX__)
#include "linux/linux_fix.h"
#endif
#include "descent.h"
#include "manage.h"
#include "pserror.h"
#include "gametexture.h"
#include "texpage.h"
#include "doorpage.h"
#include "soundpage.h"
#include "megapage.h"
#include "shippage.h"
#include "weaponpage.h"
#include "gamefilepage.h"
#include "mono.h"
#include "object.h"
#include "ddio.h"
#include "CFILE.H"
#include "appdatabase.h"
#include "genericpage.h"
#include "mem.h"
#include "dedicated_server.h"
#include "AppConsole.h"
#include "init.h"
#include "stringtable.h"
#include "args.h"
#include "vclip.h"
#include "polymodel.h"
int Old_table_method=0;
void mng_WriteNewUnknownPage (CFILE *outfile);
// This is for levels
char LocalLevelsDir[TABLE_NAME_LEN];
#ifdef MACINTOSH
char LocalPilotsDir[TABLE_NAME_LEN];
#endif
// This is for pages
char TableLockFilename[TABLE_NAME_LEN],TableFilename[TABLE_NAME_LEN];
char TempTableLockFilename[TABLE_NAME_LEN],TempTableFilename[TABLE_NAME_LEN];
char LocalTableFilename[TABLE_NAME_LEN],LocalTempTableFilename[TABLE_NAME_LEN];
char BackupTableFilename[TABLE_NAME_LEN],BackupLockFilename[TABLE_NAME_LEN];
char ManageGraphicsDir[TABLE_NAME_LEN],LocalManageGraphicsDir[TABLE_NAME_LEN];
char LocalModelsDir[TABLE_NAME_LEN],NetModelsDir[TABLE_NAME_LEN];
char LocalSoundsDir[TABLE_NAME_LEN],NetSoundsDir[TABLE_NAME_LEN];
char LocalRoomsDir[TABLE_NAME_LEN],NetRoomsDir[TABLE_NAME_LEN];
char LocalBriefingDir[TABLE_NAME_LEN],NetBriefingDir[TABLE_NAME_LEN];
char LocalScriptDir[TABLE_NAME_LEN],NetScriptDir[TABLE_NAME_LEN];
char LocalMiscDir[TABLE_NAME_LEN],NetMiscDir[TABLE_NAME_LEN];
char LocalArtDir[TABLE_NAME_LEN],NetArtDir[TABLE_NAME_LEN];
char LocalMusicDir[TABLE_NAME_LEN],NetMusicDir[TABLE_NAME_LEN];
char LocalVoiceDir[TABLE_NAME_LEN],NetVoiceDir[TABLE_NAME_LEN];
char NetTableDir[TABLE_NAME_LEN],LocalTableDir[TABLE_NAME_LEN];
char LocalD3Dir[TABLE_NAME_LEN],NetD3Dir[TABLE_NAME_LEN];
char LocalCustomGraphicsDir[TABLE_NAME_LEN];
char LocalCustomSoundsDir[TABLE_NAME_LEN];
char LockerFile [TABLE_NAME_LEN];
char VersionFile [TABLE_NAME_LEN];
char TableUser[TABLE_NAME_LEN];
char ErrorString[INFO_STRING_LEN],InfoString[INFO_STRING_LEN];
mngs_track_lock GlobalTrackLocks[MAX_TRACKLOCKS];
bool Use_old_update_method=false;
char *TablefileNameOverride = NULL;
// Only valid when first starting the editor
#define MAX_LOCKLIST_ELEMENTS 1000
mngs_Pagelock *LockList;
int Num_locklist,Starting_editor=0,Loading_locals=0,Fast_load_trick=0;
#define PRIMTYPE_OOF 0
#define PRIMTYPE_OGF 1
#define PRIMTYPE_WAV 2
#define PRIMTYPE_OAF 3
#define PRIMTYPE_FILE 4
#if defined(WIN32)
FILETIME TableTimeThreshold;
// Builds a list of old files so we know which ones to update
// Searches through all our netdirectories for old files
void BuildOldFileList (FILETIME threshold);
#endif
typedef struct
{
ubyte type;
char name[PAGENAME_LEN];
} old_file;
#define MAX_OLDFILE_ELEMENTS 10000
int Num_old_files=0;
old_file *OldFiles;
char *PageNames[]={"Unknown","Texture","Weapon","Robot","Powerup","Door","Player ship","Sound","Megacell", "Files", "Generic objects"};
#ifndef RELEASE
int Network_up=1;
int Stand_alone=0;
#else
int Network_up=0;
int Stand_alone=1;
#endif
void mng_BackupTableFile();
// returns 1 if network is up, 0 if down
int mng_IsNetworkUp()
{
char dir[100];
int ret;
if (Stand_alone)
return 0;
char net_dir[255]={0};
int dirlen=255;
Database->read("net directory", net_dir, &dirlen);
if (net_dir[0]==0)
return 0;
ddio_MakePath (dir,net_dir,"data",NULL);
ret=ddio_CreateDir (dir);
if (!ret)
{
char old_dir[100];
ddio_GetWorkingDir(old_dir,100);
if (!ddio_SetWorkingDir(dir))
return 0; // network down
else {
ddio_SetWorkingDir(old_dir); //restore directory
return 1; // directory is already there
}
}
return 1;
}
void ReorderPages (int);
//#define JASONS_REORDERING
void Read256TextureNames ();
// Sets up our table files, get their filenames, etc.
// Returns 1 on success, zero on error
int mng_InitTableFiles()
{
ulong size=TABLE_NAME_LEN;
int answer;
Database->get_user_name(TableUser, &size);
if (FindArg("-filter"))
Use_old_update_method=true;
//Read256TextureNames ();
if (FindArg("-oldmethod"))
Use_old_update_method=true;
if (mng_IsNetworkUp())
{
#ifndef RELEASE
answer=OutrageMessageBox (MBOX_YESNO, "Do you wish to update your data files from the network?\n(If NO is selected then you will have to restart to use networking functions)");
#else
answer = IDNO;
#endif
if (answer == IDNO)
Network_up=0;
else
{
Network_up=1;
#ifndef RELEASE
#if defined(WIN32)
if (cfexist("c:\\edload"))
Use_old_update_method=true;
else
{
CFILE *fp=cfopen("c:\\edload","wt");
cfclose (fp);
}
#endif
#endif
}
}
else
{
mprintf ((0,"Network is down...\n"));
Network_up=0;
}
if (Network_up==0)
{
mng_InitLocalTables();
mng_InitLocalDirectories();
mng_CheckToCreateLocalTables();
mng_InitTrackLocks();
}
else
{
// Do locals
mng_InitLocalTables ();
mng_InitLocalDirectories();
mng_CheckToCreateLocalTables();
// Do network
mng_InitNetTables();
mng_InitNetDirectories ();
mng_CheckToCreateNetTables();
mng_BackupTableFile();
mng_InitPagelocks ();
mng_InitTrackLocks();
#ifdef JASONS_REORDERING
ReorderPages(0);
return 0;
#endif
}
return 1;
}
// Loads our tables
int mng_LoadTableFiles (int show_progress)
{
if (Network_up)
{
LockList=(mngs_Pagelock *)mem_malloc (MAX_LOCKLIST_ELEMENTS*sizeof(mngs_Pagelock));
Num_locklist=mng_GetListOfLocks (LockList,MAX_LOCKLIST_ELEMENTS,TableUser);
OldFiles=(old_file *)mem_malloc (MAX_OLDFILE_ELEMENTS*sizeof(old_file));
Num_old_files=0;
ASSERT (OldFiles);
#if defined (WIN32)
if (TableTimeThreshold.dwHighDateTime!=-1)
BuildOldFileList (TableTimeThreshold);
#endif
Starting_editor=1;
}
int ret1,ret2;
if (Fast_load_trick && !FindArg ("-filter"))
Network_up=0;
ret1=mng_LoadNetPages(show_progress);
if (Fast_load_trick)
{
Network_up=1;
Fast_load_trick=0;
}
ret2=mng_LoadLocalPages();
if (Network_up)
{
Starting_editor=0;
Num_locklist=0;
Num_old_files=0;
mem_free (OldFiles);
mem_free (LockList);
#ifndef RELEASE
#if defined(WIN32)
remove ("c:\\edload");
#endif
#endif
}
RemapEverything();
if (!ret1 || !ret2)
return 0;
return 1;
}
// This is for initting tables on STAND_ALONE, if the network is down, or if
// the user doesn't want network support
int mng_InitLocalTables ()
{
//Set the local table directory from the base directory
strcpy(LocalD3Dir,Base_directory);
mprintf ((1,"Local dir:%s\n",LocalD3Dir));
// Make the CFILE system first look at our local directories. If the goods aren't
// found there, try out on the network
ddio_MakePath (LocalTableDir,LocalD3Dir,"data","tables",NULL);
ddio_MakePath (LocalManageGraphicsDir,LocalD3Dir,"data","graphics",NULL);
ddio_MakePath (LocalModelsDir,LocalD3Dir,"data","models",NULL);
ddio_MakePath (LocalSoundsDir,LocalD3Dir,"data","sounds",NULL);
ddio_MakePath (LocalCustomSoundsDir,LocalD3Dir,"custom","sounds",NULL);
ddio_MakePath (LocalCustomGraphicsDir,LocalD3Dir,"custom","graphics",NULL);
ddio_MakePath (LocalRoomsDir,LocalD3Dir,"data","rooms",NULL);
ddio_MakePath (LocalBriefingDir,LocalD3Dir,"data","briefings",NULL);
ddio_MakePath (LocalScriptDir,LocalD3Dir,"data","scripts",NULL);
ddio_MakePath (LocalMiscDir,LocalD3Dir,"data","misc",NULL);
ddio_MakePath (LocalArtDir, LocalD3Dir,"data", "art", NULL);
ddio_MakePath (LocalMusicDir, LocalD3Dir, "data", "music", NULL);
ddio_MakePath (LocalVoiceDir, LocalD3Dir, "data", "voice", NULL);
ddio_MakePath (LocalLevelsDir,LocalD3Dir,"data","levels",NULL);
cf_SetSearchPath (LocalD3Dir, NULL);
#ifdef MACINTOSH
ddio_MakePath (LocalPilotsDir,LocalD3Dir,"pilots",NULL);
cf_SetSearchPath (LocalPilotsDir, "plt", NULL);
#endif
#ifndef RELEASE
cf_SetSearchPath (LocalLevelsDir, NULL);
cf_SetSearchPath (LocalTableDir,NULL); // Local table directory
cf_SetSearchPath (LocalManageGraphicsDir,NULL);
cf_SetSearchPath (LocalModelsDir,NULL);
cf_SetSearchPath (LocalSoundsDir,NULL);
cf_SetSearchPath (LocalRoomsDir,NULL);
cf_SetSearchPath (LocalBriefingDir,NULL);
cf_SetSearchPath (LocalScriptDir,"cpp","dll","def","msg","so","msl","dylib",NULL);
cf_SetSearchPath (LocalMiscDir, NULL);
cf_SetSearchPath (LocalArtDir, NULL);
cf_SetSearchPath (LocalMusicDir, NULL);
cf_SetSearchPath (LocalVoiceDir, NULL);
#endif
if (Network_up)
{
ddio_MakePath (LocalTableFilename,LocalTableDir,LOCAL_TABLE,NULL);
ddio_MakePath (LocalTempTableFilename,LocalTableDir,TEMP_LOCAL_TABLE,NULL);
}
else
{
strcpy (LocalTableFilename,LOCAL_TABLE);
strcpy (LocalTempTableFilename,TEMP_LOCAL_TABLE);
}
return 1;
}
int mng_InitNetTables ()
{
char dir[255];
int dirlen=255;
Database->read("net directory", dir, &dirlen);
if (dir[0]==0)
Error ("D3_DIR environment variable not set.");
strcpy (NetD3Dir,dir);
mprintf ((1,"Net dir:%s\n",NetD3Dir));
ddio_MakePath (NetModelsDir,NetD3Dir,"data","models",NULL);
ddio_MakePath (NetSoundsDir,NetD3Dir,"data","sounds",NULL);
ddio_MakePath (NetRoomsDir,NetD3Dir,"data","rooms",NULL);
ddio_MakePath (NetBriefingDir,NetD3Dir,"data","briefings",NULL);
ddio_MakePath (NetScriptDir,NetD3Dir,"data","scripts",NULL);
ddio_MakePath (NetMiscDir,NetD3Dir,"data","misc",NULL);
ddio_MakePath (ManageGraphicsDir,NetD3Dir,"data","graphics",NULL);
ddio_MakePath (NetTableDir,NetD3Dir,"data","tables",NULL);
ddio_MakePath (NetArtDir,NetD3Dir,"data", "art", NULL);
ddio_MakePath (NetMusicDir, NetD3Dir, "data", "music", NULL);
ddio_MakePath (NetVoiceDir, NetD3Dir, "data", "voice", NULL);
ddio_MakePath (TableLockFilename,NetTableDir,"table.lok",NULL);
ddio_MakePath (BackupLockFilename,NetTableDir,"tablelok.bak",NULL);
ddio_MakePath (BackupTableFilename,NetTableDir,"table.bak",NULL);
ddio_MakePath (TableFilename,NetTableDir,NET_TABLE,NULL);
ddio_MakePath (TempTableLockFilename,NetTableDir,"lock.tmp",NULL);
ddio_MakePath (TempTableFilename,NetTableDir,TEMP_NET_TABLE,NULL);
ddio_MakePath (LockerFile,NetTableDir,"locker",NULL);
ddio_MakePath (VersionFile,NetTableDir,"TableVersion",NULL);
cf_SetSearchPath (ManageGraphicsDir,NULL);
cf_SetSearchPath (NetModelsDir,NULL);
cf_SetSearchPath (NetSoundsDir,NULL);
cf_SetSearchPath (NetRoomsDir,NULL);
cf_SetSearchPath (NetMiscDir,NULL);
cf_SetSearchPath (NetMusicDir, NULL);
cf_SetSearchPath (NetVoiceDir, NULL);
return 1;
}
void mng_CheckToCreateNetTables()
{
CFILE *infile,*outfile;
ASSERT (Stand_alone!=1);
infile=(CFILE *)cfopen (TableFilename,"rb");
if (infile==NULL)
{
if (errno==ENOENT)
{
outfile=(CFILE *)cfopen (TableFilename,"wb");
if (!outfile)
{
mprintf ((0,"Error creating table file! The network must be down...\n"));
Network_up=0;
}
else
{
mng_WriteNewUnknownPage (outfile);
cfclose (outfile);
}
}
else
{
mprintf ((0,"Error creating table file! The network must be down...\n"));
Network_up=0;
}
}
if (infile)
cfclose (infile);
}
// Checks to see if there is a table file...if not, create one with a dummy page
void mng_CheckToCreateLocalTables()
{
CFILE *outfile;
if (!Network_up)
{
strcpy (TableFilename,NET_TABLE);
mprintf((0, "table filename = %s\n", TableFilename));
return;
}
if (!cfexist(LocalTableFilename))
{
outfile=(CFILE *)cfopen (LocalTableFilename,"wb");
if (!outfile)
{
Error("Error creating local table file!");
return;
}
else
{
mng_WriteNewUnknownPage (outfile);
cfclose (outfile);
}
}
}
// Creates directories if needed
void mng_InitLocalDirectories ()
{
char dir[255];
ddio_MakePath (dir,LocalD3Dir,"custom",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"custom","graphics",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"custom","sounds",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"custom","cache",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"custom","settings",NULL);
ddio_CreateDir(dir);
#ifdef MACINTOSH
ddio_MakePath (dir,LocalD3Dir,"pilots",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"demo",NULL);
ddio_CreateDir(dir);
#endif
cf_SetSearchPath (LocalCustomGraphicsDir,NULL);
cf_SetSearchPath (LocalCustomSoundsDir,NULL);
if (Network_up)
{
ddio_MakePath (dir,LocalD3Dir,"data",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","tables",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","graphics",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","sounds",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","rooms",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","levels",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","models",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","briefings",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","scripts",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","misc",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","art",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","music",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,LocalD3Dir,"data","voice",NULL);
ddio_CreateDir(dir);
}
}
void mng_InitNetDirectories ()
{
char dir[255];
if (Stand_alone)
return;
ddio_MakePath (dir,NetD3Dir,"data",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","tables",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","graphics",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","sounds",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","rooms",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","levels",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","models",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","briefings",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","scripts",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","misc",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","art",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","music",NULL);
ddio_CreateDir(dir);
ddio_MakePath (dir,NetD3Dir,"data","voice",NULL);
ddio_CreateDir(dir);
}
extern int TableVersionCurrent();
#if !defined(WIN32)
void mng_BackupTableFile(){}
#else
void mng_BackupTableFile ()
{
char str[200];
Fast_load_trick=0;
if (!TableVersionCurrent())
{
Error ("You must do a source update and recompile. The data on the network is newer that your sourcecode.");
return;
}
ddio_MakePath (str,LocalTableDir,NET_TABLE,NULL);
if (!cfexist(str))
{
TableTimeThreshold.dwHighDateTime=0;
TableTimeThreshold.dwLowDateTime=0;
}
else
{
WIN32_FIND_DATA filedata;
HANDLE filehandle=FindFirstFile (str,&filedata);
if (filehandle==INVALID_HANDLE_VALUE)
{
Error ("Couldn't open net table file for some reason!");
return;
}
TableTimeThreshold=filedata.ftLastWriteTime;
FindClose (filehandle);
}
if (!cfexist(str) || cf_Diff(str,TableFilename)) {
mprintf ((0,"Making local copy of table file.\n"));
if (!cf_CopyFile (str,TableFilename,1))
Error ("There was an error making a backup copy of the table file.\n");
ddio_MakePath (str,LocalTableDir,"tablelok.loc",NULL);
if (!cf_CopyFile (str,TableLockFilename,1))
Error ("There was an error making a backup copy of the locker table file.\n");
}
else
{
mprintf((0,"Local table file same as network copy.\n"));
TableTimeThreshold.dwHighDateTime=-1;
Fast_load_trick=1;
}
}
#endif
void mng_WriteUnknownPage (CFILE *outfile)
{
// Function for writing out "undefined" page...useful for placeholding
cf_WriteByte (outfile,PAGETYPE_UNKNOWN);
}
void mng_WriteNewUnknownPage (CFILE *outfile)
{
// Function for writing out "undefined" page...useful for placeholding
int offset=StartManagePage(outfile,PAGETYPE_UNKNOWN);
EndManagePage (outfile,offset);
}
// Clear out tracklocks
void mng_InitTrackLocks ()
{
for (int i=0;i<MAX_TRACKLOCKS;i++)
{
GlobalTrackLocks[i].used=0;
GlobalTrackLocks[i].pagetype=PAGETYPE_UNKNOWN;
GlobalTrackLocks[i].name[0]=0;
}
}
// Given a name, returns the index of the tracklock with that name
// -1 indicates that it wasn't found
int mng_FindTrackLock (char *name,int pagetype)
{
int i;
for (i=0;i<MAX_TRACKLOCKS;i++)
{
if (GlobalTrackLocks[i].used && GlobalTrackLocks[i].pagetype==pagetype && !stricmp (name,GlobalTrackLocks[i].name))
return i;
}
return -1;
}
// Searches through global array of tracklocks and returns first free one
// Sets the tracklock to be named "name" and its type "pagetype"
// returns -1 if none free
int mng_AllocTrackLock(char *name,int pagetype)
{
int i;
for (i=0;i<MAX_TRACKLOCKS;i++)
if (GlobalTrackLocks[i].used==0)
{
strcpy (GlobalTrackLocks[i].name,name);
GlobalTrackLocks[i].pagetype=pagetype;
GlobalTrackLocks[i].used=1;
mprintf ((0,"Tracklock %s allocated.\n",name));
return i;
}
Error ("Couldn't get a free tracklock!");
return -1;
}
// Frees a tracklock
void mng_FreeTrackLock (int n)
{
mprintf ((0,"Tracklock %s freed.\n",GlobalTrackLocks[n].name));
GlobalTrackLocks[n].pagetype=PAGETYPE_UNKNOWN;
GlobalTrackLocks[n].used=0;
GlobalTrackLocks[n].name[0]=0;
}
// Displays all the network locks of "name"
void mng_DisplayLockList (char *name)
{
mngs_Pagelock list[100];
char temp[200];
int max=100;
int num,i;
int length=0;
char str[5000];
#ifndef RELEASE
// Get the list
if ((num=mng_GetListOfLocks (list,max,name))<0)
{
OutrageMessageBox (MBOX_OK, ErrorString);
return;
}
else if (num==0)
{
OutrageMessageBox (MBOX_OK, "User has no pages locked.");
return;
}
// Make a large string with all the info in it
sprintf (str,"User %s has the following pages locked:\n\n",TableUser);
for (i=0;i<num;i++)
{
sprintf (temp,"%s:%s",PageNames[list[i].pagetype],list[i].name);
strcat (str,temp);
strcat (str,"\n");
length+=strlen(temp);
if (length>5000-100)
break;
}
// Display that string
OutrageMessageBox (MBOX_OK, str);
#endif
}
//Declare these here because it's too big to put on the stack on the Mac
static mngs_texture_page texpage;
static mngs_door_page doorpage;
static mngs_generic_page genericpage;
static mngs_sound_page soundpage;
static mngs_megacell_page megacellpage;
static mngs_ship_page shippage;
static mngs_weapon_page weaponpage;
static mngs_gamefile_page gamefilepage;
// IF YOU ADD ANY NEW PAGETYPE YOU MUST CHANGE THE FUNCTIONS LISTED UNDER THIS LINE
// TO DEAL WITH YOUR PAGE TYPE. IF YOU FORGET, YOU CAN CORRUPT THE PAGEFILE!!!!!
//------------------------------------------------------------------------------
// Given a pagetype, reads it in but discards it. Useful for parsing.
void mng_ReadDummyPage (CFILE *infile,ubyte pagetype)
{
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mng_ReadNewTexturePage (infile,&texpage);
break;
case PAGETYPE_POWERUP:
case PAGETYPE_ROBOT:
Error("Your local table file is invalid. You must update from the network.");
break;
case PAGETYPE_DOOR:
mng_ReadNewDoorPage (infile,&doorpage);
break;
case PAGETYPE_GENERIC:
mng_ReadNewGenericPage (infile,&genericpage);
if (genericpage.objinfo_struct.description!=NULL){
mem_free (genericpage.objinfo_struct.description);
genericpage.objinfo_struct.description = NULL;
}
break;
case PAGETYPE_GAMEFILE:
mng_ReadNewGamefilePage (infile,&gamefilepage);
break;
case PAGETYPE_SOUND:
mng_ReadNewSoundPage (infile,&soundpage);
break;
case PAGETYPE_SHIP:
mng_ReadNewShipPage (infile,&shippage);
break;
case PAGETYPE_WEAPON:
mng_ReadNewWeaponPage (infile,&weaponpage);
break;
case PAGETYPE_MEGACELL:
mng_ReadNewMegacellPage (infile,&megacellpage);
break;
case PAGETYPE_UNKNOWN:
break;
default:
Int3(); // unrecognized pagetype
break;
}
}
// Reads a page in that we don't care about, and writes it right back out
// This is useful for replacing a specific page in a file but ignoring others
void mng_ReadWriteDummyPage (CFILE *infile,CFILE *outfile,ubyte pagetype)
{
switch (pagetype)
{
case PAGETYPE_TEXTURE:
// Read it in, write it out.
mng_ReadNewTexturePage (infile,&texpage);
mng_WriteNewTexturePage (outfile,&texpage);
break;
case PAGETYPE_DOOR:
// Read it in, write it out.
mng_ReadNewDoorPage (infile,&doorpage);
mng_WriteNewDoorPage (outfile,&doorpage);
break;
case PAGETYPE_GENERIC:
// Read it in, write it out.
mng_ReadNewGenericPage (infile,&genericpage);
mng_WriteNewGenericPage (outfile,&genericpage);
if (genericpage.objinfo_struct.description!=NULL)
{
mem_free (genericpage.objinfo_struct.description);
genericpage.objinfo_struct.description = NULL;
}
break;
case PAGETYPE_GAMEFILE:
// Read it in, write it out.
mng_ReadNewGamefilePage (infile,&gamefilepage);
mng_WriteNewGamefilePage (outfile,&gamefilepage);
break;
case PAGETYPE_SOUND:
// Read it in, write it out.
mng_ReadNewSoundPage (infile,&soundpage);
mng_WriteNewSoundPage (outfile,&soundpage);
break;
case PAGETYPE_MEGACELL:
// Read it in, write it out.
mng_ReadNewMegacellPage (infile,&megacellpage);
mng_WriteNewMegacellPage (outfile,&megacellpage);
break;
case PAGETYPE_SHIP:
// Read it in, write it out.
mng_ReadNewShipPage (infile,&shippage);
mng_WriteNewShipPage (outfile,&shippage);
break;
case PAGETYPE_WEAPON:
// Read it in, write it out.
mng_ReadNewWeaponPage (infile,&weaponpage);
mng_WriteNewWeaponPage (outfile,&weaponpage);
break;
case PAGETYPE_UNKNOWN:
mng_WriteNewUnknownPage (outfile);
break;
default:
Int3(); // unrecognized pagetype
break;
}
}
// Renames a page on the network
// This function is called when you rename your object, regardless if you check
// it in
int mng_RenamePage (char *oldname,char *newname,int pagetype)
{
int l,i;
mngs_Pagelock pl;
char oname[PAGENAME_LEN];
mprintf ((0,"Renaming %s to %s...\n",oldname,newname));
strcpy (oname,oldname);
strcpy (pl.name,oname);
pl.pagetype=pagetype;
// Make sure we own it
l=mng_CheckIfPageOwned (&pl,TableUser);
ASSERT (l==1);
strcpy (pl.name,newname);
strcpy (pl.holder,TableUser);
// First, change the name of the network pagelock
l=mng_ReplacePagelock (oname,&pl);
ASSERT (l==1);
switch (pagetype)
{
// Find the page type with this name and rename it
case PAGETYPE_TEXTURE:
i=FindTextureName(oname);
ASSERT (i!=-1);
strcpy (GameTextures[i].name,newname);
l=mng_ReplacePage (oname,GameTextures[i].name,i,PAGETYPE_TEXTURE,0);
ASSERT (l==1);
if (mng_FindTrackLock (oname,PAGETYPE_TEXTURE)!=-1)
mng_ReplacePage (oname,GameTextures[i].name,i,PAGETYPE_TEXTURE,1);
break;
case PAGETYPE_DOOR:
i=FindDoorName(oname);
ASSERT (i!=-1);
strcpy (Doors[i].name,newname);
l=mng_ReplacePage (oname,Doors[i].name,i,PAGETYPE_DOOR,0);
if (mng_FindTrackLock (oname,PAGETYPE_DOOR)!=-1)
mng_ReplacePage (oname,Doors[i].name,i,PAGETYPE_DOOR,1);
ASSERT (l==1);
break;
case PAGETYPE_GENERIC:
i=FindObjectIDName(oname);
ASSERT (i!=-1);
strcpy (Object_info[i].name,newname);
l=mng_ReplacePage (oname,Object_info[i].name,i,PAGETYPE_GENERIC,0);
if (mng_FindTrackLock (oname,PAGETYPE_GENERIC)!=-1)
mng_ReplacePage (oname,Object_info[i].name,i,PAGETYPE_GENERIC,1);
ASSERT (l==1);
break;
case PAGETYPE_GAMEFILE:
i=FindGamefileName(oname);
ASSERT (i!=-1);
strcpy (Gamefiles[i].name,newname);
l=mng_ReplacePage (oname,Gamefiles[i].name,i,PAGETYPE_GAMEFILE,0);
if (mng_FindTrackLock (oname,PAGETYPE_GAMEFILE)!=-1)
mng_ReplacePage (oname,Gamefiles[i].name,i,PAGETYPE_GAMEFILE,1);
ASSERT (l==1);
break;
case PAGETYPE_SOUND:
i=FindSoundName(oname);
ASSERT (i!=-1);
strcpy (Sounds[i].name,newname);
l=mng_ReplacePage (oname,Sounds[i].name,i,PAGETYPE_SOUND,0);
if (mng_FindTrackLock (oname,PAGETYPE_SOUND)!=-1)
mng_ReplacePage (oname,Sounds[i].name,i,PAGETYPE_SOUND,1);
ASSERT (l==1);
break;
case PAGETYPE_MEGACELL:
i=FindMegacellName(oname);
ASSERT (i!=-1);
strcpy (Megacells[i].name,newname);
l=mng_ReplacePage (oname,Megacells[i].name,i,PAGETYPE_MEGACELL,0);
if (mng_FindTrackLock (oname,PAGETYPE_MEGACELL)!=-1)
mng_ReplacePage (oname,Megacells[i].name,i,PAGETYPE_MEGACELL,1);
ASSERT (l==1);
break;
case PAGETYPE_SHIP:
i=FindShipName(oname);
ASSERT (i!=-1);
strcpy (Ships[i].name,newname);
l=mng_ReplacePage (oname,Ships[i].name,i,PAGETYPE_SHIP,0);
if (mng_FindTrackLock (oname,PAGETYPE_SHIP)!=-1)
mng_ReplacePage (oname,Ships[i].name,i,PAGETYPE_SHIP,1);
ASSERT (l==1);
break;
case PAGETYPE_WEAPON:
i=FindWeaponName(oname);
ASSERT (i!=-1);
strcpy (Weapons[i].name,newname);
l=mng_ReplacePage (oname,Weapons[i].name,i,PAGETYPE_WEAPON,0);
if (mng_FindTrackLock (oname,PAGETYPE_WEAPON)!=-1)
mng_ReplacePage (oname,Weapons[i].name,i,PAGETYPE_WEAPON,1);
ASSERT (l==1);
break;
default:
Int3(); // Unknown type, get Jason
break;
}
return 1;
}
#define PROGRESS_PERCENTAGE_THRESHOLD 20
// This is the function that opens the table files and reads in the individual pages
// If you want your data to be in the game, it must hook into this function
int mng_LoadNetPages (int show_progress)
{
CFILE *infile;
ubyte pagetype;
char tablename[TABLE_NAME_LEN];
float start_time;
int n_pages = 0;
int total_bytes;
int current_byte;
float progress;
int int_progress=0;
int len;
mprintf ((0,"Loading pages..."));
if (Dedicated_server)
show_progress=0; // turn off progress meter for dedicated server
// If the network is up we still want to read from the local table because it
// will allow others to start the game at the same time
if (Network_up)
{
int farg=FindArg("-filter");
if (farg)
strcpy (tablename,GameArgs[farg+1]);
else
{
ddio_MakePath (tablename,LocalTableDir,NET_TABLE,NULL);
}
infile=cfopen (tablename,"rb");
}
else
infile=cfopen (TableFilename,"rb");
if (!infile)
{
mprintf ((0,"Couldn't open table file (%s) to read pages!\n",TableFilename));
Error("Cannot open table file <%s>",TableFilename);
return 0;
}
if (show_progress)
{
cfseek (infile,0,SEEK_END);
total_bytes=cftell (infile);
cfseek (infile,0,SEEK_SET);
}
start_time = timer_GetTime();
while (!cfeof(infile))
{
// Read in a pagetype. If its a page we recognize, load it
// mprintf ((0,"."));
if (show_progress)
{
current_byte=cftell (infile);
progress=(float)current_byte/(float)total_bytes;
progress*=PROGRESS_PERCENTAGE_THRESHOLD;
int temp_int_progress=progress;
if (temp_int_progress>int_progress)
{
int_progress=temp_int_progress;
InitMessage (TXT_INITDATA,progress/PROGRESS_PERCENTAGE_THRESHOLD);
}
}
pagetype=cf_ReadByte (infile);
if (!Old_table_method)
len=cf_ReadInt (infile);
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mprintf ((0,"T"));
PrintDedicatedMessage ("T");
mng_LoadNetTexturePage (infile);
break;
case PAGETYPE_POWERUP:
case PAGETYPE_ROBOT:
Error("Your local table file is invalid. You must update from the network.");
break;
case PAGETYPE_DOOR:
mprintf ((0,"D"));
PrintDedicatedMessage ("D");
mng_LoadNetDoorPage (infile);
break;
case PAGETYPE_GENERIC:
mprintf ((0,"G"));
PrintDedicatedMessage ("G");
mng_LoadNetGenericPage (infile);
break;
case PAGETYPE_GAMEFILE:
mprintf ((0,"F"));
PrintDedicatedMessage ("F");
mng_LoadNetGamefilePage (infile);
break;
case PAGETYPE_SOUND:
mprintf ((0,"S"));
PrintDedicatedMessage ("S");
mng_LoadNetSoundPage (infile);
break;
case PAGETYPE_SHIP:
mprintf ((0,"P"));
PrintDedicatedMessage ("P");
mng_LoadNetShipPage (infile);
break;
case PAGETYPE_WEAPON:
mprintf ((0,"W"));
PrintDedicatedMessage ("W");
mng_LoadNetWeaponPage (infile);
break;
case PAGETYPE_MEGACELL:
mprintf ((0,"M"));
PrintDedicatedMessage ("M");
mng_LoadNetMegacellPage (infile);
break;
case PAGETYPE_UNKNOWN:
mprintf ((0,"?"));
break;
default:
Int3(); // Unrecognized pagetype, possible corrupt data following
return 0;
break;
}
n_pages++;
}
mprintf((0,"\n%d pages read in %.1f seconds.\n",n_pages,timer_GetTime()-start_time));
mprintf ((0,"\n"));
PrintDedicatedMessage ((0,"\nPage reading completed.\n"));
cfclose (infile);
// attempt to load extra.gam if found
char name_override[256];
strcpy(name_override,"extra.gam");
infile=cfopen (name_override,"rb");
if(!infile)
return 1;
mprintf((0,"==================================================\n"));
mprintf((0," Loading extra.gam \n"));
mprintf((0,"==================================================\n"));
PrintDedicatedMessage ("\nLoading extra.gam.....\n");
n_pages = 0;
TablefileNameOverride = name_override;
while (!cfeof(infile))
{
pagetype=cf_ReadByte (infile);
len=cf_ReadInt (infile);
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mprintf ((0,"T"));
PrintDedicatedMessage ("T");
mng_LoadNetTexturePage (infile,true);
break;
case PAGETYPE_DOOR:
mprintf ((0,"D"));
PrintDedicatedMessage ("D");
mng_LoadNetDoorPage (infile,true);
break;
case PAGETYPE_GENERIC:
mprintf ((0,"G"));
PrintDedicatedMessage ("G");
mng_LoadNetGenericPage (infile,true);
break;
case PAGETYPE_GAMEFILE:
mprintf ((0,"F"));
PrintDedicatedMessage ("F");
mng_LoadNetGamefilePage (infile,true);
break;
case PAGETYPE_SOUND:
mprintf ((0,"S"));
PrintDedicatedMessage ("S");
mng_LoadNetSoundPage (infile,true);
break;
case PAGETYPE_SHIP:
mprintf ((0,"P"));
PrintDedicatedMessage ("P");
mng_LoadNetShipPage (infile,true);
break;
case PAGETYPE_WEAPON:
mprintf ((0,"W"));
PrintDedicatedMessage ("W");
mng_LoadNetWeaponPage (infile,true);
break;
case PAGETYPE_UNKNOWN:
mprintf ((0,"?"));
break;
default:
Int3(); // Unrecognized pagetype, possible corrupt data following
cfclose(infile);
TablefileNameOverride = NULL;
return 0;
break;
}
n_pages++;
}
mprintf((0,"\n%d extra pages read.\n",n_pages));
TablefileNameOverride = NULL;
cfclose(infile);
return 1;
}
// Loads and allocs all pages found locally
int mng_LoadLocalPages ()
{
CFILE *infile;
ubyte pagetype;
int len;
mprintf ((0,"Overlaying local pages..."));
infile=cfopen (LocalTableFilename,"rb");
if (!infile)
{
mprintf ((0,"Couldn't open local table file (%s) to read pages!\n",LocalTableFilename));
return 1;
}
Loading_locals=1;
while (!cfeof(infile))
{
// Read in a pagetype. If its a page we recognize, load it
pagetype=cf_ReadByte (infile);
if (!Old_table_method)
len=cf_ReadInt (infile);
mprintf ((0,"."));
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mng_LoadLocalTexturePage (infile);
break;
case PAGETYPE_POWERUP:
case PAGETYPE_ROBOT:
Error("Your local table file is invalid. You must update from the network.");
break;
case PAGETYPE_DOOR:
mng_LoadLocalDoorPage (infile);
break;
case PAGETYPE_GENERIC:
mng_LoadLocalGenericPage (infile);
break;
case PAGETYPE_GAMEFILE:
mng_LoadLocalGamefilePage (infile);
break;
case PAGETYPE_SOUND:
mng_LoadLocalSoundPage (infile);
break;
case PAGETYPE_SHIP:
mng_LoadLocalShipPage (infile);
break;
case PAGETYPE_WEAPON:
mng_LoadLocalWeaponPage (infile);
break;
case PAGETYPE_MEGACELL:
mng_LoadLocalMegacellPage (infile);
break;
case PAGETYPE_UNKNOWN:
break;
default:
Int3(); // Unrecognized pagetype, possible corrupt data following
return 0;
break;
}
}
mprintf ((0,"\n"));
cfclose (infile);
Loading_locals=0;
return 1;
}
#define MAX_TRIES 10000
// Removes a file, then renames another file to be the removed file. Get it?
// Returns 1 on success, else 0 on fail
int SwitcherooFiles (char *name,char *tempname)
{
/*// If we're changing the net table file, make a backup first!
if ((!stricmp (name,TableFilename)))
{
cf_CopyFile (BackupTableFilename,TableFilename);
cf_CopyFile (BackupLockFilename,TableLockFilename);
}*/
int num_tries=0;
while (!ddio_DeleteFile (name) && num_tries<MAX_TRIES)
{
Sleep (100);
num_tries++;
}
if (num_tries>=MAX_TRIES)
{
strcpy (ErrorString,"MANAGE:There was a problem deleting the table file.");
ASSERT (0); // GET JASON IMMEDIATELY
Int3();
return (0);
}
num_tries=0;
while ((rename (tempname,name)) && num_tries<=MAX_TRIES)
{
Sleep (100);
num_tries++;
}
if (num_tries>=MAX_TRIES)
{
strcpy (ErrorString,"MANAGE:There was a problem renaming the temp file.");
ASSERT (0); // Get JASON IMMEDIATELY
Int3();
return (0);
}
return 1;
}
void mng_TransferPages ()
{
CFILE *infile,*outfile;
int pagetype;
int num_tracklocks=0;
mprintf ((0,"Transferring pages, please wait...\n"));
if (!mng_MakeLocker())
return;
infile=cfopen (TableFilename,"rb");
if (!infile)
{
mprintf ((0,"Couldn't open table file to transfer!\n"));
Int3();
return;
}
mngs_track_lock *local_tracklocks = (mngs_track_lock *) mem_malloc(sizeof(*local_tracklocks) * 5000);
// Do textures
int done=0;
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
int len=cf_ReadInt (infile);
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mng_ReadNewTexturePage (infile,&texpage);
strcpy (local_tracklocks[num_tracklocks].name,texpage.tex_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_TEXTURE;
num_tracklocks++;
break;
case PAGETYPE_SOUND:
mng_ReadNewSoundPage (infile,&soundpage);
strcpy (local_tracklocks[num_tracklocks].name,soundpage.sound_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_SOUND;
num_tracklocks++;
break;
case PAGETYPE_WEAPON:
mng_ReadNewWeaponPage (infile,&weaponpage);
strcpy (local_tracklocks[num_tracklocks].name,weaponpage.weapon_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_WEAPON;
num_tracklocks++;
break;
case PAGETYPE_GENERIC:
mng_ReadNewGenericPage (infile,&genericpage);
strcpy (local_tracklocks[num_tracklocks].name,genericpage.objinfo_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_GENERIC;
num_tracklocks++;
break;
case PAGETYPE_DOOR:
mng_ReadNewDoorPage (infile,&doorpage);
strcpy (local_tracklocks[num_tracklocks].name,doorpage.door_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_DOOR;
num_tracklocks++;
break;
case PAGETYPE_SHIP:
mng_ReadNewShipPage (infile,&shippage);
strcpy (local_tracklocks[num_tracklocks].name,shippage.ship_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_SHIP;
num_tracklocks++;
break;
case PAGETYPE_GAMEFILE:
mng_ReadNewGamefilePage (infile,&gamefilepage);
strcpy (local_tracklocks[num_tracklocks].name,gamefilepage.gamefile_struct.name);
local_tracklocks[num_tracklocks].pagetype=PAGETYPE_GAMEFILE;
num_tracklocks++;
break;
case PAGETYPE_MEGACELL:
Int3();// huh?
break;
default:
break;
}
}
cfclose (infile);
// Now go through and filter out all unused lock files
infile=(CFILE *)cfopen (TableLockFilename,"rb");
if (!infile)
{
strcpy (ErrorString,"Couldn't open Table lock file!");
goto done;
}
outfile=(CFILE *)cfopen (TempTableLockFilename,"wb");
if (!outfile)
{
cfclose (infile);
strcpy (ErrorString,"Couldn't open temporary table lock file!");
goto done;
}
done=0;
mngs_Pagelock temp_pl;
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
if (mng_ReadPagelock (infile,&temp_pl))
{
int found=-1;
for (int i=0;i<num_tracklocks && found==-1;i++)
{
if (local_tracklocks[i].pagetype==temp_pl.pagetype && !stricmp (local_tracklocks[i].name,temp_pl.name))
{
found=i;
}
}
if (found!=-1)
mng_WritePagelock (outfile,&temp_pl);
else
{
mprintf ((0,"Found unused lock file %s\n",temp_pl.name));
}
}
else done=1;
}
cfclose (infile);
cfclose (outfile);
if (remove (TableLockFilename))
{
sprintf (ErrorString,"There was a problem deleting the temp file - errno %d",errno);
goto done;
}
if (rename (TempTableLockFilename,TableLockFilename))
{
sprintf (ErrorString,"There was a problem renaming the temp file - errno %d",errno);
goto done;
}
mng_EraseLocker();
mprintf ((0,"Done transferring pages...good luck!\n"));
done:;
mem_free(local_tracklocks);
}
//#define DELETING_PAGELOCKS 1
//#define CLEANING_PAGELOCKS 1
// Given a list of names and a pagetype, unlocks the ones already inside the lock file
int mng_UnlockPagelockSeries (char *names[],int *pagetypes,int num);
// Goes through the pagelock table and deletes all duplicate entries
int mng_DeleteDuplicatePagelocks ();
void ReorderPagelocks ()
{
char *names[]={"Lava"};
int types[]={PAGETYPE_SOUND};
if (!mng_MakeLocker())
return;
mng_UnlockPagelockSeries (names,types,1);
//mng_DeleteDuplicatePagelocks ();
mng_EraseLocker();
}
// THIS IS A SPECIAL FUNCTION THAT YOU SHOULD ONLY USE IF YOU KNOW WHAT YOU ARE
// DOING...it simply reorders the table file so that the "primitives" are first.
// This helps in the load time of a table file.
void ReorderPages (int local)
{
CFILE *infile,*outfile;
ubyte pagetype;
int done=0;
int len;
#ifdef CLEANING_PAGELOCKS
mng_TransferPages();
return;
#endif
#ifdef DELETING_PAGELOCKS
ReorderPagelocks ();
return;
#endif
mprintf ((0,"Reordering pages, please wait...\n"));
if (local)
infile=cfopen (LocalTableFilename,"rb");
else
{
if (!mng_MakeLocker())
return;
infile=cfopen (TableFilename,"rb");
}
if (!infile)
{
mprintf ((0,"Couldn't open table file to reorder!\n"));
Int3();
return;
}
if (local)
outfile=cfopen (LocalTempTableFilename,"wb");
else
outfile=cfopen (TempTableFilename,"wb");
if (!outfile)
{
mprintf ((0,"Couldn't open temp table file to reorder!\n"));
cfclose (infile);
Int3();
return;
}
// Do textures
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_TEXTURE)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewTexturePage (infile,&texpage);
mng_WriteNewTexturePage (outfile,&texpage);
}
// Do sounds
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_SOUND)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewSoundPage (infile,&soundpage);
mng_WriteNewSoundPage (outfile,&soundpage);
}
// Do weapons
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_WEAPON)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewWeaponPage (infile,&weaponpage);
// Ignore counter measure weapons
if (!(weaponpage.weapon_struct.flags & WF_SPAWNS_ROBOT))
mng_WriteNewWeaponPage (outfile,&weaponpage);
}
// Do powerup generics
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_GENERIC)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewGenericPage (infile,&genericpage);
if (genericpage.objinfo_struct.type==OBJ_POWERUP)
mng_WriteNewGenericPage (outfile,&genericpage);
if (genericpage.objinfo_struct.description!=NULL)
{
mem_free (genericpage.objinfo_struct.description);
genericpage.objinfo_struct.description = NULL;
}
}
// Do standard generics
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_GENERIC)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewGenericPage (infile,&genericpage);
if (genericpage.objinfo_struct.type!=OBJ_POWERUP)
mng_WriteNewGenericPage (outfile,&genericpage);
if (genericpage.objinfo_struct.description!=NULL)
{
mem_free (genericpage.objinfo_struct.description);
genericpage.objinfo_struct.description = NULL;
}
}
// Do countermeasure weapons
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_WEAPON)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewWeaponPage (infile,&weaponpage);
if ((weaponpage.weapon_struct.flags & WF_SPAWNS_ROBOT))
mng_WriteNewWeaponPage (outfile,&weaponpage);
}
// Do doors
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_DOOR)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewDoorPage (infile,&doorpage);
mng_WriteNewDoorPage (outfile,&doorpage);
}
// Do player ships
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_SHIP)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewShipPage (infile,&shippage);
mng_WriteNewShipPage (outfile,&shippage);
}
// Do gamefiles
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_GAMEFILE)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewGamefilePage (infile,&gamefilepage);
mng_WriteNewGamefilePage (outfile,&gamefilepage);
}
// Do megacells
done=0;
cfseek (infile,0,SEEK_SET);
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt(infile);
// If not a door page, just read it in and ignore it
if (pagetype!=PAGETYPE_MEGACELL)
{
cfseek (infile,len-4,SEEK_CUR);
continue;
}
mng_ReadNewMegacellPage (infile,&megacellpage);
mng_WriteNewMegacellPage (outfile,&megacellpage);
}
cfclose (infile);
cfclose (outfile);
if (local)
{
SwitcherooFiles (LocalTableFilename,LocalTempTableFilename);
}
else
{
SwitcherooFiles (TableFilename,TempTableFilename);
}
mng_EraseLocker();
}
// Returns true if the passed in pagelock is in the LockList, else false
bool InLockList (mngs_Pagelock *pl)
{
if (Starting_editor)
{
for (int i=0;i<Num_locklist;i++)
{
if (LockList[i].pagetype==pl->pagetype)
{
if (!stricmp(LockList[i].name,pl->name))
return true;
}
}
}
else
{
if ((mng_CheckIfPageOwned(pl,TableUser)) > 0) //DAJ -1FIX
return true;
}
return false;
}
// Given a filename, returns the type of primitive it is
int GetPrimType (char *name)
{
char ext[10];
char tname[_MAX_PATH];
int primtype;
ddio_SplitPath(name,tname,tname,ext);
if (!stricmp ("oof",ext))
primtype=PRIMTYPE_OOF;
else if (!stricmp ("ogf",ext))
primtype=PRIMTYPE_OGF;
else if (!stricmp ("oaf",ext))
primtype=PRIMTYPE_OAF;
else if (!stricmp ("wav",ext))
primtype=PRIMTYPE_WAV;
else
primtype=PRIMTYPE_FILE;
return primtype;
}
#if defined(WIN32)
// Builds a list of old files in a path
void BuildOldFilesForDirectory (char *path,FILETIME threshold)
{
HANDLE filehandle;
WIN32_FIND_DATA filedata;
char newpath[MAX_PATH];
ddio_MakePath(newpath,path,"*.*",NULL);
filehandle=FindFirstFile (newpath,&filedata);
bool go_ahead=true;
if (filehandle==INVALID_HANDLE_VALUE)
go_ahead=false;
while (go_ahead)
{
bool add_it=false;
// if this file is newer than the last time we updated, add it to the list
if (filedata.ftLastWriteTime.dwHighDateTime>threshold.dwHighDateTime)
add_it=true;
if (filedata.ftLastWriteTime.dwHighDateTime==threshold.dwHighDateTime)
{
if (filedata.ftLastWriteTime.dwLowDateTime>threshold.dwLowDateTime)
add_it=true;
}
if (filedata.ftCreationTime.dwHighDateTime>threshold.dwHighDateTime)
add_it=true;
if (filedata.ftCreationTime.dwHighDateTime==threshold.dwHighDateTime)
{
if (filedata.ftCreationTime.dwLowDateTime>threshold.dwLowDateTime)
add_it=true;
}
// Add it to the list!
if (add_it)
{
int primtype=GetPrimType (filedata.cFileName);
OldFiles[Num_old_files].type=primtype;
strcpy (OldFiles[Num_old_files].name,filedata.cFileName);
Num_old_files++;
}
go_ahead = (FindNextFile(filehandle,&filedata) != 0);
}
if (filehandle!=INVALID_HANDLE_VALUE)
FindClose (filehandle);
}
// Builds a list of old files so we know which ones to update
// Searches through all our netdirectories for old files
void BuildOldFileList (FILETIME threshold)
{
char str[MAX_PATH];
mprintf ((0,"Building old files list!\n"));
BuildOldFilesForDirectory (NetModelsDir,threshold);
BuildOldFilesForDirectory (NetSoundsDir,threshold);
BuildOldFilesForDirectory (NetMiscDir,threshold);
BuildOldFilesForDirectory (ManageGraphicsDir,threshold);
BuildOldFilesForDirectory (NetArtDir, threshold);
BuildOldFilesForDirectory (NetMusicDir,threshold);
BuildOldFilesForDirectory (NetVoiceDir,threshold);
ddio_MakePath (str,NetD3Dir,"data","levels",NULL);
BuildOldFilesForDirectory (str,threshold);
ddio_MakePath (str,NetD3Dir,"data","briefings",NULL);
BuildOldFilesForDirectory (str,threshold);
ddio_MakePath (str,NetD3Dir,"data","scripts",NULL);
BuildOldFilesForDirectory (str,threshold);
mprintf ((0,"Found %d old files.\n",Num_old_files));
}
#endif
// Returns true if the passed in primitive is old (ie needs to be updated from the network)
bool IsPrimitiveOld (char *name)
{
int primtype=GetPrimType (name);
for (int i=0;i<Num_old_files;i++)
{
if (OldFiles[i].type==primtype && !stricmp (OldFiles[i].name,name))
return true;
}
return false;
}
// Updates a primitive if needed
// Localname = local version of the primname (with path)
// Netname = Network version of the primname (with path)
void UpdatePrimitive (char *localname,char *netname,char *primname,int pagetype,char *pagename)
{
bool update=false;
if (Starting_editor && !Use_old_update_method)
{
if (IsPrimitiveOld (primname))
update=true;
}
else
{
if (!cfexist (localname) || (cfexist(netname) && cf_Diff (localname,netname)))
update=true;
}
if (update)
{
mngs_Pagelock temp_pl;
temp_pl.pagetype=pagetype;
strcpy (temp_pl.name,pagename);
if (!InLockList(&temp_pl))
{
mprintf ((0,"Making a local copy of %s for next time.\n",primname));
if (!cf_CopyFile (localname,netname,1))
{
Int3(); //get Jason
return;
}
}
}
}
//Writes a chunk header. Writes chunk id & placeholder length. Returns chunk start pos
int StartManagePage(CFILE *ofile,ubyte pagetype)
{
int chunk_start_pos;
// Write pagetype
cf_WriteByte (ofile,pagetype);
chunk_start_pos = cftell(ofile);
cf_WriteInt(ofile,0); //placeholder for chunk len
return chunk_start_pos;
}
//Fill in page length when done writing
void EndManagePage(CFILE *ofile,int chunk_start_pos)
{
int save_pos = cftell(ofile);
int len = save_pos-chunk_start_pos;
//seek back to len field and fill in value
cfseek(ofile,chunk_start_pos,SEEK_SET);
cf_WriteInt(ofile,len); //write chunk length
//go back to end of file
cfseek(ofile,save_pos,SEEK_SET);
}
// Assigns a page to its appropriate structure and writes it out
void mng_AssignAndWritePage (int handle,int pagetype,CFILE *outfile)
{
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mng_AssignTextureToTexPage (handle,&texpage);
mng_WriteNewTexturePage (outfile,&texpage);
break;
case PAGETYPE_SOUND:
mng_AssignSoundToSoundPage (handle,&soundpage);
mng_WriteNewSoundPage (outfile,&soundpage);
break;
case PAGETYPE_WEAPON:
mng_AssignWeaponToWeaponPage (handle,&weaponpage);
mng_WriteNewWeaponPage (outfile,&weaponpage);
break;
case PAGETYPE_GENERIC:
mng_AssignObjInfoToGenericPage (handle,&genericpage);
mng_WriteNewGenericPage (outfile,&genericpage);
break;
case PAGETYPE_DOOR:
mng_AssignDoorToDoorPage (handle,&doorpage);
mng_WriteNewDoorPage (outfile,&doorpage);
break;
case PAGETYPE_MEGACELL:
mng_AssignMegacellToMegacellPage (handle,&megacellpage);
mng_WriteNewMegacellPage (outfile,&megacellpage);
break;
case PAGETYPE_SHIP:
mng_AssignShipToShipPage (handle,&shippage);
mng_WriteNewShipPage (outfile,&shippage);
break;
case PAGETYPE_GAMEFILE:
mng_AssignGamefileToGamefilePage (handle,&gamefilepage);
mng_WriteNewGamefilePage (outfile,&gamefilepage);
break;
default:
break;
}
}
#define COPYBUFFER_SIZE 200000
// Given a texture handle, searches the table file and replaces the texture with the same name
// If local=1, then does it to the users local copy
// Returns 0 on error, else 1 if all is good
int mng_ReplacePage (char *srcname,char *destname,int handle,int dest_pagetype,int local)
{
CFILE *infile,*outfile;
ubyte pagetype,replaced=0;
int done=0,len;
mprintf ((0,"Replacing '%s' with '%s' (%s).\n",srcname,destname,local?"locally":"to network"));
if (local)
infile=cfopen (LocalTableFilename,"rb");
else
infile=cfopen (TableFilename,"rb");
if (!infile)
{
mprintf ((0,"Couldn't open table file to replace page %s!\n",srcname));
Int3();
return 0;
}
if (local)
outfile=cfopen (LocalTempTableFilename,"wb");
else
outfile=cfopen (TempTableFilename,"wb");
if (!outfile)
{
mprintf ((0,"Couldn't open temp table file to replace page %s!\n",srcname));
cfclose (infile);
Int3();
return 0;
}
// Allocate memory for copying
ubyte *copybuffer=(ubyte *)mem_malloc (COPYBUFFER_SIZE);
if (!copybuffer)
{
mprintf ((0,"Couldn't allocate memory to replace page %s!\n",srcname));
cfclose (infile);
cfclose (outfile);
Int3();
return 0;
}
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
len=cf_ReadInt (infile);
// If not a texture page, just read it in and write it right back out
if (pagetype!=dest_pagetype)
{
ASSERT (len<COPYBUFFER_SIZE);
cf_ReadBytes(copybuffer, len-4,infile);
cf_WriteByte (outfile,pagetype);
cf_WriteInt (outfile,len);
if (len-4>0)
cf_WriteBytes (copybuffer,len-4,outfile);
continue;
}
switch (pagetype)
{
case PAGETYPE_TEXTURE:
{
mng_ReadNewTexturePage (infile,&texpage);
if (!stricmp(srcname,texpage.tex_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewTexturePage (outfile,&texpage);
}
break;
}
case PAGETYPE_SOUND:
{
mng_ReadNewSoundPage (infile,&soundpage);
if (!stricmp(srcname,soundpage.sound_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewSoundPage (outfile,&soundpage);
}
break;
}
case PAGETYPE_WEAPON:
{
mng_ReadNewWeaponPage (infile,&weaponpage);
if (!stricmp(srcname,weaponpage.weapon_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewWeaponPage (outfile,&weaponpage);
}
break;
}
case PAGETYPE_GENERIC:
{
mng_ReadNewGenericPage (infile,&genericpage);
if (!stricmp(srcname,genericpage.objinfo_struct.name))
{
// This is the page we want to replace, so write the new one out.
if (genericpage.objinfo_struct.description!=NULL)
{
mem_free (genericpage.objinfo_struct.description);
genericpage.objinfo_struct.description = NULL;
}
genericpage.objinfo_struct.icon_name[0] = '\0';
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewGenericPage (outfile,&genericpage);
}
break;
}
case PAGETYPE_DOOR:
{
mng_ReadNewDoorPage (infile,&doorpage);
if (!stricmp(srcname,doorpage.door_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewDoorPage (outfile,&doorpage);
}
break;
}
case PAGETYPE_MEGACELL:
{
mng_ReadNewMegacellPage (infile,&megacellpage);
if (!stricmp(srcname,megacellpage.megacell_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewMegacellPage (outfile,&megacellpage);
}
break;
}
case PAGETYPE_SHIP:
{
mng_ReadNewShipPage (infile,&shippage);
if (!stricmp(srcname,shippage.ship_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewShipPage (outfile,&shippage);
}
break;
}
case PAGETYPE_GAMEFILE:
{
mng_ReadNewGamefilePage (infile,&gamefilepage);
if (!stricmp(srcname,gamefilepage.gamefile_struct.name))
{
mng_AssignAndWritePage (handle,pagetype,outfile);
replaced=1;
}
else
{
mng_WriteNewGamefilePage (outfile,&gamefilepage);
}
break;
}
default:
break;
}
}
if (!replaced)
{
// This is a new page, so append it to the end of file.
mng_AssignAndWritePage (handle,dest_pagetype,outfile);
}
if (replaced)
mprintf ((0,"Page replaced.\n"));
else
mprintf ((0,"New page added.\n"));
cfclose (infile);
cfclose (outfile);
mem_free (copybuffer);
if (local)
{
if (!SwitcherooFiles (LocalTableFilename,LocalTempTableFilename))
return 0;
}
else
{
if (!SwitcherooFiles (TableFilename,TempTableFilename))
return 0;
}
return 1; // successful!
}
// Given a texture name, finds it in the table file and deletes it
// If local is 1, deletes from the local table file
int mng_DeletePage (char *name,int dest_pagetype,int local)
{
CFILE *infile,*outfile;
ubyte pagetype,replaced=0;
int done=0;
int deleted=0;
mprintf ((0,"Deleting %s (%s).\n",name,local?"locally":"on network"));
if (local)
infile=cfopen (LocalTableFilename,"rb");
else
infile=cfopen (TableFilename,"rb");
if (!infile)
{
mprintf ((0,"Couldn't open table file to delete page!\n"));
Int3();
return 0;
}
if (local)
outfile=cfopen (LocalTempTableFilename,"wb");
else
outfile=cfopen (TempTableFilename,"wb");
if (!outfile)
{
mprintf ((0,"Couldn't open temp table file to delete page!\n"));
cfclose (infile);
Int3();
return 0;
}
// Allocate memory for copying
ubyte *copybuffer=(ubyte *)mem_malloc (COPYBUFFER_SIZE);
if (!copybuffer)
{
mprintf ((0,"Couldn't allocate memory to delete page!\n"));
cfclose (infile);
cfclose (outfile);
Int3();
return 0;
}
while (!done)
{
if (cfeof (infile))
{
done=1;
continue;
}
pagetype=cf_ReadByte (infile);
int len=cf_ReadInt (infile);
if (pagetype!=dest_pagetype)
{
ASSERT (len<COPYBUFFER_SIZE);
cf_ReadBytes(copybuffer, len-4,infile);
cf_WriteByte (outfile,pagetype);
cf_WriteInt (outfile,len);
if (len-4>0)
cf_WriteBytes (copybuffer,len-4,outfile);
continue;
}
switch (pagetype)
{
case PAGETYPE_TEXTURE:
{
mng_ReadNewTexturePage (infile,&texpage);
if (stricmp(name,texpage.tex_struct.name))
mng_WriteNewTexturePage (outfile,&texpage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
case PAGETYPE_DOOR:
{
mng_ReadNewDoorPage (infile,&doorpage);
if (stricmp(name,doorpage.door_struct.name))
mng_WriteNewDoorPage (outfile,&doorpage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
case PAGETYPE_GENERIC:
{
mng_ReadNewGenericPage (infile,&genericpage);
if (stricmp(name,genericpage.objinfo_struct.name))
mng_WriteNewGenericPage (outfile,&genericpage);
else
deleted=1; // Don't write out the one we want to delete
if (genericpage.objinfo_struct.description!=NULL)
{
mem_free (genericpage.objinfo_struct.description);
genericpage.objinfo_struct.description = NULL;
}
genericpage.objinfo_struct.icon_name[0] = '\0';
break;
}
case PAGETYPE_SOUND:
{
mng_ReadNewSoundPage (infile,&soundpage);
if (stricmp(name,soundpage.sound_struct.name))
mng_WriteNewSoundPage (outfile,&soundpage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
case PAGETYPE_SHIP:
{
mng_ReadNewShipPage (infile,&shippage);
if (stricmp(name,shippage.ship_struct.name))
mng_WriteNewShipPage (outfile,&shippage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
case PAGETYPE_WEAPON:
{
mng_ReadNewWeaponPage (infile,&weaponpage);
if (stricmp(name,weaponpage.weapon_struct.name))
mng_WriteNewWeaponPage (outfile,&weaponpage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
case PAGETYPE_MEGACELL:
{
mng_ReadNewMegacellPage (infile,&megacellpage);
if (stricmp(name,megacellpage.megacell_struct.name))
mng_WriteNewMegacellPage (outfile,&megacellpage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
case PAGETYPE_GAMEFILE:
{
mng_ReadNewGamefilePage (infile,&gamefilepage);
if (stricmp(name,gamefilepage.gamefile_struct.name))
mng_WriteNewGamefilePage (outfile,&gamefilepage);
else
deleted=1; // Don't write out the one we want to delete
break;
}
default:
break;
}
}
if (!local)
{
// It's gotta be there if on the network
ASSERT (deleted==1);
}
else
{
if (!deleted)
{
mprintf ((0,"Not found locally?!\n"));
}
}
cfclose (infile);
cfclose (outfile);
mem_free (copybuffer);
// Now, remove our table file and rename the temp file to be the table file
if (local)
{
if (!SwitcherooFiles (LocalTableFilename,LocalTempTableFilename))
return 0;
}
else
{
if (!SwitcherooFiles (TableFilename,TempTableFilename))
return 0;
}
return 1; // successful!
}
// Reads in a physics chunk from an open file
void mng_ReadPhysicsChunk (physics_info *phys_info,CFILE *infile)
{
phys_info->mass=cf_ReadFloat (infile);
phys_info->drag=cf_ReadFloat (infile);
phys_info->full_thrust=cf_ReadFloat (infile);
phys_info->flags=cf_ReadInt (infile);
phys_info->rotdrag=cf_ReadFloat (infile);
phys_info->full_rotthrust=cf_ReadFloat (infile);
phys_info->num_bounces=cf_ReadInt (infile);
phys_info->velocity.z=cf_ReadFloat (infile);
phys_info->rotvel.x=cf_ReadFloat (infile);
phys_info->rotvel.y=cf_ReadFloat (infile);
phys_info->rotvel.z=cf_ReadFloat (infile);
phys_info->wiggle_amplitude=cf_ReadFloat (infile);
phys_info->wiggles_per_sec=cf_ReadFloat (infile);
phys_info->coeff_restitution=cf_ReadFloat (infile);
phys_info->hit_die_dot=cf_ReadFloat (infile);
phys_info->max_turnroll_rate=cf_ReadFloat (infile);
phys_info->turnroll_ratio=cf_ReadFloat (infile);
}
// Writes out a physics chunk to an open file
void mng_WritePhysicsChunk (physics_info *phys_info,CFILE *outfile)
{
cf_WriteFloat (outfile,phys_info->mass);
cf_WriteFloat (outfile,phys_info->drag);
cf_WriteFloat (outfile,phys_info->full_thrust);
cf_WriteInt (outfile,phys_info->flags);
cf_WriteFloat (outfile,phys_info->rotdrag);
cf_WriteFloat (outfile,phys_info->full_rotthrust);
cf_WriteInt (outfile,phys_info->num_bounces);
cf_WriteFloat (outfile,phys_info->velocity.z);
cf_WriteFloat (outfile,phys_info->rotvel.x);
cf_WriteFloat (outfile,phys_info->rotvel.y);
cf_WriteFloat (outfile,phys_info->rotvel.z);
cf_WriteFloat (outfile,phys_info->wiggle_amplitude);
cf_WriteFloat (outfile,phys_info->wiggles_per_sec);
cf_WriteFloat (outfile,phys_info->coeff_restitution);
cf_WriteFloat (outfile,phys_info->hit_die_dot);
cf_WriteFloat (outfile,phys_info->max_turnroll_rate);
cf_WriteFloat (outfile,phys_info->turnroll_ratio);
}
// Writes out weapon battery info
void mng_WriteWeaponBatteryChunk (otype_wb_info *static_wb,CFILE *outfile)
{
int j;
cf_WriteFloat(outfile, static_wb->energy_usage);
cf_WriteFloat(outfile, static_wb->ammo_usage);
for(j = 0; j < MAX_WB_GUNPOINTS; j++)
{
cf_WriteShort(outfile, static_wb->gp_weapon_index[j]);
}
for(j = 0; j < MAX_WB_FIRING_MASKS; j++)
{
cf_WriteByte(outfile, static_wb->gp_fire_masks[j]);
cf_WriteFloat(outfile, static_wb->gp_fire_wait[j]);
cf_WriteFloat(outfile, static_wb->anim_time[j]);
cf_WriteFloat(outfile, static_wb->anim_start_frame[j]);
cf_WriteFloat(outfile, static_wb->anim_fire_frame[j]);
cf_WriteFloat(outfile, static_wb->anim_end_frame[j]);
}
cf_WriteByte(outfile, static_wb->num_masks);
cf_WriteShort(outfile, static_wb->aiming_gp_index);
cf_WriteByte(outfile, static_wb->aiming_flags);
cf_WriteFloat(outfile, static_wb->aiming_3d_dot);
cf_WriteFloat(outfile, static_wb->aiming_3d_dist);
cf_WriteFloat(outfile, static_wb->aiming_XZ_dot);
cf_WriteShort(outfile, static_wb->flags);
cf_WriteByte(outfile, static_wb->gp_quad_fire_mask);
}
// Reads in weapon battery info
void mng_ReadWeaponBatteryChunk (otype_wb_info *static_wb,CFILE *infile,int version)
{
int j;
static_wb->energy_usage=cf_ReadFloat(infile);
static_wb->ammo_usage=cf_ReadFloat(infile);
for(j = 0; j < MAX_WB_GUNPOINTS; j++)
{
static_wb->gp_weapon_index[j]=cf_ReadShort(infile);
}
for(j = 0; j < MAX_WB_FIRING_MASKS; j++)
{
static_wb->gp_fire_masks[j]=cf_ReadByte(infile);
static_wb->gp_fire_wait[j]=cf_ReadFloat(infile);
static_wb->anim_time[j]=cf_ReadFloat (infile);
static_wb->anim_start_frame[j]=cf_ReadFloat (infile);
static_wb->anim_fire_frame[j]=cf_ReadFloat (infile);
static_wb->anim_end_frame[j]=cf_ReadFloat (infile);
}
static_wb->num_masks=cf_ReadByte (infile);
static_wb->aiming_gp_index=cf_ReadShort(infile);
static_wb->aiming_flags=cf_ReadByte(infile);
static_wb->aiming_3d_dot=cf_ReadFloat(infile);
static_wb->aiming_3d_dist=cf_ReadFloat(infile);
static_wb->aiming_XZ_dot=cf_ReadFloat(infile);
if (version>=2)
static_wb->flags=cf_ReadShort(infile);
else
static_wb->flags=cf_ReadByte(infile);
static_wb->gp_quad_fire_mask=cf_ReadByte(infile);
}
// Writes a lighting chunk in from an open file
void mng_WriteLightingChunk ( light_info *lighting_info,CFILE *outfile)
{
cf_WriteFloat (outfile,lighting_info->light_distance);
cf_WriteFloat (outfile,lighting_info->red_light1);
cf_WriteFloat (outfile,lighting_info->green_light1);
cf_WriteFloat (outfile,lighting_info->blue_light1);
cf_WriteFloat (outfile,lighting_info->time_interval);
cf_WriteFloat (outfile,lighting_info->flicker_distance);
cf_WriteFloat (outfile,lighting_info->directional_dot);
cf_WriteFloat (outfile,lighting_info->red_light2);
cf_WriteFloat (outfile,lighting_info->green_light2);
cf_WriteFloat (outfile,lighting_info->blue_light2);
cf_WriteInt (outfile,lighting_info->flags);
cf_WriteInt (outfile,lighting_info->timebits);
cf_WriteByte (outfile,lighting_info->angle);
cf_WriteByte (outfile,lighting_info->lighting_render_type);
}
// Reads a lighting chunk in from an open file
void mng_ReadLightingChunk (light_info *lighting_info,CFILE *infile)
{
lighting_info->light_distance=cf_ReadFloat (infile);
lighting_info->red_light1=cf_ReadFloat (infile);
lighting_info->green_light1=cf_ReadFloat (infile);
lighting_info->blue_light1=cf_ReadFloat (infile);
lighting_info->time_interval=cf_ReadFloat (infile);
lighting_info->flicker_distance=cf_ReadFloat (infile);
lighting_info->directional_dot=cf_ReadFloat (infile);
lighting_info->red_light2=cf_ReadFloat (infile);
lighting_info->green_light2=cf_ReadFloat (infile);
lighting_info->blue_light2=cf_ReadFloat (infile);
lighting_info->flags=cf_ReadInt (infile);
lighting_info->timebits=cf_ReadInt (infile);
lighting_info->angle=cf_ReadByte (infile);
lighting_info->lighting_render_type=cf_ReadByte (infile);
}
// Record keeping
AddOnTablefile AddOnDataTables[MAX_ADDON_TABLES];
// the number of addon tables currently in memory
int Num_addon_tables=0;
// if not -1, then it is the addon table we are working with
int Loading_addon_table=-1;
//----------------------
// Add-on data routines
//----------------------
// Frees all the primitives associated with an page
void mng_FreePagetypePrimitives (int pagetype,char *name,int freetype)
{
int n;
switch (pagetype)
{
case PAGETYPE_TEXTURE:
n=FindTextureName (name);
ASSERT (n>=0);
if (GameTextures[n].flags & TF_ANIMATED)
FreeVClip(GameTextures[n].bm_handle);
else
bm_FreeBitmap (GameTextures[n].bm_handle);
if (GameTextures[n].flags & TF_DESTROYABLE && GameTextures[n].destroy_handle>=0 && GameTextures[n].destroy_handle!=n)
{
int oldn=n;
n=GameTextures[n].destroy_handle;
if (GameTextures[n].flags & TF_ANIMATED)
FreeVClip(GameTextures[n].bm_handle);
else
bm_FreeBitmap (GameTextures[n].bm_handle);
n=oldn;
}
if (freetype)
FreeTexture(n);
break;
case PAGETYPE_SOUND:
n=FindSoundName (name);
ASSERT (n>=0);
FreeSoundFile (Sounds[n].sample_index);
if (freetype)
FreeSound (n);
break;
case PAGETYPE_WEAPON:
n=FindWeaponName (name);
ASSERT (n>=0);
// Free weapon images
if (Weapons[n].flags & WF_HUD_ANIMATED)
FreeVClip(Weapons[n].hud_image_handle);
else
bm_FreeBitmap (Weapons[n].hud_image_handle);
if (Weapons[n].fire_image_handle!=-1)
{
if (Weapons[n].flags & WF_IMAGE_BITMAP)
bm_FreeBitmap (Weapons[n].fire_image_handle);
else if (Weapons[n].flags & WF_IMAGE_VCLIP)
FreeVClip (Weapons[n].fire_image_handle);
else
FreePolyModel(Weapons[n].fire_image_handle);
}
if (freetype)
FreeWeapon (n);
break;
case PAGETYPE_SHIP:
n=FindShipName (name);
ASSERT (n>=0);
FreePolyModel (Ships[n].model_handle);
if (Ships[n].dying_model_handle!=-1)
FreePolyModel (Ships[n].dying_model_handle);
if (Ships[n].med_render_handle!=-1)
FreePolyModel (Ships[n].med_render_handle);
if (Ships[n].lo_render_handle!=-1)
FreePolyModel (Ships[n].lo_render_handle);
if (freetype)
FreeShip (n);
break;
case PAGETYPE_GENERIC:
n=FindObjectIDName (name);
ASSERT (n>=0);
FreePolyModel (Object_info[n].render_handle);
if (Object_info[n].med_render_handle!=-1)
FreePolyModel (Object_info[n].med_render_handle);
if (Object_info[n].lo_render_handle!=-1)
FreePolyModel (Object_info[n].lo_render_handle);
if (freetype)
FreeObjectID(n);
break;
case PAGETYPE_DOOR:
n=FindDoorName (name);
ASSERT (n>=0);
FreePolyModel (Doors[n].model_handle);
if (freetype)
FreeDoor (n);
break;
default:
break;
}
}
// Takes our addon pages and frees/restores our data to the appropriate pages
void mng_PopAddonPages()
{
int i,n,ok;
ASSERT(Num_addon_tables>0);
if(Num_addon_tables<=0)
return; //no addon pages to pop off
Num_addon_tables--;
Loading_locals=0;
AddOnTablefile *addondata = &AddOnDataTables[Num_addon_tables];
for (i=0;i<addondata->Num_addon_tracklocks;i++)
{
mprintf ((0,"Freeing addon page %s [%s].\n",addondata->Addon_tracklocks[i].name,addondata->AddOnTableFilename));
// set the Loading_addon_table to the appropriate value...
// it depends on if we are overlaying from a previous tablefile
// or this isn't an overlay at all
// overlay = 0 (not an overlay of anything)
// overlay = 1 (overlay of main tablefile)
// overlay > 1 (overlay of addon table [overlay-2])
if(addondata->Addon_tracklocks[i].overlay>1)
{
// this is an overlay of another table file
Loading_addon_table=addondata->Addon_tracklocks[i].overlay-2;
}else
{
// this is an overlay of the main table file
// or not an overlay at all
Loading_addon_table=-1;
}
if (addondata->Addon_tracklocks[i].overlay>0)
{
// Free this data, then read the old stuff back in
mng_FreePagetypePrimitives (addondata->Addon_tracklocks[i].pagetype,addondata->Addon_tracklocks[i].name,0);
char *name=addondata->Addon_tracklocks[i].name;
switch (addondata->Addon_tracklocks[i].pagetype)
{
case PAGETYPE_TEXTURE:
{
n=FindTextureName (name);
ASSERT (n>=0);
ok=mng_FindSpecificTexPage (name,&texpage,addondata->Addon_tracklocks[i].stack_filepos);
if (ok)
{
ok=mng_AssignTexPageToTexture (&texpage,n);
if (!ok)
Error ("Error 1 restoring page %s from addon data!",name);
}
else
Error ("Error 2 restoring page %s from addon data!",name);
break;
}
case PAGETYPE_SOUND:
{
n=FindSoundName (name);
ASSERT (n>=0);
ok=mng_FindSpecificSoundPage (name,&soundpage,addondata->Addon_tracklocks[i].stack_filepos);
if (ok)
{
ok=mng_AssignSoundPageToSound (&soundpage,n);
if (!ok)
Error ("Error 1 restoring page %s from addon data!",name);
}
else
Error ("Error 2 restoring page %s from addon data!",name);
break;
}
case PAGETYPE_DOOR:
{
n=FindDoorName (name);
ASSERT (n>=0);
ok=mng_FindSpecificDoorPage (name,&doorpage,addondata->Addon_tracklocks[i].stack_filepos);
if (ok)
{
ok=mng_AssignDoorPageToDoor (&doorpage,n);
if (!ok)
Error ("Error 1 restoring page %s from addon data!",name);
}
else
Error ("Error 2 restoring page %s from addon data!",name);
break;
}
case PAGETYPE_GENERIC:
{
n=FindObjectIDName (name);
ASSERT (n>=0);
ok=mng_FindSpecificGenericPage (name,&genericpage,addondata->Addon_tracklocks[i].stack_filepos);
if (ok)
{
ok=mng_AssignGenericPageToObjInfo (&genericpage,n);
if (!ok)
Error ("Error 1 restoring page %s from addon data!",name);
}
else
Error ("Error 2 restoring page %s from addon data!",name);
break;
}
case PAGETYPE_SHIP:
{
n=FindShipName (name);
ASSERT (n>=0);
ok=mng_FindSpecificShipPage (name,&shippage,addondata->Addon_tracklocks[i].stack_filepos);
if (ok)
{
ok=mng_AssignShipPageToShip (&shippage,n);
if (!ok)
Error ("Error 1 restoring page %s from addon data!",name);
}
else
Error ("Error 2 restoring page %s from addon data!",name);
break;
}
case PAGETYPE_WEAPON:
{
n=FindWeaponName (name);
ASSERT (n>=0);
ok=mng_FindSpecificWeaponPage (name,&weaponpage,addondata->Addon_tracklocks[i].stack_filepos);
if (ok)
{
ok=mng_AssignWeaponPageToWeapon (&weaponpage,n);
if (!ok)
Error ("Error 1 restoring page %s from addon data!",name);
}
else
Error ("Error 2 restoring page %s from addon data!",name);
break;
}
case PAGETYPE_GAMEFILE:
//I don't think there's anything we need to do here
break;
default:
Int3(); // bad type in list? Get Jason
break;
}
}
else
{
// Not overlay, just free this data
mng_FreePagetypePrimitives (addondata->Addon_tracklocks[i].pagetype,addondata->Addon_tracklocks[i].name,1);
}
}
Loading_addon_table=-1;
}
// Simply sets no addon data to be loaded
void mng_ClearAddonTables ()
{
int count = Num_addon_tables;
while(count>0)
{
ASSERT(count==Num_addon_tables);
if(AddOnDataTables[count-1].Addon_tracklocks)
{
mng_PopAddonPages();
mem_free (AddOnDataTables[count-1].Addon_tracklocks);
AddOnDataTables[count-1].Addon_tracklocks = NULL;
AddOnDataTables[count-1].Num_addon_tracklocks = 0;
}
count--;
}
}
// Push the given table file as an addon table file
// returns true on success
bool mng_SetAddonTable(char *name)
{
ASSERT(Num_addon_tables<MAX_ADDON_TABLES);
if(Num_addon_tables>=MAX_ADDON_TABLES)
return false;
//make sure the table file exists!
if(!cfexist(name))
return false;
strcpy(AddOnDataTables[Num_addon_tables].AddOnTableFilename,name);
AddOnDataTables[Num_addon_tables].Addon_tracklocks=(mngs_track_lock *)mem_malloc (MAX_ADDON_TRACKLOCKS*sizeof(mngs_track_lock));
AddOnDataTables[Num_addon_tables].Num_addon_tracklocks = 0;
ASSERT (AddOnDataTables[Num_addon_tables].Addon_tracklocks);
memset(AddOnDataTables[Num_addon_tables].Addon_tracklocks,0,MAX_ADDON_TRACKLOCKS*sizeof(mngs_track_lock));
Num_addon_tables++;
return true;
}
// Pushes an addon pack onto the stack so we can keep track of it
void mng_PushAddonPage (int pagetype,char *name,int overlay)
{
ASSERT(Loading_addon_table>=0 && Loading_addon_table<MAX_ADDON_TABLES);
AddOnTablefile *addon = &AddOnDataTables[Loading_addon_table];
ASSERT (addon->Num_addon_tracklocks<MAX_ADDON_TRACKLOCKS);
// First check to see if this is a redundant page
for (int i=0;i<addon->Num_addon_tracklocks;i++)
{
if (addon->Addon_tracklocks[i].used && addon->Addon_tracklocks[i].pagetype==pagetype)
{
if (!stricmp (addon->Addon_tracklocks[i].name,name))
{
Int3();
Error ("Redundant addon page '%s' loaded...",name);
return;
}
}
}
mprintf ((0,"Adding addon page %s [%s] to list.\n",name,addon->AddOnTableFilename));
addon->Addon_tracklocks[addon->Num_addon_tracklocks].used=1;
addon->Addon_tracklocks[addon->Num_addon_tracklocks].pagetype=pagetype;
addon->Addon_tracklocks[addon->Num_addon_tracklocks].overlay=overlay;
addon->Addon_tracklocks[addon->Num_addon_tracklocks].stack_filepos = 0;
strcpy (addon->Addon_tracklocks[addon->Num_addon_tracklocks].name,name);
addon->Num_addon_tracklocks++;
}
// Compiles the addon pages. By looking at all the addon pages (after they have been
// loaded) and does some compiling and saving of information to speed up addon page
// freeing
void mng_CompileAddonPages(void)
{
if(Num_addon_tables<=0)
return; //no addon pages to pop off
int curr_tablefile,i,tf,pagetype,len,next_pos,page_pos;
CFILE *file;
char pagename[256];
bool found_page;
for(curr_tablefile=1;curr_tablefile<=Num_addon_tables;curr_tablefile++)
{
// find all the pages that are loaded from this tablefile
// overlay = 0 (not from any tablefile)
// overlay = 1 (from main tablefile)
// overlay > 1 (from addontable[overlay-2]
if(curr_tablefile==1)
{
file = cfopen(TableFilename,"rb");
mprintf((0,"Compiling addon pages of %s\n",TableFilename));
}
else
{
file = cfopen(AddOnDataTables[curr_tablefile-2].AddOnTableFilename,"rb");
mprintf((0,"Compiling addon pages of %s\n",AddOnDataTables[curr_tablefile-2].AddOnTableFilename));
}
ASSERT(file!=NULL);
// start reading the pages from this tablefile
// as we come across each page, check to see if it was
// ever overlayed.
while(!cfeof(file))
{
// Read in a pagetype. If its a page we recognize, load it
page_pos = cftell(file);
pagetype=cf_ReadByte (file);
len=cf_ReadInt (file);
next_pos = (page_pos + 1) + len;
// get the name of the page
switch (pagetype)
{
case PAGETYPE_TEXTURE:
cf_ReadShort(file);//version
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_DOOR:
cf_ReadShort(file);//version
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_GENERIC:
cf_ReadShort(file);//version
cf_ReadByte(file);//type
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_GAMEFILE:
cf_ReadShort(file);//version
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_SOUND:
cf_ReadShort(file);//version
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_SHIP:
cf_ReadShort(file);//version
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_WEAPON:
cf_ReadShort(file);//version
cf_ReadString(pagename,PAGENAME_LEN,file);
break;
case PAGETYPE_UNKNOWN:
continue;
break;
default:
Int3(); // Unrecognized pagetype, possible corrupt data following
break;
}
// now look for all the places where this page is overlayed
found_page = false;
for(tf=0;tf<Num_addon_tables;tf++)
{
for(i=0;i<AddOnDataTables[tf].Num_addon_tracklocks;i++)
{
if(!AddOnDataTables[tf].Addon_tracklocks[i].used)
continue;
if(AddOnDataTables[tf].Addon_tracklocks[i].overlay!=curr_tablefile)
continue;
if(AddOnDataTables[tf].Addon_tracklocks[i].pagetype!=pagetype)
continue;
if(stricmp(pagename,AddOnDataTables[tf].Addon_tracklocks[i].name))
continue;
// this is it!
mprintf((0,"***Compiling: %s[%s] to %d\n",AddOnDataTables[tf].Addon_tracklocks[i].name,
(curr_tablefile==1)?TableFilename:AddOnDataTables[curr_tablefile-2].AddOnTableFilename,page_pos));
ASSERT(AddOnDataTables[tf].Addon_tracklocks[i].stack_filepos==0);
AddOnDataTables[tf].Addon_tracklocks[i].stack_filepos = page_pos;
found_page = true;
break;
}
if(found_page)
break;
}
// move on to the next page
cfseek(file,next_pos,SEEK_SET);
}
// done with this tablefile
cfclose(file);
}
}
//Error checking variables
bool Loading_addon = false;
int Data_error_count = 0;
FILE *Data_error_file = NULL;
char *Addon_filename;
// Loads and allocs all pages found locally
void mng_LoadAddonPages ()
{
CFILE *infile;
ubyte pagetype;
int len;
//Set flag & Clear error count
Loading_addon = true;
Data_error_count = 0;
if (Num_addon_tables==0)
return; // No addons to load
Loading_locals=0;
int c;
AddOnTablefile *addon;
for(c=0;c<Num_addon_tables;c++)
{
addon = &AddOnDataTables[c];
mprintf ((0,"------------------------------------\nLoading addon pages for %s....\n",addon->AddOnTableFilename));
Addon_filename = addon->AddOnTableFilename;
infile=cfopen (addon->AddOnTableFilename,"rb");
if (!infile)
{
mprintf ((0,"Couldn't addon table file (%s) to read pages!\n",addon->AddOnTableFilename));
return;
}
Loading_addon_table=c;
while (!cfeof(infile))
{
// Read in a pagetype. If its a page we recognize, load it
pagetype=cf_ReadByte (infile);
len=cf_ReadInt (infile);
mprintf ((0,"."));
switch (pagetype)
{
case PAGETYPE_TEXTURE:
mng_LoadLocalTexturePage (infile);
break;
case PAGETYPE_POWERUP:
case PAGETYPE_ROBOT:
Error("Your local table file is invalid. You must update from the network.");
break;
case PAGETYPE_DOOR:
mng_LoadLocalDoorPage (infile);
break;
case PAGETYPE_GENERIC:
mng_LoadLocalGenericPage (infile);
break;
case PAGETYPE_GAMEFILE:
mng_LoadLocalGamefilePage (infile);
break;
case PAGETYPE_SOUND:
mng_LoadLocalSoundPage (infile);
break;
case PAGETYPE_SHIP:
mng_LoadLocalShipPage (infile);
break;
case PAGETYPE_WEAPON:
mng_LoadLocalWeaponPage (infile);
break;
case PAGETYPE_MEGACELL:
mng_LoadLocalMegacellPage (infile);
break;
case PAGETYPE_UNKNOWN:
break;
default:
Int3(); // Unrecognized pagetype, possible corrupt data following
break;
}
}
mprintf ((0,"------------------------------------\n"));
cfclose (infile);
}
Loading_locals=0;
Loading_addon_table=-1;
mng_CompileAddonPages();
//Close error file
if (Data_error_file != NULL) {
fprintf(Data_error_file,"\nTotal errors: %d",Data_error_count);
fclose(Data_error_file);
}
//Clear flag
Loading_addon = false;
}
/*
#define MAX_256s 200
int Num_256s=0;
char Texture256Names[MAX_256s][80];
void Read256TextureNames ()
{
int n=FindArg ("-File256");
if (!n)
return;
CFILE *infile;
infile=(CFILE *)cfopen (GameArgs[n+1],"rt");
if (!infile)
{
mprintf ((0,"Couldn't open 256 file!\n"));
return;
}
char curline[200];
int done=0;
while (!done)
{
if (cfeof(infile))
{
done=1;
continue;
}
// Read a line and parse it
cf_ReadString (curline,200,infile);
if (curline[0]==';' || curline[1]==';' || curline[0]==' ' || curline[1]==' ')
continue;
if (!(isalnum(curline[0])))
continue;
strcpy (Texture256Names[Num_256s],curline);
Num_256s++;
}
cfclose (infile);
}*/
#include "pstring.h"
void DataError(char *fmt,...)
{
//Got a data error!
// Int3();
//Ignore this if not loading add-on data
if (! Loading_addon)
return;
//Increment error count
Data_error_count++;
//Write to file if switch specified
if (FindArg("-datacheck")) {
static char last_filename[_MAX_PATH];
va_list arglist;
char buf[1024];
va_start(arglist,fmt);
Pvsprintf(buf,sizeof(buf),fmt,arglist);
va_end(arglist);
//Open file if not already open
if (Data_error_file == NULL) {
Data_error_file = fopen("datacheck.out","wt");
if (Data_error_file == NULL)
return;
last_filename[0] = 0;
}
//If this is a new addon file, print the name
if (strcmp(last_filename,Addon_filename)) {
if (last_filename[0])
fprintf(Data_error_file,"\n\n");
fprintf(Data_error_file,"Errors in addon file <%s>:\n\n",Addon_filename);
strcpy(last_filename,Addon_filename);
}
//Print the message
fprintf(Data_error_file," ");
fprintf(Data_error_file,"%s",buf);
}
}