TombEngine/TR5Main/Game/control.cpp

379 lines
8.4 KiB
C++
Raw Normal View History

2018-08-19 09:46:58 +02:00
#include "control.h"
#include "..\Global\global.h"
#include "pickup.h"
#include "spotcam.h"
#include "camera.h"
#include "lara.h"
#include "hair.h"
#include "items.h"
#include "effect2.h"
#include "draw.h"
#include "inventory.h"
#include "gameflow.h"
#include "lot.h"
#include "pickup.h"
#include "draw.h"
#include "healt.h"
#include "savegame.h"
#include "sound.h"
2018-08-19 09:46:58 +02:00
#include "..\Specific\roomload.h"
#include "..\Specific\input.h"
#include "..\Specific\init.h"
#include "..\Specific\winmain.h"
#include <process.h>
#include <stdio.h>
extern GameScript* g_Script;
GAME_STATUS __cdecl ControlPhase(__int32 numFrames, __int32 demoMode)
2018-08-19 09:46:58 +02:00
{
GameScriptLevel* level = g_Script->GetLevel(CurrentLevel);
2018-08-19 09:46:58 +02:00
RegeneratePickups();
if (numFrames > 10)
numFrames = 10;
if (TrackCameraInit)
UseSpotCam = 0;
SetDebounce = 1;
for (FramesCount += numFrames; FramesCount > 0; FramesCount -= 2)
{
GlobalCounter++;
UpdateSky();
2018-08-19 09:46:58 +02:00
// Poll the keyboard and update input variables
if (S_UpdateInput() == -1)
return GAME_STATUS::GAME_STATUS_NONE;
2018-08-19 09:46:58 +02:00
// Has Lara control been disabled?
if (DisableLaraControl && false)
{
if (CurrentLevel != 0)
DbInput = 0;
TrInput &= 0x200;
}
// If cutscene has been triggered then clear input
if (CutSeqTriggered)
TrInput = 0;
// Does the player want to enter inventory?
SetDebounce = 0;
if (CurrentLevel != 0 || true)
{
if ((DbInput & 0x200000 || GlobalEnterInventory != -1) && !CutSeqTriggered && LaraItem->hitPoints > 0)
{
2018-09-07 18:34:18 +02:00
// Stop all sounds
INVENTORY_RESULT inventoryResult = g_Inventory->DoInventory();
switch (inventoryResult)
{
case INVENTORY_RESULT::INVENTORY_RESULT_LOAD_GAME:
return GAME_STATUS::GAME_STATUS_LOAD_GAME;
case INVENTORY_RESULT::INVENTORY_RESULT_EXIT_TO_TILE:
return GAME_STATUS::GAME_STATUS_EXIT_TO_TITLE;
}
2018-08-19 09:46:58 +02:00
}
}
// Has level been completed?
if (LevelComplete)
return GAME_STATUS::GAME_STATUS_LEVEL_COMPLETED;
2018-08-19 09:46:58 +02:00
__int32 oldInput = TrInput;
2018-09-08 20:54:13 +02:00
// Is Lara dead?
if (Lara.deathCount > 300 || Lara.deathCount > 60 && TrInput)
2018-08-19 09:46:58 +02:00
{
INVENTORY_RESULT inventoryResult = g_Inventory->DoInventory();
switch (inventoryResult)
{
case INVENTORY_RESULT::INVENTORY_RESULT_NEW_GAME:
return GAME_STATUS::GAME_STATUS_NEW_GAME;
case INVENTORY_RESULT::INVENTORY_RESULT_LOAD_GAME:
return GAME_STATUS::GAME_STATUS_LOAD_GAME;
case INVENTORY_RESULT::INVENTORY_RESULT_EXIT_TO_TILE:
return GAME_STATUS::GAME_STATUS_EXIT_TO_TITLE;
}
2018-08-19 09:46:58 +02:00
}
if (demoMode && TrInput == -1)
{
oldInput = 0;
TrInput = 0;
}
2018-09-08 20:54:13 +02:00
// CLear dynamic lights
2018-08-19 09:46:58 +02:00
ClearDynamics();
ClearFires();
g_Renderer->ClearDynamicLights();
GotLaraSpheres = false;
2018-09-08 20:54:13 +02:00
// Update all items
InItemControlLoop = true;
2018-08-19 09:46:58 +02:00
__int16 itemNum = NextItemActive;
while (itemNum != NO_ITEM)
{
ITEM_INFO* item = &Items[itemNum];
__int16 nextItem = item->nextActive;
2018-09-09 21:58:38 +02:00
//printf("Num: %d Next: %d Death: %d Hitpoints: %d Status: %d\n", itemNum, item->nextActive, item->afterDeath, item->hitPoints, item->status);
//printf("NextItemActive: %d\n", NextItemActive);
if (item->afterDeath < 128)
{
if (Objects[item->objectNumber].control)
Objects[item->objectNumber].control(itemNum);
}
else
{
KillItem(itemNum);
}
2018-08-19 09:46:58 +02:00
itemNum = nextItem;
}
InItemControlLoop = false;
KillMoveItems();
2018-09-08 20:54:13 +02:00
// Update all effects
InItemControlLoop = true;
__int16 fxNum = NextFxActive;
while (fxNum != NO_ITEM)
{
__int16 nextFx = Effects[fxNum].nextActive;
if (Objects[Effects[fxNum].objectNumber].control)
(*Objects[Effects[fxNum].objectNumber].control)(fxNum);
fxNum = nextFx;
}
InItemControlLoop = false;
KillMoveEffects();
2018-09-08 20:54:13 +02:00
// Update some effect timers
if (SmokeCountL)
SmokeCountL--;
if (SmokeCountR)
SmokeCountR--;
if (SplashCount)
SplashCount--;
if (WeaponDelay)
WeaponDelay--;
2018-09-12 20:37:37 +02:00
if (WeaponEnemyTimer)
WeaponEnemyTimer--;
2018-08-19 09:46:58 +02:00
2018-09-08 20:54:13 +02:00
// Control Lara
2018-08-19 09:46:58 +02:00
InItemControlLoop = true;
Lara.skelebob = NULL;
LaraControl();
InItemControlLoop = false;
KillMoveItems();
2018-09-08 20:54:13 +02:00
// Update Lara's ponytails
2018-09-07 18:34:18 +02:00
HairControl(0, 0, 0);
if (level->LaraType == LARA_DRAW_TYPE::LARA_YOUNG)
2018-09-07 18:34:18 +02:00
HairControl(0, 1, 0);
2018-08-19 09:46:58 +02:00
if (UseSpotCam)
2018-09-07 18:34:18 +02:00
{
2018-09-08 20:54:13 +02:00
// Draw flyby cameras
2018-09-07 18:34:18 +02:00
g_Renderer->EnableCinematicBars(true);
2018-08-19 09:46:58 +02:00
CalculateSpotCameras();
2018-09-07 18:34:18 +02:00
}
2018-08-19 09:46:58 +02:00
else
2018-09-07 18:34:18 +02:00
{
2018-09-08 20:54:13 +02:00
// Do the standard camera
2018-09-07 18:34:18 +02:00
g_Renderer->EnableCinematicBars(false);
2018-08-19 09:46:58 +02:00
CalculateCamera();
2018-09-07 18:34:18 +02:00
}
2018-09-08 20:54:13 +02:00
//WTF: what is this? It's used everywhere so it has to stay
2018-08-19 09:46:58 +02:00
Wibble = (Wibble + 4) & 0xFC;
2018-09-08 20:54:13 +02:00
// Update special effects
2018-08-19 09:46:58 +02:00
UpdateSparks();
UpdateFireSparks();
UpdateSmoke();
UpdateBlood();
UpdateBubbles();
UpdateDebris();
UpdateGunShells();
UpdateSplashes();
UpdateDrips();
UpdateRats();
UpdateBats();
UpdateSpiders();
UpdateShockwaves();
UpdateLightning();
HealtBarTimer--;
2018-08-19 09:46:58 +02:00
}
return GAME_STATUS::GAME_STATUS_NONE;
2018-08-19 09:46:58 +02:00
}
void __cdecl j_AnimateItem(ITEM_INFO* item)
{
if (item != LaraItem)
printf("AnimateItem\n");
AnimateItem(item);
}
2018-08-19 09:46:58 +02:00
unsigned __stdcall GameMain(void*)
{
DB_Log(2, "GameMain - DLL");
printf("GameMain\n");
2018-09-08 20:54:13 +02:00
// We still need legacy matrices because control routines use them
2018-08-19 09:46:58 +02:00
MatrixPtr = MatrixStack;
DxMatrixPtr = (byte*)malloc(48 * 40);
2018-09-08 20:54:13 +02:00
// Initialise legacy memory buffer and game timer
2018-08-19 09:46:58 +02:00
InitGameMalloc();
TIME_Init();
2018-09-08 20:54:13 +02:00
// TODO: deprecated, to remove because now we have LUA
2018-08-19 09:46:58 +02:00
LoadNewStrings();
2018-09-08 20:54:13 +02:00
// Execute the LUA gameflow and play the game
g_Script->DoGameflow();
2018-09-08 20:54:13 +02:00
// End the game and release some resources
2018-08-19 09:46:58 +02:00
GameClose();
2018-09-08 20:54:13 +02:00
// Finish the thread
2018-08-19 09:46:58 +02:00
PostMessageA((HWND)WindowsHandle, 0x10u, 0, 0);
_endthreadex(1);
return 1;
2018-09-01 15:46:37 +02:00
}
2018-08-19 09:46:58 +02:00
GAME_STATUS __cdecl DoTitle(__int32 index)
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "DoTitle - DLL");
printf("DoTitle\n");
2018-09-08 20:54:13 +02:00
// Load the title level
2018-08-19 09:46:58 +02:00
S_LoadLevelFile(0);
INVENTORY_RESULT inventoryResult = g_Inventory->DoTitleInventory();
switch (inventoryResult)
{
case INVENTORY_RESULT::INVENTORY_RESULT_NEW_GAME:
return GAME_STATUS::GAME_STATUS_NEW_GAME;
case INVENTORY_RESULT::INVENTORY_RESULT_LOAD_GAME:
return GAME_STATUS::GAME_STATUS_LOAD_GAME;
2018-09-08 20:54:13 +02:00
case INVENTORY_RESULT::INVENTORY_RESULT_EXIT_GAME:
return GAME_STATUS::GAME_STATUS_EXIT_GAME;
}
return GAME_STATUS::GAME_STATUS_NEW_GAME;
2018-08-19 09:46:58 +02:00
}
GAME_STATUS __cdecl DoLevel(__int32 index, __int32 ambient, bool loadFromSavegame)
2018-08-19 09:46:58 +02:00
{
CreditsDone = false;
CanLoad = false;
2018-09-08 20:54:13 +02:00
// If not loading a savegame, then clear all the infos
if (!loadFromSavegame)
{
Savegame.Level.Timer = 0;
Savegame.Game.Timer = 0;
Savegame.Level.Distance = 0;
Savegame.Game.Distance = 0;
Savegame.Level.AmmoUsed = 0;
Savegame.Game.AmmoUsed = 0;
Savegame.Level.AmmoHits = 0;
Savegame.Game.AmmoHits = 0;
Savegame.Level.Kills = 0;
Savegame.Game.Kills = 0;
}
2018-09-08 20:54:13 +02:00
// If load from savegame, then restore the game
if (loadFromSavegame)
{
RestoreGame();
gfRequiredStartPos = false;
gfInitialiseGame = false;
}
else
{
gfRequiredStartPos = false;
if (gfInitialiseGame)
{
GameTimer = 0;
gfRequiredStartPos = false;
gfInitialiseGame = false;
}
2018-08-19 09:46:58 +02:00
Savegame.Level.Timer = 0;
if (CurrentLevel == 1)
Savegame.TLCount = 0;
}
2018-09-08 20:54:13 +02:00
// Load the level
2018-08-19 09:46:58 +02:00
S_LoadLevelFile(index);
2018-09-08 20:54:13 +02:00
// TODO: deprecated?
2018-08-19 09:46:58 +02:00
GlobalLastInventoryItem = -1;
DelCutSeqPlayer = 0;
TitleControlsLockedOut = false;
2018-08-22 08:53:34 +02:00
2018-09-08 20:54:13 +02:00
// Initialise flyby cameras
InitSpotCamSequences();
// Play background music
2018-08-22 08:53:34 +02:00
CurrentAtmosphere = ambient;
S_CDPlay(CurrentAtmosphere, 1);
IsAtmospherePlaying = true;
2018-08-19 09:46:58 +02:00
2018-09-08 20:54:13 +02:00
// Initialise items, effects, lots, camera
2018-08-19 09:46:58 +02:00
InitialiseFXArray(true);
InitialiseLOTarray(true);
InitialisePickUpDisplay();
InitialiseCamera();
2018-09-08 20:54:13 +02:00
// Initialise ponytails
2018-08-19 09:46:58 +02:00
InitialiseHair();
__int32 nframes = 2;
GAME_STATUS result = ControlPhase(nframes, 0);
2018-09-07 18:34:18 +02:00
g_Renderer->FadeIn();
2018-09-08 20:54:13 +02:00
// The game loop, finally!
while (true)
2018-08-19 09:46:58 +02:00
{
nframes = DrawPhaseGame();
result = ControlPhase(nframes, 0);
2018-09-08 20:54:13 +02:00
if (result == GAME_STATUS::GAME_STATUS_EXIT_TO_TITLE ||
result == GAME_STATUS::GAME_STATUS_LOAD_GAME ||
result == GAME_STATUS::GAME_STATUS_LEVEL_COMPLETED)
2018-09-08 20:54:13 +02:00
{
// Here is the only way for exiting from the loop
SOUND_Stop();
S_CDStop();
return result;
2018-09-08 20:54:13 +02:00
}
2018-08-21 21:32:56 +03:00
Sound_UpdateScene();
2018-08-19 09:46:58 +02:00
}
}
void Inject_Control()
{
INJECT(0x0040261C, j_AnimateItem);
2018-08-19 09:46:58 +02:00
}