mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-30 00:37:58 +03:00
503 lines
No EOL
15 KiB
C++
503 lines
No EOL
15 KiB
C++
#include "GameFlowScript.h"
|
|
#include "..\Game\items.h"
|
|
#include "..\Game\box.h"
|
|
#include "..\Game\lot.h"
|
|
#include "..\Game\sound.h"
|
|
#include "..\Game\savegame.h"
|
|
|
|
ChunkId* ChunkGameFlowFlags = ChunkId::FromString("Tr5MainFlags");
|
|
ChunkId* ChunkGameFlowLevel = ChunkId::FromString("Tr5MainLevel");
|
|
ChunkId* ChunkGameFlowLevelFlags = ChunkId::FromString("Tr5MainLevelFlags");
|
|
ChunkId* ChunkGameFlowLevelInfo = ChunkId::FromString("Tr5MainLevelInfo");
|
|
ChunkId* ChunkGameFlowLevelPuzzle = ChunkId::FromString("Tr5MainLevelPuzzle");
|
|
ChunkId* ChunkGameFlowLevelKey = ChunkId::FromString("Tr5MainLevelKey");
|
|
ChunkId* ChunkGameFlowLevelPuzzleCombo = ChunkId::FromString("Tr5MainLevelPuzzleCombo");
|
|
ChunkId* ChunkGameFlowLevelKeyCombo = ChunkId::FromString("Tr5MainLevelKeyCombo");
|
|
ChunkId* ChunkGameFlowLevelPickup = ChunkId::FromString("Tr5MainLevelPickup");
|
|
ChunkId* ChunkGameFlowLevelPickupCombo = ChunkId::FromString("Tr5MainLevelPickupCombo");
|
|
ChunkId* ChunkGameFlowLevelExamine = ChunkId::FromString("Tr5MainLevelExamine");
|
|
ChunkId* ChunkGameFlowLevelLayer = ChunkId::FromString("Tr5MainLevelLayer");
|
|
ChunkId* ChunkGameFlowLevelLuaEvent = ChunkId::FromString("Tr5MainLevelLuaEvent");
|
|
ChunkId* ChunkGameFlowLevelLegend = ChunkId::FromString("Tr5MainLevelLegend");
|
|
ChunkId* ChunkGameFlowStrings = ChunkId::FromString("Tr5MainStrings");
|
|
|
|
ChunkReader* g_ScriptChunkIO;
|
|
|
|
GameFlow::GameFlow(sol::state* lua)
|
|
{
|
|
m_lua = lua;
|
|
|
|
// Settings type
|
|
m_lua->new_usertype<GameScriptSettings>("GameScriptSettings",
|
|
"screenWidth", &GameScriptSettings::ScreenWidth,
|
|
"screenHeight", &GameScriptSettings::ScreenHeight,
|
|
"windowTitle", &GameScriptSettings::WindowTitle,
|
|
"enableDynamicShadows", &GameScriptSettings::EnableDynamicShadows,
|
|
"windowed", &GameScriptSettings::Windowed,
|
|
"enableWaterCaustics", &GameScriptSettings::EnableWaterCaustics,
|
|
"drawingDistance", &GameScriptSettings::DrawingDistance,
|
|
"showRendererSteps", &GameScriptSettings::ShowRendererSteps,
|
|
"showDebugInfo", &GameScriptSettings::ShowDebugInfo
|
|
);
|
|
|
|
// Layer type
|
|
m_lua->new_usertype<GameScriptSkyLayer>("SkyLayer",
|
|
sol::constructors<GameScriptSkyLayer(byte, byte, byte, __int16)>(),
|
|
"r", &GameScriptSkyLayer::R,
|
|
"g", &GameScriptSkyLayer::G,
|
|
"b", &GameScriptSkyLayer::B,
|
|
"speed", &GameScriptSkyLayer::CloudSpeed
|
|
);
|
|
|
|
// Mirror type
|
|
m_lua->new_usertype<GameScriptMirror>("Mirror",
|
|
sol::constructors<GameScriptMirror(__int16, __int32, __int32, __int32, __int32)>(),
|
|
"room", &GameScriptMirror::Room,
|
|
"startX", &GameScriptMirror::StartX,
|
|
"endX", &GameScriptMirror::EndX,
|
|
"startZ", &GameScriptMirror::StartZ,
|
|
"endZ", &GameScriptMirror::EndZ
|
|
);
|
|
|
|
// Fog type
|
|
m_lua->new_usertype<GameScriptFog>("Fog",
|
|
sol::constructors<GameScriptFog(byte, byte, byte)>(),
|
|
"r", &GameScriptFog::R,
|
|
"g", &GameScriptFog::G,
|
|
"b", &GameScriptFog::B
|
|
);
|
|
|
|
// Level type
|
|
m_lua->new_usertype<GameScriptLevel>("Level",
|
|
sol::constructors<GameScriptLevel()>(),
|
|
"name", &GameScriptLevel::Name,
|
|
"script", &GameScriptLevel::ScriptFileName,
|
|
"fileName", &GameScriptLevel::FileName,
|
|
"loadScreen", &GameScriptLevel::LoadScreenFileName,
|
|
"soundTrack", &GameScriptLevel::Soundtrack,
|
|
"layer1", &GameScriptLevel::Layer1,
|
|
"layer2", &GameScriptLevel::Layer2,
|
|
"fog", &GameScriptLevel::Fog,
|
|
"horizon", &GameScriptLevel::Horizon,
|
|
"colAddHorizon", &GameScriptLevel::ColAddHorizon,
|
|
"storm", &GameScriptLevel::Storm,
|
|
"background", &GameScriptLevel::Background,
|
|
"rain", &GameScriptLevel::Rain,
|
|
"snow", &GameScriptLevel::Snow,
|
|
"laraType", &GameScriptLevel::LaraType,
|
|
"rumble", &GameScriptLevel::Rumble,
|
|
"resetHub", &GameScriptLevel::ResetHub,
|
|
"mirror", &GameScriptLevel::Mirror
|
|
);
|
|
|
|
(*m_lua)["Gameflow"] = this;
|
|
}
|
|
|
|
GameFlow::~GameFlow()
|
|
{
|
|
|
|
}
|
|
|
|
bool __cdecl readGameFlowFlags()
|
|
{
|
|
g_GameFlow->EnableLoadSave = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
g_GameFlow->PlayAnyLevel = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
g_GameFlow->FlyCheat = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
g_GameFlow->DebugMode = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
g_GameFlow->LevelFarView = LEB128::ReadInt32(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool __cdecl readGameFlowStrings()
|
|
{
|
|
char* name;
|
|
g_ScriptChunkIO->GetRawStream()->ReadString(&name);
|
|
LanguageScript* lang = new LanguageScript(name);
|
|
free(name);
|
|
|
|
int numStrings = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (int i = 0; i < numStrings; i++)
|
|
{
|
|
char* str;
|
|
g_ScriptChunkIO->GetRawStream()->ReadString(&str);
|
|
lang->Strings.push_back(string(str));
|
|
free(str);
|
|
}
|
|
|
|
g_GameFlow->Strings.push_back(lang);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool __cdecl readGameFlowLevelChunks(ChunkId* chunkId, __int32 maxSize, __int32 arg)
|
|
{
|
|
GameScriptLevel* level = g_GameFlow->Levels[arg];
|
|
|
|
if (chunkId->EqualsTo(ChunkGameFlowLevelInfo))
|
|
{
|
|
char* str;
|
|
|
|
g_ScriptChunkIO->GetRawStream()->ReadString(&str);
|
|
level->FileName = string(str);
|
|
free(str);
|
|
|
|
g_ScriptChunkIO->GetRawStream()->ReadString(&str);
|
|
level->LoadScreenFileName = string(str);
|
|
free(str);
|
|
|
|
level->NameStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
level->Soundtrack = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelFlags))
|
|
{
|
|
level->Horizon = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Sky = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->ColAddHorizon = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Storm = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->ResetHub = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->LaraType = (LARA_DRAW_TYPE)LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->UVRotate = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->LevelFarView = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelFlags))
|
|
{
|
|
level->Horizon = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Sky = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->ColAddHorizon = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Storm = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->ResetHub = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->LaraType = (LARA_DRAW_TYPE)LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->UVRotate = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->LevelFarView = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelPuzzle))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelKey))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelPickup))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelExamine))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelPuzzleCombo))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int piece = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelKeyCombo))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int piece = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelPickupCombo))
|
|
{
|
|
int itemIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int piece = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
int itemStringIndex = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream());
|
|
for (__int32 i = 0; i < 6; i++)
|
|
LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
|
|
return true;
|
|
}
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevelLayer))
|
|
{
|
|
int layerIndex = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
|
|
if (layerIndex == 1)
|
|
{
|
|
level->Layer1.R = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Layer1.G = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Layer1.B = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Layer1.CloudSpeed = LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
}
|
|
else
|
|
{
|
|
level->Layer2.R = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Layer2.G = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Layer2.B = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream());
|
|
level->Layer2.CloudSpeed = LEB128::ReadInt16(g_ScriptChunkIO->GetRawStream());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool __cdecl readGameFlowLevel()
|
|
{
|
|
g_GameFlow->Levels.push_back(new GameScriptLevel());
|
|
return g_ScriptChunkIO->ReadChunks(readGameFlowLevelChunks, g_GameFlow->Levels.size() - 1);
|
|
}
|
|
|
|
bool __cdecl readGameFlowChunks(ChunkId* chunkId, __int32 maxSize, __int32 arg)
|
|
{
|
|
if (chunkId->EqualsTo(ChunkGameFlowFlags))
|
|
return readGameFlowFlags();
|
|
else if (chunkId->EqualsTo(ChunkGameFlowStrings))
|
|
return readGameFlowStrings();
|
|
else if (chunkId->EqualsTo(ChunkGameFlowLevel))
|
|
return readGameFlowLevel();
|
|
return false;
|
|
}
|
|
|
|
bool __cdecl LoadScript()
|
|
{
|
|
// Initialise an empty legacy GAMEFLOW object for avoiding exceptions in the few functions left that use it
|
|
LegacyGameFlow = (GAMEFLOW*)malloc(sizeof(GAMEFLOW));
|
|
|
|
// Load the new script file
|
|
FileStream stream("Script.dat", true, false);
|
|
g_ScriptChunkIO = new ChunkReader(0x4D355254, &stream);
|
|
if (!g_ScriptChunkIO->IsValid())
|
|
return false;
|
|
|
|
g_ScriptChunkIO->ReadChunks(readGameFlowChunks, 0);
|
|
|
|
g_GameFlow->CurrentStrings = g_GameFlow->Strings[0];
|
|
|
|
return true;
|
|
}
|
|
|
|
string GameFlow::loadScriptFromFile(char* luaFilename)
|
|
{
|
|
ifstream ifs(luaFilename, ios::in | ios::binary | ios::ate);
|
|
|
|
ifstream::pos_type fileSize = ifs.tellg();
|
|
ifs.seekg(0, ios::beg);
|
|
|
|
vector<char> bytes(fileSize);
|
|
ifs.read(bytes.data(), fileSize);
|
|
|
|
return string(bytes.data(), fileSize);
|
|
}
|
|
|
|
bool GameFlow::LoadGameStrings(char* luaFilename)
|
|
{
|
|
string script = loadScriptFromFile(luaFilename);
|
|
m_lua->script(script);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GameFlow::LoadGameSettings(char* luaFilename)
|
|
{
|
|
string script = loadScriptFromFile(luaFilename);
|
|
m_lua->script(script);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GameFlow::ExecuteScript(char* luaFilename)
|
|
{
|
|
string script = loadScriptFromFile(luaFilename);
|
|
m_lua->script(script);
|
|
|
|
return true;
|
|
}
|
|
|
|
char* GameFlow::GetString(__int32 id)
|
|
{
|
|
return (char*)(CurrentStrings->Strings[id].c_str());
|
|
}
|
|
|
|
GameScriptSettings* GameFlow::GetSettings()
|
|
{
|
|
return &m_settings;
|
|
}
|
|
|
|
GameScriptLevel* GameFlow::GetLevel(__int32 id)
|
|
{
|
|
return Levels[id];
|
|
}
|
|
|
|
void GameFlow::SetHorizon(bool horizon, bool colAddHorizon)
|
|
{
|
|
DrawHorizon = horizon;
|
|
ColAddHorizon = colAddHorizon;
|
|
}
|
|
|
|
void GameFlow::SetLayer1(byte r, byte g, byte b, __int16 speed)
|
|
{
|
|
SkyColor1.r = r;
|
|
SkyColor1.g = g;
|
|
SkyColor1.b = b;
|
|
SkyVelocity1 = speed;
|
|
|
|
SkyColorLayer1.x = r / 255.0f;
|
|
SkyColorLayer1.y = g / 255.0f;
|
|
SkyColorLayer1.z = b / 255.0f;
|
|
SkySpeedLayer1 = speed;
|
|
}
|
|
|
|
void GameFlow::SetLayer2(byte r, byte g, byte b, __int16 speed)
|
|
{
|
|
SkyColor2.r = r;
|
|
SkyColor2.g = g;
|
|
SkyColor2.b = b;
|
|
SkyVelocity2 = speed;
|
|
|
|
SkyColorLayer2.x = r / 255.0f;
|
|
SkyColorLayer2.y = g / 255.0f;
|
|
SkyColorLayer2.z = b / 255.0f;
|
|
SkySpeedLayer2 = speed;
|
|
}
|
|
|
|
void GameFlow::SetFog(byte r, byte g, byte b, __int16 startDistance, __int16 endDistance)
|
|
{
|
|
FogColor.x = r / 255.0f;
|
|
FogColor.y = g / 255.0f;
|
|
FogColor.z = b / 255.0f;
|
|
FogInDistance = startDistance;
|
|
FogOutDistance = endDistance;
|
|
}
|
|
|
|
__int32 GameFlow::GetNumLevels()
|
|
{
|
|
return Levels.size();
|
|
}
|
|
|
|
bool GameFlow::DoGameflow()
|
|
{
|
|
// We start with the title level
|
|
CurrentLevel = 0;
|
|
SelectedLevelForNewGame = 0;
|
|
SelectedSaveGame = 0;
|
|
SaveGameHeader header;
|
|
|
|
// DEBUG: test
|
|
/*CurrentLevel = 1;
|
|
SelectedLevelForNewGame = 0;
|
|
gfInitialiseGame = true;
|
|
DoLevel(CurrentLevel, 126, false);
|
|
|
|
return true;*/
|
|
|
|
// We loop indefinitely, looking for return values of DoTitle or DoLevel
|
|
bool loadFromSavegame = false;
|
|
while (true)
|
|
{
|
|
// First we need to fill some legacy variables in PCTomb5.exe
|
|
GameScriptLevel* level = Levels[CurrentLevel];
|
|
|
|
CurrentAtmosphere = level->Soundtrack;
|
|
|
|
if (level->Horizon)
|
|
{
|
|
SkyColor1.r = level->Layer1.R;
|
|
SkyColor1.g = level->Layer1.G;
|
|
SkyColor1.b = level->Layer1.B;
|
|
SkyVelocity1 = level->Layer1.CloudSpeed;
|
|
|
|
SkyColor2.r = level->Layer2.R;
|
|
SkyColor2.g = level->Layer2.G;
|
|
SkyColor2.b = level->Layer2.B;
|
|
SkyVelocity2 = level->Layer2.CloudSpeed;
|
|
}
|
|
|
|
if (level->Storm)
|
|
{
|
|
SkyStormColor[0] = level->Layer1.R;
|
|
SkyStormColor[1] = level->Layer1.G;
|
|
SkyStormColor[2] = level->Layer1.B;
|
|
|
|
SkyStormColor2[0] = level->Layer1.R;
|
|
SkyStormColor2[1] = level->Layer1.G;
|
|
SkyStormColor2[2] = level->Layer1.B;
|
|
}
|
|
|
|
GAME_STATUS status;
|
|
|
|
if (CurrentLevel == 0)
|
|
{
|
|
status = DoTitle(0);
|
|
}
|
|
else
|
|
{
|
|
status = DoLevel(CurrentLevel, CurrentAtmosphere, loadFromSavegame);
|
|
loadFromSavegame = false;
|
|
}
|
|
|
|
switch (status)
|
|
{
|
|
case GAME_STATUS::GAME_STATUS_EXIT_GAME:
|
|
return true;
|
|
case GAME_STATUS::GAME_STATUS_EXIT_TO_TITLE:
|
|
CurrentLevel = 0;
|
|
break;
|
|
case GAME_STATUS::GAME_STATUS_NEW_GAME:
|
|
CurrentLevel = (SelectedLevelForNewGame != 0 ? SelectedLevelForNewGame : 1);
|
|
SelectedLevelForNewGame = 0;
|
|
gfInitialiseGame = true;
|
|
break;
|
|
case GAME_STATUS::GAME_STATUS_LOAD_GAME:
|
|
// Load the header of the savegame for getting the level to load
|
|
char fileName[255];
|
|
ZeroMemory(fileName, 255);
|
|
sprintf(fileName, "savegame.%d", SelectedSaveGame);
|
|
SaveGame::LoadHeader(fileName, &header);
|
|
|
|
// Load level
|
|
CurrentLevel = header.Level;
|
|
loadFromSavegame = true;
|
|
|
|
break;
|
|
case GAME_STATUS::GAME_STATUS_LEVEL_COMPLETED:
|
|
if (LevelComplete == Levels.size())
|
|
{
|
|
// TODO: final credits
|
|
}
|
|
else
|
|
CurrentLevel++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GameFlow* g_GameFlow; |