#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"); ChunkId* ChunkGameFlowAudioTracks = ChunkId::FromString("Tr5MainAudioTracks"); ChunkId* ChunkGameFlowTitleBackground = ChunkId::FromString("Tr5MainTitleBackground"); ChunkReader* g_ScriptChunkIO; extern vector g_AudioTracks; GameFlow::GameFlow(sol::state* lua) { m_lua = lua; // Settings type m_lua->new_usertype("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("SkyLayer", sol::constructors(), "r", &GameScriptSkyLayer::R, "g", &GameScriptSkyLayer::G, "b", &GameScriptSkyLayer::B, "speed", &GameScriptSkyLayer::CloudSpeed ); // Mirror type m_lua->new_usertype("Mirror", sol::constructors(), "room", &GameScriptMirror::Room, "startX", &GameScriptMirror::StartX, "endX", &GameScriptMirror::EndX, "startZ", &GameScriptMirror::StartZ, "endZ", &GameScriptMirror::EndZ ); // Fog type m_lua->new_usertype("Fog", sol::constructors(), "r", &GameScriptFog::R, "g", &GameScriptFog::G, "b", &GameScriptFog::B ); // Level type /*m_lua->new_usertype("Level", sol::constructors(), "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()); //g_GameFlow->TitleType = LEB128::ReadInt32(g_ScriptChunkIO->GetRawStream()); char* str; g_ScriptChunkIO->GetRawStream()->ReadString(&str); g_GameFlow->Intro = str; return true; } bool __cdecl readGameFlowStrings() { char* name; g_ScriptChunkIO->GetRawStream()->ReadString(&name); LanguageScript* lang = new LanguageScript(name); free(name); __int32 numStrings = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream()); for (__int32 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 readGameFlowTracks() { __int32 numTracks = LEB128::ReadUInt32(g_ScriptChunkIO->GetRawStream()); for (__int32 i = 0; i < numTracks; i++) { char* str; g_ScriptChunkIO->GetRawStream()->ReadString(&str); AudioTrack track; track.Name = str; track.Mask = 0; g_AudioTracks.push_back(track); } 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); g_ScriptChunkIO->GetRawStream()->ReadString(&str); level->Background = 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()); level->Rumble = LEB128::ReadByte(g_ScriptChunkIO->GetRawStream()); level->Weather = (WEATHER_TYPES)LEB128::ReadByte(g_ScriptChunkIO->GetRawStream()); level->UnlimitedAir = (WEATHER_TYPES)LEB128::ReadByte(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.Enabled = true; 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.Enabled = true; 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(ChunkGameFlowAudioTracks)) return readGameFlowTracks(); 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)); ZeroMemory(LegacyGameFlow, 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 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; // We loop indefinitely, looking for return values of DoTitle or DoLevel bool loadFromSavegame = false; //DoLevel(0, 120, false); while (true) { // First we need to fill some legacy variables in PCTomb5.exe GameScriptLevel* level = Levels[CurrentLevel]; CurrentAtmosphere = level->Soundtrack; if (level->Sky) { 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_EXIT_GAME: return true; case GAME_STATUS_EXIT_TO_TITLE: CurrentLevel = 0; break; case GAME_STATUS_NEW_GAME: CurrentLevel = (SelectedLevelForNewGame != 0 ? SelectedLevelForNewGame : 1); SelectedLevelForNewGame = 0; InitialiseGame = true; break; case 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_LEVEL_COMPLETED: if (LevelComplete == Levels.size()) { // TODO: final credits } else CurrentLevel++; break; } } return true; } GameFlow* g_GameFlow;