Files
firestorm/Gameleap/code/mw4/Code/MW4Application/MW4Application.cpp
T
308fe041d4 Make -help a complete command line reference
MW4.exe accepts 76 command line switches. Only 27 of them appeared in the old
-help output, that output went to the debug log rather than to the user, and it
did not stop the game from launching afterwards -- so in practice the switches
were undocumented.

-help now writes a full, categorised reference to mw4-help.txt next to the
executable, opens it in Notepad, and returns from WinMain without starting the
game. If Notepad cannot be launched, a message box reports where the file was
written. The check runs immediately after the command line is lower-cased at the
top of WinMain, before any subsystem is initialised.

A file plus a viewer was chosen over a message box because MW4 is a GUI-subsystem
application with no console, and 76 switches with real descriptions do not fit
legibly in a dialog.

The reference documents every switch actually parsed, grouped as: display and
video, audio and plasma display, pod hardware and arcade (CTCL), zoom and field
of view, multiplayer and network, logging and diagnostics, development and test
builds, and other. Each entry records the accepted value range where the parser
enforces one -- for example -tbaud 9600-921600, -armorlevel 0-4, -tmfds 0-4,
-zmfovb 0.01-0.5, and the -zmtime special case where 0 means instant.

Two switches are listed under "recognised but inactive" so their behaviour is not
misrepresented: -join, whose consuming line is commented out, and -noabzug, which
is only parsed inside a disabled code path. The LAB-only switches are marked as
accepted and ignored in Release builds.

The old partial SPEWALWAYS list in GetGameOSEnvironment was removed so there is a
single maintained reference rather than two that can drift apart. A comment there
points at the new one.

Also adds an explicit #include <stdio.h>; this translation unit previously had no
direct stdio use and relied on transitive inclusion.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 08:54:10 -05:00

2133 lines
63 KiB
C++

//===========================================================================//
// File: MW4Application.cpp //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 08/25/97 JMA Infrastructure changes. //
// 08/25/97 ECH Infrastructure changes. //
// 08/27/98 BDB Made it MW4 //
// 09/29/98 BDB added gosFX shit //
//---------------------------------------------------------------------------//
// Copyright (C) 1995-97, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "MW4AppHeaders.hpp"
#include "MW4Application.hpp"
#include <windows.h>
#include <stdio.h> // [help] FILE/fopen/fprintf used by MW4_ShowCommandLineHelp
#include <MW4DedicatedUI\DedicatedUI.hpp>
#include <GameOS\GameOS.hpp>
#include <GameOS\Platform.hpp>
#include <GameOs\Network.hpp>
#include <gosFX\gosFX.hpp>
#include <gosFX\EffectLibrary.hpp>
#include <Adept\Application.hpp>
#include <MW4\MWApplication.hpp>
#include <gosScript\gosScriptHeaders.hpp>
#include <Adept\ResourceImagePool.hpp>
#include <MW4\MWMission.hpp>
#include <MW4\MWPlayer.hpp>
#include <Compost\Compost.hpp>
#include <mw4\gameinfo.hpp>
#include <Adept\ResourceEffectLibrary.hpp>
#include <mw4\ai_statistics.hpp>
#include "mw4\mw4shell.hpp"
#include "mw4\hudcomp.hpp"
#include <Adept\GlobalPointerManager.hpp>
#include <MW4\MWTool.hpp>
#include <Stuff\Random.hpp>
#include <MLR\MLR.hpp>
#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRTexture.hpp>
#include <adept\gamespy\gamespy.h>
#include <GameOS\GUNGameList.h>
#include <process.h>
#if 0
extern MidLevelRenderer::MLRTexture *g_BergerName;
extern bool s_NoAbzug;
#endif
#include "..\buildnum\buildnum.h" // current version and build number
#include "..\missionLang\resource.h" // current version and build number
#include "eula.h"
// jcem - start
#include "ctcls.h"
#include "ctcl.h" // jcem
extern Time g_fLastGameStart;
void CTCL_API CTCL_DoGame1st();
#pragma data_seg(".SHARED_DATA")
// all data in this section must be INITIALIZED!!!!!!!!!!!!!
BOOL g_bLaunched = FALSE;
#pragma data_seg()
#pragma comment(linker, "/section:.SHARED_DATA,RWS")
extern bool g_bTeslaIsCameraShip;
extern CamerashipParams g_CamerashipParams;
extern int g_bUseOrgJoy;
extern bool g_bNoWeaponRangeCheck;
extern bool g_bPRTest;
extern bool g_bMRTest;
extern int g_bNoPlasma;
extern bool g_bNoTOCKeys;
extern float g_fZoomMarginLR;
extern float g_fZoomFOVA;
extern float g_fZoomFOVB;
extern float g_fZoomTime;
extern Time g_PlasmaClearTime;
extern Time g_TOC_ADT;
extern Time g_AUX_ADT;
extern bool g_UseMSRSP;
extern int g_nTypeOfMFDs; // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480
// [tmon] Display-device override in Main/Radar/MFD1/MFD2 order; -1 = auto-detect.
// Defined in CoreTech GameOS VideoCard.cpp and consumed by FindVideoCards().
extern int g_naMonitorOverride[4];
extern int g_nRIOType;
extern DWORD g_dwRIOBaud; // [tbaud]
extern LONG g_ThrottleDir;
extern bool g_bCanSuicideAllways;
extern bool g_f3dtarget;
extern char g_szTeslaAddr[128];
extern DWORD g_dwTeslaAddr;
extern void (__stdcall *g_pfnCTCL_Proc)();
extern int (_stdcall* g_pfnCTCL_GetType)();
int _stdcall __CTCL_GetType();
extern int _stdcall VehGetShutdownState();
extern int (_stdcall *g_pfnVehGetShutdownState)();
extern int g_nCTCL;
BOOL __stdcall CTCL_Before();
void __stdcall CTCL_After();
void __stdcall CTCL_Proc();
extern bool g_bCOOP; // COin OPeration
extern int g_nCoinCount;
extern int g_nCoinPerGame;
extern bool g_bUseCam;
extern bool g_bUseJPD; // Use Joystick as Pointing Device
extern bool g_bOldLOG;
extern int g_nMechViewType;
// jcem - end
extern void _stdcall ExitGameOS();
// ngLog addition
#include <mw4/nglog_mw4.hpp>
extern DWORD LogMode;
bool __stdcall AlreadyRunning();
#ifdef LAB_ONLY
extern bool
saveMapBspDifference;
#endif
//#############################################################################
//############################# GameEngine ##############################
//#############################################################################
char *Command_Line;
extern void * __cdecl GetMech4SpecialGameData(int data_type, ...);
#ifdef LAB_ONLY
bool Bloat = true;
#endif
int bloatSizeTable[8] = {
16,
32,
64,
128,
256,
1024,
2048,
4096
};
#define BLOAT_MEMORY_LAB_ONLY(heap)\
{\
if (Bloat)\
{\
int total_bloat = Random::GetLessThan(8);\
Min_Clamp(total_bloat, 4);\
for (int i = 0; i < total_bloat; ++i)\
{\
int size_to_alloc = Random::GetLessThan(8);\
gos_Malloc(bloatSizeTable[size_to_alloc], heap);\
}\
}\
}
#define BLOAT_MEMORY_REL(heap)\
{\
int total_bloat = Random::GetLessThan(8);\
Min_Clamp(total_bloat, 4);\
for (int i = 0; i < total_bloat; ++i)\
{\
int size_to_alloc = Random::GetLessThan(8);\
gos_Malloc(bloatSizeTable[size_to_alloc], heap);\
}\
}
#ifdef LAB_ONLY
#define BLOAT_MEMORY BLOAT_MEMORY_LAB_ONLY
#else
#define BLOAT_MEMORY BLOAT_MEMORY_REL
#endif
extern bool(__cdecl *NoCDMessageFunction)(void);
extern bool gNoDialogs;
//sanghoon begin
extern bool use_shgui;
extern int SCREENS;
//sanghoon end
bool gRunEula=true;
bool gNoCD=false;
bool gNoAutoConfig=false;
extern bool gShowScriptErrors;
bool _cdecl NoCDWarning(void)
{
return WinMessageBox(MWApplication::GetInstance()->GetLocString(IDS_INSERTCD),MWApplication::GetInstance()->GetLocString(IDS_PLAY_CD_MESSAGE));
}
bool IsPlayCDPresent()
{
if(gNoCD) return true;
char cd_path[256];
DWORD size=sizeof(cd_path);
gos_LoadDataFromRegistry(
"CDPath",
cd_path,
&size,
TRUE
);
if (size>0)
{
char *tmpptr=cd_path;
if(tmpptr[0]=='\\' && tmpptr[1]=='\\') tmpptr+=2;
while(*tmpptr!='\\' && *tmpptr) tmpptr++;
if(*tmpptr=='\0') tmpptr[0]='\\';
tmpptr[1]='\0';
char vlabel[256];
bool res=gos_GetDriveLabel(cd_path,vlabel,256);
if(!res) return false;
if(strcmpi(vlabel,"MECHWARR_01") && strcmpi(vlabel,"MECHWARR_02"))
return false;
}
else
{
STOP(("%s",MWApplication::GetInstance()->GetLocString(IDS_BADSETUP)));
}
return true;
}
bool IsFirstRun()
{
DWORD frun=false;
DWORD size=sizeof(frun);
gos_LoadDataFromRegistry(
"FIRSTRUN",
&frun,
&size,
FALSE
);
return !frun;
}
bool RunAutoConfigIfNeeded()
{
#if 0 // jcem
if (IsFirstRun())
{
if(!gos_DoesFileExist("autoconfig.exe"))
return true;
//STOP(("Cannot Locate Autoconfig.exe"));
ExecuteAndWait("autoconfig.exe");
}
#endif // jcem
return true;
}
extern void __stdcall EnterWindowMode();
extern void __stdcall EnterFullScreenMode();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void _stdcall InitializeGameEngine()
{
// Set_Heap_Check(1, 100);
//
//---------------------
// Initialize libraries
//---------------------
//
// bool needflip=Environment.fullScreen && IsFirstRun();
//sanghoon begin
bool needflip=false;
//sanghoon end
if(needflip){
//sanghoon begin
//MessageBeep(MB_ICONEXCLAMATION);
//sanghoon end
EnterWindowMode();
}
Stuff::InitializeClasses(4800, 40000);
#if defined(LAB_ONLY)
if (!CallDebuggerMenuItem("Debugger\\Options\\Show percentages as milliseconds", gosMenu_CheckMark))
CallDebuggerMenuItem("Debugger\\Options\\Show percentages as milliseconds", gosMenu_Activated);
#endif
BLOAT_MEMORY(Stuff::g_Heap);
if(!gNoAutoConfig)
RunAutoConfigIfNeeded();
NotationFile startup_ini("options.ini", NotationFile::Standard, true);
g_CamerashipParams.LoadOptions(startup_ini);
Stuff::Page *compage = startup_ini.FindPage("special commands");
if(compage!=NULL)
{
bool kill;
if(compage->GetEntry("killgame",&kill) && kill)
{
compage->SetEntry("killgame",false);
startup_ini.Save();
ExitGameOS();
}
}
Page *page=startup_ini.FindPage("graphics options");
if(page!=NULL)
{
//Original
//page->GetEntry("videodriverindex",&Environment.FullScreenDevice);
//sanghoon
Environment.FullScreenDevice=0;
page->GetEntry("antialias",&Environment.AntiAlias);
page->GetEntry("bitdepth",&Environment.bitDepth);
}
page=startup_ini.FindPage("sound options");
if(page!=NULL)
{
page->GetEntry("hardwaremixing",&Environment.soundMixInHardware);
}
page=startup_ini.FindPage("special commands");
if(page!=NULL)
{
page->GetEntry("AutoTorsoCenter",&VehicleInterface::perminateTorsoMode);
//Original
//page->GetEntry("HudDamageMode",&VehicleInterface::hudDamageMode);
//page->GetEntry("HudTargetDamageMode",&VehicleInterface::hudTargetDamageMode);
//sanghoon
VehicleInterface::hudDamageMode=false;
VehicleInterface::hudTargetDamageMode=false;
}
MidLevelRenderer::InitializeClasses(&startup_ini, 2048, 2048);
gosFX::InitializeClasses(&startup_ini);
ElementRenderer::InitializeClasses(&startup_ini);
Compost::InitializeClasses(&startup_ini);
Adept::InitializeClasses(&startup_ini);
BLOAT_MEMORY(Adept::g_Heap);
MechWarrior4::InitializeClasses(&startup_ini);
BLOAT_MEMORY(MechWarrior4::Heap);
HUDText::LoadFontSizeDelta (&startup_ini);
VehicleInterface::LoadMouseYFlag (&startup_ini);
VehicleInterface::LoadMouseMinMax (&startup_ini);
#if 0
WORD day, month, year;
gos_GetUnformattedDate(&year, &month, &day);
if (year > 2000)
{
// this is just to make it look a little less obvious!
int port = 24000;
gos_SaveDataToRegistry("proxyport",&port, 4);
STOP(("MechWarrior4 Beta has expired"));
gos_TerminateApplication();
}
if (year == 2000)
{
if (month >= 12)
{
int port = 24000;
gos_SaveDataToRegistry("proxyport",&port, 4);
STOP(("MechWarrior4 Beta has expired"));
gos_TerminateApplication();
}
}
int port = 0;
DWORD size = 4;
gos_LoadDataFromRegistry("proxyport",&port,&size);
if (size > 0)
{
STOP(("MechWarrior4 Beta has expired"));
}
#endif
//
//----------------------------------------------------------
// Parse command line and verify that game name has been set
//----------------------------------------------------------
//
if (Application::TestClasses)
MW4Testall();
//
//--------------------------------------
// Create and initialize the application
//--------------------------------------
//
gos_PushCurrentHeap(MechWarrior4::Heap);
MWApplication *MW_Application =
new MWApplication(MWApplication::DefaultData,true);
Check_Object(MW_Application);
//Adept::Application::GetInstance() = MW_Application;
GlobalPointers::AddGlobalPointer(MW_Application, ApplicationGlobalPointerIndex);
MW_Application->Initialize();
// Set the Localized No CD Message for Stuff DataBase
NoCDMessageFunction=NoCDWarning;
//
//---------------------------------------------------------
// If we have a resource build command, build the resources
//---------------------------------------------------------
//
if (Adept::Application::BuildOK)
{
Verify(!NotationFile::s_cachedIncludes);
NotationFile::s_cachedIncludes = new stlport::map<MString, FileStream*>;
Tool::Instance = new MWTool();
Check_Object(Tool::Instance);
gos_PushCurrentHeap(gosFX::Heap);
gosFX::EffectLibrary::Instance = new ResourceEffectLibrary(true);
gos_PopCurrentHeap();
Stuff::NotationFile build_script("Content\\MechWarrior4.build");
FileDependencies deps;
Tool::Instance->BuildResources(&build_script, VER_CONTENTVERSION, &deps);
delete gosFX::EffectLibrary::Instance;
Verify(!gosFX::EffectLibrary::Instance);
Adept::Application::BuildOK = false;
delete Tool::Instance;
Tool::Instance = NULL;
stlport::map<MString, FileStream*> *map = (stlport::map<MString, FileStream*>*)NotationFile::s_cachedIncludes;
stlport::map<MString, FileStream*>::iterator seeker = map->begin();
while (seeker != map->end())
{
FileStream *file = (*seeker).second;
Check_Object(file);
delete file;
++seeker;
}
delete map;
NotationFile::s_cachedIncludes = NULL;
}
else if (!gos_DoesFileExist("Resource\\Variants"))
gos_CreateDirectory("Resource\\Variants");
//--------------------------------------
// Run the Eula
//--------------------------------------
if(gRunEula && Application::RunOK && !gNoDialogs)
{
bool gotlicense=false;
while(!gotlicense)
{
MString ename,wname;
ename=MWApplication::GetInstance()->GetLocString(IDS_EULA_FILENAME);
wname=MWApplication::GetInstance()->GetLocString(IDS_WARRANTY_FILENAME);
if(!FirstRunEula(ename,wname))
{
MString msg,cap;
msg=MWApplication::GetInstance()->GetLocString(IDS_EULA_FAIL_MESSAGE);
cap=MWApplication::GetInstance()->GetLocString(IDS_EULA_FAIL_CAPTION);
if(EulaDeclineMsg(msg,cap))
{
ExitGameOS();
}
}
else
{
gotlicense=true;
}
}
//--------------------------------------
// Verify the CD
//--------------------------------------
if(!gNoCD) {
bool res=true;
while(!IsPlayCDPresent() && res)
{
res=NoCDWarning();
if(!res)
ExitGameOS();
}
}
}
if(needflip) EnterFullScreenMode();
if (!MWApplication::AutoLaunchServerGame)
{
if(!gos_GetMachineInformation(gos_Info_UsingHardwareRenderer))
{
MString msg,cap;
msg=MWApplication::GetInstance()->GetLocString(IDS_NOHARDWARE);
cap=MWApplication::GetInstance()->GetLocString(IDS_HARDWAREERROR);
WinMessageBox(cap,msg,1);
ExitGameOS();
}
}
//
//------------------------------------------------------------------
// Now that we are out of building mode, reset the file hooks to use
// resources
//------------------------------------------------------------------
//
Environment.HookGetFile = Application::GetFileForGOS;
Environment.HookDoesFileExist = Application::FindFileForGOS;
Environment.defaultPlayerName = NULL;
//
// Now that resources are built. Add another layer in the getfile and find file change that can
// watch for .mw4 file requests and potentially remap them for 8.3 compatibility.
//
// Environment.HookGetFile = MWApplication::MW4GetFileForGOS;
// Environment.HookDoesFileExist = MWApplication::MW4FindFileForGOS;
//
//-----------------------------------------------
// Terminate the game if running is not permitted
//-----------------------------------------------
//
if (!Adept::Application::RunOK)
{
gos_TerminateApplication();
}
else
{
// generate the keys...
MWApplication::GetInstance()->localKey = MWApplication::GetInstance()->GetUniqueKey();
//
//--------------------------------------------------------
// We have disabled building, so load up the required data
//--------------------------------------------------------
//
ResourceManager::Instance->OpenResourceFile(
"Resource\\textures.mw4",
NULL,
TexturesResourceFileID,
VER_CONTENTVERSION,
true,
false
);
ResourceManager::Instance->OpenResourceFile(
"Resource\\core.mw4",
NULL,
CoreResourceFileID,
VER_CONTENTVERSION,
true,
false
);
ResourceManager::Instance->OpenResourceFile(
"Resource\\props.mw4",
NULL,
PropsResourceFileID,
VER_CONTENTVERSION,
true,
false
);
MWApplication::GetInstance()->LoadLookupTables();
}
//#ifdef LAB_ONLY
// g_BergerName = MidLevelRenderer::MLRTexturePool::Instance->Add ("bf");
//#endif
BLOAT_MEMORY(MechWarrior4::Heap);
gos_PopCurrentHeap();
// jcem - begin
if (!CTCL_Before()) {
gos_TerminateApplication();
}
// jcem - end
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void _stdcall TerminateGameEngine()
{
//
//-------------------
// Shut down the game
//-------------------
//
// jcem - start
CTCL_After();
if ( ServerBrowser::GetGameList() ) {
ServerBrowser::GetGameList()->ShutdownPing();
ServerBrowser::DestroyGameList();
}
// jcem - end
gos_PushCurrentHeap(MechWarrior4::Heap);
Adept::Application::GetInstance()->StopGame();
Adept::Application::GetInstance()->Terminate();
Unregister_Object(Adept::Application::GetInstance());
delete Adept::Application::GetInstance();
GlobalPointers::ClearPointer(ApplicationGlobalPointerIndex);
//
//------------------------------------------------------
// If we are shutting down a tool run, kill off the tool
//------------------------------------------------------
//
if (Tool::Instance)
{
Unregister_Object(Tool::Instance);
delete Tool::Instance;
}
gos_PopCurrentHeap();
//
//-----------------------
// Shutdown the libraries
//-----------------------
//
{
NotationFile startup_ini("options.ini", NotationFile::Standard, true);
MechWarrior4::TerminateClasses(&startup_ini);
Adept::TerminateClasses(&startup_ini);
Compost::TerminateClasses(&startup_ini);
ElementRenderer::TerminateClasses(&startup_ini);
gosFX::TerminateClasses(&startup_ini);
MidLevelRenderer::TerminateClasses(&startup_ini);
Page *page=startup_ini.SetPage("graphics options");
Check_Object(page);
// MSL 5.02 Prevent Option Overwrite
// page->SetEntry("bitdepth",Environment.bitDepth);
page->SetEntry("videodriverindex",Environment.FullScreenDevice);
// MSL 5.02 Prevent Option Overwrite
// page->SetEntry("antialias",Environment.AntiAlias);
page=startup_ini.SetPage("sound options");
Check_Object(page);
page->SetEntry("hardwaremixing",Environment.soundMixInHardware);
page=startup_ini.SetPage("special commands");
Check_Object(page);
page->SetEntry("AutoTorsoCenter",VehicleInterface::perminateTorsoMode);
//Original
//page->SetEntry("HudDamageMode",VehicleInterface::hudDamageMode);
//page->SetEntry("HudTargetDamageMode",VehicleInterface::hudTargetDamageMode);
startup_ini.Save();
}
Stuff::TerminateClasses();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
char *
MakeArgumentString(char *start)
{
char *current_pos = start;
int length = -1;
while (current_pos != NULL)
{
if (*current_pos == '-')
{
length = current_pos - start - 1;
break;
}
if (*current_pos == '\0')
{
length = current_pos - start;
break;
}
++current_pos;
}
// CHECK FOR NO PARAMETERS
if (length == -1)
{
STOP(("INVALID PARAMETER : No parameter specified"));
}
// CHECK FOR A SPACE AT THE END OF THE PARAMETER
if (start[length] != ' ' && start[length] != '\0')
{
STOP(("INVALID PARAMETER : No space after parameter"));
}
// CHECK FOR ALL SPACES
{
for (int i = 0; i < length; ++i)
{
if (start[i] != ' ')
break;
}
if (i == length)
{
STOP(("INVALID PARAMETER : No parameter specified"));
}
}
char *argument_string = new char [length+1];
// can't use strcopy since we don't have a null after the parameter
strncpy(argument_string, start, length);
argument_string[length] = '\0';
return argument_string;
}
//========================================================================
//========================================================================
#ifdef _DEBUG
//extern "C" void __stdcall RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const DWORD *lpArguments);
//extern "C" DWORD __stdcall GetCurrentThreadId(void);
WINBASEAPI
VOID
WINAPI
RaiseException(
DWORD dwExceptionCode,
DWORD dwExceptionFlags,
DWORD nNumberOfArguments,
CONST DWORD *lpArguments
);
WINBASEAPI
DWORD
WINAPI
GetCurrentThreadId(
VOID
);
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
char * szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} THREADNAME_INFO;
void __stdcall SetThreadName(DWORD dwThreadID, char *szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
}
__except (-1)
{
}
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//extern "C" DWORD __stdcall GetEnvironmentVariableA(char * lpName, char * lpBuffer, DWORD nSize);
WINBASEAPI
DWORD
WINAPI
GetEnvironmentVariableA(
LPCSTR lpName,
LPSTR lpBuffer,
DWORD nSize
);
// [help] ---------------------------------------------------------------------
// Complete command-line reference, shown by "MW4.exe -help".
//
// MW4 is a GUI-subsystem application, so there is no console to print to when it
// is launched normally. -help therefore writes the full reference to
// mw4-help.txt next to the executable, opens it in Notepad, and exits without
// starting the game. If Notepad cannot be launched, a message box reports where
// the file was written.
//
// KEEP THIS IN SYNC when adding or changing a command-line switch.
static const char* const g_apszCommandLineHelp[] =
{
"BattleTech: FireStorm - MW4.exe command line reference",
"======================================================",
"",
"Usage: MW4.exe [options]",
"",
"Options may appear in any order and are case-insensitive. An option that takes",
"a value must be followed by a single space and then the value, for example:",
"",
" MW4.exe -tmfds 4 -tmon 1,2,3,4 -tbaud 115200",
"",
"Values outside the documented range are ignored and the default is kept.",
"",
"",
"DISPLAY AND VIDEO",
"-----------------",
" -window Run in a window instead of fullscreen.",
" -fullscreen Force fullscreen. Overrides -window.",
" -tmfds <0-4> MFD output mode:",
" 0 = no MFDs",
" 1 = original 1280x480 span (5 channels + radar)",
" 2 = black and white (3 channels + 1 dual)",
" 3 = colour (3 channels + 2 dual)",
" 4 = split dual 640x480 - drives two independent",
" MFD monitors, so no span hardware is needed",
" -tmon <m>,<r>,<f1>,<f2> Hard-assign display devices in the order",
" main, radar, MFD1, MFD2. Values are 1-based; a",
" value of 0 leaves that slot auto-detected.",
" Separators may be ',' '/' or ':'.",
" MFD1 and MFD2 only apply with -tmfds 4.",
" Example: -tmon 1,2,4,3 swaps the two MFD panels.",
" -mechview <1|2> Show the rotating mech view. 1 = on the radar",
" -mv <1|2> screen, 2 = on the main screen. Default: off.",
" -3dt Draw the MFD target as a live 3D model instead of",
" the pre-rendered 2D bitmaps.",
" -capdev <0-7> Select which device screen captures come from:",
" 0 main, 1 radar, 2 mission review, 3 hudchat,",
" 4 nav, 5 weapon, 6 target, 7 armor",
"",
"",
"AUDIO AND PLASMA DISPLAY",
"------------------------",
" -nosound Disable all sound output.",
" -noplasma Disable the COM2 plasma score display.",
" -pctime <seconds> Plasma display clear time. Minimum 3.",
"",
"",
"POD HARDWARE AND ARCADE (CTCL)",
"------------------------------",
" -ctcltype <1-3> CTCL role for this machine:",
" -ctcl <1-3> 1 = console, 2 = game pod, 3 = cameraship.",
" Default when absent: console.",
" -dragon Disable CTCL entirely and run standalone.",
" -coop Co-operative arcade mode. Implies 1 coin per game",
" and the game-pod role.",
" -#coop <coins> Co-op with an explicit coin count. A negative",
" value selects the cameraship role instead.",
" -trio <0|1> RIO cockpit board protocol. 0 = original board,",
" 1 = newer protocol (different framing and acks).",
" -tbaud <9600-921600> Force the COM1 baud rate for the RIO board. Use",
" for replica boards with a high-speed UART. The",
" wire protocol is unchanged; only the rate differs.",
" -useorgjoy Use the original joystick axis mapping.",
" -ojoy Same as -useorgjoy.",
" -usetockeys Enable TOC keys. They are disabled by default.",
" -tocadt <seconds> TOC auto-detect timeout. Minimum 5.",
" -auxadt <seconds> AUX auto-detect timeout. Minimum 3.",
" -usecam Force camera mode. Implied by the cameraship role.",
" -suicide Allow self-destruct at any time.",
" -jpd Enable JPD input handling.",
"",
"",
"ZOOM AND FIELD OF VIEW",
"----------------------",
" -zmfova <0.01-0.5> Zoom field-of-view, stage A.",
" -zmfovb <0.01-0.5> Zoom field-of-view, stage B. A and B are swapped",
" automatically so that A is the wider of the two.",
" -zmmrgn <0.01-0.49> Zoom left/right margin, as a fraction of width.",
" -zmtime <0, or 0.05-3.0> Zoom transition time in seconds. 0 = instant.",
"",
"",
"MULTIPLAYER AND NETWORK",
"-----------------------",
" -serve Automatically host a server game on startup.",
" -lobby Indicates the game was started from a lobby.",
" -game <file> Load the named game/mission file.",
" -gamename <name> Name advertised for the hosted game.",
" -playername <name> Player name to use.",
" -password <password> Password for the hosted or joined game.",
" -advertiseport <port> Port used to advertise the server.",
" -ipx Use IPX in the server browser.",
" -nodplay Disable DirectPlay networking.",
" -directplayprotocol Force use of the DirectPlay protocol.",
" -secure Enable secure networking for the game session.",
" -set_internet Configure network settings for internet play.",
" -set_lan Configure network settings for LAN play.",
" -win32dedicated Run as a Win32 dedicated server. Disables sound",
" and rendering and uses the dedicated server UI.",
" -allowmultiple Allow more than one instance of the game to run.",
" -oldmpui Use the older multiplayer user interface.",
"",
"",
"LOGGING AND DIAGNOSTICS",
"-----------------------",
" -zlogstyle <value> ZLog output style.",
" -zlogflush <value> ZLog flush behaviour.",
" -zlogbuffer <size> ZLog buffer size.",
" -zlogname <filename> ZLog output file name.",
" -olog Write the legacy .log match report instead of the",
" newer .rpt format.",
" -gamestats Save game statistics.",
" -help Show this reference and exit without starting.",
"",
"",
"DEVELOPMENT AND TEST BUILDS",
"---------------------------",
"The following are only active in LAB (Debug, Armor and Profile) builds. In a",
"Release build they are accepted and ignored.",
"",
" -build Rebuild the resource packages at startup.",
" -norun Do not run the game after building.",
" -demo Demo mode.",
" -rekey Re-key resources.",
" -bloat Enable bloat diagnostics.",
" -reportnotresourced Report assets that are not in a resource package.",
" -armorlevel <0-4> Assertion/armor checking level.",
" -leak <n> Memory trace level.",
" -diskfirst Prefer loose files on disk over packaged data.",
" -testclasses Run internal class self-tests.",
" -aistats Enable AI statistics collection.",
" -bspmap Save BSP map differences.",
" -showscripterrors Display script errors as they occur.",
" -mrtest Mission review test mode.",
" -prtest Print report test mode.",
" -nowrc Disable weapon range checking.",
" -regs Debug builds only: enable script regions.",
" -spew Debug builds only: enable script spews.",
"",
"",
"OTHER",
"-----",
" -nocd Skip the CD check. (The CD check is already",
" disabled unconditionally in this build.)",
" -noeula Skip the end user licence agreement screen.",
" -noautoconfig Skip automatic video and sound configuration.",
"",
"",
"RECOGNISED BUT INACTIVE",
"-----------------------",
" -join Parsed for compatibility but has no effect; the",
" code that consumed it is commented out.",
" -noabzug Parsed only in a disabled code path.",
"",
"",
"RELATED CONFIGURATION",
"---------------------",
"Most persistent settings live in options.ini next to MW4.exe rather than on the",
"command line. See OPTIONS-INI.md in the source repository for a full reference.",
"Arcade pod assignments live in c:\\ctcl.ini.",
NULL
};
static void MW4_ShowCommandLineHelp()
{
char szDir[MAX_PATH];
char szPath[MAX_PATH];
// Write next to the executable rather than the working directory, so the file
// is easy to find no matter how the game was launched.
szDir[0] = '\0';
GetModuleFileNameA(NULL, szDir, sizeof(szDir));
char* pSlash = strrchr(szDir, '\\');
if (pSlash)
*(pSlash + 1) = '\0';
else
szDir[0] = '\0';
sprintf(szPath, "%smw4-help.txt", szDir);
FILE* f = fopen(szPath, "wt");
if (!f)
{
MessageBoxA(NULL,
"Could not write mw4-help.txt next to MW4.exe.\n"
"Check that the folder is writable.",
"MW4 command line help", MB_OK | MB_ICONWARNING);
return;
}
for (int i = 0; g_apszCommandLineHelp[i] != NULL; i++)
fprintf(f, "%s\n", g_apszCommandLineHelp[i]);
fclose(f);
// Open it for the user. WinExec is used rather than ShellExecute to avoid a
// dependency on shellapi.h in this translation unit.
char szCmd[MAX_PATH + 32];
sprintf(szCmd, "notepad.exe \"%s\"", szPath);
if (WinExec(szCmd, SW_SHOWNORMAL) < 32)
{
char szMsg[MAX_PATH + 128];
sprintf(szMsg,
"The MW4.exe command line reference was written to:\n\n%s",
szPath);
MessageBoxA(NULL, szMsg, "MW4 command line help", MB_OK | MB_ICONINFORMATION);
}
}
void __stdcall GetGameOSEnvironment(char* CommandLine)
{
#ifdef _DEBUG
//
// name that thread
//
SetThreadName(GetCurrentThreadId(), "MainThread");
#endif
//
//-----------------------------------------------
// This is where to set GOS environment settings.
//-----------------------------------------------
//
Command_Line = CommandLine;
if (true)
{
static char szFullCommandLine[256];
strcpy(szFullCommandLine, CommandLine);
strcat(szFullCommandLine, " ");
char szMech4EnvironmentVariable[256];
szMech4EnvironmentVariable[0] = 0;
GetEnvironmentVariableA("mw4", szMech4EnvironmentVariable, sizeof(szMech4EnvironmentVariable));
strcat(szFullCommandLine, szMech4EnvironmentVariable);
CommandLine = szFullCommandLine;
Command_Line = szFullCommandLine;
}
Environment.applicationName = "BattleTech Firestorm"; // "MechWarrior Vengeance";
Environment.version = VER_PRODUCTVERSION_STR;
Environment.directoryPath = "code\\MW4Application;Binaries\\MW4";
Environment.screenWidth = 800;
Environment.screenHeight = 600;
Environment.bitDepth = 16;
Environment.FullScreenDevice = 0;
Environment.Renderer = 0;
Environment.disableZBuffer = false;
Environment.AntiAlias = false;
Environment.MegMemoryRequired = 192;
Environment.MinimumTextureMemory = 5*1024; // cards with less than this video memory - use Blade
Environment.Key_FullScreen = 0;
Environment.Key_SwitchMonitors = 0;
Environment.Key_Exit = 0;
Environment.debugLog = "Mechwarrior4.txt";
Environment.spew = "GameOS_Memory"; //GROUP_ADEPT_RESOURCE;
#if defined(_ARMOR)
Environment.memoryTraceLevel = 5;
#endif
Environment.TimeStampSpew = false;
Environment.MaxTimeDelta = 0.25f;
Environment.MinimumTimeDelta = 0.25f;
Environment.soundHiFi = false;
Environment.soundDevice = 0;
Environment.soundChannels = 32;
Environment.allowMultipleApps = false;
Environment.AllowJoinInProgress = true;
Environment.NetworkGame = true;
Environment.NetworkMaxPlayers = 16;
Environment.NetworkGUID[0] = 0x95;
Environment.NetworkGUID[1] = 0x78;
Environment.NetworkGUID[2] = 0xFF;
Environment.NetworkGUID[3] = 0xD5;
Environment.NetworkGUID[4] = 0x13;
Environment.NetworkGUID[5] = 0x81;
Environment.NetworkGUID[6] = 0x9F;
Environment.NetworkGUID[7] = 0x47;
Environment.NetworkGUID[8] = 0xBB;
Environment.NetworkGUID[9] = 0xD5;
Environment.NetworkGUID[10] = 0xD3;
Environment.NetworkGUID[11] = 0x95;
Environment.NetworkGUID[12] = 0xE5;
Environment.NetworkGUID[13] = 0x51;
Environment.NetworkGUID[14] = 0xD0;
Environment.NetworkGUID[15] = 0xA8;
Environment.allowDoubleClicks = true;
#ifdef LAB_ONLY
Environment.GetGameInformation = GameInfo;
#else
Environment.GetGameInformation = NULL;
#endif
Environment.RaidDataSource = "MechWarrior 4:Raid4";
Environment.RaidFilePath = "\\\\cpaas2\\mw\\test\\goserrors";
Environment.RaidCustomFields = "AssignedTo=jmayo;Area=GOSRaid";
Environment.RaidDescTemplate = "Description:\n\nSteps to Repro:\n\nResult:\n\nExpected:\n\nNotes:\n\n";
Environment.InitializeGameEngine = InitializeGameEngine;
Environment.DoGameLogic = &MWApplication::StartUpDoShellLogic;
Environment.UpdateRenderers = &MWApplication::UpdateDisplay;
Environment.TerminateGameEngine = TerminateGameEngine;
Environment.GetSpecialGameData = GetMech4SpecialGameData;
if (MWApplication::Win32DedicatedServer)
{
Environment.InitializeGameEngine = CDedicatedServerUI::InitializeGameEngine;
Environment.DoGameLogic = &MWApplication::DoShellLogic;
Environment.UpdateRenderers = NULL;
Environment.TerminateGameEngine = CDedicatedServerUI::TerminateGameEngine;
}
gos_EnableSetting(gos_Set_IgnoreMaxUV, 1);
//
//
//
DWORD __stdcall gos_EnableSetting( gosSetting Setting, DWORD Value );
//
//-------------------------------------------------------------------
// we need to parse out our commandline options, so convert it all to
// lowercase
//-------------------------------------------------------------------
//
static char all_lower[1024];
strncpy(all_lower, CommandLine, sizeof(all_lower));
all_lower[sizeof(all_lower)-1] = '\0';
char *p;
int i = strlen(all_lower);
for (p=all_lower; i>0; ++p,--i)
*p=(char)tolower(*p);
//
//--------------------------------------------------------------------------
// Check the various options that don't affect debugging during log playback
//--------------------------------------------------------------------------
//
Environment.allowMultipleApps = (strstr(all_lower, "-allowmultiple") != NULL);
MWApplication::RunFromLobby = (strstr(all_lower, "-lobby") != NULL);
char *token;
#ifdef LAB_ONLY
token = strstr(all_lower, "-game ");
if (token && token[6])
{
MWApplication::GameFile = MakeArgumentString(&token[6]);
}
MWApplication::DemoMode = (strstr(all_lower, "-demo") != NULL);
#endif
token = strstr(all_lower, "-gamename ");
if (token && token[10])
{
MWApplication::NetGameName = MakeArgumentString(&token[10]);
}
token = strstr(all_lower, "-password ");
if (token && token[10])
{
MWApplication::NetPassword = MakeArgumentString(&token[10]);
}
token = strstr(all_lower, "-playername ");
if (token && token[12])
{
MWApplication::NetPlayerName = MakeArgumentString(&token[12]);
}
token = strstr(all_lower, "-advertiseport ");
if ( token && token[15])
{
int port = atoi(&token[15]);
if ( port <= 0 )
{
STOP(("INVALID PARAMETER : Advertise port invalid."));
}
int valSize = sizeof(port);
gos_SaveDataToRegistry( (char *) ZONE_ADVERTISE_PORT_KEY, &port, valSize);
Environment.ZoneAdvertisePort = port;
}
MWApplication::SaveGameStats = (strstr(all_lower, "-gamestats") != NULL);
MWApplication::AutoLaunchServerGame = (strstr(all_lower, "-serve") != NULL);
//MWApplication::AutoLaunchClientGame = (strstr(all_lower, "-join") != NULL);
Environment.DirectPlayProtocol = (strstr(all_lower, "-directplayprotocol") != NULL);
if (MWApplication::AutoLaunchServerGame || MWApplication::AutoLaunchClientGame)
{
if (MWApplication::NetPlayerName == NULL)
{
STOP(("Cant autolaunch without -playername <name> specified"));
}
if (MWApplication::NetGameName == NULL)
{
STOP(("Cant autolaunch without -gamename <name> specified"));
}
}
////////////////////////////////////////////////////////////////////////////
// START - ngLog addition
////////////////////////////////////////////////////////////////////////////
// Set defaults
#if !defined(NO_LOG)
MW4log_options_init();
// Style of local logging
// -zlogstyle:
// 0 - Disable local logging (default)
// 1 - Append/Create to specified logfile.
// 2 - Create/overwrite any existing log file.
// 3 - Rotate: If logname exists, create unique identifier
// and create new logfile with this unique name.
// 4 - Use unique names and individual logs for each map.
// Also forces a call to the zStats backend processor
// (local zStats processing is currently not supported)
//
token = strstr(all_lower, "-zlogstyle ");
if(token && token[11]) {
z_style = atoi(&token[11]);
}
// Flushing semantics for local logging
// -zlogflush:
// 0 - Flush on every write (default).
// 1 - Flush after "zlogbuffer" lines written.
// 2 - Wait for system to write out buffer.
token = strstr(all_lower, "-zlogflush ");
if(token && token[11]) {
z_flush = atoi(&token[11]);
}
// Size (in terms of lines) of internal buffer for local log flushing
// (Default = 10 lines of buffer).
token = strstr(all_lower, "-zlogbuffer ");
if(token && token[12]) {
z_buffer = atoi(&token[12]);
}
// Name of local log to generate (if not zStats-style log)
// (Default = "MW4_log.log")
token = strstr(all_lower, "-zlogname ");
if(token && token[10]) {
strcpy(z_logname, MakeArgumentString(&token[10]));
}
#endif // !defined(NO_LOG)
////////////////////////////////////////////////////////////////////////////
// END - ngLog addition - END
////////////////////////////////////////////////////////////////////////////
//
//-----------------------------------------------------------------------
// If we aren't playing back a log file, allow setting these other things
//-----------------------------------------------------------------------
//
if (!LogMode)
{
Environment.soundDisable = (strstr(all_lower, "-nosound") != NULL);
Environment.fullScreen = (strstr(all_lower, "-window") == NULL);
//sanghoon begin
use_shgui=Environment.fullScreen?1:0;
//sanghoon end
gNoAutoConfig= (strstr(all_lower, "-noautoconfig") != NULL);
Application::TestClasses = false;
Application::RunOK = true;
Application::BuildOK = false;
gRunEula= true;
MW4AI::Statistics::SetEnabled(false);
Network::bUseNewUI = true;
gNoCD= false;
gShowScriptErrors = (strstr(all_lower, "-showscripterrors") != NULL);
#ifdef LAB_ONLY
gShowScriptErrors = true;
gNoCD = (strstr(all_lower, "-nocd") != NULL);
if (strstr(all_lower, "-fullscreen")) Environment.fullScreen=1;
Application::TestClasses = (strstr(all_lower, "-testclasses") != NULL);
Application::RunOK = (strstr(all_lower, "-norun") == NULL);
Application::BuildOK = (strstr(all_lower, "-build") != NULL);
Application::ReportNotResourced = (strstr(all_lower, "-reportnotresourced") != NULL);
gRunEula= (strstr(all_lower, "-noeula") == NULL);
MW4AI::Statistics::SetEnabled(strstr(all_lower, "-aistats") != NULL);
Network::bUseNewUI = (strstr(all_lower, "-oldmpui") == NULL);
MWApplication::DplayNetGame = (strstr(all_lower, "-nodplay") == NULL);
if (strstr(all_lower, "-set_internet") != NULL)
{
int port;
gos_SaveStringToRegistry((char *)ZONE_SERVER_KEY, (char *)ZONE_SERVER_INTERNET_ADDRESS, strlen(ZONE_SERVER_INTERNET_ADDRESS)+1);
gos_SaveStringToRegistry(GAMESPY_MASTER_SERVER_KEY, GAMESPY_MASTER_INTERNET_ADDR, strlen(GAMESPY_MASTER_INTERNET_ADDR)+1);
port = GAMESPY_MASTER_INTERNET_HEARTBEAT_PORT;
gos_SaveDataToRegistry(GAMESPY_MASTER_HEARTBEAT_PORT_KEY, &port, sizeof(port));
port = GAMESPY_MASTER_INTERNET_QUERY_PORT;
gos_SaveDataToRegistry(GAMESPY_MASTER_QUERY_PORT_KEY, &port, sizeof(port));
port = GAMESPY_MASTER_INTERNET_SERVERLIST_PORT;
gos_SaveDataToRegistry(GAMESPY_MASTER_SERVERLIST_PORT_KEY, &port, sizeof(port));
}
else if (strstr(all_lower, "-set_lan") != NULL)
{
int port;
gos_SaveStringToRegistry((char *)ZONE_SERVER_KEY, (char *)ZONE_SERVER_LAN_ADDRESS, strlen(ZONE_SERVER_LAN_ADDRESS)+1);
gos_SaveStringToRegistry(GAMESPY_MASTER_SERVER_KEY, GAMESPY_MASTER_LAN_ADDR, strlen(GAMESPY_MASTER_LAN_ADDR)+1);
port = GAMESPY_MASTER_LAN_HEARTBEAT_PORT;
gos_SaveDataToRegistry(GAMESPY_MASTER_HEARTBEAT_PORT_KEY, &port, sizeof(port));
port = GAMESPY_MASTER_LAN_QUERY_PORT;
gos_SaveDataToRegistry(GAMESPY_MASTER_QUERY_PORT_KEY, &port, sizeof(port));
port = GAMESPY_MASTER_LAN_SERVERLIST_PORT;
gos_SaveDataToRegistry(GAMESPY_MASTER_SERVERLIST_PORT_KEY, &port, sizeof(port));
}
saveMapBspDifference = (strstr(all_lower, "-bspmap") != NULL);;
#endif
gNoCD = true; // jcem
MWApplication::SecureNetGame = (strstr(all_lower, "-secure") != NULL);
ServerBrowser::IPX = (strstr(all_lower, "-ipx") != NULL);
Application::s_DiskFirst = false;
#ifdef LAB_ONLY
MWApplication::ReKeyResources = (strstr(all_lower, "-rekey") != NULL);
Bloat = (strstr(all_lower, "-bloat") != NULL);
token = strstr(all_lower, "-armorlevel ");
if (token && token[12]>='0' && token[12]<='4')
ArmorLevel = token[12]-'0';
token = strstr(all_lower, "-leak ");
if (token && token[6])
{
Environment.memoryTraceLevel = atoi(&token[6]);
}
#endif
Application::s_DiskFirst = (strstr(all_lower, "-diskfirst") != NULL);
#if 0
s_NoAbzug = (strstr(all_lower, "-noabzug") != NULL);
#endif
}
// [help] -help is handled at the top of WinMain (see MW4_ShowCommandLineHelp),
// which runs before this and exits the process. The old partial list that used
// to live here was incomplete and only reached the debug log, so it was removed
// in favour of a single maintained reference.
if (MWApplication::AutoLaunchServerGame || MWApplication::Win32DedicatedServer)
{
Environment.soundDisable = true;
Environment.fullScreen = false;
}
}
Scalar GetNumber(const char* token, bool bAllowFloat = false)
{
while((*token == ' ') || (*token == '\t')) {
token++;
}
const char *tokenStart = token;
char c;
bool b1st = true;
bool bsign = false;
bool bDotExist = false;
while(((c = *token) == '-') || (c == '+') || (('0' <= c) && (c <= '9')) || (bAllowFloat && (c == '.'))) {
if ((c == '-') || (c == '+')) {
if (!b1st)
break;
if (c == '-')
bsign = !bsign;
tokenStart = ++token;
} else {
b1st = false;
if (c == '.') {
if (bDotExist) {
break;
}
bDotExist = true;
}
token++;
}
}
if (tokenStart < token) {
char sz[256];
memcpy(sz, tokenStart, token - tokenStart);
sz[token - tokenStart] = '\0';
Scalar f = atof(sz);
if (bsign)
return -f;
return f;
} else {
return 0.0;
}
}
HINSTANCE g_hInst;
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow )
{
#ifdef _DEBUG // jcem
Vector3D::TestClass();
#endif // _DEBUG
#ifdef _ICECAP
StopCAPAll ();
#endif
// jcem - begin
g_pfnVehGetShutdownState = VehGetShutdownState;
if (g_bLaunched || (CTCL_GetApplType() != _EAT_None))
return 0;
g_bLaunched = TRUE;
// jcem - end
g_hInst = hInst;
static char all_lower[1024];
strncpy(all_lower, lpCmdLine, sizeof(all_lower));
all_lower[sizeof(all_lower)-1] = '\0';
char *p;
int i = strlen(all_lower);
for (p=all_lower; i>0; ++p,--i)
*p=(char)tolower(*p);
// [help] Handle -help before anything is initialised: write the full command
// line reference next to the exe, open it, and exit without starting the game.
if (strstr(all_lower, "-help"))
{
MW4_ShowCommandLineHelp();
return 0;
}
char *token;
// jcem - begin
token = strstr(all_lower, "-ctcltype ");
if (token) {
token = &token[10];
} else {
token = strstr(all_lower, "-ctcl ");
if (token) {
token = &token[6];
}
}
if (token) {
if (token[0]>='1' && token[0]<='3') {
g_nCTCL = (token[0]-'0');
} else {
g_nCTCL = _ECTCL_Console;
}
} else {
g_nCTCL = _ECTCL_Console;
}
// MechViewType : 0 - no mechview, 1 - on radar screen, 2 - on main screen
token = strstr(all_lower, "-mechview ");
if (token) {
token = &token[10];
} else {
token = strstr(all_lower, "-mv ");
if (token) {
token = &token[4];
}
}
if (token) {
if (token[0]>='1' && token[0]<='2') {
g_nMechViewType = (token[0]-'0');
} else {
g_nMechViewType = 0;
}
} else {
g_nMechViewType = 0;
}
token = strstr(all_lower, "-#coop ");
if (token) {
g_bCOOP = true;
g_nCoinPerGame = GetNumber(&token[7]);
if (g_nCoinPerGame < 0) {
g_nCTCL = _ECTCL_CameraShip;
g_nCoinPerGame = 0;
} else {
g_nCTCL = _ECTCL_Game;
}
} else {
g_bCOOP = (strstr(all_lower, "-coop") != NULL);
if (g_bCOOP) {
g_nCoinPerGame = 1;
g_nCTCL = _ECTCL_Game;
}
}
if (strstr(all_lower, "-dragon") != NULL)
g_nCTCL = _ECTCL_None;
if (g_nCTCL != _ECTCL_None) {
g_pfnCTCL_Proc = CTCL_Proc;
}
g_pfnCTCL_GetType = __CTCL_GetType;
g_bUseJPD = (strstr(all_lower, "-jpd") != NULL);
g_bUseOrgJoy = (strstr(all_lower, "-useorgjoy") != NULL);
if (!g_bUseOrgJoy) {
g_bUseOrgJoy = (strstr(all_lower, "-ojoy") != NULL);
}
g_bNoWeaponRangeCheck = (strstr(all_lower, "-nowrc") != NULL);
g_bPRTest = (strstr(all_lower, "-prtest") != NULL);
g_bMRTest = (strstr(all_lower, "-mrtest") != NULL);
g_bNoPlasma = (strstr(all_lower, "-noplasma") != NULL);
g_bNoTOCKeys = (strstr(all_lower, "-usetockeys") == NULL);
token = strstr(all_lower, "-zmmrgn ");
if (token) {
Scalar f = GetNumber(token, true);
if ((0.01 <= fabs(f)) && (fabs(f) <= 0.49)) {
g_fZoomMarginLR = f;
}
}
float fZoomFOVA = g_fZoomFOVA;
float fZoomFOVB = g_fZoomFOVB;
token = strstr(all_lower, "-zmfova ");
if (token) {
Scalar f = GetNumber(token, true);
if ((0.01 <= fabs(f)) && (fabs(f) <= 0.5)) {
fZoomFOVA = f;
}
}
token = strstr(all_lower, "-zmfovb ");
if (token) {
Scalar f = GetNumber(token, true);
if ((0.01 <= fabs(f)) && (fabs(f) <= 0.5)) {
fZoomFOVB = f;
}
}
if (fZoomFOVA < fZoomFOVB) {
float f;
f = fZoomFOVB;
fZoomFOVB = fZoomFOVA;
fZoomFOVA = f;
}
g_fZoomFOVA = fZoomFOVA;
g_fZoomFOVB = fZoomFOVB;
token = strstr(all_lower, "-zmtime ");
if (token) {
Scalar f = GetNumber(token, true);
if (Stuff::Close_Enough(f, 0.0)) {
g_fZoomTime = 0.0f;
} else {
if ((0.05 <= fabs(f)) && (fabs(f) <= 3.0)) {
g_fZoomTime = f;
}
}
}
token = strstr(all_lower, "-pctime ");
if (token) {
Scalar f = GetNumber(token, true);
if (f >= 3.0) {
g_PlasmaClearTime = f;
}
}
token = strstr(all_lower, "-tocadt ");
if (token) {
Scalar f = GetNumber(token, true);
if (f >= 5.0) {
g_TOC_ADT = f;
}
}
token = strstr(all_lower, "-auxadt ");
if (token) {
Scalar f = GetNumber(token, true);
if (f >= 3.0) {
g_AUX_ADT = f;
}
}
token = strstr(all_lower, "-tmfds ");
if (token && token[7])
{
int n = atoi(&token[7]);
if ((0 <= n) && (n <= 4)) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480
g_nTypeOfMFDs = n;
}
// [tmon] Hard-assign the display devices when DirectDraw enumerates them in an
// unexpected order. Syntax: -tmon <main>,<radar>,<mfd1>,<mfd2>
// Values are 1-based (the normal case is "-tmon 1,2,3,4"); a value of 0 leaves that
// slot to auto-detection, so "-tmon 2,1,0,0" only swaps main and radar. Separators
// may be ',' '/' or ':'. mfd1/mfd2 are only used by -tmfds 4.
token = strstr(all_lower, "-tmon ");
if (token)
{
const char* p = &token[6];
int slot = 0;
while (slot < 4)
{
while (*p == ' ')
p++;
if ((*p < '0') || ('9' < *p))
break;
int v = atoi(p);
while (('0' <= *p) && (*p <= '9'))
p++;
// 0 = leave auto-detected, otherwise convert 1-based to a 0-based device index
g_naMonitorOverride[slot] = (0 < v) ? (v - 1) : -1;
slot++;
if ((*p == ',') || (*p == '/') || (*p == ':'))
p++;
else
break;
}
}
token = strstr(all_lower, "-trio ");
if (token && token[6])
{
int n = atoi(&token[6]);
if ((n == 0) || (n == 1))
g_nRIOType = n;
}
token = strstr(all_lower, "-tbaud "); // [tbaud] force COM1 baud; must match the RIO board's UART rate
if (token && token[7])
{
int n = atoi(&token[7]);
if ((9600 <= n) && (n <= 921600))
g_dwRIOBaud = (DWORD)n;
}
g_bCanSuicideAllways = (strstr(all_lower, "-suicide") != NULL);
g_f3dtarget = (strstr(all_lower, "-3dt") != NULL);
g_bOldLOG = (strstr(all_lower, "-olog") != NULL);
#ifdef _DEBUG
if (strstr(all_lower, "-regs") != NULL) {
bool __stdcall CheckScriptRegions();
void __stdcall EnableScriptRegions();
if (!CheckScriptRegions())
EnableScriptRegions();
} else if (strstr(all_lower, "-spew") != NULL) {
bool __stdcall CheckScriptSpews();
void __stdcall EnableScriptSpews();
if (!CheckScriptSpews())
EnableScriptSpews();
}
#endif // _DEBUG
if (g_nCTCL == _ECTCL_CameraShip) {
g_bUseCam = true;
} else {
token = strstr(all_lower, "-usecam");
if (token) {
g_bUseCam = true;
}
}
token = strstr(all_lower, "-capdev ");
if (token) {
int nCapDev = (int)GetNumber(&token[8], false);
if ((0 <= nCapDev) && (nCapDev < 8)) {
// 0 - main, 1 - radar, 2 - mr
// 3 - hudchat(left/top), 4 - nav(top/center), 5 - weapon(right/top)
// 6 - target(left/top), 7 - armor(right/bottom)
extern DWORD gCaptureDevice;
gCaptureDevice = (DWORD)nCapDev;
}
}
// jcem - end
MWApplication::Win32DedicatedServer = (strstr(all_lower, "-win32dedicated") != NULL);
if (MWApplication::Win32DedicatedServer) {
Platform=Platform_MFC;
RunFromOtherApp( hInst, ::GetDesktopWindow(), lpCmdLine );
CDedicatedServerUI::Run(hInst, hPrevInst, lpCmdLine, nCmdShow);
}
else {
Platform=Platform_Game;
RunFromWinMain( hInst, hPrevInst, lpCmdLine, nCmdShow );
}
// jcem - begin
g_bLaunched = FALSE;
g_pfnVehGetShutdownState = NULL;
g_pfnCTCL_GetType = NULL;
// jcem - end
return 0;
}
// jcem - start
int __stdcall CTCL_GetType(void* instance, int args, void* data[])
{
return CTCL_GetType();
}
int __stdcall CTCL_IsConsole(void* instance, int args, void* data[])
{
return CTCL_IsConsole();
}
int __stdcall CTCL_IsConsoleX(void* instance, int args, void* data[])
{
return CTCL_IsConsoleX();
}
int __stdcall CTCL_Get(void* instance, int args, void* data[])
{
// mw4 project - mw4shell.cpp
int nRet = 0, param_number = VALUEPARM(0);
switch (param_number)
{
case _CTCL_GetTeslaCountAll:
ASSERT(CTCL_IsConsole());
nRet = CTCL_GetTeslaCountAll();
break;
case _CTCL_GetTeslaCount:
ASSERT(CTCL_IsConsole());
nRet = CTCL_GetTeslaCount();
break;
case _CTCL_GetTeslaInfo:
{
ASSERT(CTCL_IsConsole());
int nIdx = INTPARM(1);
ASSERT((0 <= nIdx) && (nIdx < CTCL_GetTeslaCountAll()));
STeslaInfo TI;
CTCL_GetTeslaInfo(nIdx, TI);
nRet = TI.m_nLauncherConnection;
INTPARM(2) = TI.m_nConnection2;
INTPARM(3) = TI.m_nApplType;
INTPARM(4) = TI.m_nApplState;
INTPARM(5) = TI.m_nGameState;
int nGameTime = TI.m_nGameTime;
int nGameIsServer = TI.m_nGameIsServer;
if ((TI.m_nApplType != _EAT_None) && (TI.m_nApplState == _EAS_Launched)) {
switch(TI.m_nGameState)
{
default:
case _EGS_None:
case _EGS_Idle:
case _EGS_Closing:
nGameTime = -1; // indetermined
nGameIsServer = 2; // indetermined
break;
case _EGS_Preparing:
nGameTime = -1; // indetermined
break;
case _EGS_Running:
//if (!nGameIsServer)
// nGameTime = -1; // indetermined
break;
}
} else {
nGameTime = -1; // indetermined
nGameIsServer = 2; // indetermined
}
INTPARM(6) = nGameTime;
INTPARM(7) = nGameIsServer;
break;
}
case _CTCL_GetTeslaName:
{
ASSERT(CTCL_IsConsole());
int nIdx = INTPARM(1);
ASSERT((0 <= nIdx) && (nIdx < CTCL_GetTeslaCountll()));
strcpy(STRPARM(2), CTCL_GetTeslaName(nIdx));
break;
}
case _CTCL_GetInviteCOOP:
gosASSERT(FALSE);
break;
default:
break;
}
return nRet;
}
int __stdcall CTCL_Set(void* instance, int args, void* data[])
{
// mw4 project - mw4shell.cpp
int nRet = 0, param_number = VALUEPARM(0);
switch (param_number)
{
case _CTCL_GetTeslaCountAll:
case _CTCL_GetTeslaCount:
ASSERT(CTCL_IsConsole());
ASSERT(FALSE);
break;
case _CTCL_GetTeslaInfo:
case _CTCL_GetTeslaName:
gosASSERT(FALSE);
break;
case _CTCL_OrderAppl:
{
ASSERT(CTCL_IsConsole());
int nIdx = INTPARM(1);
ASSERT((0 <= nIdx) && (nIdx < CTCL_GetTeslaCountAll()));
CTCL_OrderAppl(nIdx, VALUEPARM(2), _EAT_MW4);
}
break;
case _CTCL_SetInviteCOOP:
gosASSERT(FALSE);
break;
default:
break;
}
return nRet;
}
BOOL __stdcall CTCL_Before()
{
BOOL bRet;
gos_PushCurrentHeap(MechWarrior4::Heap);
if (g_nCTCL != _ECTCL_None) {
if (g_nCTCL != _ECTCL_Console) {
// _ECTCL_Game or _ECTCL_CameraShip
CTCL_SetApplType(_EAT_MW4);
CTCL_SetApplState(_EAS_PreLaunch);
}
if (CTCL_Start(g_nCTCL)) {
bRet = TRUE;
} else {
bRet = FALSE;
}
} else {
bRet = TRUE;
}
gos_PopCurrentHeap();
return bRet;
}
void __stdcall CTCL_After()
{
gos_PushCurrentHeap(MechWarrior4::Heap);
if (g_nCTCL != _ECTCL_None) {
CTCL_SetApplState(_EAS_PostLaunch);
g_pfnCTCL_Proc = NULL;
CTCL_Stop();
if (g_nCTCL != _ECTCL_Console) {
// _ECTCL_Game or _ECTCL_CameraShip
CTCL_SetGameState(_EGS_None);
CTCL_SetApplState(_EAS_None);
CTCL_SetApplType(_EAT_None);
}
}
gos_PopCurrentHeap();
}
void __stdcall CTCL_Proc()
{
gos_PushCurrentHeap(MechWarrior4::Heap);
CTCL_Run();
gos_PopCurrentHeap();
}
void CTCL_API CTCL_DoTerminateAppl()
{
gos_TerminateApplication();
}
void CTCL_API CTCL_DoMainShell()
{
if (MW4Shell::Instance)
MW4Shell::Instance->StartMainShell();
}
void CTCL_API CTCL_DoCreateGame()
{
//$$COOP
g_fLastGameStart = gos_GetElapsedTime();
gos_NetStartGame(NULL, MWApplication::SecureNetGame);
CancelDialup(NULL, 0, NULL);
LoadMPConnectionSettings(NULL, 0, NULL);
InitConnectionWizard(NULL, 0, NULL);
ConnectionIndex = 0;
PreConnect(NULL, 0, NULL);
char* pcsz = &g_aPlayerInfos[0].m_szName[0];;
if (*pcsz == '\0')
pcsz = &g_szTeslaAddr[0];
if (*pcsz == '\x01')
pcsz++;
CTCL_DefaultHostSetup(0);
int error = Mech4CreateGame(&g_szGameName[0], pcsz/*PlayerName*/, NULL/*GamePassword*/);
if (error == 0) {
CTCL_DoGame1st();
} else {
if (g_bCOOP) {
g_InviteCOOP.m_pParent = NULL;
g_InviteCOOP.Clear();
}
g_nMech4Comm = 0;
gos_NetEndGame(); // gos_NetDoneStartGame(); ?
MW4Shell::Instance->StartMainShell();
if (!g_bCOOP) {
CTCL_DoSendGameReturn(_EGR_ErrCreateSession);
}
}
}
void CTCL_API CTCL_DoJoinGame()
{
gos_NetStartGame(NULL, MWApplication::SecureNetGame);
CancelDialup(NULL, 0, NULL);
LoadMPConnectionSettings(NULL, 0, NULL);
InitConnectionWizard(NULL, 0, NULL);
ConnectionIndex = 0;
PreConnect(NULL, 0, NULL);
CreateBrowsers(NULL, 0, NULL);
#if 0
if (0 < GetTotalGameCount(NULL, 0, NULL))
RefreshGameList();
else
#endif
UpdateGameList(NULL, 0, NULL);
g_nMech4Comm = 1;
g_dwJoinStartTicks = GetTickCount();
}
void CTCL_API CTCL_CheckJoinGame()
{
extern int __stdcall gos_GameIsExist( const char* pcszGameName);
if (gos_GameIsExist(&g_szGameName[0])) {
MWApplication* app = MWApplication::GetInstance();
app->haveNetworkMap = false;
char* pcsz = &g_aPlayerInfos[0].m_szName[0];
if (*pcsz == '\0')
pcsz = &g_szTeslaAddr[0];
if (*pcsz == '\x01')
pcsz++;
int error = gos_JoinGame(&g_szGameName[0], pcsz/*PlayerName*/, NULL/*GamePassword*/, NULL/*NGPassword*/);
if (error == 0) {
CTCL_DoGame1st();
} else {
if (g_bCOOP) {
g_InviteCOOP.m_pParent = NULL;
g_InviteCOOP.Clear();
}
g_nMech4Comm = 0;
gos_NetEndGame(); // gos_NetDoneStartGame(); ?
MW4Shell::Instance->StartMainShell();
if (!g_bCOOP) {
CTCL_DoSendGameReturn(_EGR_ErrJoinSession);
}
}
} else {
if ((g_dwJoinStartTicks + 25000) <= GetTickCount()) {
if (g_bCOOP) {
g_InviteCOOP.m_pParent = NULL;
g_InviteCOOP.Clear();
}
g_nMech4Comm = 0;
gos_NetEndGame(); // gos_NetDoneStartGame(); ?
MW4Shell::Instance->StartMainShell();
if (!g_bCOOP) {
CTCL_DoSendGameReturn(_EGR_ErrJoinSession);
}
}
}
}
void CTCL_API CTCL_DoGame1st()
{
MWApplication* app = MWApplication::GetInstance();
/*MWApplication *app = Cast_Object(MWApplication *, Application::GetInstance());
NetMissionParameters::MWNetMissionParameters *params = app->GetLocalNetParams();
Str_Copy(params->m_serverName, GameName, STRING_SIZE);
Str_Copy(params->m_serverIP, LocalIPAddress, STRING_SIZE);*/
gos_NetDoneStartGame();
DWORD networking;
networking = reinterpret_cast<DWORD>(gos_NetInformation(gos_Networking, 0));
app->networkingFlag = (networking)?true:false;
if (app->networkingFlag)
{
//$$COOP
DWORD server = reinterpret_cast<DWORD>(gos_NetInformation(gos_AmITheServer, 0));
app->serverFlag = (server)?true:false;
if (Network::GetInstance() == NULL)
{
gos_PushCurrentHeap(MechWarrior4::Heap);
Verify(!Network::GetInstance());
GlobalPointers::AddGlobalPointer(new Network, NetworkGlobalPointerIndex);
Register_Object(Network::GetInstance());
gos_PopCurrentHeap();
}
if (app->serverFlag)
{
ASSERT(g_bIsServer);
// save the options that were set
app->SaveServerOptions();
#if defined(LAB_ONLY)
MWGameInfo::g_lastGameType = MWGameInfo::g_currentGameType;
MWGameInfo::g_currentGameType = MWGameInfo::MultiServer;
#endif
//app->LoadServerOptions();
app->SendRequestConnectionMessage();
}
else
{
ASSERT(!g_bIsServer);
app->GetLocalNetParams()->ResetParameters();
app->GetServerNetParams()->ResetParameters();
app->haveNetworkMap = false;
}
g_fLastGameStart = gos_GetElapsedTime();
if (g_bCOOP) {
if (app->serverFlag) {
MW4Shell::Instance->StartNetworkServerExecute();
g_nMech4Comm = 0;
} else {
MW4Shell::Instance->StartNetworkClientExecute();
g_nMech4Comm = 2;
}
} else {
for (int i = 0; i < Maximum_Lancemates; ++i)
{
app->lancemateConnectionData[i].Disconnect();
}
app->memoryDiffKiller.Init();
g_nMech4Comm = 2;
}
} else {
// is this possible?
if (g_bCOOP) {
g_InviteCOOP.m_pParent = NULL;
g_InviteCOOP.Clear();
}
g_nMech4Comm = 0;
gos_NetEndGame();
MW4Shell::Instance->StartMainShell();
if (!g_bCOOP) {
if (g_bIsServer)
CTCL_DoSendGameReturn(_EGR_ErrCreateSession);
else
CTCL_DoSendGameReturn(_EGR_ErrJoinSession);
}
}
}
void CTCL_API CTCL_StartGame(BOOL bRealLaunch)
{
//$$COOP
if (bRealLaunch) {
g_nMech4Comm = 11;
} else {
MW4Shell::Instance->EndAllScripts();
MW4Shell::Instance->currentShellRunning = MW4Shell::MainShellRunning; //MW4Shell::NoShellRunning;
MW4Shell::Instance->shellCommand = MW4Shell::StartNetworkGameCommand;
MW4Shell::Instance->shellStart = MW4Shell::MainShellStart;
g_nMech4Comm = 9;
}
}
int _stdcall __CTCL_GetType()
{
return g_nCTCL;
}
// jcem - end