TombEngine/TR5Main/Scripting/GameFlowScript.cpp
hispidence 10419d15a8 Fixed some GameFlowScript.cpp warnings:
Remove SkyVelocity1 and SkyVelocity2 - they weren't being used.
Change a loop var to a size_t.
Make GameScriptInventoryObject.yOffset a short.
2021-08-20 02:42:47 +01:00

331 lines
No EOL
8.3 KiB
C++

#include "framework.h"
#include "GameFlowScript.h"
#include "items.h"
#include "box.h"
#include "lot.h"
#include "sound.h"
#include "savegame.h"
#include "draw.h"
#include "AudioTracks.h"
#include "GameScriptInventoryObject.h"
#include "InventorySlots.h"
#include <Objects/objectslist.h>
#include <Game/newinv2.h>
/***
Files that will be run on game startup.
@module gameflow
@pragma nostrip
*/
using std::string;
using std::vector;
using std::unordered_map;
extern unordered_map<string, AudioTrack> g_AudioTracks;
GameFlow::GameFlow(sol::state* lua) : LuaHandler{ lua }
{
GameScriptLevel::Register(m_lua);
GameScriptSkyLayer::Register(m_lua);
GameScriptMirror::Register(m_lua);
GameScriptInventoryObject::Register(m_lua);
GameScriptSettings::Register(m_lua);
GameScriptAudioTrack::Register(m_lua);
GameScriptColor::Register(m_lua);
GameScriptRotation::Register(m_lua);
/*** gameflow.lua.
These functions are called in gameflow.lua, a file loosely equivalent to winroomedit's SCRIPT.DAT.
They handle a game's 'metadata'; i.e., things such as level titles, loading screen paths, and default
ambient tracks.
@section gameflowlua
*/
/***
Add a level to the gameflow.
@function AddLevel
@tparam Level level a level object
*/
m_lua->set_function("AddLevel", &GameFlow::AddLevel, this);
/*** The path of the .jpg or .png image to show when loading the game.
@function SetIntroImagePath
@tparam string path the path to the image, relative to the TombEngine exe
*/
m_lua->set_function("SetIntroImagePath", &GameFlow::SetIntroImagePath, this);
/*** The path of the .jpg or .png image to show in the background of the title screen.
__(not yet implemented)__
@function SetTitleScreenImagePath
@tparam string path the path to the image, relative to the TombEngine exe
*/
m_lua->set_function("SetTitleScreenImagePath", &GameFlow::SetTitleScreenImagePath, this);
/*** The maximum draw distance, in sectors (blocks), of any level in the game.
This is equivalent to TRNG's WorldFarView variable.
__(not yet implemented)__
@function SetGameFarView
@tparam byte farview Number of sectors. Must be in the range [1, 127].
*/
m_lua->set_function("SetGameFarView", &GameFlow::SetGameFarView, this);
/*** settings.lua.
These functions are called in settings.lua, a file which holds your local settings.
settings.lua shouldn't be bundled with any finished levels/games.
@section settingslua
*/
/***
@function SetSettings
@tparam Settings settings a settings object
*/
m_lua->set_function("SetSettings", &GameFlow::SetSettings, this);
/*** tracks.lua.
__TODO CONFIRM PROPER BEHAVIOUR__
@section trackslua
*/
/***
@function SetAudioTracks
@tparam table table array-style table with @{AudioTrack} objects
*/
//TODO confirm proper behaviour
m_lua->set_function("SetAudioTracks", &GameFlow::SetAudioTracks, this);
/*** strings.lua.
These functions used in strings.lua, which is generated by TombIDE.
You will not need to call them manually.
@section stringslua
*/
/*** Set string variable keys and their translations.
@function SetStrings
@tparam table table array-style table with strings
*/
m_lua->set_function("SetStrings", &GameFlow::SetStrings, this);
/*** Specify which translations in the strings table correspond to which languages.
@function SetLanguageNames
@tparam table table array-style table with language names
*/
m_lua->set_function("SetLanguageNames", &GameFlow::SetLanguageNames, this);
MakeReadOnlyTable("WeatherType", kWeatherTypes);
MakeReadOnlyTable("LaraType", kLaraTypes);
MakeReadOnlyTable("InvItem", kInventorySlots);
MakeReadOnlyTable("RotationAxis", kRotAxes);
MakeReadOnlyTable("ItemAction", kItemActions);
MakeReadOnlyTable("ErrorMode", kErrorModes);
}
GameFlow::~GameFlow()
{
for (auto& lev : Levels)
{
delete lev;
}
}
void GameFlow::SetLanguageNames(sol::as_table_t<std::vector<std::string>> && src)
{
m_languageNames = std::move(src);
}
void GameFlow::SetStrings(sol::nested<std::unordered_map<std::string, std::vector<std::string>>> && src)
{
m_translationsMap = std::move(src);
}
void GameFlow::SetSettings(GameScriptSettings const & src)
{
m_settings = src;
}
void GameFlow::AddLevel(GameScriptLevel const& level)
{
Levels.push_back(new GameScriptLevel{ level });
}
void GameFlow::SetIntroImagePath(std::string const& path)
{
IntroImagePath = path;
}
void GameFlow::SetTitleScreenImagePath(std::string const& path)
{
TitleScreenImagePath = path;
}
void GameFlow::SetGameFarView(byte val)
{
bool cond = val <= 127 && val >= 1;
std::string msg{ "Game far view value must be in the range [1, 127]." };
if (!ScriptAssert(cond, msg))
{
ScriptWarn("Setting game far view to 32.");
GameFarView = 32;
}
else
{
GameFarView = val;
}
}
void GameFlow::SetAudioTracks(sol::as_table_t<std::vector<GameScriptAudioTrack>>&& src)
{
std::vector<GameScriptAudioTrack> tracks = std::move(src);
for (auto t : tracks) {
AudioTrack track;
track.Name = t.trackName;
track.Mask = 0;
track.looped = t.looped;
g_AudioTracks.insert_or_assign(track.Name, track);
}
}
void GameFlow::LoadGameFlowScript()
{
ExecuteScript("Scripts/Enums.lua");
ExecuteScript("Scripts/Tracks.lua");
ExecuteScript("Scripts/Gameflow.lua");
ExecuteScript("Scripts/Strings.lua");
ExecuteScript("Scripts/Settings.lua");
SetErrorMode(GetSettings()->ErrorMode);
}
char const * GameFlow::GetString(const char* id) const
{
if (!ScriptAssert(m_translationsMap.find(id) != m_translationsMap.end(), std::string{ "Couldn't find string " } + id))
{
return "String not found";
}
else
return m_translationsMap.at(string(id)).at(0).c_str();
}
GameScriptSettings* GameFlow::GetSettings()
{
return &m_settings;
}
GameScriptLevel* GameFlow::GetLevel(int id)
{
return Levels[id];
}
int GameFlow::GetNumLevels() const
{
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;
while (true)
{
// First we need to fill some legacy variables in PCTomb5.exe
GameScriptLevel* level = Levels[CurrentLevel];
CurrentAtmosphere = level->AmbientTrack;
if (level->Horizon)
{
SkyColor1.r = level->Layer1.R;
SkyColor1.g = level->Layer1.G;
SkyColor1.b = level->Layer1.B;
SkyColor2.r = level->Layer2.R;
SkyColor2.g = level->Layer2.G;
SkyColor2.b = level->Layer2.B;
}
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
{
// Prepare inventory objects table
for (size_t i = 0; i < level->InventoryObjects.size(); i++)
{
GameScriptInventoryObject* obj = &level->InventoryObjects[i];
if (obj->slot >= 0 && obj->slot < INVENTORY_TABLE_SIZE)
{
INVOBJ* invObj = &inventry_objects_list[obj->slot];
invObj->objname = obj->name.c_str();
invObj->scale1 = obj->scale;
invObj->yoff = obj->yOffset;
invObj->xrot = FROM_DEGREES(obj->rot.x);
invObj->yrot = FROM_DEGREES(obj->rot.y);
invObj->zrot = FROM_DEGREES(obj->rot.z);
invObj->meshbits = obj->meshBits;
invObj->opts = obj->action;
invObj->rot_flags = obj->rotationFlags;
}
}
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;