1136 lines
No EOL
34 KiB
C++
1136 lines
No EOL
34 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** Confidential - Westwood Studios ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : Commando *
|
|
* *
|
|
* $Archive:: /Commando/Code/Commando/init.cpp $*
|
|
* *
|
|
* $Author:: Steve_t $*
|
|
* *
|
|
* $Modtime:: 10/16/02 11:10a $*
|
|
* *
|
|
* $Revision:: 258 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* Commando_Assert_Handler -- Commando callback function for WWASSERT's *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "init.h"
|
|
#include "debug.h"
|
|
#include "wwmath.h"
|
|
#include "ww3d.h"
|
|
#include "wwphys.h"
|
|
#include "WWAudio.H"
|
|
#include "wwsaveload.h"
|
|
#include "input.h"
|
|
#include "inputconfigmgr.h"
|
|
//#include "gamesettings.h"
|
|
#include "ffactory.h"
|
|
#include "assets.h"
|
|
#include "_globals.h"
|
|
#include "combatgmode.h" // gamemode
|
|
#include "langmode.h" // gamemode
|
|
#include "wolgmode.h" // gamemode
|
|
#include "movie.h" // gamemode
|
|
#include "gamemenu.h" // gamemode
|
|
#include "overlay.h" // gamemode
|
|
#include "multihud.h" // gamemode
|
|
#include "console.h" // gamemode
|
|
#include "textdisplay.h" // gamemode
|
|
#include "scorescreen.h" // gamemode
|
|
#include "msgloop.h"
|
|
#include "Resource.H"
|
|
#include "miscutil.h"
|
|
#include "cnetwork.h"
|
|
#include "mathutil.h"
|
|
#include "win.h"
|
|
#include "Part_Ldr.H"
|
|
#include "savegame.H"
|
|
#include "systemsettings.h"
|
|
#include "gamedata.h"
|
|
#include "sphereobj.h"
|
|
#include "ringobj.h"
|
|
#include "diagnostics.h"
|
|
#include "devoptions.h"
|
|
#include "translatedb.h"
|
|
#include "useroptions.h"
|
|
#include "pathmgr.h"
|
|
#include "string_ids.h"
|
|
#include "soundrobj.h"
|
|
#include "crandom.h"
|
|
#include "systimer.h"
|
|
#include "renegadedialogmgr.h"
|
|
#include "campaign.h"
|
|
#include "diaglog.h"
|
|
#include "mpsettingsmgr.h"
|
|
#include "mixfile.h"
|
|
#include "ffactorylist.h"
|
|
#include "gameinitmgr.h"
|
|
#include "serverfps.h"
|
|
#include "nicenum.h"
|
|
#include "encyclopediamgr.h"
|
|
#include "texturethumbnail.h"
|
|
#include "playermanager.h"
|
|
#include "teammanager.h"
|
|
#include "stackdump.h"
|
|
#include "registry.h"
|
|
#include "bandwidthgraph.h"
|
|
#include "buildnum.h"
|
|
#include "dx8wrapper.h"
|
|
#include "autostart.h"
|
|
#include "except.h"
|
|
#include "wwmemlog.h"
|
|
#include "except.h"
|
|
#include "consolemode.h"
|
|
#include "serversettings.h"
|
|
#include "pscene.h"
|
|
#include "dazzle.h"
|
|
#include "skinpackagemgr.h"
|
|
#include "modpackagemgr.h"
|
|
#include "GameSpy_QnR.h"
|
|
#include "gamespyadmin.h"
|
|
#include "shutdown.h"
|
|
#include "specialbuilds.h"
|
|
|
|
extern const char *VALUE_NAME_TEXTURE_FILTER_MODE;
|
|
|
|
/*
|
|
** Define IMMEDIATE_LOAD if you want to have the game start right
|
|
** up in a given level (for profiling for example)
|
|
*/
|
|
|
|
// HACK: ATI demo loads the demo level bypassing the mainmenu
|
|
#ifdef ATI_DEMO_HACK
|
|
#define IMMEDIATE_LOAD 1
|
|
#define IMMEDIATE_LOAD_LEVELNAME "MDD_0807.mix"
|
|
#else
|
|
#define IMMEDIATE_LOAD 0
|
|
#define IMMEDIATE_LOAD_LEVELNAME "MDD_0803.mix"
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
** This defines the subdirectory where the game will load all data from
|
|
*/
|
|
const char * DATA_SUBDIRECTORY = "DATA\\";
|
|
const char * SAVE_SUBDIRECTORY = "DATA\\SAVE\\";
|
|
const char * CONFIG_SUBDIRECTORY = "DATA\\CONFIG\\";
|
|
const char * MOVIES_SUBDIRECTORY = "DATA\\MOVIES\\";
|
|
|
|
|
|
#define STRINGS_FILENAME "STRINGS.TDB"
|
|
#define CONV_DB_FILENAME "CONV10.CDB"
|
|
|
|
/*
|
|
** DebugDisplayHandler
|
|
*/
|
|
TextDebugDisplayHandlerClass TextDisplayHandler;
|
|
|
|
/*
|
|
** Used to modify where game entries are kept in the registry.
|
|
*/
|
|
extern char DefaultRegistryModifier[1024];
|
|
|
|
/*
|
|
** Static global lod settings for particles
|
|
*/
|
|
static const float _ParticleLODScreenSizes[17] =
|
|
{
|
|
0.0025f,
|
|
0.0050f,
|
|
0.0075f,
|
|
0.0100f,
|
|
0.0300f,
|
|
0.0500f,
|
|
0.0700f,
|
|
0.0900f,
|
|
0.1000f,
|
|
0.3000f,
|
|
0.5000f,
|
|
1.0000f,
|
|
1.2500f,
|
|
1.5000f,
|
|
1.7500f,
|
|
2.0000f,
|
|
NO_MAX_SCREEN_SIZE
|
|
};
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Append_To_Assert_History -- keeps a timestamped history of asserts. *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 9/26/2001 tss : Created. *
|
|
*=============================================================================================*/
|
|
void Append_To_Assert_History(const char * message)
|
|
{
|
|
if (message == NULL) {
|
|
//
|
|
// bail
|
|
//
|
|
return;
|
|
}
|
|
|
|
FILE * file = ::fopen("_asserts.txt", "at");
|
|
if (file == NULL) {
|
|
return;
|
|
}
|
|
|
|
char line[2000] = "";
|
|
|
|
//
|
|
// Blank lines plus timestamp
|
|
//
|
|
::sprintf(line, "\n\nWhen: %s\n", cMiscUtil::Get_Text_Time());
|
|
::fwrite(line, 1, ::strlen(line), file);
|
|
|
|
//
|
|
// version #
|
|
//
|
|
::sprintf(line, "Version: %d\n", DebugManager::Get_Version_Number());
|
|
::fwrite(line, 1, ::strlen(line), file);
|
|
|
|
//
|
|
// Full filename
|
|
//
|
|
char full_filename[MAX_PATH];
|
|
::GetModuleFileName(NULL, full_filename, sizeof(full_filename));
|
|
::sprintf(line, "Filename: %s\n", full_filename);
|
|
::fwrite(line, 1, ::strlen(line), file);
|
|
|
|
//
|
|
// File size
|
|
//
|
|
HANDLE hfile = ::CreateFile(full_filename, 0, 0, NULL, OPEN_EXISTING, 0L, NULL);
|
|
if (hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD file_size = ::GetFileSize(hfile, NULL);
|
|
::CloseHandle(hfile);
|
|
::sprintf(line, "Filesize: %d\n", file_size);
|
|
::fwrite(line, 1, ::strlen(line), file);
|
|
}
|
|
|
|
//
|
|
// The assert message itself
|
|
//
|
|
::sprintf(line, "Assert: %s\n", message);
|
|
::fwrite(line, 1, ::strlen(line), file);
|
|
|
|
::fclose(file);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Commando_Assert_Handler -- Commando callback function for WWASSERT's *
|
|
* *
|
|
* INPUT: *
|
|
* *
|
|
* OUTPUT: *
|
|
* *
|
|
* WARNINGS: *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/28/2000 gth : Created. *
|
|
*=============================================================================================*/
|
|
void Commando_Assert_Handler(const char * message)
|
|
{
|
|
if (message == NULL) {
|
|
//
|
|
// bail
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// TSS092601
|
|
//
|
|
Append_To_Assert_History(message);
|
|
|
|
//
|
|
// If the exception handler is try to quit the game then don't show an assert.
|
|
//
|
|
if (Is_Trying_To_Exit()) {
|
|
ExitProcess(0);
|
|
}
|
|
|
|
//
|
|
// Hand the message off to the scrolling debug screen
|
|
//
|
|
DebugManager::Display( message );
|
|
|
|
//
|
|
//
|
|
// IF YOU WANT TO DISABLE CERTAIN ACTIONS HERE, USE
|
|
// THE REGISTRY SWITCHES!!!!!!!!!!!!!
|
|
//
|
|
//
|
|
#ifdef WWDEBUG
|
|
Copy_Logs(DebugManager::Get_Version_Number());
|
|
#endif // WWDEBUG
|
|
RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG );
|
|
if ( registry.Is_Valid() ) {
|
|
registry.Set_Int( VALUE_NAME_APPLICATION_CRASH_VERSION, 0 );
|
|
|
|
}
|
|
|
|
#ifdef WWDEBUG
|
|
|
|
if (cDevOptions::SoundEffectOnAssert.Is_True() &&
|
|
WWAudioClass::Get_Instance() != NULL) {
|
|
//
|
|
// Sound effect
|
|
//
|
|
WWAudioClass::Get_Instance()->Create_Instant_Sound("Debug_Assertion", Matrix3D(1));
|
|
}
|
|
|
|
if (cDevOptions::DisplayLogfileOnAssert.Is_True()) {
|
|
//
|
|
// Open up the logfile so that the user can see the assert
|
|
// at the bottom.
|
|
//
|
|
cNetwork::Shell_Command(DebugManager::Logfile_Name());
|
|
}
|
|
|
|
//LOG_CALL_STACK;
|
|
|
|
if (cDevOptions::BreakToDebuggerOnAssert.Is_True()) {
|
|
|
|
if (cDevOptions::ShutdownInputOnAssert.Is_True()) {
|
|
//
|
|
// This input shutdown is to help those of us who still have the
|
|
// DirectInput / debugger problem. For some of us the registry fix
|
|
// doesn't help.
|
|
//
|
|
Input::Shutdown();
|
|
}
|
|
/*
|
|
|
|
m
|
|
$m mm m
|
|
"$mmmmm m$" mmmmmmm$"
|
|
"""$m m$ m$""""""
|
|
mmmmmmm$$$$$$$$$"mmmm
|
|
mmm$$$$$$$$$$$$$$$$$$ m$$$$m " m "
|
|
$$$$$$$$$$$$$$$$$$$$$$ $$$$$$"$$$
|
|
mmmmmmmmmmmmmmmmmmmmm $$$$$$$$$$
|
|
$$$$$$$$$$$$$$$$$$$$$ $$$$$$$""" m
|
|
"$$$$$$$$$$$$$$$$$$$$$ $$$$$$ " "
|
|
"""""""$$$$$$$$$$$m """"
|
|
mmmmmmmm" m$ "$mmmmm
|
|
$$"""""" "$ """"""$$
|
|
m$" "m "
|
|
*/
|
|
|
|
_asm int 0x03;
|
|
}
|
|
|
|
if (cDevOptions::ExitThreadOnAssert.Is_True()) {
|
|
ExitThread(1);
|
|
}
|
|
|
|
#endif // WWDEBUG
|
|
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void _stdcall AudioTextCallback(AudibleSoundClass *sound_obj, const StringClass &text, uint32 user_param)
|
|
{
|
|
Vector3 red = Vector3( 1, 0.5f, 0.5f );
|
|
StringClass str;
|
|
str.Format( "%s\n", (const char *)text );
|
|
DebugManager::Display_Text( str, red );
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
class LoggingFileFactoryClass : public SimpleFileFactoryClass {
|
|
public:
|
|
virtual FileClass * Get_File( const char * filename ) {
|
|
FileClass * file = BaseFactory->Get_File( filename );
|
|
Debug_Say(( "FILE_LOG : %s %s\n", filename, ((file==NULL||!file->Is_Available())?"MISSING":"") ));
|
|
return file;
|
|
}
|
|
void Set_Base_Factory( FileFactoryClass * factory ) { BaseFactory = factory; }
|
|
private:
|
|
FileFactoryClass * BaseFactory;
|
|
};
|
|
|
|
/*
|
|
**
|
|
*/
|
|
class StrippingFileFactoryClass : public SimpleFileFactoryClass {
|
|
public:
|
|
virtual FileClass * Get_File( const char * filename ) {
|
|
StringClass stripped(true);
|
|
Strip_Path_From_Filename( stripped, filename );
|
|
return BaseFactory->Get_File( stripped );
|
|
}
|
|
void Set_Base_Factory( FileFactoryClass * factory ) { BaseFactory = factory; }
|
|
private:
|
|
FileFactoryClass * BaseFactory;
|
|
};
|
|
|
|
/*
|
|
**
|
|
*/
|
|
SimpleFileFactoryClass RenegadeWritingFileFactory;
|
|
|
|
SimpleFileFactoryClass RenegadeBaseFileFactory;
|
|
MixFileFactoryClass * AlwaysMixFileFactory;
|
|
FileFactoryListClass _RenegadeFileFactory;
|
|
StrippingFileFactoryClass AudioFileFactory;
|
|
LoggingFileFactoryClass LoggingFileFactory;
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Construct_Directory_Structure(void)
|
|
{
|
|
//
|
|
// Lookup the path of the executable
|
|
//
|
|
char path[MAX_PATH] = { 0 };
|
|
::GetModuleFileName (NULL, path, sizeof (path));
|
|
|
|
//
|
|
// Strip off the filename
|
|
//
|
|
char *filename = ::strrchr (path, '\\');
|
|
if (filename != NULL) {
|
|
filename[1] = 0;
|
|
}
|
|
|
|
StringClass data_dir(path,true);
|
|
data_dir += "data";
|
|
|
|
StringClass save_dir(data_dir + "\\save",true);
|
|
StringClass config_dir(data_dir + "\\config",true);
|
|
|
|
//
|
|
// Create the data directory if necessary
|
|
//
|
|
if (GetFileAttributes (data_dir) == 0xFFFFFFFF) {
|
|
::CreateDirectory (data_dir, NULL);
|
|
}
|
|
|
|
//
|
|
// Create the save directory if necessary
|
|
//
|
|
if (GetFileAttributes (save_dir) == 0xFFFFFFFF) {
|
|
::CreateDirectory (save_dir, NULL);
|
|
}
|
|
|
|
//
|
|
// Create the config directory if necessary
|
|
//
|
|
if (GetFileAttributes (config_dir) == 0xFFFFFFFF) {
|
|
::CreateDirectory (config_dir, NULL);
|
|
}
|
|
|
|
|
|
return ;
|
|
}
|
|
|
|
static bool Verify_Log_Directory(const StringClass& folder)
|
|
{
|
|
if (GetFileAttributes(folder)!=0xffffffff) return true;
|
|
//HANDLE file;
|
|
//file = CreateFile(folder, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
//if (file!=INVALID_HANDLE_VALUE) {
|
|
// CloseHandle(file);
|
|
// return true;
|
|
//}
|
|
|
|
if (CreateDirectory(folder,NULL)) {
|
|
return true;
|
|
}
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
return(true);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool Create_Log_File_Name(const StringClass& folder, StringClass& filename,bool use_numbering)
|
|
{
|
|
StringClass original(filename);
|
|
if (!use_numbering) {
|
|
filename.Format("%s\\%s",folder,original);
|
|
return true;
|
|
}
|
|
for (int i=0;i<999;++i) {
|
|
HANDLE file;
|
|
filename.Format("%s\\%3.3d%s",folder,i,original);
|
|
file = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (file!=INVALID_HANDLE_VALUE) {
|
|
CloseHandle(file);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void Copy_Log(const StringClass& folder,const char* filename,bool use_numbering)
|
|
{
|
|
RawFileClass raw_log_file(filename);
|
|
if (raw_log_file.Is_Available()) {
|
|
int size=raw_log_file.Size();
|
|
if (size) {
|
|
StringClass log_file_name(filename);
|
|
if (Create_Log_File_Name(folder,log_file_name,use_numbering)) {
|
|
DWORD written;
|
|
HANDLE file;
|
|
file = CreateFile(log_file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE != file) {
|
|
raw_log_file.Open();
|
|
unsigned char* memory=new unsigned char[size];
|
|
raw_log_file.Read(memory,size);
|
|
raw_log_file.Close();
|
|
WriteFile(file, memory, size, &written, NULL);
|
|
delete[] memory;
|
|
CloseHandle(file);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static class CopyThreadClass : public ThreadClass
|
|
{
|
|
public:
|
|
unsigned Version;
|
|
|
|
CopyThreadClass()
|
|
:
|
|
Version(0),
|
|
ThreadClass("LogCopyThread", &Exception_Handler) {}
|
|
|
|
void Thread_Function()
|
|
{
|
|
// Write log to network folder
|
|
|
|
char computer_name[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD size = sizeof(computer_name);
|
|
::GetComputerName(computer_name, &size);
|
|
|
|
RegistryClass reg(APPLICATION_SUB_KEY_NAME_DEBUG);
|
|
char path[MAX_PATH];
|
|
reg.Get_String("LogPath", path, sizeof(path), "\\\\tanya\\game\\projects\\renegade\\_error_logs");
|
|
strcat(path, "\\");
|
|
|
|
StringClass folder_name(0,true);
|
|
folder_name.Format("%s%d.%d",path,Version>>16,Version&0xffff);
|
|
if (!Verify_Log_Directory(folder_name)) return;
|
|
folder_name+="\\";
|
|
folder_name+=computer_name;
|
|
if (!Verify_Log_Directory(folder_name)) return;
|
|
|
|
Copy_Log(folder_name,DebugManager::Logfile_Name(),true); //"_logfile.txt",true);
|
|
Copy_Log(folder_name,"_asserts.txt",true);
|
|
Copy_Log(folder_name,"_except.txt",true);
|
|
Copy_Log(folder_name,"sysinfo.txt",false);
|
|
}
|
|
} CopyThread;
|
|
|
|
void Copy_Logs(unsigned version)
|
|
{
|
|
RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG );
|
|
if ( registry.Is_Valid() ) {
|
|
if (registry.Get_Int( VALUE_NAME_DISABLE_LOG_COPYING,0 )) return;
|
|
}
|
|
|
|
if (CopyThread.Is_Running()) return;
|
|
CopyThread.Version=version;
|
|
CopyThread.Execute();
|
|
|
|
int time=TIMEGETTIME();
|
|
while (TIMEGETTIME()-time<5000) {
|
|
if (!CopyThread.Is_Running()) {
|
|
break;
|
|
}
|
|
Sleep(100);
|
|
}
|
|
}
|
|
|
|
void Application_Exception_Callback(void)
|
|
{
|
|
#ifdef WWDEBUG
|
|
Copy_Logs(DebugManager::Get_Version_Number());
|
|
#endif // WWDEBUG
|
|
RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG );
|
|
if ( registry.Is_Valid() ) {
|
|
registry.Set_Int( VALUE_NAME_APPLICATION_CRASH_VERSION, 0 );
|
|
}
|
|
}
|
|
|
|
bool RestartNeeded = true;
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Get_Version_Number -- Collate version information. *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: Ptr to var to fill with major version number *
|
|
* Ptr to var to fill with minor version number *
|
|
* *
|
|
* *
|
|
* OUTPUT: Nothing *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 12/3/2001 11:26PM ST : Created *
|
|
*=============================================================================================*/
|
|
void Get_Version_Number(unsigned long *major, unsigned long *minor)
|
|
{
|
|
// Version info removed per Legal review requirements. LFeenanEA - 8th February 2025
|
|
|
|
unsigned long version_major = 0;
|
|
unsigned long version_minor = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
**
|
|
*/
|
|
#if 0
|
|
#define FIRST_CHAR 'a'
|
|
#define LAST_CHAR 'z'
|
|
|
|
#include "realcrc.h"
|
|
int CRC_Next( unsigned char ** p, int length )
|
|
{
|
|
int ret = 0;
|
|
if ( length == -1 ) {
|
|
return 1;
|
|
}
|
|
if ( **p == LAST_CHAR ) {
|
|
*p = *p-1;
|
|
ret |= CRC_Next( p, length-1 );
|
|
*p = *p+1;
|
|
**p = FIRST_CHAR;
|
|
} else {
|
|
**p = **p+1;
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
void CRC_Check( void )
|
|
{
|
|
Debug_Say(( "CRC_Check\n" ));
|
|
int count = 0;
|
|
|
|
#define MAX_STRING 10
|
|
#define GOAL_CRC 65729409
|
|
|
|
int start = timeGetTime();
|
|
|
|
unsigned char string[MAX_STRING+1];
|
|
for ( int length = 1; length <= MAX_STRING; length++ )
|
|
{
|
|
unsigned char * p = &string[length-1];
|
|
string[length] = 0;
|
|
for ( int i = 0; i < length; i++ ) {
|
|
string[i] = FIRST_CHAR;
|
|
}
|
|
|
|
while ( 1 ) {
|
|
/* if ( (count & 0x0FFFF) == 0 ) {
|
|
Debug_Say(( "Checking %d \"%s\"\n", count, string ));
|
|
}*/
|
|
int crc = CRC_String( (char *)string );
|
|
if ( crc == GOAL_CRC ) {
|
|
Debug_Say(( "CRC MATCH \"%s\" (count %d) at %d\n\n", string, count, timeGetTime()-start ));
|
|
}
|
|
count++;
|
|
if ( CRC_Next( &p, length-1 ) != 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
Debug_Say(( "End length %d (count %d) at %d\n", length, count, timeGetTime()-start ));
|
|
}
|
|
|
|
// strcpy( string, "miketheheadlesschickenisgod" );
|
|
// Debug_Say(( "CRC %d\n", crc ));
|
|
return;
|
|
}
|
|
#endif
|
|
/*
|
|
**
|
|
*/
|
|
bool Game_Init(void)
|
|
{
|
|
WWMEMLOG(MEM_GAMEINIT);
|
|
|
|
// Set registry key to 1 for the duration of the init. This way we know if the program crashed while the init.
|
|
RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG );
|
|
if ( registry.Is_Valid() ) {
|
|
registry.Set_Int( VALUE_NAME_GAME_INITIALIZATION_IN_PROGRESS, 1 );
|
|
unsigned crash_version=registry.Get_Int( VALUE_NAME_APPLICATION_CRASH_VERSION, 0 );
|
|
#ifdef WWDEBUG
|
|
if (crash_version) Copy_Logs(crash_version);
|
|
#endif // WWDEBUG
|
|
registry.Set_Int( VALUE_NAME_APPLICATION_CRASH_VERSION, 0 );
|
|
}
|
|
|
|
//
|
|
// Ensure our directory structure exists
|
|
//
|
|
Construct_Directory_Structure ();
|
|
|
|
//
|
|
// Initialize our debugging framework
|
|
//
|
|
DebugManager::Init();
|
|
DebugManager::Load_Registry_Settings( APPLICATION_SUB_KEY_NAME_DEBUG );
|
|
WWDebug_Install_Assert_Handler(Commando_Assert_Handler);
|
|
BuildInfoClass::Log_Build_Info();
|
|
|
|
//CRC_Check();
|
|
|
|
Get_Version_Number(NULL, NULL);
|
|
|
|
// setup Writing Factory
|
|
RenegadeWritingFileFactory.Set_Sub_Directory( DATA_SUBDIRECTORY );
|
|
_TheWritingFileFactory = &RenegadeWritingFileFactory;
|
|
|
|
RenegadeBaseFileFactory.Set_Sub_Directory( DATA_SUBDIRECTORY );
|
|
RenegadeBaseFileFactory.Append_Sub_Directory( SAVE_SUBDIRECTORY );
|
|
RenegadeBaseFileFactory.Append_Sub_Directory( CONFIG_SUBDIRECTORY );
|
|
|
|
_TheSimpleFileFactory->Set_Sub_Directory( DATA_SUBDIRECTORY );
|
|
_TheSimpleFileFactory->Append_Sub_Directory( SAVE_SUBDIRECTORY );
|
|
_TheSimpleFileFactory->Append_Sub_Directory( CONFIG_SUBDIRECTORY );
|
|
|
|
_TheSimpleFileFactory->Set_Strip_Path( true );
|
|
|
|
_RenegadeFileFactory.Add_FileFactory( &RenegadeBaseFileFactory, "" );
|
|
_RenegadeFileFactory.Add_FileFactory( new MixFileFactoryClass( "Always2.dat", &RenegadeBaseFileFactory ), "Always2.dat" );
|
|
_RenegadeFileFactory.Add_FileFactory( new MixFileFactoryClass( "Always.dbs", &RenegadeBaseFileFactory ), "Always.dbs" );
|
|
_RenegadeFileFactory.Add_FileFactory( new MixFileFactoryClass( "Always.dat", &RenegadeBaseFileFactory ), "Always.dat" );
|
|
|
|
//
|
|
// Search for all mix files in the data directory
|
|
//
|
|
WIN32_FIND_DATA find_info = { 0 };
|
|
BOOL keep_going = TRUE;
|
|
HANDLE file_find = NULL;
|
|
for (file_find = ::FindFirstFile ("data\\*.mix", &find_info);
|
|
(file_find != INVALID_HANDLE_VALUE) && keep_going;
|
|
keep_going = ::FindNextFile (file_find, &find_info))
|
|
{
|
|
//
|
|
// Add this mix file to our mix file factory list
|
|
//
|
|
_RenegadeFileFactory.Add_FileFactory( new MixFileFactoryClass (find_info.cFileName, &RenegadeBaseFileFactory ), find_info.cFileName );
|
|
}
|
|
|
|
//
|
|
// Close the search handle
|
|
//
|
|
if (file_find != INVALID_HANDLE_VALUE) {
|
|
::FindClose (file_find);
|
|
}
|
|
|
|
_TheFileFactory = &_RenegadeFileFactory;
|
|
|
|
// Logging File Factory
|
|
if ( DebugManager::Is_File_Logging_Enabled() ) {
|
|
LoggingFileFactory.Set_Base_Factory( &_RenegadeFileFactory );
|
|
_TheFileFactory = &LoggingFileFactory;
|
|
}
|
|
|
|
AudioFileFactory.Set_Base_Factory( _TheFileFactory );
|
|
|
|
//Setup_Mix_File();
|
|
|
|
// Lets seed the Random Generator, a little
|
|
int count = TIMEGETTIME() & 0xFF;
|
|
while ( count-- > 0 ) {
|
|
FreeRandom.Get_Int();
|
|
}
|
|
|
|
// Thumbnail manager pre init will ensure that thumbnail database
|
|
// is up-to-date.
|
|
bool show_thumbnail_pre_init_dialog = true;
|
|
#ifdef WWDEBUG
|
|
show_thumbnail_pre_init_dialog = cDevOptions::ShowThumbnailPreInitDialog.Get();
|
|
#endif // WWDEBUG
|
|
// ThumbnailManagerClass::Pre_Init(show_thumbnail_pre_init_dialog);
|
|
|
|
//
|
|
// Create an instance of the sound library
|
|
//
|
|
new WWAudioClass(ConsoleBox.Is_Exclusive());
|
|
WWAudioClass::Get_Instance()->Initialize( APPLICATION_SUB_KEY_NAME_SOUND );
|
|
WWAudioClass::Get_Instance()->Set_File_Factory( &AudioFileFactory );
|
|
// Install text callback
|
|
WWAudioClass::Get_Instance()->Register_Text_Callback(AudioTextCallback,0);
|
|
|
|
//
|
|
// Load the multiplayer settings
|
|
//
|
|
MPSettingsMgrClass::Load_Settings ();
|
|
|
|
/*
|
|
**
|
|
*/
|
|
WW3DAssetManager * asset_manager = new WW3DAssetManager;
|
|
// asset_manager->Open_Texture_File_Cache("cache_");
|
|
asset_manager->Set_WW3D_Load_On_Demand( true );
|
|
asset_manager->Register_Prototype_Loader(&_ParticleEmitterLoader);
|
|
asset_manager->Register_Prototype_Loader(&_SphereLoader);
|
|
asset_manager->Register_Prototype_Loader(&_RingLoader);
|
|
asset_manager->Register_Prototype_Loader (&_SoundRenderObjLoader);
|
|
asset_manager->Set_Activate_Fog_On_Load (true);
|
|
|
|
//GameSettings::Init();
|
|
|
|
// Initialize WWMath
|
|
WWMath::Init();
|
|
|
|
// Initialize the pathfind system
|
|
PathMgrClass::Initialize ();
|
|
|
|
// Initialize WW3D
|
|
switch ( WW3D::Init(MainWindow, NULL, ConsoleBox.Is_Exclusive() ? true : false)) {
|
|
case WW3D_ERROR_OK: // Success!
|
|
break;
|
|
case WW3D_ERROR_DIRECTX8_INITIALIZATION_FAILED:
|
|
default:
|
|
WWDEBUG_SAY(("WW3D::Init Failed!\r\n"));
|
|
::MessageBox(NULL,
|
|
"DirectX 8.0 or later is required to play C&C:Renegade.",
|
|
"Renegade Graphics Initialization Error.",
|
|
MB_OK);
|
|
return false;
|
|
}
|
|
|
|
if (ConsoleBox.Is_Exclusive()) {
|
|
WW3D::Enable_Decals(false);
|
|
PhysicsSceneClass * scene = PhysicsSceneClass::Get_Instance();
|
|
scene->Set_Max_Simultaneous_Shadows(0);
|
|
DazzleRenderObjClass::Enable_Dazzle_Rendering(false);
|
|
} else {
|
|
if ( WW3D::Registry_Load_Render_Device( APPLICATION_SUB_KEY_NAME_RENDER, true ) != WW3D_ERROR_OK ) {
|
|
WWDEBUG_SAY(("WW3D::Registry_Load_Render_Device Failed!\r\n"));
|
|
return false;
|
|
}
|
|
|
|
if ( WW3D::Registry_Save_Render_Device( APPLICATION_SUB_KEY_NAME_RENDER ) != WW3D_ERROR_OK ) {
|
|
WWDEBUG_SAY(("WW3D::Registry_Save_Render_Device Failed!\r\n"));
|
|
return false;
|
|
}
|
|
WW3D::Enable_Static_Sort_Lists (true);
|
|
}
|
|
if (AutoRestart.Get_Restart_Flag() || ServerSettingsClass::Is_Command_Line_Mode() || ConsoleBox.Is_Exclusive()) {
|
|
if (!ConsoleBox.Is_Exclusive()) {
|
|
::ShowWindow( MainWindow, SW_MINIMIZE ); // minimize if we are starting automatically.
|
|
}
|
|
ConsoleBox.Init();
|
|
} else {
|
|
::ShowWindow( MainWindow, SW_SHOW ); // show the (initially hidden) window
|
|
}
|
|
|
|
// Clear screen
|
|
for (int frame=0;frame<3;++frame) {
|
|
WW3D::Begin_Render(true,true,Vector3(0.0f,0.0f,0.0f));
|
|
WW3D::End_Render();
|
|
}
|
|
|
|
ParticleEmitterClass::Set_Default_Remove_On_Complete(false); // (gth) 09/17/2000 - by default emitters shouldn't self-destruct
|
|
|
|
for (int i=0; i<17; i++) {
|
|
ParticleBufferClass::Set_LOD_Max_Screen_Size(i,_ParticleLODScreenSizes[i]);
|
|
}
|
|
|
|
if ( cUserOptions::PermitDiagLogging.Is_True() &&
|
|
DebugManager::Is_Diag_Logging_Enabled() ) {
|
|
|
|
DiagLogClass::Init();
|
|
}
|
|
|
|
WWPhys::Init();
|
|
WWSaveLoad::Init();
|
|
|
|
//
|
|
// Load the strings table
|
|
//
|
|
TranslateDBClass::Initialize();
|
|
FileClass *file = _TheFileFactory->Get_File( STRINGS_FILENAME );
|
|
if (file != NULL) {
|
|
file->Open (FileClass::READ); // Open or the file
|
|
if ( file->Is_Available() ) {
|
|
ChunkLoadClass cload (file); // Load the database
|
|
SaveLoadSystemClass::Load(cload);
|
|
}
|
|
file->Close (); // Close the file
|
|
_TheFileFactory->Return_File (file);
|
|
}
|
|
//TranslateDBClass::Set_Current_Language (TranslateDBClass::LANGID_CHINESE);
|
|
|
|
//
|
|
// Initialize the input control system
|
|
//
|
|
bool dinput_avail = (ConsoleBox.Is_Exclusive()) ? false : true;
|
|
|
|
Input::Init(dinput_avail);
|
|
Input::Load_Registry( APPLICATION_SUB_KEY_NAME_CONTROLS );
|
|
InputConfigMgrClass::Initialize();
|
|
|
|
//
|
|
// Initialize the skin selection framework
|
|
//
|
|
SkinPackageMgrClass::Initialize ();
|
|
ModPackageMgrClass::Initialize ();
|
|
ModPackageMgrClass::Build_List ();
|
|
|
|
//
|
|
// Load the conversation database
|
|
//
|
|
file = _TheFileFactory->Get_File( CONV_DB_FILENAME );
|
|
if (file != NULL) {
|
|
file->Open (FileClass::READ); // Open or the file
|
|
if ( file->Is_Available() ) {
|
|
ChunkLoadClass cload (file); // Load the database
|
|
SaveLoadSystemClass::Load(cload);
|
|
}
|
|
file->Close (); // Close the file
|
|
_TheFileFactory->Return_File (file);
|
|
}
|
|
|
|
//
|
|
// Check to make sure the code version matches the strings
|
|
// table version
|
|
//
|
|
if (TranslateDBClass::Get_Version_Number () != STRINGS_VER) {
|
|
MessageBox( 0,
|
|
"This build of Renegade is out of sync with the strings database (strings.tdb). Strings will be incorrect and may cause the game to crash.",
|
|
"Version Error",
|
|
MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND );
|
|
}
|
|
|
|
//
|
|
// Note: Due to interdependencies (yuck!) between these subsystems, here's the
|
|
// order they need to be initialized in:
|
|
//
|
|
// - Physics Scene Class (via CombatManager::Scene_Init)
|
|
// - SystemSettings
|
|
// - RenegadeDialogMgrClass
|
|
//
|
|
//
|
|
CombatManager::Scene_Init();
|
|
if (!ConsoleBox.Is_Exclusive()) {
|
|
SystemSettings::Init();
|
|
}
|
|
RenegadeDialogMgrClass::Initialize();
|
|
|
|
cNetwork::Onetime_Init();
|
|
|
|
cServerFps::Create_Instance();
|
|
|
|
cPlayerManager::Onetime_Init();
|
|
cTeamManager::Onetime_Init();
|
|
cGameData::Onetime_Init();
|
|
cBandwidthGraph::Onetime_Init();
|
|
|
|
cNetUtil::Wsa_Init();
|
|
|
|
CombatManager::Init(ConsoleBox.Is_Exclusive() ? false : true);
|
|
|
|
CampaignManager::Init();
|
|
|
|
// This order is also draw and think order
|
|
GameModeManager::Add( new CombatGameModeClass );
|
|
GameModeManager::Add( new LanGameModeClass );
|
|
GameModeManager::Add( new WolGameModeClass );
|
|
GameModeManager::Add( new OverlayGameModeClass );
|
|
GameModeManager::Add( new MenuGameModeClass2 ); // Putting menu after overlay so we see the text
|
|
GameModeManager::Add( new MovieGameModeClass );
|
|
GameModeManager::Add( new ConsoleGameModeClass );
|
|
GameModeManager::Add( new ScoreScreenGameModeClass );
|
|
//GameModeManager::Add( new LobbyGameModeClass );
|
|
GameModeManager::Add( new TextDisplayGameModeClass );
|
|
GameModeManager::Add( new Overlay3DGameModeClass );
|
|
|
|
GameModeManager::Find( "Overlay3D" )->Activate();
|
|
GameModeManager::Find( "Overlay" )->Activate();
|
|
GameModeManager::Find( "Console" )->Activate();
|
|
GameModeManager::Find( "Menu" )->Activate();
|
|
GameModeManager::Find( "TextDisplay" )->Activate();
|
|
|
|
// After TextDisplay is created, install the Display Handler
|
|
DebugManager::Set_Display_Handler(&TextDisplayHandler);
|
|
|
|
//DEADMENU MenuManager::Set_Menu( "Menu_Main" );
|
|
|
|
// Load the accelerator table and hand it off to WWLIB.
|
|
// Note: Accelerator tables that are loaded from resources (like
|
|
// we are doing here) do not need to be manually freed. Windows
|
|
// will cleanup for us when the process terminates.
|
|
HACCEL haccel = ::LoadAccelerators (::GetModuleHandle (NULL), MAKEINTRESOURCE (IDR_ACCELERATOR));
|
|
if (haccel) {
|
|
::Add_Accelerator (MainWindow, haccel);
|
|
}
|
|
|
|
//WW3D::Set_Texture_Reduction( 1 );
|
|
|
|
//
|
|
// Initialize the encyclopedia logic
|
|
//
|
|
EncyclopediaMgrClass::Initialize ();
|
|
|
|
#if (IMMEDIATE_LOAD)
|
|
// Immediately load up the specified level
|
|
GameInitMgrClass::Initialize_SP ();
|
|
GameInitMgrClass::Start_Game (IMMEDIATE_LOAD_LEVELNAME);
|
|
#endif
|
|
|
|
cDiagnostics::Init();
|
|
//cHelpText::Init();
|
|
|
|
//
|
|
// NIC initialization
|
|
//
|
|
cNicEnum::Init();
|
|
|
|
|
|
|
|
if ( registry.Is_Valid() ) {
|
|
registry.Set_Int( VALUE_NAME_GAME_INITIALIZATION_IN_PROGRESS, 0 );
|
|
registry.Set_Int( VALUE_NAME_APPLICATION_CRASH_VERSION, DebugManager::Get_Version_Number() );
|
|
}
|
|
|
|
|
|
#if (IMMEDIATE_LOAD==0)
|
|
|
|
#if 0 // Not anymore
|
|
//
|
|
// Start the main menu
|
|
//
|
|
RenegadeDialogMgrClass::Goto_Location (RenegadeDialogMgrClass::LOC_MAIN_MENU);
|
|
#else
|
|
|
|
|
|
//
|
|
// Parse the server settings files if they will be used soon to make sure there are no errors.
|
|
//
|
|
if (ServerSettingsClass::Is_Command_Line_Mode()) {
|
|
if (!ServerSettingsClass::Parse(false)) {
|
|
AutoRestart.Set_Restart_Flag(false);
|
|
Game_Shutdown();
|
|
return (false);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If this is a post crash restart (or a FDS starting up) then just go straight into the game.
|
|
//
|
|
if (AutoRestart.Get_Restart_Flag()) {
|
|
AutoRestart.Restart_Game();
|
|
} else if (cGameSpyAdmin::Is_Gamespy_Game()) {
|
|
if (!ConsoleBox.Is_Exclusive()) {
|
|
RenegadeDialogMgrClass::Goto_Location (RenegadeDialogMgrClass::LOC_SPLASH_IN);
|
|
}
|
|
} else {
|
|
MovieGameModeClass * mode = (MovieGameModeClass *)GameModeManager::Find ("Movie");
|
|
if ( mode ) {
|
|
mode->Activate();
|
|
mode->Startup_Movies( );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#endif
|
|
|
|
|
|
//
|
|
// Send our Spy Usage Info off to Gamespy
|
|
//
|
|
GameSpyQnR.TrackUsage();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Build_Registry_Location_String -- Get a complete path to a registry location *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: Game base path *
|
|
* Base modifier path *
|
|
* Sub path *
|
|
* *
|
|
* OUTPUT: Ptr to complete path *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 11/9/2001 3:39PM ST : Created *
|
|
*=============================================================================================*/
|
|
char *Build_Registry_Location_String(char *base, char *modifier, char *sub)
|
|
{
|
|
static char _whole_registry_string[1024];
|
|
|
|
WWASSERT(base != NULL);
|
|
WWASSERT(sub != NULL);
|
|
|
|
|
|
if (modifier == NULL) {
|
|
modifier = DefaultRegistryModifier;
|
|
}
|
|
|
|
if (base && *base != 0) {
|
|
strcpy(_whole_registry_string, base);
|
|
}
|
|
if (modifier && *modifier != 0) {
|
|
strcat(_whole_registry_string, "\\");
|
|
strcat(_whole_registry_string, modifier);
|
|
}
|
|
if (sub && *sub != 0) {
|
|
strcat(_whole_registry_string, "\\");
|
|
strcat(_whole_registry_string, sub);
|
|
}
|
|
return(_whole_registry_string);
|
|
} |