Serious-Engine/Sources/GameMP/Game.cpp
Daniel Gibson 72edf1c720 Commented out unused functions and variables
many unused functions and variables are now commented out

You'll still get tons of warnings, which should mostly fall in one of
the following categories:
1. Unnecessary variables or values generated from .es scripts
2. Pointers assigned to from functions with side-effects: DO NOT REMOVE!
   Like CEntity *penNew = CreateEntity_t(...); - even if penNew isn't
   used, CreateEntity() must be called there!
2016-05-09 18:51:03 +02:00

3082 lines
102 KiB
C++
Executable File

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
// Game.cpp : Defines the initialization routines for the DLL.
//
#include "StdAfx.h"
#include "GameMP/Game.h"
#include <sys/timeb.h>
#include <time.h>
#include <locale.h>
#ifdef PLATFORM_WIN32
#include <direct.h> // for _mkdir()
#include <io.h>
#endif
#include <Engine/Base/Profiling.h>
#include <Engine/Base/Statistics.h>
#include <Engine/CurrentVersion.h>
#include "Camera.h"
#include "LCDDrawing.h"
FLOAT con_fHeightFactor = 0.5f;
FLOAT con_tmLastLines = 5.0f;
INDEX con_bTalk = 0;
CTimerValue _tvMenuQuickSave((__int64) 0);
// used filenames
CTFileName fnmPersistentSymbols = CTString("Scripts\\PersistentSymbols.ini");
CTFileName fnmStartupScript = CTString("Scripts\\Game_startup.ini");
CTFileName fnmConsoleHistory = CTString("Temp\\ConsoleHistory.txt");
CTFileName fnmCommonControls = CTString("Controls\\System\\Common.ctl");
// force dependency for player class
DECLARE_CTFILENAME( fnmPlayerClass, "Classes\\Player.ecl");
#define MAX_HIGHSCORENAME 16
#define MAX_HIGHSCORETABLESIZE ((MAX_HIGHSCORENAME+1+sizeof(INDEX)*4)*HIGHSCORE_COUNT)*2
UBYTE _aubHighScoreBuffer[MAX_HIGHSCORETABLESIZE];
UBYTE _aubHighScorePacked[MAX_HIGHSCORETABLESIZE];
// controls used for all commands not belonging to any particular player
static CControls _ctrlCommonControls;
// array for keeping all frames' times
static CStaticStackArray<TIME> _atmFrameTimes;
static CStaticStackArray<INDEX> _actTriangles; // world, model, particle, total
// one and only Game object
// rcg11162001 This will resolve to the main binary under Linux, so it's
// okay. It's just another copy of the same otherwise.
#ifdef PLATFORM_UNIX
extern CGame *_pGame;
#else
CGame *_pGame = NULL;
#endif
extern "C"
{
#ifdef PLATFORM_WIN32
#define EXPORTABLE __declspec (dllexport)
#else
#define EXPORTABLE
#endif
EXPORTABLE CGame *GAME_Create(void)
{
_pGame = new CGame;
return _pGame;
}
} // extern "C"
// Just working around a symbol reference in a shared library that isn't
// available in SeriousSam by turning gm_ctrlControlsExtra into a pointer
// instead of a full object. Messy; sorry! --ryan.
CGame::CGame() : gm_ctrlControlsExtra(new CControls) {}
CGame::~CGame() { delete gm_ctrlControlsExtra; }
// recorded profiling stats
static CTimerValue _tvDemoStarted;
static CTimerValue _tvLastFrame;
static CTString _strProfile;
static BOOL _bDumpNextTime = FALSE;
static BOOL _bStartProfilingNextTime = FALSE;
static BOOL _bProfiling = FALSE;
static INDEX _ctProfileRecording = 0;
static FLOAT gam_iRecordHighScore = -1.0f;
FLOAT gam_afAmmoQuantity[5] = {2.0f, 2.0f, 1.0f, 1.0f , 2.0f };
FLOAT gam_afDamageStrength[5] = {0.25f, 0.5f, 1.0f, 1.5f , 2.0f };
FLOAT gam_afEnemyAttackSpeed[5] = {0.75f, 0.75f, 1.0f, 2.0f , 2.0f };
FLOAT gam_afEnemyMovementSpeed[5] = {1.0f , 1.0f , 1.0f, 1.25f, 1.25f};
FLOAT gam_fManaTransferFactor = 0.5f;
FLOAT gam_fExtraEnemyStrength = 0;
FLOAT gam_fExtraEnemyStrengthPerPlayer = 0;
INDEX gam_iCredits = -1; // number of credits for respawning
FLOAT gam_tmSpawnInvulnerability = 3;
INDEX gam_iScoreLimit = 100000;
INDEX gam_iFragLimit = 20;
INDEX gam_iTimeLimit = 0;
INDEX gam_bWeaponsStay = TRUE;
INDEX gam_bAmmoStays = TRUE;
INDEX gam_bHealthArmorStays = TRUE;
INDEX gam_bAllowHealth = TRUE;
INDEX gam_bAllowArmor = TRUE;
INDEX gam_bInfiniteAmmo = FALSE;
INDEX gam_bRespawnInPlace = TRUE;
INDEX gam_bPlayEntireGame = TRUE;
INDEX gam_bFriendlyFire = FALSE;
INDEX gam_ctMaxPlayers = 8;
INDEX gam_bWaitAllPlayers = FALSE;
INDEX gam_iInitialMana = 100;
INDEX gam_bQuickLoad = FALSE;
INDEX gam_bQuickSave = FALSE;
INDEX gam_iQuickSaveSlots = 8;
INDEX gam_iQuickStartDifficulty = 1;
INDEX gam_iQuickStartMode = 0;
INDEX gam_bQuickStartMP = 0;
INDEX gam_bEnableAdvancedObserving = 0;
INDEX gam_iObserverConfig = 0;
INDEX gam_iObserverOffset = 0;
INDEX gam_iStartDifficulty = 1;
INDEX gam_iStartMode = 0;
CTString gam_strGameAgentExtras = "";
INDEX gam_iBlood = 2; // 0=none, 1=green, 2=red, 3=hippie
INDEX gam_bGibs = TRUE;
INDEX gam_bUseExtraEnemies = TRUE;
static INDEX hud_iEnableStats = 1;
static FLOAT hud_fEnableFPS = 1;
static INDEX hud_iStats = 0;
static INDEX hud_bShowTime = FALSE;
static INDEX hud_bShowClock = FALSE;
static INDEX hud_bShowNetGraph = FALSE;
static INDEX hud_bShowResolution = FALSE;
static INDEX dem_bOSD = FALSE;
static INDEX dem_bPlay = FALSE;
static INDEX dem_bPlayByName = FALSE;
static INDEX dem_bProfile = FALSE;
static INDEX dem_iProfileRate = 5;
static CTString dem_strPostExec = "";
static INDEX ctl_iCurrentPlayerLocal = -1;
static INDEX ctl_iCurrentPlayer = -1;
static FLOAT gam_fChatSoundVolume = 0.25f;
BOOL map_bIsFirstEncounter = FALSE;
BOOL _bUserBreakEnabled = FALSE;
// make sure that console doesn't show last lines if not playing in network
void MaybeDiscardLastLines(void)
{
// if not in network
if (!_pNetwork->IsNetworkEnabled()) {
// don't show last lines on screen after exiting console
CON_DiscardLastLineTimes();
}
}
class CEnableUserBreak {
public:
BOOL bOld;
CEnableUserBreak();
~CEnableUserBreak();
};
CEnableUserBreak::CEnableUserBreak() {
bOld = _bUserBreakEnabled;
_bUserBreakEnabled = TRUE;
}
CEnableUserBreak::~CEnableUserBreak() {
_bUserBreakEnabled = bOld;
}
// wrapper function for dump and printout of extensive demo profile report
static void DumpDemoProfile(void)
{
CTString strFragment, strAnalyzed;
dem_iProfileRate = Clamp( dem_iProfileRate, 0, 60);
strFragment = _pGame->DemoReportFragmentsProfile( dem_iProfileRate);
strAnalyzed = _pGame->DemoReportAnalyzedProfile();
try {
// create file
CTFileStream strm;
CTString strFileName = CTString( "temp\\DemoProfile.lst");
strm.Create_t( strFileName, CTStream::CM_TEXT);
// dump results
strm.FPrintF_t( strFragment);
strm.FPrintF_t( strAnalyzed);
// done!
CPrintF( TRANS("Demo profile data dumped to '%s'.\n"), (const char *) strFileName);
}
catch (char *strError) {
// something went wrong :(
CPrintF( TRANS("Cannot dump demo profile data: %s\n"), strError);
}
}
static void ReportDemoProfile(void)
{
CTString strFragment, strAnalyzed;
dem_iProfileRate = Clamp( dem_iProfileRate, 0, 60);
strFragment = _pGame->DemoReportFragmentsProfile( dem_iProfileRate);
strAnalyzed = _pGame->DemoReportAnalyzedProfile();
CPrintF( strFragment);
CPrintF( strAnalyzed);
CPrintF( "-\n");
}
#define MAX_SCRIPTSOUNDS 16
static CSoundObject *_apsoScriptChannels[MAX_SCRIPTSOUNDS] = {0};
static void PlayScriptSound(INDEX iChannel, const CTString &strSound, FLOAT fVolume, FLOAT fPitch, BOOL bLooping)
{
if (iChannel<0 || iChannel>=MAX_SCRIPTSOUNDS) {
return;
}
if (_apsoScriptChannels[iChannel]==NULL) {
_apsoScriptChannels[iChannel] = new CSoundObject;
}
_apsoScriptChannels[iChannel]->SetVolume(fVolume, fVolume);
_apsoScriptChannels[iChannel]->SetPitch(fPitch);
try {
_apsoScriptChannels[iChannel]->Play_t(strSound, SOF_NONGAME|(bLooping?SOF_LOOP:0));
} catch (char *strError) {
CPrintF("%s\n", strError);
}
}
#if 0 // DG: unused.
static void PlayScriptSoundCfunc(void* pArgs)
{
INDEX iChannel = NEXTARGUMENT(INDEX);
CTString strSound = *NEXTARGUMENT(CTString*);
FLOAT fVolume = NEXTARGUMENT(FLOAT);
FLOAT fPitch = NEXTARGUMENT(FLOAT);
BOOL bLooping = NEXTARGUMENT(INDEX);
PlayScriptSound(iChannel, strSound, fVolume, fPitch, bLooping);
}
#endif // 0 (unused)
static void StopScriptSound(void* pArgs)
{
INDEX iChannel = NEXTARGUMENT(INDEX);
if (iChannel<0 || iChannel>=MAX_SCRIPTSOUNDS||_apsoScriptChannels[iChannel]==NULL) {
return;
}
_apsoScriptChannels[iChannel]->Stop();
}
static INDEX IsScriptSoundPlaying(INDEX iChannel)
{
if (iChannel<0 || iChannel>=MAX_SCRIPTSOUNDS||_apsoScriptChannels[iChannel]==NULL) {
return 0;
}
return _apsoScriptChannels[iChannel]->IsPlaying();
}
// Dump recorded profiling stats to file.
static void DumpProfileToFile(void)
{
_bDumpNextTime = TRUE;
}
// Dump recorded profiling stats to console.
static void DumpProfileToConsole(void)
{
CPutString(_strProfile);
}
// Record profiling stats.
static void RecordProfile(void)
{
_bStartProfilingNextTime = TRUE;
}
// screen shot saving feature in console
static BOOL bSaveScreenShot = FALSE;
static INDEX dem_iAnimFrame = -1;
static void SaveScreenShot(void)
{
bSaveScreenShot=TRUE;
}
static void Say(void* pArgs)
{
CTString strText = *NEXTARGUMENT(CTString*);
_pNetwork->SendChat(-1, -1, strText);
}
static void SayFromTo(void* pArgs)
{
INDEX ulFrom = NEXTARGUMENT(INDEX);
INDEX ulTo = NEXTARGUMENT(INDEX);
CTString strText = *NEXTARGUMENT(CTString*);
_pNetwork->SendChat(ulFrom, ulTo, strText);
}
// create name for a new screenshot
static CTFileName MakeScreenShotName(void)
{
// create base name from the world name
CTFileName fnmBase = CTString("ScreenShots\\")+_pNetwork->GetCurrentWorld().FileName();
// start at counter of zero
INDEX iShot = 0;
// repeat forever
FOREVER {
// create number for the file
CTString strNumber;
strNumber.PrintF("_shot%04d", iShot);
// create the full filename
CTFileName fnmFullTGA = fnmBase+strNumber+".tga";
CTFileName fnmFullJPG = fnmBase+strNumber+".jpg";
// if the file doesn't exist
if (!FileExistsForWriting(fnmFullTGA) && !FileExistsForWriting(fnmFullJPG)) {
// that is the right filename
return fnmFullTGA;
}
// if it exists, increment the number and retry
iShot++;
}
}
CButtonAction::CButtonAction(void)
{
ba_iFirstKey = KID_NONE;
ba_iSecondKey = KID_NONE;
ba_bFirstKeyDown = FALSE;
ba_bSecondKeyDown = FALSE;
}
// Assignment operator.
CButtonAction &CButtonAction ::operator=(const CButtonAction &baOriginal)
{
ba_iFirstKey = baOriginal.ba_iFirstKey;
ba_iSecondKey = baOriginal.ba_iSecondKey;
ba_strName = baOriginal.ba_strName;
ba_strCommandLineWhenPressed = baOriginal.ba_strCommandLineWhenPressed;
ba_strCommandLineWhenReleased = baOriginal.ba_strCommandLineWhenReleased;
ba_bFirstKeyDown = FALSE;
ba_bSecondKeyDown = FALSE;
return *this;
}
void CButtonAction::Read_t( CTStream &istrm)
{
istrm>>ba_iFirstKey;
istrm>>ba_iSecondKey;
istrm>>ba_strName;
istrm>>ba_strCommandLineWhenPressed;
istrm>>ba_strCommandLineWhenReleased;
}
void CButtonAction::Write_t( CTStream &ostrm)
{
ostrm<<ba_iFirstKey;
ostrm<<ba_iSecondKey;
ostrm<<ba_strName;
ostrm<<ba_strCommandLineWhenPressed;
ostrm<<ba_strCommandLineWhenReleased;
}
void CControls::DoButtonActions(void)
{
// for all button actions
FOREACHINLIST( CButtonAction, ba_lnNode, ctrl_lhButtonActions, itButtonAction)
{
// test if first button is pressed
BOOL bFirstPressed = _pInput->GetButtonState( itButtonAction->ba_iFirstKey);
// if it was just pressed
if (bFirstPressed && !itButtonAction->ba_bFirstKeyDown) {
// call pressed command
_pShell->Execute(itButtonAction->ba_strCommandLineWhenPressed);
// if it was just released
} else if (!bFirstPressed && itButtonAction->ba_bFirstKeyDown) {
// call released command
_pShell->Execute(itButtonAction->ba_strCommandLineWhenReleased);
}
// remember pressed state
itButtonAction->ba_bFirstKeyDown = bFirstPressed;
// test if second button is pressed
BOOL bSecondPressed = _pInput->GetButtonState( itButtonAction->ba_iSecondKey);
// if it was just pressed
if (bSecondPressed && !itButtonAction->ba_bSecondKeyDown) {
// call pressed command
_pShell->Execute(itButtonAction->ba_strCommandLineWhenPressed);
// if it was just released
} else if (!bSecondPressed && itButtonAction->ba_bSecondKeyDown) {
// call released command
_pShell->Execute(itButtonAction->ba_strCommandLineWhenReleased);
}
// remember pressed state
itButtonAction->ba_bSecondKeyDown = bSecondPressed;
}
}
// get current reading of an axis
FLOAT CControls::GetAxisValue(INDEX iAxis)
{
CAxisAction &aa = ctrl_aaAxisActions[iAxis];
FLOAT fReading = 0.0f;
if (aa.aa_iAxisAction!=AXIS_NONE) {
// get the reading
fReading = _pInput->GetAxisValue(aa.aa_iAxisAction);
// smooth the reading if needed
if ( ctrl_bSmoothAxes || aa.aa_bSmooth) {
FLOAT fSmoothed = (aa.aa_fLastReading+fReading)/2.0f;
aa.aa_fLastReading = fReading;
fReading = fSmoothed;
}
// integrate to get the absolute reading
aa.aa_fAbsolute+=fReading;
// get relative or absolute reading
if (!aa.aa_bRelativeControler) {
fReading = aa.aa_fAbsolute;
}
}
// compensate for the deadzone
if (aa.aa_fDeadZone>0) {
FLOAT fDeadZone = aa.aa_fDeadZone/100.0f;
if (fReading<-fDeadZone) {
fReading = (fReading+fDeadZone)/(1-fDeadZone);
} else if (fReading>fDeadZone) {
fReading = (fReading-fDeadZone)/(1-fDeadZone);
} else {
fReading = 0.0f;
}
}
// apply sensitivity and inversion
return fReading*aa.aa_fAxisInfluence;
}
void CControls::CreateAction(const CPlayerCharacter &pc, CPlayerAction &paAction, BOOL bPreScan)
{
// set axis-controlled moving
paAction.pa_vTranslation(1) = -GetAxisValue( AXIS_MOVE_LR);
paAction.pa_vTranslation(2) = GetAxisValue( AXIS_MOVE_UD);
paAction.pa_vTranslation(3) = -GetAxisValue( AXIS_MOVE_FB);
// set axis-controlled rotation
paAction.pa_aRotation(1) = (ANGLE)-GetAxisValue( AXIS_TURN_LR);
paAction.pa_aRotation(2) = (ANGLE)GetAxisValue( AXIS_TURN_UD);
paAction.pa_aRotation(3) = (ANGLE)GetAxisValue( AXIS_TURN_BK);
// set axis-controlled view rotation
paAction.pa_aViewRotation(1) = (ANGLE)GetAxisValue( AXIS_LOOK_LR);
paAction.pa_aViewRotation(2) = (ANGLE)GetAxisValue( AXIS_LOOK_UD);
paAction.pa_aViewRotation(3) = (ANGLE)GetAxisValue( AXIS_LOOK_BK);
// execute all button-action shell commands
if (!bPreScan) {
DoButtonActions();
}
//CPrintF("creating: prescan %d, x:%g\n", bPreScan, paAction.pa_aRotation(1));
// make the player class create the action packet
ctl_ComposeActionPacket(pc, paAction, bPreScan);
}
CButtonAction &CControls::AddButtonAction(void)
{
// create a new action
CButtonAction *pbaNew = new CButtonAction;
// add it to end of list
ctrl_lhButtonActions.AddTail(pbaNew->ba_lnNode);
return *pbaNew;
}
void CControls::RemoveButtonAction( CButtonAction &baButtonAction)
{
// remove from list
baButtonAction.ba_lnNode.Remove();
// free it
delete &baButtonAction;
}
void CControls::DeleteAllButtonActions()
{
FORDELETELIST(CButtonAction, ba_lnNode, this->ctrl_lhButtonActions, itAct) {
delete &itAct.Current();
}
}
// calculate some useful demo vars
static void CalcDemoProfile( INDEX ctFrames, INDEX &ctFramesNoPeaks,
DOUBLE &dTimeSum, DOUBLE &dTimeSumNoPeaks, TIME &tmAverage, TIME &tmAverageNoPeaks,
TIME &tmSigma, TIME &tmHighLimit, TIME &tmLowLimit, TIME &tmHighPeak, TIME &tmLowPeak,
FLOAT &fAvgWTris, FLOAT &fAvgMTris, FLOAT &fAvgPTris, FLOAT &fAvgTTris,
FLOAT &fAvgWTrisNoPeaks, FLOAT &fAvgMTrisNoPeaks, FLOAT &fAvgPTrisNoPeaks, FLOAT &fAvgTTrisNoPeaks)
{
// calculate raw average
INDEX i;
TIME tmCurrent;
dTimeSum = 0;
DOUBLE dWTriSum=0, dMTriSum=0, dPTriSum=0, dTTriSum=0;
DOUBLE dWTriSumNoPeaks=0, dMTriSumNoPeaks=0, dPTriSumNoPeaks=0, dTTriSumNoPeaks=0;
for( i=0; i<ctFrames; i++) {
dTimeSum += _atmFrameTimes[i];
dWTriSum += _actTriangles[i*4 +0]; // world
dMTriSum += _actTriangles[i*4 +1]; // model
dPTriSum += _actTriangles[i*4 +2]; // particle
dTTriSum += _actTriangles[i*4 +3]; // total
}
tmAverage = dTimeSum / ctFrames;
fAvgWTris = dWTriSum / ctFrames;
fAvgMTris = dMTriSum / ctFrames;
fAvgPTris = dPTriSum / ctFrames;
fAvgTTris = dTTriSum / ctFrames;
// calc raw sigma and limits
DOUBLE dSigmaSum=0;
for( i=0; i<ctFrames; i++) {
tmCurrent = _atmFrameTimes[i];
TIME tmDelta = tmCurrent-tmAverage;
dSigmaSum += tmDelta*tmDelta;
}
tmSigma = Sqrt(dSigmaSum/ctFrames);
tmHighLimit = (tmAverage-tmSigma*2);
tmLowLimit = (tmAverage+tmSigma*2);
// eliminate low peaks
ctFramesNoPeaks = ctFrames;
dTimeSumNoPeaks = dTimeSum;
dWTriSumNoPeaks = dWTriSum;
dMTriSumNoPeaks = dMTriSum;
dPTriSumNoPeaks = dPTriSum;
dTTriSumNoPeaks = dTTriSum;
for( i=0; i<ctFrames; i++) {
tmCurrent = _atmFrameTimes[i];
if( tmHighLimit>tmCurrent || tmLowLimit<tmCurrent) {
dTimeSumNoPeaks -= tmCurrent;
dWTriSumNoPeaks -= _actTriangles[i*4 +0];
dMTriSumNoPeaks -= _actTriangles[i*4 +1];
dPTriSumNoPeaks -= _actTriangles[i*4 +2];
dTTriSumNoPeaks -= _actTriangles[i*4 +3];
ctFramesNoPeaks--;
}
}
// calculate peaks, new averages and sigma (without peaks)
tmAverageNoPeaks = dTimeSumNoPeaks / ctFramesNoPeaks;
fAvgWTrisNoPeaks = dWTriSumNoPeaks / ctFramesNoPeaks;
fAvgMTrisNoPeaks = dMTriSumNoPeaks / ctFramesNoPeaks;
fAvgPTrisNoPeaks = dPTriSumNoPeaks / ctFramesNoPeaks;
fAvgTTrisNoPeaks = dTTriSumNoPeaks / ctFramesNoPeaks;
dSigmaSum=0;
tmHighPeak=99999, tmLowPeak=0;
for( i=0; i<ctFrames; i++) {
tmCurrent = _atmFrameTimes[i];
if( tmHighLimit>tmCurrent || tmLowLimit<tmCurrent) continue;
TIME tmDelta = tmCurrent-tmAverageNoPeaks;
dSigmaSum += tmDelta*tmDelta;
if( tmHighPeak > tmCurrent) tmHighPeak = tmCurrent;
if( tmLowPeak < tmCurrent) tmLowPeak = tmCurrent;
}
tmSigma = Sqrt( dSigmaSum/ctFramesNoPeaks);
}
// dump demo profile to file
CTString CGame::DemoReportFragmentsProfile( INDEX iRate)
{
CTString strRes="";
CTString strTmp;
INDEX ctFrames = _atmFrameTimes.Count();
// if report is not required
if( dem_iProfileRate==0) {
strRes.PrintF( TRANS("\nFragments report disabled.\n"));
return strRes;
}
// if not enough frames
if( ctFrames<20) {
strRes.PrintF( TRANS("\nNot enough recorded frames to make fragments report.\n"));
return strRes;
}
// enough frames - calc almost everything
strRes.PrintF( TRANS("\nDemo performance results (fragment time = %d seconds):\n"), dem_iProfileRate);
strTmp.PrintF( "------------------------------------------------------\n\n");
strRes += strTmp;
DOUBLE dTimeSum, dTimeSumNoPeaks;
INDEX ctFramesNoPeaks;
TIME tmAverage, tmAverageNoPeaks;
TIME tmSigma, tmHighLimit, tmLowLimit, tmHighPeak, tmLowPeak;
FLOAT fAvgWTris, fAvgMTris, fAvgPTris, fAvgTTris;
FLOAT fAvgWTrisNoPeaks, fAvgMTrisNoPeaks, fAvgPTrisNoPeaks, fAvgTTrisNoPeaks;
CalcDemoProfile( ctFrames, ctFramesNoPeaks, dTimeSum, dTimeSumNoPeaks, tmAverage, tmAverageNoPeaks,
tmSigma, tmHighLimit, tmLowLimit, tmHighPeak, tmLowPeak,
fAvgWTris, fAvgMTris, fAvgPTris, fAvgTTris,
fAvgWTrisNoPeaks, fAvgMTrisNoPeaks, fAvgPTrisNoPeaks, fAvgTTrisNoPeaks);
strTmp.PrintF( TRANS(" # average FPS average FPS (W/O peaks)\n"));
strRes += strTmp;
// loop thru frames and create output of time fragmens
dTimeSum = 0;
dTimeSumNoPeaks = 0;
ctFramesNoPeaks = 0;
FLOAT fFrameCounter = 0;
FLOAT fFrameCounterNoPeaks = 0;
TIME tmRate = dem_iProfileRate;
INDEX iFragment=1;
for( INDEX i=0; i<ctFrames; i++)
{ // get current frame time and calc sums
TIME tmCurrent = _atmFrameTimes[i];
dTimeSum += tmCurrent;
fFrameCounter++;
if( tmHighLimit<=tmCurrent && tmLowLimit>=tmCurrent) {
dTimeSumNoPeaks += tmCurrent;
fFrameCounterNoPeaks++;
}
// enough data for one time fragment
if( dTimeSum>=tmRate) {
FLOAT fTimeOver = dTimeSum - tmRate;
FLOAT fFrameOver = fTimeOver/tmCurrent;
FLOAT fFragmentAverage = tmRate / (fFrameCounter-fFrameOver);
FLOAT fFragmentNoPeaks = (tmRate-(dTimeSum-dTimeSumNoPeaks)) / (fFrameCounterNoPeaks-fFrameOver);
strTmp.PrintF( "%4d %6.1f %6.1f", iFragment, 1.0f/fFragmentAverage, 1.0f/fFragmentNoPeaks);
strRes += strTmp;
INDEX iFragmentAverage10 = FloatToInt(5.0f/fFragmentAverage);
INDEX iFragmentNoPeaks10 = FloatToInt(5.0f/fFragmentNoPeaks);
if( iFragmentAverage10 != iFragmentNoPeaks10) strTmp.PrintF( " !\n");
else strTmp.PrintF( "\n");
strRes += strTmp;
// restart time and frames
dTimeSum = fTimeOver;
dTimeSumNoPeaks = fTimeOver;
fFrameCounter = fFrameOver;
fFrameCounterNoPeaks = fFrameOver;
iFragment++;
}
}
// all done
return strRes;
}
// printout extensive demo profile report
CTString CGame::DemoReportAnalyzedProfile(void)
{
CTString strRes="";
INDEX ctFrames = _atmFrameTimes.Count();
// nothing kept?
if( ctFrames<20) {
strRes.PrintF( TRANS("\nNot enough recorded frames to analyze.\n"));
return strRes;
}
// calc almost everything
DOUBLE dTimeSum, dTimeSumNoPeaks;
INDEX ctFramesNoPeaks;
TIME tmAverage, tmAverageNoPeaks;
TIME tmSigma, tmHighLimit, tmLowLimit, tmHighPeak, tmLowPeak;
FLOAT fAvgWTris, fAvgMTris, fAvgPTris, fAvgTTris;
FLOAT fAvgWTrisNoPeaks, fAvgMTrisNoPeaks, fAvgPTrisNoPeaks, fAvgTTrisNoPeaks;
CalcDemoProfile( ctFrames, ctFramesNoPeaks, dTimeSum, dTimeSumNoPeaks, tmAverage, tmAverageNoPeaks,
tmSigma, tmHighLimit, tmLowLimit, tmHighPeak, tmLowPeak,
fAvgWTris, fAvgMTris, fAvgPTris, fAvgTTris,
fAvgWTrisNoPeaks, fAvgMTrisNoPeaks, fAvgPTrisNoPeaks, fAvgTTrisNoPeaks);
// calc sustains
DOUBLE dHighSum=0, dLowSum=0;
DOUBLE dCurrentHighSum=0, dCurrentLowSum=0;
INDEX ctHighFrames=0, ctLowFrames=0;
INDEX ctCurrentHighFrames=0, ctCurrentLowFrames=0;
for( INDEX i=0; i<ctFrames; i++)
{ // skip low peaks
TIME tmCurrent = _atmFrameTimes[i];
if( tmHighLimit>tmCurrent || tmLowLimit<tmCurrent) continue;
// high?
if( (tmAverageNoPeaks-tmSigma) > tmCurrent) {
// keep high sustain
dCurrentHighSum += tmCurrent;
ctCurrentHighFrames++;
} else {
// new high sustain found?
if( ctHighFrames < ctCurrentHighFrames) {
ctHighFrames = ctCurrentHighFrames;
dHighSum = dCurrentHighSum;
}
// reset high sustain
ctCurrentHighFrames = 0;
dCurrentHighSum = 0;
}
// low?
if( (tmAverageNoPeaks+tmSigma) < tmCurrent) {
// keep low sustain
dCurrentLowSum += tmCurrent;
ctCurrentLowFrames++;
} else {
// new low sustain found?
if( ctLowFrames < ctCurrentLowFrames) {
ctLowFrames = ctCurrentLowFrames;
dLowSum = dCurrentLowSum;
}
// reset low sustain
ctCurrentLowFrames = 0;
dCurrentLowSum = 0;
}
}
// and results are ...
TIME tmHighSustained = ctHighFrames / dHighSum;
TIME tmLowSustained = ctLowFrames / dLowSum;
// printout
CTString strTmp;
strTmp.PrintF( TRANS("\n%.1f KB used for demo profile:\n"), 1+ ctFrames*5*sizeof(FLOAT)/1024.0f);
strRes += strTmp;
strTmp.PrintF( TRANS(" Originally recorded: %d frames in %.1f seconds => %5.1f FPS average.\n"),
ctFrames, dTimeSum, 1.0f/tmAverage);
strRes += strTmp;
strTmp.PrintF( TRANS("Without excessive peaks: %d frames in %.1f seconds => %5.1f FPS average.\n"),
ctFramesNoPeaks, dTimeSumNoPeaks, 1.0f/tmAverageNoPeaks);
strRes += strTmp;
strTmp.PrintF( TRANS(" High peak: %5.1f FPS\n"), 1.0f/tmHighPeak);
strRes += strTmp;
strTmp.PrintF( TRANS(" Low peak: %5.1f FPS\n"), 1.0f/tmLowPeak);
strRes += strTmp;
// enough values recorder for high sustain?
if( ctHighFrames > (ctFrames/1024+5)) {
strTmp.PrintF( TRANS(" High sustained: %5.1f FPS (%d frames in %.1f seconds)\n"),
tmHighSustained, ctHighFrames, dHighSum);
strRes += strTmp;
}
// enough values recorder for low sustain?
if( ctLowFrames > (ctFrames/1024+5)) {
strTmp.PrintF( TRANS(" Low sustained: %5.1f FPS (%d frames in %.1f seconds)\n"),
tmLowSustained, ctLowFrames, dLowSum);
strRes += strTmp;
}
// do triangle profile output (hidden - maybe not so wise idea)
if( dem_bProfile==217) {
const FLOAT fAvgRTris = fAvgTTris - (fAvgWTris+fAvgMTris+fAvgPTris);
const FLOAT fAvgRTrisNoPeaks = fAvgTTrisNoPeaks - (fAvgWTrisNoPeaks+fAvgMTrisNoPeaks+fAvgPTrisNoPeaks);
strTmp.PrintF( TRANS("Triangles per frame (with and without excessive peaks):\n")); strRes += "\n"+strTmp;
strTmp.PrintF( TRANS(" World: %7.1f / %.1f\n"), fAvgWTris, fAvgWTrisNoPeaks); strRes += strTmp;
strTmp.PrintF( TRANS(" Model: %7.1f / %.1f\n"), fAvgMTris, fAvgMTrisNoPeaks); strRes += strTmp;
strTmp.PrintF( TRANS(" Particle: %7.1f / %.1f\n"), fAvgPTris, fAvgPTrisNoPeaks); strRes += strTmp;
strTmp.PrintF( TRANS(" rest (2D): %7.1f / %.1f\n"), fAvgRTris, fAvgRTrisNoPeaks); strRes += strTmp;
strRes += " --------------------\n";
strTmp.PrintF( TRANS(" TOTAL: %7.1f / %.1f\n"), fAvgTTris, fAvgTTrisNoPeaks); strRes += strTmp;
}
// all done
return strRes;
}
/* This is called every TickQuantum seconds. */
void CGameTimerHandler::HandleTimer(void)
{
// call game's timer routine
_pGame->GameHandleTimer();
}
void CGame::GameHandleTimer(void)
{
// if direct input is active
if( _pInput->IsInputEnabled() && !gm_bMenuOn)
{
// check if any active control uses joystick
BOOL bAnyJoy = _ctrlCommonControls.UsesJoystick();
for( INDEX iPlayer=0; iPlayer<4; iPlayer++) {
if( gm_lpLocalPlayers[ iPlayer].lp_pplsPlayerSource != NULL) {
INDEX iCurrentPlayer = gm_lpLocalPlayers[ iPlayer].lp_iPlayer;
CControls &ctrls = gm_actrlControls[ iCurrentPlayer];
if (ctrls.UsesJoystick()) {
bAnyJoy = TRUE;
break;
}
}
}
_pInput->SetJoyPolling(bAnyJoy);
// read input devices
_pInput->GetInput(FALSE);
// if game is currently active, and not paused
if (gm_bGameOn && !_pNetwork->IsPaused() && !_pNetwork->GetLocalPause())
{
// for all possible local players
for( INDEX iPlayer=0; iPlayer<4; iPlayer++)
{
// if this player exist
if( gm_lpLocalPlayers[ iPlayer].lp_pplsPlayerSource != NULL)
{
// publish player index to console
ctl_iCurrentPlayerLocal = iPlayer;
ctl_iCurrentPlayer = gm_lpLocalPlayers[ iPlayer].lp_pplsPlayerSource->pls_Index;
// copy its local controls to current controls
memcpy(
ctl_pvPlayerControls,
gm_lpLocalPlayers[ iPlayer].lp_ubPlayerControlsState,
ctl_slPlayerControlsSize);
// create action for it for this tick
CPlayerAction paAction;
INDEX iCurrentPlayer = gm_lpLocalPlayers[ iPlayer].lp_iPlayer;
CControls &ctrls = gm_actrlControls[ iCurrentPlayer];
ctrls.CreateAction(gm_apcPlayers[iCurrentPlayer], paAction, FALSE);
// set the action in the client source object
gm_lpLocalPlayers[ iPlayer].lp_pplsPlayerSource->SetAction(paAction);
// copy the local controls back
memcpy(
gm_lpLocalPlayers[ iPlayer].lp_ubPlayerControlsState,
ctl_pvPlayerControls,
ctl_slPlayerControlsSize);
}
}
// clear player indices
ctl_iCurrentPlayerLocal = -1;
ctl_iCurrentPlayer = -1;
}
// execute all button-action shell commands for common controls
if (gm_bGameOn) {
_ctrlCommonControls.DoButtonActions();
}
}
// if DirectInput is disabled, and game is currently active
else if (gm_bGameOn)
{
// for all possible local players
for( INDEX iPlayer=0; iPlayer<4; iPlayer++)
{ // if this player exist
if( gm_lpLocalPlayers[iPlayer].lp_pplsPlayerSource != NULL)
{
CPlayerSource &pls = *gm_lpLocalPlayers[iPlayer].lp_pplsPlayerSource;
// create dummy action for the player for this tick
CPlayerAction paClearAction;
// clear actions
paClearAction = pls.pls_paAction;
paClearAction.pa_vTranslation = FLOAT3D(0.0f,0.0f,0.0f);
// paClearAction.pa_aRotation = ANGLE3D(0,0,0);
// paClearAction.pa_aViewRotation = ANGLE3D(0,0,0);
paClearAction.pa_ulButtons = 0;
// clear the action in the client source object
pls.SetAction(paClearAction);
}
}
}
}
/*
* Global game object (in our case Flesh) initialization function
*/
void CGame::InitInternal( void)
{
gam_strCustomLevel = ""; // filename of custom level chosen
gam_strSessionName = TRANS("Unnamed session"); // name of multiplayer network session
gam_strJoinAddress = TRANS("serveraddress"); // join address
gm_MenuSplitScreenCfg = SSC_PLAY1;
gm_StartSplitScreenCfg = SSC_PLAY1;
gm_CurrentSplitScreenCfg = SSC_PLAY1;
gm_iLastSetHighScore = 0;
gm_iSinglePlayer = 0;
gm_iWEDSinglePlayer = 0;
gm_bGameOn = FALSE;
gm_bMenuOn = FALSE;
gm_bFirstLoading = FALSE;
gm_bProfileDemo = FALSE;
gm_slPlayerControlsSize = 0;
gm_pvGlobalPlayerControls = NULL;
memset(gm_aiMenuLocalPlayers, 0, sizeof(gm_aiMenuLocalPlayers));
memset(gm_aiStartLocalPlayers, 0, sizeof(gm_aiStartLocalPlayers));
// first assign translated to make dependcy catcher extract the translations
gm_astrAxisNames[AXIS_MOVE_UD] = TRANS("move u/d");
gm_astrAxisNames[AXIS_MOVE_LR] = TRANS("move l/r");
gm_astrAxisNames[AXIS_MOVE_FB] = TRANS("move f/b");
gm_astrAxisNames[AXIS_TURN_UD] = TRANS("look u/d");
gm_astrAxisNames[AXIS_TURN_LR] = TRANS("turn l/r");
gm_astrAxisNames[AXIS_TURN_BK] = TRANS("banking");
gm_astrAxisNames[AXIS_LOOK_UD] = TRANS("view u/d");
gm_astrAxisNames[AXIS_LOOK_LR] = TRANS("view l/r");
gm_astrAxisNames[AXIS_LOOK_BK] = TRANS("view banking");
// but we must not really use the translation for loading
gm_astrAxisNames[AXIS_MOVE_UD] = "move u/d"; //
gm_astrAxisNames[AXIS_MOVE_LR] = "move l/r"; //
gm_astrAxisNames[AXIS_MOVE_FB] = "move f/b"; //
gm_astrAxisNames[AXIS_TURN_UD] = "look u/d"; //
gm_astrAxisNames[AXIS_TURN_LR] = "turn l/r"; //
gm_astrAxisNames[AXIS_TURN_BK] = "banking"; //
gm_astrAxisNames[AXIS_LOOK_UD] = "view u/d"; //
gm_astrAxisNames[AXIS_LOOK_LR] = "view l/r"; //
gm_astrAxisNames[AXIS_LOOK_BK] = "view banking"; //
gm_csConsoleState = CS_OFF;
gm_csComputerState = CS_OFF;
gm_bGameOn = FALSE;
gm_bMenuOn = FALSE;
gm_bFirstLoading = FALSE;
gm_aiMenuLocalPlayers[0] = 0;
gm_aiMenuLocalPlayers[1] = -1;
gm_aiMenuLocalPlayers[2] = -1;
gm_aiMenuLocalPlayers[3] = -1;
gm_MenuSplitScreenCfg = SSC_PLAY1;
LoadPlayersAndControls();
gm_iWEDSinglePlayer = 0;
gm_iSinglePlayer = 0;
// add game timer handler
_pTimer->AddHandler(&m_gthGameTimerHandler);
// add shell variables
_pShell->DeclareSymbol("user void RecordProfile(void);", (void *)&RecordProfile);
_pShell->DeclareSymbol("user void SaveScreenShot(void);", (void *)&SaveScreenShot);
_pShell->DeclareSymbol("user void DumpProfileToConsole(void);", (void *)&DumpProfileToConsole);
_pShell->DeclareSymbol("user void DumpProfileToFile(void);", (void *)&DumpProfileToFile);
_pShell->DeclareSymbol("user INDEX hud_iStats;", (void *)&hud_iStats);
_pShell->DeclareSymbol("user INDEX hud_bShowResolution;", (void *)&hud_bShowResolution);
_pShell->DeclareSymbol("persistent user INDEX hud_bShowTime;", (void *)&hud_bShowTime);
_pShell->DeclareSymbol("persistent user INDEX hud_bShowClock;", (void *)&hud_bShowClock);
_pShell->DeclareSymbol("user INDEX dem_bOnScreenDisplay;", (void *)&dem_bOSD);
_pShell->DeclareSymbol("user INDEX dem_bPlay;", (void *)&dem_bPlay);
_pShell->DeclareSymbol("user INDEX dem_bPlayByName;", (void *)&dem_bPlayByName);
_pShell->DeclareSymbol("user INDEX dem_bProfile;", (void *)&dem_bProfile);
_pShell->DeclareSymbol("user INDEX dem_iAnimFrame;", (void *)&dem_iAnimFrame);
_pShell->DeclareSymbol("user CTString dem_strPostExec;", (void *)&dem_strPostExec);
_pShell->DeclareSymbol("persistent user INDEX dem_iProfileRate;", (void *)&dem_iProfileRate);
_pShell->DeclareSymbol("persistent user INDEX hud_bShowNetGraph;", (void *)&hud_bShowNetGraph);
_pShell->DeclareSymbol("FLOAT gam_afEnemyMovementSpeed[5];", (void *)&gam_afEnemyMovementSpeed);
_pShell->DeclareSymbol("FLOAT gam_afEnemyAttackSpeed[5];", (void *)&gam_afEnemyAttackSpeed);
_pShell->DeclareSymbol("FLOAT gam_afDamageStrength[5];", (void *)&gam_afDamageStrength);
_pShell->DeclareSymbol("FLOAT gam_afAmmoQuantity[5];", (void *)&gam_afAmmoQuantity);
_pShell->DeclareSymbol("persistent user FLOAT gam_fManaTransferFactor;", (void *)&gam_fManaTransferFactor);
_pShell->DeclareSymbol("persistent user FLOAT gam_fExtraEnemyStrength ;", (void *)&gam_fExtraEnemyStrength );
_pShell->DeclareSymbol("persistent user FLOAT gam_fExtraEnemyStrengthPerPlayer;", (void *)&gam_fExtraEnemyStrengthPerPlayer );
_pShell->DeclareSymbol("persistent user INDEX gam_iInitialMana;", (void *)&gam_iInitialMana);
_pShell->DeclareSymbol("persistent user INDEX gam_iScoreLimit;", (void *)&gam_iScoreLimit);
_pShell->DeclareSymbol("persistent user INDEX gam_iFragLimit;", (void *)&gam_iFragLimit);
_pShell->DeclareSymbol("persistent user INDEX gam_iTimeLimit;", (void *)&gam_iTimeLimit);
_pShell->DeclareSymbol("persistent user INDEX gam_ctMaxPlayers;", (void *)&gam_ctMaxPlayers);
_pShell->DeclareSymbol("persistent user INDEX gam_bWaitAllPlayers;", (void *)&gam_bWaitAllPlayers);
_pShell->DeclareSymbol("persistent user INDEX gam_bFriendlyFire;", (void *)&gam_bFriendlyFire);
_pShell->DeclareSymbol("persistent user INDEX gam_bPlayEntireGame;", (void *)&gam_bPlayEntireGame);
_pShell->DeclareSymbol("persistent user INDEX gam_bWeaponsStay;", (void *)&gam_bWeaponsStay);
_pShell->DeclareSymbol("persistent user INDEX gam_bAmmoStays ;", (void *)&gam_bAmmoStays );
_pShell->DeclareSymbol("persistent user INDEX gam_bHealthArmorStays;", (void *)&gam_bHealthArmorStays);
_pShell->DeclareSymbol("persistent user INDEX gam_bAllowHealth ;", (void *)&gam_bAllowHealth );
_pShell->DeclareSymbol("persistent user INDEX gam_bAllowArmor ;", (void *)&gam_bAllowArmor );
_pShell->DeclareSymbol("persistent user INDEX gam_bInfiniteAmmo ;", (void *)&gam_bInfiniteAmmo );
_pShell->DeclareSymbol("persistent user INDEX gam_bRespawnInPlace ;", (void *)&gam_bRespawnInPlace );
_pShell->DeclareSymbol("persistent user INDEX gam_iCredits;", (void *)&gam_iCredits);
_pShell->DeclareSymbol("persistent user FLOAT gam_tmSpawnInvulnerability;", (void *)&gam_tmSpawnInvulnerability);
_pShell->DeclareSymbol("persistent user INDEX gam_iBlood;", (void *)&gam_iBlood);
_pShell->DeclareSymbol("persistent user INDEX gam_bGibs;", (void *)&gam_bGibs);
_pShell->DeclareSymbol("persistent user INDEX gam_bUseExtraEnemies;", (void *)&gam_bUseExtraEnemies);
_pShell->DeclareSymbol("user INDEX gam_bQuickLoad;", (void *)&gam_bQuickLoad);
_pShell->DeclareSymbol("user INDEX gam_bQuickSave;", (void *)&gam_bQuickSave);
_pShell->DeclareSymbol("user INDEX gam_iQuickSaveSlots;", (void *)&gam_iQuickSaveSlots);
_pShell->DeclareSymbol("user INDEX gam_iQuickStartDifficulty;", (void *)&gam_iQuickStartDifficulty);
_pShell->DeclareSymbol("user INDEX gam_iQuickStartMode;", (void *)&gam_iQuickStartMode);
_pShell->DeclareSymbol("user INDEX gam_bQuickStartMP;", (void *)&gam_bQuickStartMP);
_pShell->DeclareSymbol("persistent user INDEX gam_iStartDifficulty;", (void *)&gam_iStartDifficulty);
_pShell->DeclareSymbol("persistent user INDEX gam_iStartMode;", (void *)&gam_iStartMode);
_pShell->DeclareSymbol("persistent user CTString gam_strGameAgentExtras;", (void *)&gam_strGameAgentExtras);
_pShell->DeclareSymbol("persistent user CTString gam_strCustomLevel;", (void *)&gam_strCustomLevel);
_pShell->DeclareSymbol("persistent user CTString gam_strSessionName;", (void *)&gam_strSessionName);
_pShell->DeclareSymbol("persistent user CTString gam_strJoinAddress;", (void *)&gam_strJoinAddress);
_pShell->DeclareSymbol("persistent user INDEX gam_bEnableAdvancedObserving;", (void *)&gam_bEnableAdvancedObserving);
_pShell->DeclareSymbol("user INDEX gam_iObserverConfig;", (void *)&gam_iObserverConfig);
_pShell->DeclareSymbol("user INDEX gam_iObserverOffset;", (void *)&gam_iObserverOffset);
_pShell->DeclareSymbol("INDEX gam_iRecordHighScore;", (void *)&gam_iRecordHighScore);
_pShell->DeclareSymbol("persistent user FLOAT con_fHeightFactor;", (void *)&con_fHeightFactor);
_pShell->DeclareSymbol("persistent user FLOAT con_tmLastLines;", (void *)&con_tmLastLines);
_pShell->DeclareSymbol("user INDEX con_bTalk;", (void *)&con_bTalk);
_pShell->DeclareSymbol("user void ReportDemoProfile(void);", (void *)&ReportDemoProfile);
_pShell->DeclareSymbol("user void DumpDemoProfile(void);", (void *)&DumpDemoProfile);
extern CTString GetGameAgentRulesInfo(void);
extern CTString GetGameTypeName(INDEX);
extern CTString GetGameTypeNameCfunc(void* pArgs);
extern CTString GetCurrentGameTypeName(void);
extern ULONG GetSpawnFlagsForGameType(INDEX);
extern ULONG GetSpawnFlagsForGameTypeCfunc(void* pArgs);
extern BOOL IsMenuEnabled_(const CTString &);
extern BOOL IsMenuEnabledCfunc(void* pArgs);
_pShell->DeclareSymbol("user CTString GetGameAgentRulesInfo(void);", (void *)&GetGameAgentRulesInfo);
_pShell->DeclareSymbol("user CTString GetGameTypeName(INDEX);", (void *)&GetGameTypeNameCfunc);
_pShell->DeclareSymbol("user CTString GetCurrentGameTypeName(void);", (void *)&GetCurrentGameTypeName);
_pShell->DeclareSymbol("user INDEX GetSpawnFlagsForGameType(INDEX);", (void *)&GetSpawnFlagsForGameTypeCfunc);
_pShell->DeclareSymbol("user INDEX IsMenuEnabled(CTString);", (void *)&IsMenuEnabledCfunc);
_pShell->DeclareSymbol("user void Say(CTString);", (void *)&Say);
_pShell->DeclareSymbol("user void SayFromTo(INDEX, INDEX, CTString);", (void *)&SayFromTo);
_pShell->DeclareSymbol("CTString GetGameTypeNameSS(INDEX);", (void *)&GetGameTypeName);
_pShell->DeclareSymbol("INDEX GetSpawnFlagsForGameTypeSS(INDEX);", (void *)&GetSpawnFlagsForGameType);
_pShell->DeclareSymbol("INDEX IsMenuEnabledSS(CTString);", (void *)&IsMenuEnabled_);
_pShell->DeclareSymbol("user const INDEX ctl_iCurrentPlayerLocal;", (void *)&ctl_iCurrentPlayerLocal);
_pShell->DeclareSymbol("user const INDEX ctl_iCurrentPlayer;", (void *)&ctl_iCurrentPlayer);
_pShell->DeclareSymbol("user FLOAT gam_fChatSoundVolume;", (void *)&gam_fChatSoundVolume);
_pShell->DeclareSymbol("user void PlaySound(INDEX, CTString, FLOAT, FLOAT, INDEX);", (void *)&PlayScriptSound);
_pShell->DeclareSymbol("user void StopSound(INDEX);", (void *)&StopScriptSound);
_pShell->DeclareSymbol("user INDEX IsSoundPlaying(INDEX);", (void *)&IsScriptSoundPlaying);
CAM_Init();
// load persistent symbols
if (!_bDedicatedServer) {
_pShell->Execute(CTString("include \"")+fnmPersistentSymbols+"\";");
}
// execute the startup script
_pShell->Execute(CTString("include \"")+fnmStartupScript+"\";");
// check the size and pointer of player control variables that are local to each player
if (ctl_slPlayerControlsSize<=0
||ctl_slPlayerControlsSize>sizeof(((CLocalPlayer*)NULL)->lp_ubPlayerControlsState)
||ctl_pvPlayerControls==NULL) {
FatalError(TRANS("Current player controls are invalid."));
}
// load common controls
try {
_ctrlCommonControls.Load_t(fnmCommonControls);
} catch (char * /*strError*/) {
//FatalError(TRANS("Cannot load common controls: %s\n"), strError);
}
// init LCD textures/fonts
LCDInit();
// load console history
CTString strConsole;
try {
strConsole.LoadKeepCRLF_t(fnmConsoleHistory);
gam_strConsoleInputBuffer = strConsole;
} catch (char *strError) {
(void)strError; // must ignore if there is no history file
}
// load game shell settings
try {
Load_t();
} catch (char *strError) {
CPrintF(TRANSV("Cannot load game settings:\n%s\n Using defaults\n"), strError);
}
CON_DiscardLastLineTimes();
// provide URL to the engine
_strModURL = "http://www.croteam.com/mods/TheSecondEncounter";
}
// internal cleanup
void CGame::EndInternal(void)
{
// stop game if eventually started
StopGame();
// remove game timer handler
_pTimer->RemHandler( &m_gthGameTimerHandler);
// save persistent symbols
if (!_bDedicatedServer) {
_pShell->StorePersistentSymbols(fnmPersistentSymbols);
}
LCDEnd();
// stop and delete any playing sound
#define MAX_SCRIPTSOUNDS 16
for( INDEX i=0; i<MAX_SCRIPTSOUNDS; i++) {
if( _apsoScriptChannels[i]==NULL) continue;
_apsoScriptChannels[i]->Stop();
delete _apsoScriptChannels[i];
}
// save console history
CTString strConsole = gam_strConsoleInputBuffer;
strConsole.TrimLeft(8192);
try {
strConsole.SaveKeepCRLF_t(fnmConsoleHistory);
} catch (char *strError) {
WarningMessage(TRANS("Cannot save console history:\n%s"), strError);
}
SavePlayersAndControls();
// save game shell settings
try {
Save_t();
} catch (char *strError) {
WarningMessage("Cannot load game settings:\n%s\nUsing defaults!", strError);
}
}
BOOL CGame::NewGame(const CTString &strSessionName, const CTFileName &fnWorld,
CSessionProperties &sp)
{
gam_iObserverConfig = 0;
gam_iObserverOffset = 0;
// stop eventually running game
StopGame();
CEnableUserBreak eub;
if (!gm_bFirstLoading) {
_bUserBreakEnabled = FALSE;
}
// try to start current network provider
if( !StartProviderFromName()) {
return FALSE;
gm_bFirstLoading = FALSE;
}
// clear profile array and start game
_atmFrameTimes.Clear();
_actTriangles.Clear();
gm_bProfileDemo = FALSE;
// start the new session
try {
if( dem_bPlay) {
gm_aiStartLocalPlayers[0] = -2;
CTFileName fnmDemo = CTString("Temp\\Play.dem");
if( dem_bPlayByName) {
fnmDemo = fnWorld;
}
CAM_Start(fnmDemo);
_pNetwork->StartDemoPlay_t(fnmDemo);
} else {
BOOL bWaitAllPlayers = sp.sp_bWaitAllPlayers && _pNetwork->IsNetworkEnabled();
_pNetwork->StartPeerToPeer_t( strSessionName, fnWorld,
sp.sp_ulSpawnFlags, sp.sp_ctMaxPlayers, bWaitAllPlayers, &sp);
}
} catch (char *strError) {
gm_bFirstLoading = FALSE;
// stop network provider
_pNetwork->StopProvider();
// and display error
CPrintF(TRANSV("Cannot start game:\n%s\n"), strError);
return FALSE;
}
// setup players from given indices
SetupLocalPlayers();
if( !dem_bPlay && !AddPlayers()) {
_pNetwork->StopGame();
_pNetwork->StopProvider();
gm_bFirstLoading = FALSE;
return FALSE;
}
gm_bFirstLoading = FALSE;
gm_bGameOn = TRUE;
gm_CurrentSplitScreenCfg = gm_StartSplitScreenCfg;
// clear last set highscore
gm_iLastSetHighScore = -1;
MaybeDiscardLastLines();
return TRUE;
}
BOOL CGame::JoinGame(const CNetworkSession &session)
{
CEnableUserBreak eub;
gam_iObserverConfig = 0;
gam_iObserverOffset = 0;
// stop eventually running game
StopGame();
// try to start current network provider
if( !StartProviderFromName()) return FALSE;
// start the new session
try {
INDEX ctLocalPlayers = 0;
if (gm_StartSplitScreenCfg>=SSC_PLAY1 && gm_StartSplitScreenCfg<=SSC_PLAY4) {
ctLocalPlayers = (gm_StartSplitScreenCfg-SSC_PLAY1)+1;
}
_pNetwork->JoinSession_t(session, ctLocalPlayers);
} catch (char *strError) {
// stop network provider
_pNetwork->StopProvider();
// and display error
CPrintF(TRANSV("Cannot join game:\n%s\n"), strError);
return FALSE;
}
// setup players from given indices
SetupLocalPlayers();
if( !AddPlayers())
{
_pNetwork->StopGame();
_pNetwork->StopProvider();
return FALSE;
}
gm_bGameOn = TRUE;
gm_CurrentSplitScreenCfg = gm_StartSplitScreenCfg;
return TRUE;
}
BOOL CGame::LoadGame(const CTFileName &fnGame)
{
gam_iObserverConfig = 0;
gam_iObserverOffset = 0;
// stop eventually running game
StopGame();
// try to start current network provider
if( !StartProviderFromName()) return FALSE;
// start the new session
try {
_pNetwork->Load_t( fnGame);
CPrintF(TRANSV("Loaded game: %s\n"), (const char *) fnGame);
} catch (char *strError) {
// stop network provider
_pNetwork->StopProvider();
// and display error
CPrintF(TRANSV("Cannot load game: %s\n"), strError);
return FALSE;
}
// setup players from given indices
SetupLocalPlayers();
if( !AddPlayers())
{
_pNetwork->StopGame();
_pNetwork->StopProvider();
return FALSE;
}
gm_bGameOn = TRUE;
gm_CurrentSplitScreenCfg = gm_StartSplitScreenCfg;
// clear last set highscore
gm_iLastSetHighScore = -1;
// if it was a quicksave, and not the newest one
if (fnGame.Matches("*\\QuickSave*") && fnGame!=GetQuickSaveName(FALSE)) {
// mark that it should be resaved as newest
gam_bQuickSave = TRUE;
}
MaybeDiscardLastLines();
return TRUE;
}
BOOL CGame::StartDemoPlay(const CTFileName &fnDemo)
{
CEnableUserBreak eub;
// stop eventually running game
StopGame();
// try to start current network provider
if( !StartProviderFromName()) {
gm_bFirstLoading = FALSE;
return FALSE;
}
// start the new session
try {
_pNetwork->StartDemoPlay_t( fnDemo);
CPrintF(TRANSV("Started playing demo: %s\n"), (const char *) fnDemo);
} catch (char *strError) {
// stop network provider
_pNetwork->StopProvider();
// and display error
CPrintF(TRANSV("Cannot play demo: %s\n"), strError);
gm_bFirstLoading = FALSE;
return FALSE;
}
gm_bFirstLoading = FALSE;
// setup players from given indices
gm_StartSplitScreenCfg = CGame::SSC_OBSERVER;
SetupLocalPlayers();
gm_bGameOn = TRUE;
gm_CurrentSplitScreenCfg = gm_StartSplitScreenCfg;
// prepare array for eventual profiling
_atmFrameTimes.PopAll();
_actTriangles.PopAll();
gm_bProfileDemo = FALSE;
if( dem_bProfile) gm_bProfileDemo = TRUE;
_tvDemoStarted = _pTimer->GetHighPrecisionTimer();
_tvLastFrame = _tvDemoStarted;
CTFileName fnmScript = fnDemo.NoExt()+".ini";
if (!FileExists(fnmScript)) {
fnmScript = CTString("Demos\\Default.ini");
}
CTString strCmd;
strCmd.PrintF("include \"%s\"", (const char*)fnmScript);
_pShell->Execute(strCmd);
MaybeDiscardLastLines();
// all done
return TRUE;
}
BOOL CGame::StartDemoRec(const CTFileName &fnDemo)
{
// save demo recording
try {
_pNetwork->StartDemoRec_t( fnDemo);
CPrintF(TRANSV("Started recording demo: %s\n"), (const char *) fnDemo);
// save a thumbnail
SaveThumbnail(fnDemo.NoExt()+"Tbn.tex");
return TRUE;
} catch (char *strError) {
// and display error
CPrintF(TRANSV("Cannot start recording: %s\n"), strError);
return FALSE;
}
}
void CGame::StopDemoRec(void)
{
// if no game is currently running
if (!gm_bGameOn) return;
_pNetwork->StopDemoRec();
CPrintF(TRANSV("Finished recording.\n"));
}
BOOL CGame::SaveGame(const CTFileName &fnGame)
{
// if no live players
INDEX ctPlayers = GetPlayersCount();
INDEX ctLivePlayers = GetLivePlayersCount();
if (ctPlayers>0 && ctLivePlayers<=0) {
// display error
CPrintF(TRANSV("Won't save game when dead!\n"));
// do not save
return FALSE;
}
// save new session
try {
_pNetwork->Save_t( fnGame);
CPrintF(TRANSV("Saved game: %s\n"), (const char *) fnGame);
SaveThumbnail(fnGame.NoExt()+"Tbn.tex");
return TRUE;
} catch (char *strError) {
// and display error
CPrintF(TRANSV("Cannot save game: %s\n"), (const char *) strError);
return FALSE;
}
}
void CGame::StopGame(void)
{
// disable computer quickly
ComputerForceOff();
// if no game is currently running
if (!gm_bGameOn)
{
// do nothing
return;
}
// stop eventual camera
CAM_Stop();
// disable direct input
// _pInput->DisableInput();
// and game
gm_bGameOn = FALSE;
// stop the game
_pNetwork->StopGame();
// stop the provider
_pNetwork->StopProvider();
// for all four local players
for( INDEX iPlayer=0; iPlayer<4; iPlayer++)
{
// mark that current player does not exist any more
gm_lpLocalPlayers[ iPlayer].lp_bActive = FALSE;
gm_lpLocalPlayers[ iPlayer].lp_pplsPlayerSource = NULL;
}
}
BOOL CGame::StartProviderFromName(void)
{
BOOL bSuccess = FALSE;
// list to contain available network providers
CListHead lhAvailableProviders;
// enumerate all providers
_pNetwork->EnumNetworkProviders( lhAvailableProviders);
// for each provider
FOREACHINLIST(CNetworkProvider, np_Node, lhAvailableProviders, litProviders)
{
// generate provider description
CTString strProviderName = litProviders->GetDescription();
// is this the provider we are searching for ?
if( strProviderName == gm_strNetworkProvider)
{
// it is, set it as active network provider
gm_npNetworkProvider = litProviders.Current();
bSuccess = TRUE;
break;
}
}
// delete list of providers
FORDELETELIST(CNetworkProvider, np_Node, lhAvailableProviders, litDelete)
{
delete &litDelete.Current();
}
// try to
try
{
// start selected network provider
_pNetwork->StartProvider_t( gm_npNetworkProvider);
}
// catch throwed error
catch (char *strError)
{
// if unable, report error
CPrintF( TRANS("Can't start provider:\n%s\n"), strError);
bSuccess = FALSE;
}
return bSuccess;
}
CHighScoreEntry::CHighScoreEntry(void)
{
hse_strPlayer = "";
hse_gdDifficulty = (CSessionProperties::GameDifficulty)-100;
hse_tmTime = -1.0f;
hse_ctKills = -1;
hse_ctScore = 0;
}
SLONG CGame::PackHighScoreTable(void)
{
// start at the beginning of buffer
UBYTE *pub = _aubHighScoreBuffer;
// for each entry
for (INDEX i=0; i<HIGHSCORE_COUNT; i++) {
// make its string
char str[MAX_HIGHSCORENAME+1];
memset(str, 0, sizeof(str));
strncpy(str, gm_ahseHighScores[i].hse_strPlayer, MAX_HIGHSCORENAME);
// copy the value and the string
memcpy(pub, str, sizeof(str));
pub += MAX_HIGHSCORENAME+1;
INDEX ival;
FLOAT fval;
ival = gm_ahseHighScores[i].hse_gdDifficulty;
BYTESWAP(ival);
memcpy(pub, &ival, sizeof(INDEX));
pub += sizeof(INDEX);
fval = gm_ahseHighScores[i].hse_tmTime;
BYTESWAP(fval);
memcpy(pub, &fval, sizeof(FLOAT));
pub += sizeof(FLOAT);
ival = gm_ahseHighScores[i].hse_ctKills;
BYTESWAP(ival);
memcpy(pub, &ival, sizeof(INDEX));
pub += sizeof(INDEX);
ival = gm_ahseHighScores[i].hse_ctScore;
BYTESWAP(ival);
memcpy(pub, &ival, sizeof(INDEX));
pub += sizeof(INDEX);
}
// just copy it for now
memcpy(_aubHighScorePacked, _aubHighScoreBuffer, MAX_HIGHSCORETABLESIZE);
return MAX_HIGHSCORETABLESIZE;
}
void CGame::UnpackHighScoreTable(SLONG slSize)
{
// just copy it for now
memcpy(_aubHighScoreBuffer, _aubHighScorePacked, slSize);
// start at the beginning of buffer
UBYTE *pub = _aubHighScoreBuffer;
// for each entry
for (INDEX i=0; i<HIGHSCORE_COUNT; i++) {
gm_ahseHighScores[i].hse_strPlayer = (const char*)pub;
pub += MAX_HIGHSCORENAME+1;
memcpy(&gm_ahseHighScores[i].hse_gdDifficulty, pub, sizeof(INDEX));
BYTESWAP(gm_ahseHighScores[i].hse_gdDifficulty);
pub += sizeof(INDEX);
memcpy(&gm_ahseHighScores[i].hse_tmTime , pub, sizeof(FLOAT));
BYTESWAP(gm_ahseHighScores[i].hse_tmTime);
pub += sizeof(FLOAT);
memcpy(&gm_ahseHighScores[i].hse_ctKills , pub, sizeof(INDEX));
BYTESWAP(gm_ahseHighScores[i].hse_ctKills);
pub += sizeof(INDEX);
memcpy(&gm_ahseHighScores[i].hse_ctScore , pub, sizeof(INDEX));
BYTESWAP(gm_ahseHighScores[i].hse_ctScore);
pub += sizeof(INDEX);
}
// try to
try {
CTFileStream strm;
strm.Open_t(CTString("table.txt"));
{for (INDEX i=0; i<HIGHSCORE_COUNT; i++) {
gm_ahseHighScores[i].hse_gdDifficulty = (CSessionProperties::GameDifficulty)-100;
}}
{for (INDEX i=0; i<HIGHSCORE_COUNT; i++) {
CTString strLine;
strm.GetLine_t(strLine);
char strName[256];
strLine.ScanF("\"%256[^\"]\" %d %g %d %d",
strName,
&gm_ahseHighScores[i].hse_gdDifficulty,
&gm_ahseHighScores[i].hse_tmTime,
&gm_ahseHighScores[i].hse_ctKills,
&gm_ahseHighScores[i].hse_ctScore);
gm_ahseHighScores[i].hse_strPlayer = strName;
}}
} catch (char *strError) {
(void)strError;
}
// remember best for player hud and statistics
plr_iHiScore = gm_ahseHighScores[0].hse_ctScore;
// no last set
gm_iLastSetHighScore = -1;
}
/*
* Loads CGame from file with file name given trough SetGameSettingsSaveFileName() function
*/
void CGame::Load_t( void)
{
ASSERT( gm_fnSaveFileName != "");
CTFileStream strmFile;
// open file with saved CGameObject
strmFile.Open_t( gm_fnSaveFileName,CTStream::OM_READ);
// read file ID
strmFile.ExpectID_t( CChunkID( "GAME")); // game
// check version number
if( !( CChunkID(GAME_SHELL_VER) == strmFile.GetID_t()) )
{
throw( TRANS("Invalid version of game shell."));
}
// load all of the class members
strmFile>>gm_strNetworkProvider;
strmFile>>gm_iWEDSinglePlayer;
strmFile>>gm_iSinglePlayer;
strmFile>>gm_aiMenuLocalPlayers[0];
strmFile>>gm_aiMenuLocalPlayers[1];
strmFile>>gm_aiMenuLocalPlayers[2];
strmFile>>gm_aiMenuLocalPlayers[3];
strmFile>>(INDEX&)gm_MenuSplitScreenCfg;
// read high-score table
SLONG slHSSize;
strmFile>>slHSSize;
strmFile.Read_t(&_aubHighScorePacked, slHSSize);
UnpackHighScoreTable(slHSSize);
}
/*
* Saves current state of CGame under file name given trough SetGameSettingsSaveFileName() function
*/
void CGame::Save_t( void)
{
ASSERT( gm_fnSaveFileName != "");
CTFileStream strmFile;
// create file to save CGameObject
strmFile.Create_t( gm_fnSaveFileName);
// write file ID
strmFile.WriteID_t( CChunkID( "GAME")); // game shell
// write version number
strmFile.WriteID_t( CChunkID(GAME_SHELL_VER));
// save all of the class members
strmFile<<gm_strNetworkProvider;
strmFile<<gm_iWEDSinglePlayer;
strmFile<<gm_iSinglePlayer;
strmFile<<gm_aiMenuLocalPlayers[0];
strmFile<<gm_aiMenuLocalPlayers[1];
strmFile<<gm_aiMenuLocalPlayers[2];
strmFile<<gm_aiMenuLocalPlayers[3];
strmFile.Write_t( &gm_MenuSplitScreenCfg, sizeof( enum SplitScreenCfg));
// write high-score table
SLONG slHSSize = PackHighScoreTable();
strmFile<<slHSSize;
strmFile.Write_t(&_aubHighScorePacked, slHSSize);
}
void LoadControls(CControls &ctrl, INDEX i)
{
try {
CTFileName fnm;
fnm.PrintF("Controls\\Controls%d.ctl", i);
ctrl.Load_t(fnm);
} catch (char *strError) {
(void) strError;
try {
ctrl.Load_t(CTFILENAME("Controls\\00-Default.ctl"));
} catch (char *strError) {
(void) strError;
ctrl.SwitchToDefaults();
}
}
}
void LoadPlayer(CPlayerCharacter &pc, INDEX i)
{
try {
CTFileName fnm;
fnm.PrintF("Players\\Player%d.plr", i);
pc.Load_t(fnm);
} catch (char *strError) {
(void) strError;
CTString strName;
if (i==0) {
LoadStringVar(CTString("Data\\Var\\DefaultPlayer.var"), strName);
strName.OnlyFirstLine();
}
if (strName=="") {
strName.PrintF("Player %d", i);
}
pc = CPlayerCharacter(strName);
}
}
/*
* Loads 8 players and 8 controls
*/
void CGame::LoadPlayersAndControls( void)
{
for (INDEX iControls=0; iControls<8; iControls++) {
LoadControls(gm_actrlControls[iControls], iControls);
}
for (INDEX iPlayer=0; iPlayer<8; iPlayer++) {
LoadPlayer(gm_apcPlayers[iPlayer], iPlayer);
}
SavePlayersAndControls();
}
/*
* Saves 8 players and 8 controls
*/
void CGame::SavePlayersAndControls( void)
{
try
{
// save players
gm_apcPlayers[0].Save_t( CTString( "Players\\Player0.plr"));
gm_apcPlayers[1].Save_t( CTString( "Players\\Player1.plr"));
gm_apcPlayers[2].Save_t( CTString( "Players\\Player2.plr"));
gm_apcPlayers[3].Save_t( CTString( "Players\\Player3.plr"));
gm_apcPlayers[4].Save_t( CTString( "Players\\Player4.plr"));
gm_apcPlayers[5].Save_t( CTString( "Players\\Player5.plr"));
gm_apcPlayers[6].Save_t( CTString( "Players\\Player6.plr"));
gm_apcPlayers[7].Save_t( CTString( "Players\\Player7.plr"));
// save controls
gm_actrlControls[0].Save_t( CTString( "Controls\\Controls0.ctl"));
gm_actrlControls[1].Save_t( CTString( "Controls\\Controls1.ctl"));
gm_actrlControls[2].Save_t( CTString( "Controls\\Controls2.ctl"));
gm_actrlControls[3].Save_t( CTString( "Controls\\Controls3.ctl"));
gm_actrlControls[4].Save_t( CTString( "Controls\\Controls4.ctl"));
gm_actrlControls[5].Save_t( CTString( "Controls\\Controls5.ctl"));
gm_actrlControls[6].Save_t( CTString( "Controls\\Controls6.ctl"));
gm_actrlControls[7].Save_t( CTString( "Controls\\Controls7.ctl"));
}
// catch throwed error
catch (char *strError)
{
(void) strError;
}
// skip checking of players if game isn't on
if( !gm_bGameOn) return;
// for each local player
for( INDEX i=0; i<4; i++) {
CLocalPlayer &lp = gm_lpLocalPlayers[i];
// if active
if( lp.lp_bActive && lp.lp_pplsPlayerSource!=NULL && lp.lp_iPlayer>=0 && lp.lp_iPlayer<8) {
// if its character in game is different than the one in config
CPlayerCharacter &pcInGame = lp.lp_pplsPlayerSource->pls_pcCharacter;
CPlayerCharacter &pcConfig = gm_apcPlayers[lp.lp_iPlayer];
if( pcConfig.pc_strName!=pcInGame.pc_strName
|| pcConfig.pc_strTeam!=pcInGame.pc_strTeam
|| memcmp(pcConfig.pc_aubAppearance, pcInGame.pc_aubAppearance, sizeof(pcInGame.pc_aubAppearance))!=0 ) {
// demand change in game
lp.lp_pplsPlayerSource->ChangeCharacter(pcConfig);
}
}
}
}
void CGame::SetupLocalPlayers( void)
{
// setup local players and their controls
gm_lpLocalPlayers[0].lp_iPlayer = gm_aiStartLocalPlayers[0];
gm_lpLocalPlayers[1].lp_iPlayer = gm_aiStartLocalPlayers[1];
gm_lpLocalPlayers[2].lp_iPlayer = gm_aiStartLocalPlayers[2];
gm_lpLocalPlayers[3].lp_iPlayer = gm_aiStartLocalPlayers[3];
if (gm_StartSplitScreenCfg < CGame::SSC_PLAY1) {
gm_lpLocalPlayers[0].lp_iPlayer = -1;
}
if (gm_StartSplitScreenCfg < CGame::SSC_PLAY2) {
gm_lpLocalPlayers[1].lp_iPlayer = -1;
}
if (gm_StartSplitScreenCfg < CGame::SSC_PLAY3) {
gm_lpLocalPlayers[2].lp_iPlayer = -1;
}
if (gm_StartSplitScreenCfg < CGame::SSC_PLAY4) {
gm_lpLocalPlayers[3].lp_iPlayer = -1;
}
}
BOOL CGame::AddPlayers(void)
{
// add local player(s) into game
try {
for(INDEX i=0; i<4; i++) {
CLocalPlayer &lp = gm_lpLocalPlayers[i];
INDEX iPlayer = lp.lp_iPlayer;
if (iPlayer>=0) {
ASSERT(iPlayer>=0 && iPlayer<8);
lp.lp_pplsPlayerSource = _pNetwork->AddPlayer_t(gm_apcPlayers[iPlayer]);
lp.lp_bActive = TRUE;
}
}
} catch (char *strError) {
CPrintF(TRANSV("Cannot add player:\n%s\n"), strError);
return FALSE;
}
return TRUE;
}
// save thumbnail for savegame
static CTFileName _fnmThumb=CTString("");
void CGame::SaveThumbnail( const CTFileName &fnm)
{
// request saving of thumbnail only (need drawport)
// (saving will take place in GameRedrawView())
_fnmThumb = fnm;
}
// timer variables
#define FRAMES_AVERAGING_MAX 20L
static CTimerValue _tvLasts[FRAMES_AVERAGING_MAX];
static CTimerValue _tvDelta[FRAMES_AVERAGING_MAX];
static INDEX _iCheckNow = 0;
static INDEX _iCheckMax = 0;
// print resolution, frame rate or extensive profiling, and elapsed time
static void PrintStats( CDrawPort *pdpDrawPort)
{
// cache some general vars
SLONG slDPWidth = pdpDrawPort->GetWidth();
SLONG slDPHeight = pdpDrawPort->GetHeight();
// determine proper text scale for statistics display
FLOAT fTextScale = (FLOAT)slDPWidth/640.0f;
// display resolution info (if needed)
if( hud_bShowResolution) {
CTString strRes;
strRes.PrintF( "%dx%dx%s", slDPWidth, slDPHeight, (const char *) _pGfx->gl_dmCurrentDisplayMode.DepthString());
pdpDrawPort->SetFont( _pfdDisplayFont);
pdpDrawPort->SetTextScaling( fTextScale);
pdpDrawPort->SetTextAspect( 1.0f);
pdpDrawPort->PutTextC( strRes, slDPWidth*0.5f, slDPHeight*0.15f, C_WHITE|255);
}
// if required, print elapsed playing time
if( hud_bShowTime) {
// set font, spacing and scale
pdpDrawPort->SetFont( _pfdDisplayFont);
pdpDrawPort->SetTextScaling( fTextScale);
pdpDrawPort->SetTextAspect( 1.0f);
// calculate elapsed time
CTimerValue tvNow = _pTimer->CurrentTick();
ULONG ulTime = (ULONG)tvNow.GetSeconds();
// printout elapsed time
CTString strTime;
if( ulTime >= (60*60)) {
// print hours
strTime.PrintF( "%02d:%02d:%02d", ulTime/(60*60), (ulTime/60)%60, ulTime%60);
} else {
// skip hours
strTime.PrintF( "%2d:%02d", ulTime/60, ulTime%60);
}
pdpDrawPort->PutTextC( strTime, slDPWidth*0.5f, slDPHeight*0.06f, C_WHITE|CT_OPAQUE);
}
// if required, print real time
if( hud_bShowClock) {
// set font, spacing and scale
pdpDrawPort->SetFont( _pfdConsoleFont);
pdpDrawPort->SetTextScaling(1.0f);
pdpDrawPort->SetTextAspect( 1.0f);
// determine time
struct tm *newtime;
time_t long_time;
time(&long_time);
newtime = localtime(&long_time);
// printout
CTString strTime;
strTime.PrintF( "%2d:%02d", newtime->tm_hour, newtime->tm_min);
pdpDrawPort->PutTextR( strTime, slDPWidth-3, 2, C_lYELLOW|CT_OPAQUE);
}
// if required, draw netgraph
if( hud_bShowNetGraph)
{ // determine and clamp size
INDEX ctLines = _pNetwork->ga_angeNetGraph.Count();
ctLines = ClampUp( ctLines, (INDEX)(slDPHeight*0.7f));
FLOAT f192oLines = 192.0f / (FLOAT)ctLines;
const FLOAT fMaxWidth = slDPWidth *0.1f;
const PIX pixJ = (PIX) (slDPHeight *0.9f);
// draw canvas
pdpDrawPort->Fill( slDPWidth-1-fMaxWidth, pixJ-ctLines+1, fMaxWidth, ctLines, SE_COL_BLUE_DARK_HV|64);
pdpDrawPort->DrawBorder( slDPWidth-2-fMaxWidth, pixJ-ctLines, fMaxWidth+2, ctLines+2, C_WHITE |192);
// draw graph
for( INDEX i=0; i<ctLines; i++) {
FLOAT fValue = _pNetwork->ga_angeNetGraph[i].nge_fLatency;
enum NetGraphEntryType nge = _pNetwork->ga_angeNetGraph[i].nge_ngetType;
FLOAT fWidth = Clamp( fValue, 0.0f, 1.0f)*fMaxWidth;
COLOR colLine = C_GREEN;
if( nge==NGET_ACTION) colLine = C_GREEN; // normal action (default)
else if( nge==NGET_MISSING) colLine = C_RED; // missing sequence
else if( nge==NGET_NONACTION) colLine = C_WHITE; // non-action sequence
else if( nge==NGET_REPLICATEDACTION) colLine = C_BLUE; // duplicated action
else if( nge==NGET_SKIPPEDACTION) colLine = C_YELLOW; // skipped action
else colLine = C_BLACK; // unknown ???
ULONG ulAlpha = FloatToInt( ((FLOAT)ctLines-(i*0.3333f)) *f192oLines);
pdpDrawPort->DrawLine( slDPWidth-2, pixJ-i, slDPWidth-2-fWidth, pixJ-i, colLine|ulAlpha);
}
}
// if stats aren't required
hud_iStats = Clamp( hud_iStats, 0, 2);
if( hud_iStats==0 || (hud_iEnableStats==0 && hud_fEnableFPS==0)) {
// display nothing
_iCheckNow = 0;
_iCheckMax = 0;
return;
}
// calculate FPS
FLOAT fFPS = 0.0f;
_iCheckMax++;
if( _iCheckMax >= FRAMES_AVERAGING_MAX) {
for( INDEX i=0; i<FRAMES_AVERAGING_MAX; i++) fFPS += _tvDelta[i].GetSeconds();
fFPS = FRAMES_AVERAGING_MAX*FRAMES_AVERAGING_MAX / fFPS;
_iCheckMax = FRAMES_AVERAGING_MAX;
}
// determine newest time
CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
_tvDelta[_iCheckNow] = tvNow - _tvLasts[_iCheckNow];
_tvLasts[_iCheckNow] = tvNow;
_iCheckNow = (_iCheckNow+1) % FRAMES_AVERAGING_MAX;
// set display interface (proportional) font
pdpDrawPort->SetFont( _pfdDisplayFont);
pdpDrawPort->SetTextAspect( 1.0f);
pdpDrawPort->SetTextScaling( fTextScale);
// display colored FPS
COLOR colFPS = C_RED;
if( fFPS >= 20) colFPS = C_GREEN;
if( fFPS >= 60) colFPS = C_WHITE;
if( fFPS < 10) pdpDrawPort->SetTextScaling( fTextScale*1.5); // enlarge output if FPS is extremely low
// prepare FPS string for printing
CTString strFPS = "?";
if( fFPS >= 30) strFPS.PrintF( "%3.0f", fFPS);
else if( fFPS >= 0.1f) strFPS.PrintF( "%3.1f", fFPS);
// printout FPS number (if allowed)
if( hud_fEnableFPS) pdpDrawPort->PutTextC( strFPS, slDPWidth*0.75f, slDPHeight*0.005f, colFPS|192);
// if in extensive stats mode
if( hud_iStats==2 && hud_iEnableStats)
{ // display extensive statistics
CTString strReport;
STAT_Report(strReport);
STAT_Reset();
// adjust and set font
pdpDrawPort->SetFont( _pfdConsoleFont);
pdpDrawPort->SetTextScaling( 1.0f);
pdpDrawPort->SetTextLineSpacing( -1);
// put filter
pdpDrawPort->Fill( 0,0, 128,slDPHeight, C_BLACK|128, C_BLACK|0, C_BLACK|128, C_BLACK|0);
// printout statistics
strFPS.PrintF( " frame =%3.0f ms\n---------------\n", 1000.0f/fFPS);
pdpDrawPort->PutText( strFPS, 0, 40, C_WHITE|CT_OPAQUE);
pdpDrawPort->PutText( strReport, 4, 65, C_GREEN|CT_OPAQUE);
}
}
// max possible drawports
CDrawPort adpDrawPorts[7];
// and ptrs to them
CDrawPort *apdpDrawPorts[7];
INDEX iFirstObserver = 0;
static void MakeSplitDrawports(enum CGame::SplitScreenCfg ssc, INDEX iCount, CDrawPort *pdp)
{
apdpDrawPorts[0] = NULL;
apdpDrawPorts[1] = NULL;
apdpDrawPorts[2] = NULL;
apdpDrawPorts[3] = NULL;
apdpDrawPorts[4] = NULL;
apdpDrawPorts[5] = NULL;
apdpDrawPorts[6] = NULL;
// if observer
if (ssc==CGame::SSC_OBSERVER) {
// must have at least one screen
iCount = Clamp(iCount, 1, 4);
// starting at first drawport
iFirstObserver = 0;
}
// if one player or observer with one screen
if (ssc==CGame::SSC_PLAY1 || ssc==CGame::SSC_OBSERVER && iCount==1) {
// the only drawport covers entire screen
adpDrawPorts[0] = CDrawPort( pdp, 0.0, 0.0, 1.0, 1.0);
apdpDrawPorts[0] = &adpDrawPorts[0];
// if two players or observer with two screens
} else if (ssc==CGame::SSC_PLAY2 || ssc==CGame::SSC_OBSERVER && iCount==2) {
// if the drawport is not dualhead
if (!pdp->IsDualHead()) {
// need two drawports for filling the empty spaces left and right
CDrawPort dpL( pdp, 0.0, 0.0, 0.2, 1.0f);
CDrawPort dpR( pdp, 0.8, 0.0, 0.2, 1.0f);
dpL.Lock(); dpL.Fill(C_BLACK|CT_OPAQUE); dpL.Unlock();
dpR.Lock(); dpR.Fill(C_BLACK|CT_OPAQUE); dpR.Unlock();
// first of two draw ports covers upper half of the screen
adpDrawPorts[0] = CDrawPort( pdp, 0.1666, 0.0, 0.6668, 0.5);
apdpDrawPorts[0] = &adpDrawPorts[0];
// second draw port covers lower half of the screen
adpDrawPorts[1] = CDrawPort( pdp, 0.1666, 0.5, 0.6668, 0.5);
apdpDrawPorts[1] = &adpDrawPorts[1];
// if the drawport is dualhead
} else {
// first of two draw ports covers left half of the screen
adpDrawPorts[0] = CDrawPort( pdp, 0.0, 0.0, 0.5, 1.0);
apdpDrawPorts[0] = &adpDrawPorts[0];
// second draw port covers right half of the screen
adpDrawPorts[1] = CDrawPort( pdp, 0.5, 0.0, 0.5, 1.0);
apdpDrawPorts[1] = &adpDrawPorts[1];
}
// if three players or observer with three screens
} else if (ssc==CGame::SSC_PLAY3 || ssc==CGame::SSC_OBSERVER && iCount==3) {
// if the drawport is not dualhead
if (!pdp->IsDualHead()) {
// need two drawports for filling the empty spaces left and right
CDrawPort dpL( pdp, 0.0, 0.0, 0.2, 0.5f);
CDrawPort dpR( pdp, 0.8, 0.0, 0.2, 0.5f);
dpL.Lock(); dpL.Fill(C_BLACK|CT_OPAQUE); dpL.Unlock();
dpR.Lock(); dpR.Fill(C_BLACK|CT_OPAQUE); dpR.Unlock();
// first of three draw ports covers center upper half of the screen
adpDrawPorts[0] = CDrawPort( pdp, 0.1666, 0.0, 0.6667, 0.5);
apdpDrawPorts[0] = &adpDrawPorts[0];
// second draw port covers lower-left part of the screen
adpDrawPorts[1] = CDrawPort( pdp, 0.0, 0.5, 0.5, 0.5);
apdpDrawPorts[1] = &adpDrawPorts[1];
// third draw port covers lower-right part of the screen
adpDrawPorts[2] = CDrawPort( pdp, 0.5, 0.5, 0.5, 0.5);
apdpDrawPorts[2] = &adpDrawPorts[2];
// if the drawport is dualhead
} else {
// first player uses entire left part
adpDrawPorts[0] = CDrawPort( pdp, 0.0, 0.0, 0.5, 1.0);
apdpDrawPorts[0] = &adpDrawPorts[0];
// make right DH part
CDrawPort dpDHR( pdp, 0.5, 0.0, 0.5, 1.0);
// need two drawports for filling the empty spaces left and right on the right DH part
CDrawPort dpL( &dpDHR, 0.0, 0.0, 0.2, 1.0f);
CDrawPort dpR( &dpDHR, 0.8, 0.0, 0.2, 1.0f);
dpL.Lock(); dpL.Fill(C_BLACK|CT_OPAQUE); dpL.Unlock();
dpR.Lock(); dpR.Fill(C_BLACK|CT_OPAQUE); dpR.Unlock();
// second draw port covers upper half of the right screen
adpDrawPorts[1] = CDrawPort( &dpDHR, 0.1666, 0.0, 0.6667, 0.5);
apdpDrawPorts[1] = &adpDrawPorts[1];
// third draw port covers lower half of the right screen
adpDrawPorts[2] = CDrawPort( &dpDHR, 0.1666, 0.5, 0.6667, 0.5);
apdpDrawPorts[2] = &adpDrawPorts[2];
}
// if four players or observer with four screens
} else if (ssc==CGame::SSC_PLAY4 || ssc==CGame::SSC_OBSERVER && iCount==4) {
// if the drawport is not dualhead
if (!pdp->IsDualHead()) {
// first of four draw ports covers upper-left part of the screen
adpDrawPorts[0] = CDrawPort( pdp, 0.0, 0.0, 0.5, 0.5);
apdpDrawPorts[0] = &adpDrawPorts[0];
// second draw port covers upper-right part of the screen
adpDrawPorts[1] = CDrawPort( pdp, 0.5, 0.0, 0.5, 0.5);
apdpDrawPorts[1] = &adpDrawPorts[1];
// third draw port covers lower-left part of the screen
adpDrawPorts[2] = CDrawPort( pdp, 0.0, 0.5, 0.5, 0.5);
apdpDrawPorts[2] = &adpDrawPorts[2];
// fourth draw port covers lower-right part of the screen
adpDrawPorts[3] = CDrawPort( pdp, 0.5, 0.5, 0.5, 0.5);
apdpDrawPorts[3] = &adpDrawPorts[3];
// if the drawport is dualhead
} else {
// make the DH parts
CDrawPort dpDHL( pdp, 0.0, 0.0, 0.5, 1.0);
CDrawPort dpDHR( pdp, 0.5, 0.0, 0.5, 1.0);
// on the left part
{
// need two drawports for filling the empty spaces left and right
CDrawPort dpL( &dpDHL, 0.0, 0.0, 0.2, 1.0f);
CDrawPort dpR( &dpDHL, 0.8, 0.0, 0.2, 1.0f);
dpL.Lock(); dpL.Fill(C_BLACK|CT_OPAQUE); dpL.Unlock();
dpR.Lock(); dpR.Fill(C_BLACK|CT_OPAQUE); dpR.Unlock();
// first of two draw ports covers upper half of the screen
adpDrawPorts[0] = CDrawPort( &dpDHL, 0.1666, 0.0, 0.6667, 0.5);
apdpDrawPorts[0] = &adpDrawPorts[0];
// second draw port covers lower half of the screen
adpDrawPorts[1] = CDrawPort( &dpDHL, 0.1666, 0.5, 0.6667, 0.5);
apdpDrawPorts[1] = &adpDrawPorts[1];
}
// on the right part
{
// need two drawports for filling the empty spaces left and right
CDrawPort dpL( &dpDHR, 0.0, 0.0, 0.2, 1.0f);
CDrawPort dpR( &dpDHR, 0.8, 0.0, 0.2, 1.0f);
dpL.Lock(); dpL.Fill(C_BLACK|CT_OPAQUE); dpL.Unlock();
dpR.Lock(); dpR.Fill(C_BLACK|CT_OPAQUE); dpR.Unlock();
// first of two draw ports covers upper half of the screen
adpDrawPorts[2] = CDrawPort( &dpDHR, 0.1666, 0.0, 0.6667, 0.5);
apdpDrawPorts[2] = &adpDrawPorts[2];
// second draw port covers lower half of the screen
adpDrawPorts[3] = CDrawPort( &dpDHR, 0.1666, 0.5, 0.6667, 0.5);
apdpDrawPorts[3] = &adpDrawPorts[3];
}
}
}
// if observer
if (ssc==CGame::SSC_OBSERVER) {
// observing starts at first drawport
iFirstObserver = 0;
// if not observer
} else {
// observing starts after all players
iFirstObserver = INDEX(ssc)+1;
}
// if not observer and using more than one screen
if (ssc!=CGame::SSC_OBSERVER && iCount>=1) {
// create extra small screens
#define FREE (1/16.0)
#define FULL (4/16.0)
if (iCount==1) {
adpDrawPorts[iFirstObserver+0] = CDrawPort( pdp, 1.0-FREE-FULL, FREE, FULL, FULL);
apdpDrawPorts[iFirstObserver+0] = &adpDrawPorts[iFirstObserver+0];
} else if (iCount==2) {
adpDrawPorts[iFirstObserver+0] = CDrawPort( pdp, 1.0-FREE-FULL, FREE+0*(FULL+FREE), FULL, FULL);
apdpDrawPorts[iFirstObserver+0] = &adpDrawPorts[iFirstObserver+0];
adpDrawPorts[iFirstObserver+1] = CDrawPort( pdp, 1.0-FREE-FULL, FREE+1*(FULL+FREE), FULL, FULL);
apdpDrawPorts[iFirstObserver+1] = &adpDrawPorts[iFirstObserver+1];
} else if (iCount==3) {
adpDrawPorts[iFirstObserver+0] = CDrawPort( pdp, 1.0-FREE-FULL, FREE+0*(FULL+FREE), FULL, FULL);
apdpDrawPorts[iFirstObserver+0] = &adpDrawPorts[iFirstObserver+0];
adpDrawPorts[iFirstObserver+1] = CDrawPort( pdp, 1.0-FREE-FULL, FREE+1*(FULL+FREE), FULL, FULL);
apdpDrawPorts[iFirstObserver+1] = &adpDrawPorts[iFirstObserver+1];
adpDrawPorts[iFirstObserver+2] = CDrawPort( pdp, 1.0-FREE-FULL, FREE+2*(FULL+FREE), FULL, FULL);
apdpDrawPorts[iFirstObserver+2] = &adpDrawPorts[iFirstObserver+2];
}
}
}
// this is used to make sure that the thumbnail is never saved with an empty screen
static BOOL _bPlayerViewRendered = FALSE;
// redraw all game views (for case of split-screens and such)
void CGame::GameRedrawView( CDrawPort *pdpDrawPort, ULONG ulFlags)
{
// if thumbnail saving has been required
if( _fnmThumb!="")
{ // reset the need for saving thumbnail
CTFileName fnm = _fnmThumb;
_fnmThumb = CTString("");
// render one game view to a small cloned drawport
//PIX pixSizeJ = pdpDrawPort->GetHeight();
PIXaabbox2D boxThumb( PIX2D(0,0), PIX2D(128,128));
CDrawPort dpThumb( pdpDrawPort, boxThumb);
_bPlayerViewRendered = FALSE;
GameRedrawView( &dpThumb, 0);
if (_bPlayerViewRendered) {
// grab screenshot
CImageInfo iiThumb;
CTextureData tdThumb;
dpThumb.GrabScreen( iiThumb);
// try to save thumbnail
try {
CTFileStream strmThumb;
tdThumb.Create_t( &iiThumb, 128, MAX_MEX_LOG2, FALSE);
strmThumb.Create_t(fnm);
tdThumb.Write_t( &strmThumb);
strmThumb.Close();
} catch( char *strError) {
// report an error to console, if failed
CPrintF( "%s\n", strError);
}
} else {
_fnmThumb = fnm;
}
}
if( ulFlags) {
// pretouch memory if required (only if in game mode, not screengrabbing or profiling!)
SE_PretouchIfNeeded();
}
// if game is started and computer isn't on
//BOOL bClientJoined = FALSE;
if( gm_bGameOn && (_pGame->gm_csComputerState==CS_OFF || pdpDrawPort->IsDualHead())
&& gm_CurrentSplitScreenCfg!=SSC_DEDICATED )
{
INDEX ctObservers = Clamp(gam_iObserverConfig, 0, 4);
INDEX iObserverOffset = ClampDn(gam_iObserverOffset, 0);
if (gm_CurrentSplitScreenCfg==SSC_OBSERVER) {
ctObservers = ClampDn(ctObservers, 1);
}
if (gm_CurrentSplitScreenCfg!=SSC_OBSERVER) {
if (!gam_bEnableAdvancedObserving || !GetSP()->sp_bCooperative) {
ctObservers = 0;
}
}
MakeSplitDrawports(gm_CurrentSplitScreenCfg, ctObservers, pdpDrawPort);
// get number of local players
INDEX ctLocals = 0;
{for (INDEX i=0; i<4; i++) {
if (gm_lpLocalPlayers[i].lp_pplsPlayerSource!=NULL) {
ctLocals++;
}
}}
CEntity *apenViewers[7];
apenViewers[0] = NULL;
apenViewers[1] = NULL;
apenViewers[2] = NULL;
apenViewers[3] = NULL;
apenViewers[4] = NULL;
apenViewers[5] = NULL;
apenViewers[6] = NULL;
INDEX ctViewers = 0;
// check if input is enabled
BOOL bDoPrescan = _pInput->IsInputEnabled() &&
!_pNetwork->IsPaused() && !_pNetwork->GetLocalPause() &&
_pShell->GetINDEX("inp_bAllowPrescan");
// prescan input
if (bDoPrescan) {
_pInput->GetInput(TRUE);
}
// timer must not occur during prescanning
{
#if defined(PLATFORM_UNIX) && !defined(SINGLE_THREADED)
#warning "This seems to cause Race Condition, so disabled"
#else
CTSingleLock csTimer(&_pTimer->tm_csHooks, TRUE);
#endif
// for each local player
for( INDEX i=0; i<4; i++) {
// if local player
CPlayerSource *ppls = gm_lpLocalPlayers[i].lp_pplsPlayerSource;
if( ppls!=NULL) {
// get local player entity
apenViewers[ctViewers++] = _pNetwork->GetLocalPlayerEntity(ppls);
// precreate action for it for this tick
if (bDoPrescan) {
// copy its local controls to current controls
memcpy(
ctl_pvPlayerControls,
gm_lpLocalPlayers[i].lp_ubPlayerControlsState,
ctl_slPlayerControlsSize);
// do prescanning
CPlayerAction paPreAction;
INDEX iCurrentPlayer = gm_lpLocalPlayers[i].lp_iPlayer;
CControls &ctrls = gm_actrlControls[ iCurrentPlayer];
ctrls.CreateAction(gm_apcPlayers[iCurrentPlayer], paPreAction, TRUE);
// copy the local controls back
memcpy(
gm_lpLocalPlayers[i].lp_ubPlayerControlsState,
ctl_pvPlayerControls,
ctl_slPlayerControlsSize);
}
}
}}
// fill in all players that are not local
INDEX ctNonlocals = 0;
CEntity *apenNonlocals[16];
memset(apenNonlocals, 0, sizeof(apenNonlocals));
{for (INDEX i=0; i<16; i++) {
CEntity *pen = CEntity::GetPlayerEntity(i);
if (pen!=NULL && !_pNetwork->IsPlayerLocal(pen)) {
apenNonlocals[ctNonlocals++] = pen;
}
}}
// if there are any non-local players
if (ctNonlocals>0) {
// for each observer
{for (INDEX i=0; i<ctObservers; i++) {
// get the given player with given offset that is not local
INDEX iPlayer = (i+iObserverOffset)%ctNonlocals;
apenViewers[ctViewers++] = apenNonlocals[iPlayer];
}}
}
// for each view
BOOL bHadViewers = FALSE;
{for (INDEX i=0; i<ctViewers; i++) {
CDrawPort *pdp = apdpDrawPorts[i];
if (pdp!=NULL && pdp->Lock()) {
// if there is a viewer
if (apenViewers[i]!=NULL) {
bHadViewers = TRUE;
// if predicted
if (apenViewers[i]->IsPredicted()) {
// use predictor instead
apenViewers[i] = apenViewers[i]->GetPredictor();
}
if (!CAM_IsOn()) {
_bPlayerViewRendered = TRUE;
// render it
apenViewers[i]->RenderGameView(pdp, (void*)((size_t)ulFlags));
} else {
CAM_Render(apenViewers[i], pdp);
}
} else {
pdp->Fill( C_BLACK|CT_OPAQUE);
}
pdp->Unlock();
}
}}
if (!bHadViewers) {
pdpDrawPort->Lock();
pdpDrawPort->Fill( C_BLACK|CT_OPAQUE);
pdpDrawPort->Unlock();
}
// create drawport for messages (left on DH)
CDrawPort dpMsg(pdpDrawPort, TRUE);
if ((ulFlags&GRV_SHOWEXTRAS) && dpMsg.Lock())
{
// print pause indicators
CTString strIndicator;
if (_pNetwork->IsDisconnected()) {
strIndicator.PrintF(TRANSV("Disconnected: %s\nPress F9 to reconnect"), (const char *)_pNetwork->WhyDisconnected());
} else if (_pNetwork->IsWaitingForPlayers()) {
strIndicator = TRANS("Waiting for all players to connect");
} else if (_pNetwork->IsWaitingForServer()) {
strIndicator = TRANS("Waiting for server to continue");
} else if (!_pNetwork->IsConnectionStable()) {
strIndicator = TRANS("Trying to stabilize connection...");
} else if (_pNetwork->IsGameFinished()) {
strIndicator = TRANS("Game finished");
} else if (_pNetwork->IsPaused() || _pNetwork->GetLocalPause()) {
strIndicator = TRANS("Paused");
} else if (_tvMenuQuickSave.tv_llValue!=0 &&
(_pTimer->GetHighPrecisionTimer()-_tvMenuQuickSave).GetSeconds()<3) {
strIndicator = TRANS("Use F6 for QuickSave during game!");
} else if (_pNetwork->ga_sesSessionState.ses_strMOTD!="") {
CTString strMotd = _pNetwork->ga_sesSessionState.ses_strMOTD;
static CTString strLastMotd = "";
static CTimerValue tvLastMotd((__int64) 0);
if (strLastMotd!=strMotd) {
tvLastMotd = _pTimer->GetHighPrecisionTimer();
strLastMotd = strMotd;
}
if (tvLastMotd.tv_llValue!=((__int64) 0) && (_pTimer->GetHighPrecisionTimer()-tvLastMotd).GetSeconds()<3) {
strIndicator = strMotd;
}
}
if (strIndicator!="") {
// setup font
dpMsg.SetFont( _pfdDisplayFont);
dpMsg.SetTextAspect( 1.0f);
dpMsg.PutTextCXY( strIndicator,
dpMsg.GetWidth()*0.5f,
dpMsg.GetHeight()*0.4f, SE_COL_BLUEGREEN_LT|192);
}
// print recording indicator
if (_pNetwork->IsRecordingDemo()) {
// setup font
dpMsg.SetFont( _pfdDisplayFont);
dpMsg.SetTextScaling( 1.0f);
dpMsg.SetTextAspect( 1.0f);
dpMsg.PutText( TRANS("Recording"),
dpMsg.GetWidth()*0.1f,
dpMsg.GetHeight()*0.1f, C_CYAN|192);
}
// print some statistics
PrintStats( &dpMsg);
// print last few lines from console to top of screen
if (_pGame->gm_csConsoleState==CS_OFF) ConsolePrintLastLines( &dpMsg);
// print demo OSD
if( dem_bOSD) {
CTString strMessage;
// print the message
strMessage.PrintF("%.2fs", _pNetwork->ga_fDemoTimer);
dpMsg.SetFont( _pfdDisplayFont);
dpMsg.SetTextAspect( 1.0f);
dpMsg.PutText( strMessage, 20, 20);
}
dpMsg.Unlock();
}
// keep frames' time if required
if( gm_bProfileDemo)
{
CTimerValue tvThisFrame = _pTimer->GetHighPrecisionTimer();
// if demo has been finished
if( _pNetwork->IsDemoPlayFinished()) {
// end profile
gm_bProfileDemo = FALSE;
CPrintF( DemoReportAnalyzedProfile());
CPrintF( "-\n");
} else {
// determine frame time delta
TIME tmDelta = (tvThisFrame - _tvLastFrame).GetSeconds();
_tvLastFrame = tvThisFrame;
_atmFrameTimes.Push() = tmDelta; // add new frame time stamp
INDEX *piTriangles = _actTriangles.Push(4); // and polygons count
piTriangles[0] = _pGfx->gl_ctWorldTriangles;
piTriangles[1] = _pGfx->gl_ctModelTriangles;
piTriangles[2] = _pGfx->gl_ctParticleTriangles;
piTriangles[3] = _pGfx->gl_ctTotalTriangles;
}
}
// execute cvar after demoplay
if( _pNetwork->IsDemoPlayFinished() && dem_strPostExec!="") _pShell->Execute(dem_strPostExec);
}
// if no game is active
else
{
// clear background
if( pdpDrawPort->Lock()) {
pdpDrawPort->Fill( SE_COL_BLUE_DARK|CT_OPAQUE);
pdpDrawPort->FillZBuffer( ZBUF_BACK);
pdpDrawPort->Unlock();
}
}
// check for new chat message
static INDEX ctChatMessages=0;
INDEX ctNewChatMessages = _pShell->GetINDEX("net_ctChatMessages");
if (ctNewChatMessages!=ctChatMessages) {
ctChatMessages=ctNewChatMessages;
PlayScriptSound(MAX_SCRIPTSOUNDS-1, CTFILENAME("Sounds\\Menu\\Chat.wav"), 4.0f*gam_fChatSoundVolume, 1.0f, FALSE);
}
// update sounds and forbid probing
_pSound->UpdateSounds();
_pGfx->gl_bAllowProbing = FALSE;
if( bSaveScreenShot || dem_iAnimFrame>=0)
{
// make the screen shot directory if it doesn't already exist
bSaveScreenShot = FALSE;
CTFileName fnmExpanded;
ExpandFilePath(EFP_WRITE, CTString("ScreenShots"), fnmExpanded);
// rcg01052002 This is done in Stream.cpp, now. --ryan.
//_mkdir(fnmExpanded);
// create a name for screenshot
CTFileName fnmScreenShot;
if( dem_iAnimFrame<0) {
fnmScreenShot = MakeScreenShotName();
} else {
// create number for the file
CTString strNumber;
strNumber.PrintF("%05d", (INDEX)dem_iAnimFrame);
fnmScreenShot = CTString("ScreenShots\\Anim_")+strNumber+".tga";
dem_iAnimFrame+=1;
}
// grab screen creating image info
CImageInfo iiImageInfo;
if( pdpDrawPort->Lock()) {
pdpDrawPort->GrabScreen( iiImageInfo, 1);
pdpDrawPort->Unlock();
}
// try to
try {
// save screen shot as TGA
iiImageInfo.SaveTGA_t( fnmScreenShot);
if( dem_iAnimFrame<0) CPrintF( TRANS("screen shot: %s\n"), (const char *) (CTString&)fnmScreenShot);
}
// if failed
catch (char *strError) {
// report error
CPrintF( TRANS("Cannot save screenshot:\n%s\n"), strError);
}
}
}
void CGame::RecordHighScore(void)
{
// if game is not running
if (!gm_bGameOn) {
// do nothing
return;
}
// find that player
INDEX ipl= Clamp(int(gam_iRecordHighScore), 0, NET_MAXGAMEPLAYERS);
CPlayer *penpl = (CPlayer *)&*CEntity::GetPlayerEntity(ipl);
if (penpl==NULL) {
//CPrintF( TRANS("Warning: cannot record score for player %d!\n"), ipl);
return;
}
// get its score
INDEX ctScore = penpl->m_psGameStats.ps_iScore;
// find entry with lower score
INDEX iLess;
for(iLess=0; iLess<HIGHSCORE_COUNT; iLess++) {
if (gm_ahseHighScores[iLess].hse_ctScore<ctScore) {
break;
}
}
// if none
if (iLess>=HIGHSCORE_COUNT) {
// do nothing more
return;
}
// move all lower entries one place down, dropping the last one
for(INDEX i=HIGHSCORE_COUNT-1; i>iLess; i--) {
gm_ahseHighScores[i] = gm_ahseHighScores[i-1];
}
// remember new one
gm_ahseHighScores[iLess].hse_ctScore = ctScore;
gm_ahseHighScores[iLess].hse_strPlayer = penpl->GetPlayerName();
gm_ahseHighScores[iLess].hse_gdDifficulty = GetSP()->sp_gdGameDifficulty;
if (GetSP()->sp_bMental) {
(INDEX&)gm_ahseHighScores[iLess].hse_gdDifficulty = CSessionProperties::GD_EXTREME+1;
}
gm_ahseHighScores[iLess].hse_tmTime = _pTimer->CurrentTick();
gm_ahseHighScores[iLess].hse_ctKills = penpl->m_psGameStats.ps_iKills;
// remember best for player hud and statistics
plr_iHiScore = gm_ahseHighScores[0].hse_ctScore;
// remember last set
gm_iLastSetHighScore = iLess;
}
INDEX CGame::GetLivePlayersCount(void)
{
INDEX ctLive = 0;
for (INDEX ipl=0; ipl<NET_MAXGAMEPLAYERS; ipl++) {
CEntity *penpl = CEntity::GetPlayerEntity(ipl);
if (penpl!=NULL && (penpl->GetFlags()&ENF_ALIVE)) {
ctLive++;
}
}
return ctLive;
}
INDEX CGame::GetPlayersCount(void)
{
INDEX ctPlayers = 0;
for (INDEX ipl=0; ipl<NET_MAXGAMEPLAYERS; ipl++) {
CEntity *penpl = CEntity::GetPlayerEntity(ipl);
if (penpl!=NULL) {
ctPlayers++;
}
}
return ctPlayers;
}
// get default description for a game (for save games/demos)
CTString CGame::GetDefaultGameDescription(BOOL bWithInfo)
{
CTString strDescription;
struct tm *newtime;
time_t long_time;
time(&long_time);
newtime = localtime(&long_time);
setlocale(LC_ALL, "");
CTString strTimeline;
char achTimeLine[256];
strftime( achTimeLine, sizeof(achTimeLine)-1, "%a %x %H:%M", newtime);
strTimeline = achTimeLine;
setlocale(LC_ALL, "C");
strDescription.PrintF( "%s - %s", (const char *) TranslateConst(_pNetwork->ga_World.GetName(), 0), (const char *) strTimeline);
if (bWithInfo) {
CPlayer *penPlayer = (CPlayer *)&*CEntity::GetPlayerEntity(0);
CTString strStats;
if (penPlayer!=NULL) {
penPlayer->GetStats(strStats, CST_SHORT, 40);
}
strDescription += "\n"+strStats;
}
return strDescription;
}
struct QuickSave {
CListNode qs_lnNode;
CTFileName qs_fnm;
INDEX qs_iNumber;
};
int qsort_CompareQuickSaves_FileUp( const void *elem1, const void *elem2)
{
const QuickSave &qs1 = **(QuickSave **)elem1;
const QuickSave &qs2 = **(QuickSave **)elem2;
return strcmp(qs1.qs_fnm, qs2.qs_fnm);
}
// delete extra quicksaves and find the next free number
INDEX FixQuicksaveDir(const CTFileName &fnmDir, INDEX ctMax)
{
// list the directory
CDynamicStackArray<CTFileName> afnmDir;
MakeDirList(afnmDir, fnmDir, CTString("*.sav"), 0);
CListHead lh;
INDEX iMaxNo = -1;
// for each file in the directory
for (INDEX i=0; i<afnmDir.Count(); i++) {
CTFileName fnmName = afnmDir[i];
// parse it
INDEX iFile = -1;
fnmName.FileName().ScanF("QuickSave%d", &iFile);
// if it can be parsed
if (iFile>=0) {
// create new info for that file
QuickSave *pqs = new QuickSave;
pqs->qs_fnm = fnmName;
pqs->qs_iNumber = iFile;
if (iFile>iMaxNo) {
iMaxNo = iFile;
}
// add it to list
lh.AddTail(pqs->qs_lnNode);
}
}
// sort the list
lh.Sort(qsort_CompareQuickSaves_FileUp, _offsetof(QuickSave, qs_lnNode));
INDEX ctCount = lh.Count();
// delete all old ones while number of files is too large
FORDELETELIST(QuickSave, qs_lnNode, lh, itqs) {
if (ctCount>ctMax) {
RemoveFile(itqs->qs_fnm);
RemoveFile(itqs->qs_fnm.NoExt()+"Tbn.tex");
RemoveFile(itqs->qs_fnm.NoExt()+".des");
ctCount--;
}
delete &*itqs;
}
return iMaxNo;
}
CTFileName CGame::GetQuickSaveName(BOOL bSave)
{
// find out base directory
CTFileName fnmDir;
if (GetSP()->sp_ctMaxPlayers==1) {
INDEX iPlayer = gm_iSinglePlayer;
if (GetSP()->sp_bQuickTest) {
iPlayer = gm_iWEDSinglePlayer;
}
fnmDir.PrintF("SaveGame\\Player%d\\Quick\\", iPlayer);
} else {
if (_pNetwork->IsNetworkEnabled()) {
fnmDir = CTString("SaveGame\\Network\\Quick\\");
} else {
fnmDir = CTString("SaveGame\\SplitScreen\\Quick\\");
}
}
// load last saved number
INDEX iLast = FixQuicksaveDir(fnmDir, bSave ? gam_iQuickSaveSlots-1 : gam_iQuickSaveSlots );
if (bSave) {
iLast++;
}
// add save name to that
CTFileName fnmName;
fnmName.PrintF("QuickSave%06d.sav", iLast);
return fnmDir+fnmName;
}
void CGame::GameMainLoop(void)
{
if (gam_bQuickSave && GetSP()->sp_gmGameMode!=CSessionProperties::GM_FLYOVER) {
if (gam_bQuickSave==2) {
_tvMenuQuickSave = _pTimer->GetHighPrecisionTimer();
}
gam_bQuickSave = FALSE;
CTFileName fnm = GetQuickSaveName(TRUE);
CTString strDes = GetDefaultGameDescription(TRUE);
SaveGame(fnm);
SaveStringVar(fnm.NoExt()+".des", strDes);
}
// if quickload invoked
if (gam_bQuickLoad && GetSP()->sp_gmGameMode!=CSessionProperties::GM_FLYOVER) {
gam_bQuickLoad = FALSE;
// if no game active, or this computer is server
if (!gm_bGameOn || _pNetwork->IsServer()) {
// do a quickload
LoadGame(GetQuickSaveName(FALSE));
// otherwise
} else {
// rejoin current section
JoinGame(CNetworkSession(gam_strJoinAddress));
}
}
if (gam_iRecordHighScore>=0) {
RecordHighScore();
gam_iRecordHighScore = -1.0f;
}
// if server was restarted
if (gm_bGameOn && !_pNetwork->IsServer() && _pNetwork->IsGameFinished() && _pNetwork->IsDisconnected()) {
// automatically reconnect
JoinGame(CNetworkSession(gam_strJoinAddress));
}
if (_bStartProfilingNextTime) {
_bStartProfilingNextTime = FALSE;
_bProfiling = TRUE;
_ctProfileRecording = 50;
// reset the profiles
_pfRenderProfile.Reset();
_pfGfxProfile.Reset();
_pfModelProfile.Reset();
_pfSoundProfile.Reset();
_pfNetworkProfile.Reset();
_pfPhysicsProfile.Reset();
} else if (_bProfiling) {
_ctProfileRecording--;
if (_ctProfileRecording<=0) {
_bProfiling = FALSE;
_bDumpNextTime = TRUE;
_strProfile = "===========================================================\n";
/* Render profile */
CTString strRenderReport;
_pfRenderProfile.Report(strRenderReport);
_strProfile+=strRenderReport;
_pfRenderProfile.Reset();
/* Model profile */
CTString strModelReport;
_pfModelProfile.Report(strModelReport);
_strProfile+=strModelReport;
_pfModelProfile.Reset();
/* Gfx profile */
CTString strGfxReport;
_pfGfxProfile.Report(strGfxReport);
_strProfile+=strGfxReport;
_pfGfxProfile.Reset();
/* Sound profile */
CTString strSoundReport;
_pfSoundProfile.Report(strSoundReport);
_strProfile+=strSoundReport;
_pfSoundProfile.Reset();
/* Network profile */
CTString strNetworkReport;
_pfNetworkProfile.Report(strNetworkReport);
_strProfile+=strNetworkReport;
_pfNetworkProfile.Reset();
/* Physics profile */
CTString strPhysicsReport;
_pfPhysicsProfile.Report(strPhysicsReport);
_strProfile+=strPhysicsReport;
_pfPhysicsProfile.Reset();
CPrintF( TRANS("Profiling done.\n"));
}
}
if (_bDumpNextTime) {
_bDumpNextTime = FALSE;
try {
// create a file for profile
CTFileStream strmProfile;
strmProfile.Create_t(CTString("Game.profile"));
strmProfile.Write_t(_strProfile, strlen(_strProfile));
} catch (char *strError) {
CPutString(strError);
}
}
// if game is started
if (gm_bGameOn) {
// do main loop procesing
_pNetwork->MainLoop();
}
}
/*************************************************************
* S E C O N D E N C O U N T E R M E N U *
*************************************************************/
static CTextureObject _toPointer;
static CTextureObject _toBcgClouds;
static CTextureObject _toBcgGrid;
static CTextureObject _toBackdrop;
static CTextureObject _toSamU;
static CTextureObject _toSamD;
static CTextureObject _toLeftU;
static CTextureObject _toLeftD;
static PIXaabbox2D _boxScreen_SE;
static PIX _pixSizeI_SE;
static PIX _pixSizeJ_SE;
CDrawPort *_pdp_SE = NULL;
static FLOAT _tmNow_SE;
static ULONG _ulA_SE;
static BOOL _bPopup;
void TiledTextureSE( PIXaabbox2D &_boxScreen, FLOAT fStretch, const MEX2D &vScreen, MEXaabbox2D &boxTexture)
{
PIX pixW = _boxScreen.Size()(1);
PIX pixH = _boxScreen.Size()(2);
boxTexture = MEXaabbox2D(MEX2D(0, 0), MEX2D(pixW/fStretch, pixH/fStretch));
boxTexture+=vScreen;
}
////
void CGame::LCDInit(void)
{
try {
_toBcgClouds.SetData_t(CTFILENAME("Textures\\General\\Background6.tex"));
#ifdef FIRST_ENCOUNTER
_toPointer.SetData_t(CTFILENAME("Textures\\General\\Pointer.tex"));
_toBcgGrid.SetData_t(CTFILENAME("Textures\\General\\Grid16x16-dot.tex"));
#else
_toPointer.SetData_t(CTFILENAME("TexturesMP\\General\\Pointer.tex"));
_toBcgGrid.SetData_t(CTFILENAME("TexturesMP\\General\\grid.tex"));
#endif
// thoses are not in original TFE datas and must be added externaly (with SE1_10.gro or a minimal versio of it)
_toBackdrop.SetData_t(CTFILENAME("TexturesMP\\General\\MenuBack.tex"));
_toSamU.SetData_t(CTFILENAME("TexturesMP\\General\\SamU.tex"));
_toSamD.SetData_t(CTFILENAME("TexturesMP\\General\\SamD.tex"));
_toLeftU.SetData_t(CTFILENAME("TexturesMP\\General\\LeftU.tex"));
_toLeftD.SetData_t(CTFILENAME("TexturesMP\\General\\LeftD.tex"));
// force constant textures
((CTextureData*)_toBcgClouds.GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toPointer .GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toBcgGrid .GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toBackdrop .GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toSamU .GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toSamD .GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toLeftU .GetData())->Force(TEX_CONSTANT);
((CTextureData*)_toLeftD .GetData())->Force(TEX_CONSTANT);
} catch (char *strError) {
FatalError("%s\n", strError);
}
::_LCDInit();
}
void CGame::LCDEnd(void)
{
::_LCDEnd();
}
void CGame::LCDPrepare(FLOAT fFade)
{
// get current time and alpha value
_tmNow_SE = (FLOAT)_pTimer->GetHighPrecisionTimer().GetSeconds();
_ulA_SE = NormFloatToByte(fFade);
::_LCDPrepare(fFade);
}
void CGame::LCDSetDrawport(CDrawPort *pdp)
{
_pdp_SE = pdp;
_pixSizeI_SE = _pdp_SE->GetWidth();
_pixSizeJ_SE = _pdp_SE->GetHeight();
_boxScreen_SE = PIXaabbox2D ( PIX2D(0,0), PIX2D(_pixSizeI_SE, _pixSizeJ_SE));
if (pdp->dp_SizeIOverRasterSizeI==1.0f) {
_bPopup = FALSE;
} else {
_bPopup = TRUE;
}
::_LCDSetDrawport(pdp);
}
void CGame::LCDDrawBox(PIX pixUL, PIX pixDR, const PIXaabbox2D &box, COLOR col)
{
col = SE_COL_BLUE_NEUTRAL|255;
::_LCDDrawBox(pixUL, pixDR, box, col);
}
void CGame::LCDScreenBox(COLOR col)
{
col = SE_COL_BLUE_NEUTRAL|255;
::_LCDScreenBox(col);
}
void CGame::LCDScreenBoxOpenLeft(COLOR col)
{
col = SE_COL_BLUE_NEUTRAL|255;
::_LCDScreenBoxOpenLeft(col);
}
void CGame::LCDScreenBoxOpenRight(COLOR col)
{
col = SE_COL_BLUE_NEUTRAL|255;
::_LCDScreenBoxOpenRight(col);
}
void CGame::LCDRenderClouds1(void)
{
_pdp_SE->PutTexture(&_toBackdrop, _boxScreen_SE, C_WHITE|255);
if (!_bPopup) {
PIXaabbox2D box;
// right character - Sam
INDEX iSize = 170;
INDEX iYU = 120;
INDEX iYM = iYU + iSize;
INDEX iYB = iYM + iSize;
INDEX iXL = 420;
INDEX iXR = (INDEX) (iXL + iSize*_pdp_SE->dp_fWideAdjustment);
box = PIXaabbox2D( PIX2D( iXL*_pdp_SE->GetWidth()/640, iYU*_pdp_SE->GetHeight()/480) ,
PIX2D( iXR*_pdp_SE->GetWidth()/640, iYM*_pdp_SE->GetHeight()/480));
_pdp_SE->PutTexture(&_toSamU, box, SE_COL_BLUE_NEUTRAL|255);
box = PIXaabbox2D( PIX2D( iXL*_pdp_SE->GetWidth()/640, iYM*_pdp_SE->GetHeight()/480) ,
PIX2D( iXR*_pdp_SE->GetWidth()/640, iYB*_pdp_SE->GetHeight()/480));
_pdp_SE->PutTexture(&_toSamD, box, SE_COL_BLUE_NEUTRAL|255);
iSize = 120;
iYU = 0;
iYM = iYU + iSize;
iYB = iYM + iSize;
iXL = -20;
iXR = iXL + iSize;
box = PIXaabbox2D( PIX2D( iXL*_pdp_SE->GetWidth()/640, iYU*_pdp_SE->GetWidth()/640) ,
PIX2D( iXR*_pdp_SE->GetWidth()/640, iYM*_pdp_SE->GetWidth()/640));
_pdp_SE->PutTexture(&_toLeftU, box, SE_COL_BLUE_NEUTRAL|200);
box = PIXaabbox2D( PIX2D( iXL*_pdp_SE->GetWidth()/640, iYM*_pdp_SE->GetWidth()/640) ,
PIX2D( iXR*_pdp_SE->GetWidth()/640, iYB*_pdp_SE->GetWidth()/640));
_pdp_SE->PutTexture(&_toLeftD, box, SE_COL_BLUE_NEUTRAL|200);
iYU = iYB;
iYM = iYU + iSize;
iYB = iYM + iSize;
iXL = -20;
iXR = iXL + iSize;
box = PIXaabbox2D( PIX2D( iXL*_pdp_SE->GetWidth()/640, iYU*_pdp_SE->GetWidth()/640) ,
PIX2D( iXR*_pdp_SE->GetWidth()/640, iYM*_pdp_SE->GetWidth()/640));
_pdp_SE->PutTexture(&_toLeftU, box, SE_COL_BLUE_NEUTRAL|200);
box = PIXaabbox2D( PIX2D( iXL*_pdp_SE->GetWidth()/640, iYM*_pdp_SE->GetWidth()/640) ,
PIX2D( iXR*_pdp_SE->GetWidth()/640, iYB*_pdp_SE->GetWidth()/640));
_pdp_SE->PutTexture(&_toLeftD, box, SE_COL_BLUE_NEUTRAL|200);
}
MEXaabbox2D boxBcgClouds1;
TiledTextureSE(_boxScreen_SE, 1.2f*_pdp_SE->GetWidth()/640.0f,
MEX2D(sin(_tmNow_SE*0.5f)*35,sin(_tmNow_SE*0.7f+1)*21), boxBcgClouds1);
_pdp_SE->PutTexture(&_toBcgClouds, _boxScreen_SE, boxBcgClouds1, C_BLACK|_ulA_SE>>2);
TiledTextureSE(_boxScreen_SE, 0.7f*_pdp_SE->GetWidth()/640.0f,
MEX2D(sin(_tmNow_SE*0.6f+1)*32,sin(_tmNow_SE*0.8f)*25), boxBcgClouds1);
_pdp_SE->PutTexture(&_toBcgClouds, _boxScreen_SE, boxBcgClouds1, C_BLACK|_ulA_SE>>2);
}
void CGame::LCDRenderCloudsForComp(void)
{
MEXaabbox2D boxBcgClouds1;
TiledTextureSE(_boxScreen_SE, 1.856f*_pdp_SE->GetWidth()/640.0f,
MEX2D(sin(_tmNow_SE*0.5f)*35,sin(_tmNow_SE*0.7f)*21), boxBcgClouds1);
_pdp_SE->PutTexture(&_toBcgClouds, _boxScreen_SE, boxBcgClouds1, SE_COL_BLUE_NEUTRAL|_ulA_SE>>2);
TiledTextureSE(_boxScreen_SE, 1.323f*_pdp_SE->GetWidth()/640.0f,
MEX2D(sin(_tmNow_SE*0.6f)*31,sin(_tmNow_SE*0.8f)*25), boxBcgClouds1);
_pdp_SE->PutTexture(&_toBcgClouds, _boxScreen_SE, boxBcgClouds1, SE_COL_BLUE_NEUTRAL|_ulA_SE>>2);
}
void CGame::LCDRenderClouds2(void)
{
NOTHING;
}
void CGame::LCDRenderGrid(void)
{
NOTHING;
}
void CGame::LCDRenderCompGrid(void)
{
MEXaabbox2D boxBcgGrid;
TiledTextureSE(_boxScreen_SE, 0.5f*_pdp_SE->GetWidth()/(_pdp_SE->dp_SizeIOverRasterSizeI*640.0f), MEX2D(0,0), boxBcgGrid);
_pdp_SE->PutTexture(&_toBcgGrid, _boxScreen_SE, boxBcgGrid, SE_COL_BLUE_NEUTRAL|_ulA_SE>>1);
}
void CGame::LCDDrawPointer(PIX pixI, PIX pixJ)
{
CDisplayMode dmCurrent;
_pGfx->GetCurrentDisplayMode(dmCurrent);
if (dmCurrent.IsFullScreen()) {
while (ShowCursor(FALSE) >= 0);
} else {
if (!_pInput->IsInputEnabled()) {
while (ShowCursor(TRUE) < 0);
}
return;
}
PIX pixSizeI = _toPointer.GetWidth();
PIX pixSizeJ = _toPointer.GetHeight();
pixI-=1;
pixJ-=1;
_pdp_SE->PutTexture( &_toPointer, PIXaabbox2D( PIX2D(pixI, pixJ), PIX2D(pixI+pixSizeI, pixJ+pixSizeJ)),
LCDFadedColor(C_WHITE|255));
//::_LCDDrawPointer(pixI, pixJ);
}
COLOR CGame::LCDGetColor(COLOR colDefault, const char *strName)
{
if (!strcmp(strName, "thumbnail border")) {
colDefault = SE_COL_BLUE_NEUTRAL|255;
} else if (!strcmp(strName, "no thumbnail")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "popup box")) {
colDefault = SE_COL_BLUE_NEUTRAL|255;
} else if (!strcmp(strName, "tool tip")) {
colDefault = SE_COL_ORANGE_LIGHT|255;
} else if (!strcmp(strName, "unselected")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "selected")) {
colDefault = SE_COL_ORANGE_LIGHT|255;
} else if (!strcmp(strName, "disabled selected")) {
colDefault = SE_COL_ORANGE_DARK_LT |255;
} else if (!strcmp(strName, "disabled unselected")) {
colDefault = SE_COL_ORANGE_DARK|255;
} else if (!strcmp(strName, "label")) {
colDefault = C_WHITE|255;
} else if (!strcmp(strName, "title")) {
colDefault = C_WHITE|255;
} else if (!strcmp(strName, "editing")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "hilited")) {
colDefault = SE_COL_ORANGE_LIGHT|255;
} else if (!strcmp(strName, "hilited rectangle")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "edit fill")) {
colDefault = SE_COL_BLUE_DARK_LT|75;
} else if (!strcmp(strName, "editing cursor")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "model box")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "hiscore header")) {
colDefault = SE_COL_ORANGE_LIGHT|255;
} else if (!strcmp(strName, "hiscore data")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "hiscore last set")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "slider box")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "file info")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "display mode")) {
colDefault = SE_COL_ORANGE_NEUTRAL|255;
} else if (!strcmp(strName, "bcg fill")) {
colDefault = SE_COL_BLUE_DARK|255;
}
return ::_LCDGetColor(colDefault, strName);
}
COLOR CGame::LCDFadedColor(COLOR col)
{
return ::_LCDFadedColor(col);
}
COLOR CGame::LCDBlinkingColor(COLOR col0, COLOR col1)
{
return ::_LCDBlinkingColor(col0, col1);
}
// menu interface functions
void CGame::MenuPreRenderMenu(const char *strMenuName)
{
}
void CGame::MenuPostRenderMenu(const char *strMenuName)
{
}