Files
firestorm/Gameleap/code/mw4/Code/MW4Application/MW4Application.cpp
T
9c67dddd83 Display diagnostics + -fps/-tcoop; native multi-monitor MFD ruled out
Four-monitor MFD bring-up on the new bench (MR_new: AMD FirePro W4100, 4 outputs,
Win10). Adds permanent display diagnostics, a Release-capable frame pacing logger,
a self-locating AppCompat shim installer, and settles -- empirically -- whether
dgVoodoo2 can be dropped for the multi-monitor MFD modes. It cannot.

WHY THIS WAS HARD
-----------------
CHSH_Device::InitFirst/InitSecond discarded EVERY HRESULT (SetCooperativeLevel,
SetDisplayMode, CreateSurface, GetAttachedSurface, QueryInterface, CreateDevice)
and returned true unconditionally. A panel that failed to open produced no error,
no crash and no log entry -- the monitor just stayed on the desktop. SPEW is
compiled out of shipping builds, so none of it was visible. Restoring that
visibility is what unblocked everything else.

DIAGNOSTICS ADDED (keep these)
------------------------------
* VideoCard.cpp -- LogDisplayDevices() writes gos-displays.txt next to the exe:
  NumDevices/NumHWDevices/NumMonitors, every DirectDraw device with its
  hw_rasterization flag, the role assignment (FullScreenDevice / g_nNonDualHead /
  g_nDualHead / g_nDualHead2 / g_nMFD1 / g_nMFD2), per-slot -tmon APPLIED/REJECTED
  (previously silent), and whether mode 4's "BOTH mfd1 and mfd2" requirement is met.
* render.cpp -- HSH_LogInit()/HSH_CheckHR()/HSH_HRName() log every DirectDraw call
  in the panel init path with its HRESULT decoded by name (27 DDERR_* codes, all
  verified present and collision-free against build-env/dx7asdk/include/ddraw.h).
  Each line is opened/appended/closed individually so the log survives a crash.
* WinMain.cpp -- GOS_LogFrameRate() writes gos-fps.txt: per second, frame count,
  average fps, 1% low (mean of the worst 1% of frames), worst frame in ms, and a
  count of frames exceeding 2x average ("hitches"). Average fps alone cannot
  distinguish 60fps from 60fps-with-a-dropped-frame-every-second; the 1% low can.
  The engine's own FrameRate readout is #ifdef LAB_ONLY (MWMission.cpp) so it only
  exists in MW4pro.exe; this works in Release, which is what runs on the pods.

NEW SWITCHES (both documented in -help)
---------------------------------------
* -fps    Enable the frame pacing report. Off by default: the gate is the first
          statement in GOS_LogFrameRate, so an unflagged run does no arithmetic
          and does not even create the file. The file handle is held open for the
          process lifetime -- opening/closing it every second would put a syscall
          of unpredictable latency on the render thread, i.e. the measurement tool
          perturbing what it measures.
* -tcoop <0-5>  Selects the SetCooperativeLevel form used by the radar/MFD panels.
          0 = legacy (unchanged shipped behaviour, remains the default).
          Exists so every candidate fix could be compared on real hardware without
          a rebuild between attempts.

CRASH-SAFETY FIX
----------------
hsh_initialized was set unconditionally after panel init, so a failed panel left
null surfaces and a null IDirect3DDevice7 behind and the per-frame path called
straight through them. Now:
  - all four InitSecond overrides (CMR/CRadar/CMFD/CMFDRight) bail on base failure,
  - CMFD_Device::InitFirst reports its real result instead of always returning true,
  - hsh_initialized is only set when the panels genuinely came up.
A display failure now leaves the game running without MFDs instead of bombing to
desktop. Crash signature for the record: `call [ecx+0x44]` with ECX=0 is
IDirectDrawSurface7::GetDC on a never-created surface (vtable offset confirmed
against the DX7 header), reported as "Attempt to read from address 0x00000044".

APPCOMPAT SHIM INSTALLER (new)
------------------------------
build-env/set-appcompat.ps1 + set-appcompat.bat. Self-locating via $PSScriptRoot:
applies DWM8And16BitMitigation to the MW4 executables sitting next to it, wherever
that install lives. HKCU always, HKLM too when elevated (the HKLM value format
differs -- it carries a leading "$" marker -- so the two must not be interchanged).
Verifies by reading back; detects the HIGHDPIAWARE-only entry that SUPPRESSES the
automatic shim; supports -Remove and -WhatIfOnly. deploy-mw4.ps1 now ships both
files into every deployment.

This matters because the layer is keyed on the executable's FULL PATH -- any copy
of an install to another folder or machine silently loses it, and the resulting
error is actively misleading (see below).

WHAT WE LEARNED
---------------
* The AppCompat shim SYNTHESISES 16-bit display modes. Proved directly: the crash
  dump shows "16 bit modes :" EMPTY without it and fully populated with it. MW4
  renders at bitdepth=16 and modern GPUs expose no 16-bit modes at all.
* Without the shim, GameOS reports "Another application is preventing use of full
  screen mode" (GOS_DXRASTERIZER_NOFULLSCREEN, DXRasterizer.cpp ~1125). That is a
  catch-all fired after every SetDisplayMode attempt fails -- it even scans for
  NetMeeting -- and it sends you looking for a conflicting program that does not
  exist. The real cause is the missing shim.
* Exclusive fullscreen DOES work on Win10 with the system ddraw.dll and dgVoodoo2
  physically removed, once the shim is applied to that exe path.
* Windowed mode works natively with no shim at all: the windowed path sets
  Environment.bitDepth = DesktopBpp (32), so there is no mode switch. Verified for
  the console/shell; a full mission windowed is still untested.
* Native DirectDraw enumerates all four W4100 outputs, so dgVoodoo2 was never
  needed for device enumeration.
* The engine is 4:3 ONLY. ImageHlp.cpp ~464 asserts the complete supported set:
  640x480, 512x384, 800x600, 960x720, 1024x768, 1280x1024 (5:4), 1600x1200. No
  16:9 mode and no aspect correction anywhere in the codebase. On a 16:9 monitor
  the scaler must adapt: plain stretch distorts geometry, keep-aspect pillarboxes.
* -2dt is not a recognised switch anywhere in the codebase, despite appearing in
  production ctcl.ini launch lines. Completely inert.
* NumHWDevices (5) can exceed NumDevices (4): it counts D3D device-enumeration
  callbacks, and an adapter exposing both a HAL and a T&L HAL yields two. Benign.

WHAT WE TRIED AND WHY IT FAILED
-------------------------------
The panel cooperative-level call was genuinely wrong -- a latent 2002 bug. Every
panel asked to be BOTH the process focus window AND its own device window, on the
one shared hWindow, after the main device had already taken exclusive mode on it.
The main device (DXRasterizer.cpp ~1027) already uses the correct two-call idiom
(SETFOCUSWINDOW alone, then EXCLUSIVE|FULLSCREEN) -- tagged //sanghoon, the same
author. The panels never were.

Results on real hardware, no dgVoodoo2, shim applied, -tmfds 4:

  -tcoop 0  SETFOCUSWINDOW|CREATEDEVICEWINDOW|ALLOWREBOOT|EXCLUSIVE|FULLSCREEN
            -> DDERR_EXCLUSIVEMODEALREADYSET
  -tcoop 1  CREATEDEVICEWINDOW|EXCLUSIVE|FULLSCREEN (no focus claim)
            -> DDERR_INVALIDPARAMS (CREATEDEVICEWINDOW needs a focus window)
  -tcoop 2  SETFOCUSWINDOW, then CREATEDEVICEWINDOW|EXCLUSIVE|FULLSCREEN
            -> DDERR_INVALIDPARAMS
  -tcoop 3  SETFOCUSWINDOW, then EXCLUSIVE|FULLSCREEN
            -> first panel collides, but that collision STEALS exclusive mode from
               the main display, after which panels 2 and 3 fully initialise (the
               radar reached CreateDevice(HAL) = DD_OK -- a secondary panel running
               entirely on native DirectDraw). Side effect: the desktop was left at
               1920x1080 16bpp. Not viable.
  -tcoop 4  EXCLUSIVE|FULLSCREEN only          -> EXCLUSIVEMODEALREADYSET, all panels
  -tcoop 5  ALLOWREBOOT|EXCLUSIVE|FULLSCREEN   -> EXCLUSIVEMODEALREADYSET, all panels

CONCLUSION: on modern Windows only ONE DirectDraw object per process may hold
exclusive fullscreen. The main display takes it; every secondary panel is refused.
XP allowed multiple. dgVoodoo2 allows it because it is a full reimplementation of
ddraw and is not bound by that rule -- it is not papering over a bug we can fix.

=> dgVoodoo2 CANNOT be removed for -tmfds 1/3/4 by correcting these flags. The
default stays -tcoop 0. The switch is retained because it is how this was settled
and it will re-settle it on different hardware.

The only native path is a borderless windowed panel design (DDSCL_NORMAL + clipper
per monitor, no exclusive mode anywhere). Assessment and staged plan are recorded
in CLAUDE.md STEP 10; not started.

WORKING 4-MONITOR CONFIG (with dgVoodoo2)
-----------------------------------------
dgVoodoo2 Scaling mode MUST be "Stretched, Keep Aspect Ratio". Plain "Stretched"
fails silently: main and radar go fullscreen black, both MFD monitors keep showing
the desktop, and every DirectDraw call still returns DD_OK -- the devices are alive
but dgVoodoo2 never drives those outputs. Diagnosed with a temporary per-panel
colour-flash test (since removed), which also established that device index maps
1:1 to physical monitor on this bench, so -tmon 1,2,3,4 equals auto-detection.
Confirmed working end to end: all three secondary panels present, full mission
played.

KNOWN GAP: the working dgVoodoo.conf is still not versioned in the repo (removed
in 0ceba9c7), so a fresh deploy will reproduce the silent MFD failure.

Behaviour with no new switches supplied is unchanged from the previous build
except on failure paths, which now degrade gracefully instead of crashing.

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

2169 lines
66 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]
// [fpslog] Non-zero enables the per-second frame pacing report (gos-fps.txt).
// Defined in CoreTech GameOS WinMain.cpp.
extern int g_nFpsLog;
// [panelcoop] SetCooperativeLevel form used by the radar/MFD panels; 0 = legacy.
// Defined in CoreTech GameOS render.cpp.
extern int g_nHshCoopMode;
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.",
" -tcoop <0-5> How the radar/MFD panels claim their displays.",
" 0 = legacy single call (as shipped; works on XP",
" and under dgVoodoo2, fails on Windows 10).",
" 1 = drop SETFOCUSWINDOW, let DirectDraw create",
" the device window.",
" 2 = SETFOCUSWINDOW first, then CREATEDEVICEWINDOW.",
" 3 = SETFOCUSWINDOW first, then EXCLUSIVE only,",
" matching what the main display already does.",
" 4 = EXCLUSIVE|FULLSCREEN only. The main display",
" has already set the focus window, so the",
" panels never contend for it.",
" 5 = as 4, plus ALLOWREBOOT.",
" Results are reported in gos-displays.txt.",
" -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.",
" -fps Write a per-second frame pacing report to",
" gos-fps.txt next to the executable: average fps,",
" 1% low, worst frame in ms, and a count of frames",
" taking over twice the average (hitches). Useful",
" for confirming smooth pacing on the MFD modes.",
" Off unless this switch is given.",
" -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;
}
// [panelcoop] Cooperative-level form for the radar/MFD panels. 0 = legacy combined
// call (what shipped); 1-3 are forms compatible with strict modern DirectDraw.
token = strstr(all_lower, "-tcoop ");
if (token && token[7])
{
int n = atoi(&token[7]);
if ((0 <= n) && (n <= 5))
g_nHshCoopMode = n;
}
// [fpslog] Enable the per-second frame pacing report written to gos-fps.txt.
g_nFpsLog = (strstr(all_lower, "-fps") != NULL) ? 1 : 0;
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