TombEngine/Scripting/src/Flow/FlowHandler.cpp

307 lines
8.1 KiB
C++
Raw Normal View History

#include "frameworkandsol.h"
#include "FlowHandler.h"
2022-02-05 20:38:45 +00:00
#include "ReservedScriptNames.h"
2021-09-16 01:12:19 +03:00
#include "Sound/sound.h"
2021-12-22 16:23:57 +03:00
#include "Game/savegame.h"
#include "GameScriptInventoryObject.h"
#include "InventorySlots.h"
2021-11-16 15:51:50 +03:00
#include "Game/gui.h"
2022-02-05 15:56:04 +00:00
#include "Objects/ScriptInterfaceObjectsHandler.h"
2021-07-28 19:06:15 +01:00
/***
Functions for use in Flow.lua, settings.lua and strings.lua
2022-02-05 20:38:45 +00:00
@tentable Flow
2021-07-28 19:06:15 +01:00
@pragma nostrip
*/
2020-12-21 13:16:29 -03:00
using std::string;
using std::vector;
using std::unordered_map;
2020-12-21 13:16:29 -03:00
ScriptInterfaceGame* g_GameScript;
2022-02-05 15:56:04 +00:00
ScriptInterfaceObjectsHandler* g_GameScriptEntities;
ScriptInterfaceStringsHandler* g_GameStringsHandler;
ScriptInterfaceFlowHandler* g_GameFlowHandler;
2020-12-21 13:16:29 -03:00
FlowHandler::FlowHandler(sol::state* lua, sol::table & parent) : LuaHandler{ lua }
2020-12-21 13:16:29 -03:00
{
2021-07-28 19:06:15 +01:00
GameScriptLevel::Register(m_lua);
GameScriptSkyLayer::Register(m_lua);
2021-11-23 09:10:07 +01:00
GameScriptFog::Register(m_lua);
2021-07-28 19:06:15 +01:00
GameScriptMirror::Register(m_lua);
GameScriptInventoryObject::Register(m_lua);
GameScriptSettings::Register(m_lua);
2021-12-01 15:18:47 +03:00
GameScriptAnimations::Register(m_lua);
2021-07-28 19:06:15 +01:00
GameScriptAudioTrack::Register(m_lua);
GameScriptColor::Register(m_lua);
GameScriptRotation::Register(m_lua);
2022-02-06 12:51:24 +00:00
/*** 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 Flowlua
*/
sol::table table_flow{ m_lua->lua_state(), sol::create };
parent.set(ScriptReserved_Flow, table_flow);
2021-07-28 19:06:15 +01:00
/***
Add a level to the Flow.
2021-07-28 19:06:15 +01:00
@function AddLevel
@tparam Level level a level object
2021-07-28 19:06:15 +01:00
*/
table_flow.set_function(ScriptReserved_AddLevel, &FlowHandler::AddLevel, this);
2021-07-28 19:06:15 +01:00
/*** Image to show when loading the game.
Must be a .jpg or .png image.
2021-07-28 19:06:15 +01:00
@function SetIntroImagePath
@tparam string path the path to the image, relative to the TombEngine exe
*/
table_flow.set_function(ScriptReserved_SetIntroImagePath, &FlowHandler::SetIntroImagePath, this);
2021-07-28 19:06:15 +01:00
/*** Image to show in the background of the title screen.
Must be a .jpg or .png image.
__(not yet implemented)__
@function SetTitleScreenImagePath
@tparam string path the path to the image, relative to the TombEngine exe
*/
table_flow.set_function(ScriptReserved_SetTitleScreenImagePath, &FlowHandler::SetTitleScreenImagePath, this);
/*** Maximum draw distance.
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 SetFarView
@tparam byte farview Number of sectors. Must be in the range [1, 127].
*/
table_flow.set_function(ScriptReserved_SetFarView, &FlowHandler::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
*/
table_flow.set_function(ScriptReserved_SetSettings, &FlowHandler::SetSettings, this);
2021-12-01 15:18:47 +03:00
/***
@function SetAnimations
@tparam Animations animations an animations object
2021-12-01 15:18:47 +03:00
*/
table_flow.set_function(ScriptReserved_SetAnimations, &FlowHandler::SetAnimations, 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.
2021-07-28 19:06:15 +01:00
@function SetStrings
@tparam tab table array-style table with strings
2021-07-28 19:06:15 +01:00
*/
table_flow.set_function(ScriptReserved_SetStrings, &FlowHandler::SetStrings, this);
2021-07-28 19:06:15 +01:00
/*** Set language names for translations.
Specify which translations in the strings table correspond to which languages.
2021-07-28 19:06:15 +01:00
@function SetLanguageNames
@tparam tab table array-style table with language names
2021-07-28 19:06:15 +01:00
*/
table_flow.set_function(ScriptReserved_SetLanguageNames, &FlowHandler::SetLanguageNames, this);
MakeReadOnlyTable(ScriptReserved_WeatherType, kWeatherTypes);
MakeReadOnlyTable(ScriptReserved_LaraType, kLaraTypes);
MakeReadOnlyTable(ScriptReserved_InvItem, kInventorySlots);
MakeReadOnlyTable(ScriptReserved_RotationAxis, kRotAxes);
MakeReadOnlyTable(ScriptReserved_ItemAction, kItemActions);
MakeReadOnlyTable(ScriptReserved_ErrorMode, kErrorModes);
2020-12-21 13:16:29 -03:00
}
FlowHandler::~FlowHandler()
2020-12-21 13:16:29 -03:00
{
for (auto& lev : Levels)
2020-12-21 13:16:29 -03:00
{
delete lev;
2020-12-21 13:16:29 -03:00
}
}
void FlowHandler::SetLanguageNames(sol::as_table_t<std::vector<std::string>> && src)
2020-12-21 13:16:29 -03:00
{
m_languageNames = std::move(src);
2020-12-21 13:16:29 -03:00
}
void FlowHandler::SetStrings(sol::nested<std::unordered_map<std::string, std::vector<std::string>>> && src)
2020-12-21 13:16:29 -03:00
{
m_translationsMap = std::move(src);
2020-12-21 13:16:29 -03:00
}
void FlowHandler::SetSettings(GameScriptSettings const & src)
{
m_settings = src;
}
void FlowHandler::SetAnimations(GameScriptAnimations const& src)
2021-12-01 15:18:47 +03:00
{
Animations = src;
}
void FlowHandler::AddLevel(GameScriptLevel const& level)
2020-12-21 13:16:29 -03:00
{
2021-07-28 19:06:15 +01:00
Levels.push_back(new GameScriptLevel{ level });
2020-12-21 13:16:29 -03:00
}
void FlowHandler::SetIntroImagePath(std::string const& path)
2020-12-21 13:16:29 -03:00
{
2021-07-28 19:06:15 +01:00
IntroImagePath = path;
2020-12-21 13:16:29 -03:00
}
void FlowHandler::SetTitleScreenImagePath(std::string const& path)
{
TitleScreenImagePath = path;
}
void FlowHandler::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 FlowHandler::LoadFlowScript()
2020-12-21 13:16:29 -03:00
{
ExecuteScript("Scripts/Enums.lua");
2022-02-06 12:51:24 +00:00
ExecuteScript("Scripts/Gameflow.lua");
ExecuteScript("Scripts/Strings.lua");
ExecuteScript("Scripts/Settings.lua");
2021-08-21 00:15:56 +01:00
SetScriptErrorMode(GetSettings()->ErrorMode);
2020-12-21 13:16:29 -03:00
}
char const * FlowHandler::GetString(const char* id) const
2020-12-21 13:16:29 -03:00
{
2021-08-16 12:52:45 +01:00
if (!ScriptAssert(m_translationsMap.find(id) != m_translationsMap.end(), std::string{ "Couldn't find string " } + id))
{
return "String not found";
2021-08-16 12:52:45 +01:00
}
else
2021-07-28 19:06:15 +01:00
return m_translationsMap.at(string(id)).at(0).c_str();
2020-12-21 13:16:29 -03:00
}
GameScriptSettings* FlowHandler::GetSettings()
2020-12-21 13:16:29 -03:00
{
return &m_settings;
}
GameScriptLevel* FlowHandler::GetLevel(int id)
2020-12-21 13:16:29 -03:00
{
return Levels[id];
}
int FlowHandler::GetNumLevels() const
2020-12-21 13:16:29 -03:00
{
return Levels.size();
}
bool FlowHandler::IsFlyCheatEnabled() const
{
return FlyCheat;
}
bool FlowHandler::DoFlow()
2020-12-21 13:16:29 -03:00
{
// 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];
2020-12-21 13:16:29 -03:00
GAME_STATUS status;
if (CurrentLevel == 0)
{
status = DoTitle(0, level->AmbientTrack);
2020-12-21 13:16:29 -03:00
}
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)
{
2021-11-16 14:52:52 +03:00
InventoryObject* 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, level->AmbientTrack, loadFromSavegame);
2020-12-21 13:16:29 -03:00
loadFromSavegame = false;
}
switch (status)
{
2021-09-25 16:03:28 -05:00
case GAME_STATUS::GAME_STATUS_EXIT_GAME:
2020-12-21 13:16:29 -03:00
return true;
2021-09-25 16:03:28 -05:00
case GAME_STATUS::GAME_STATUS_EXIT_TO_TITLE:
2020-12-21 13:16:29 -03:00
CurrentLevel = 0;
break;
2021-09-25 16:03:28 -05:00
case GAME_STATUS::GAME_STATUS_NEW_GAME:
2020-12-21 13:16:29 -03:00
CurrentLevel = (SelectedLevelForNewGame != 0 ? SelectedLevelForNewGame : 1);
SelectedLevelForNewGame = 0;
InitialiseGame = true;
break;
2021-09-25 16:03:28 -05:00
case GAME_STATUS::GAME_STATUS_LOAD_GAME:
2020-12-21 13:16:29 -03:00
// Load the header of the savegame for getting the level to load
SaveGame::LoadHeader(SelectedSaveGame, &header);
2020-12-21 13:16:29 -03:00
// Load level
2021-10-31 23:55:17 +03:00
CurrentLevel = header.Level;
2020-12-21 13:16:29 -03:00
loadFromSavegame = true;
break;
2021-09-25 16:03:28 -05:00
case GAME_STATUS::GAME_STATUS_LEVEL_COMPLETED:
2020-12-21 13:16:29 -03:00
if (LevelComplete == Levels.size())
{
// TODO: final credits
}
else
CurrentLevel++;
break;
}
}
return true;
}
2022-01-28 00:01:42 +00:00
bool FlowHandler::CanPlayAnyLevel() const
2022-01-28 00:01:42 +00:00
{
return PlayAnyLevel;
}