mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-09 03:58:19 +03:00
Revert "Move scripting source files into new filder. Obviously, these won't work yet or even compile."
This reverts commit 8a31dbf644
.
This commit is contained in:
parent
69de6e4502
commit
6983e09a6a
24 changed files with 0 additions and 0 deletions
|
@ -1,315 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameFlowScript.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Game/savegame.h"
|
||||
#include "GameScriptInventoryObject.h"
|
||||
#include "InventorySlots.h"
|
||||
#include "Game/gui.h"
|
||||
|
||||
/***
|
||||
Scripts that will be run on game startup.
|
||||
@files Pre-game
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::unordered_map;
|
||||
|
||||
GameFlow* g_GameFlow;
|
||||
ScriptInterfaceGame* g_GameScript;
|
||||
|
||||
GameFlow::GameFlow(sol::state* lua) : LuaHandler{ lua }
|
||||
{
|
||||
GameScriptLevel::Register(m_lua);
|
||||
GameScriptSkyLayer::Register(m_lua);
|
||||
GameScriptFog::Register(m_lua);
|
||||
GameScriptMirror::Register(m_lua);
|
||||
GameScriptInventoryObject::Register(m_lua);
|
||||
GameScriptSettings::Register(m_lua);
|
||||
GameScriptAnimations::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);
|
||||
|
||||
/*** Image to show when loading the game.
|
||||
Must be a .jpg or .png image.
|
||||
@function SetIntroImagePath
|
||||
@tparam string path the path to the image, relative to the TombEngine exe
|
||||
*/
|
||||
m_lua->set_function("SetIntroImagePath", &GameFlow::SetIntroImagePath, this);
|
||||
|
||||
/*** 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
|
||||
*/
|
||||
m_lua->set_function("SetTitleScreenImagePath", &GameFlow::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 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);
|
||||
/***
|
||||
@function SetSettings
|
||||
@tparam Settings settings a settings object
|
||||
*/
|
||||
m_lua->set_function("SetAnimations", &GameFlow::SetAnimations, 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 tab table array-style table with strings
|
||||
*/
|
||||
m_lua->set_function("SetStrings", &GameFlow::SetStrings, this);
|
||||
|
||||
/*** Set language names for translations.
|
||||
Specify which translations in the strings table correspond to which languages.
|
||||
@function SetLanguageNames
|
||||
@tparam tab 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::SetAnimations(GameScriptAnimations const& src)
|
||||
{
|
||||
Animations = 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);
|
||||
SoundTracks.clear();
|
||||
|
||||
for (auto t : tracks) {
|
||||
SoundTrackInfo track;
|
||||
track.Name = t.trackName;
|
||||
track.Mask = 0;
|
||||
track.Mode = t.looped ? SOUNDTRACK_PLAYTYPE::BGM : SOUNDTRACK_PLAYTYPE::OneShot;
|
||||
SoundTracks.push_back(track);
|
||||
}
|
||||
}
|
||||
|
||||
void GameFlow::LoadGameFlowScript()
|
||||
{
|
||||
ExecuteScript("Scripts/Enums.lua");
|
||||
ExecuteScript("Scripts/Tracks.lua");
|
||||
ExecuteScript("Scripts/Gameflow.lua");
|
||||
ExecuteScript("Scripts/Strings.lua");
|
||||
ExecuteScript("Scripts/Settings.lua");
|
||||
|
||||
SetScriptErrorMode(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];
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
InitialiseGame = true;
|
||||
break;
|
||||
case GAME_STATUS::GAME_STATUS_LOAD_GAME:
|
||||
// Load the header of the savegame for getting the level to load
|
||||
SaveGame::LoadHeader(SelectedSaveGame, &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;
|
||||
}
|
|
@ -1,823 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameLogicScript.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/savegame.h"
|
||||
#include "Game/control/lot.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/setup.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Game/effects/tomb4fx.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/pickup/pickup.h"
|
||||
#include "Game/gui.h"
|
||||
#include "ObjectIDs.h"
|
||||
#include "GameScriptDisplayString.h"
|
||||
#include "ReservedScriptNames.h"
|
||||
#include "Game/camera.h"
|
||||
#include <Renderer/Renderer11Enums.h>
|
||||
#include "Game/effects/lightning.h"
|
||||
|
||||
using namespace TEN::Effects::Lightning;
|
||||
|
||||
/***
|
||||
Functions and callbacks for level-specific logic scripts.
|
||||
@files Level-specific
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
static void PlayAudioTrack(std::string const & trackName, sol::optional<bool> looped)
|
||||
{
|
||||
auto mode = looped.value_or(false) ? SOUNDTRACK_PLAYTYPE::OneShot : SOUNDTRACK_PLAYTYPE::BGM;
|
||||
PlaySoundTrack(trackName, mode);
|
||||
}
|
||||
|
||||
static void PlaySoundEffect(int id, GameScriptPosition p, int flags)
|
||||
{
|
||||
PHD_3DPOS pos;
|
||||
|
||||
pos.xPos = p.x;
|
||||
pos.yPos = p.y;
|
||||
pos.zPos = p.z;
|
||||
pos.xRot = 0;
|
||||
pos.yRot = 0;
|
||||
pos.zRot = 0;
|
||||
|
||||
SoundEffect(id, &pos, flags);
|
||||
}
|
||||
|
||||
static void PlaySoundEffect(int id, int flags)
|
||||
{
|
||||
SoundEffect(id, NULL, flags);
|
||||
}
|
||||
|
||||
static void SetAmbientTrack(std::string const & trackName)
|
||||
{
|
||||
PlaySoundTrack(trackName, SOUNDTRACK_PLAYTYPE::BGM);
|
||||
}
|
||||
|
||||
static int FindRoomNumber(GameScriptPosition pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void AddLightningArc(GameScriptPosition src, GameScriptPosition dest, GameScriptColor color, int lifetime, int amplitude, int beamWidth, int segments, int flags)
|
||||
{
|
||||
PHD_VECTOR p1;
|
||||
p1.x = src.x;
|
||||
p1.y = src.y;
|
||||
p1.z = src.z;
|
||||
|
||||
PHD_VECTOR p2;
|
||||
p2.x = dest.x;
|
||||
p2.y = dest.y;
|
||||
p2.z = dest.z;
|
||||
|
||||
TriggerLightning(&p1, &p2, amplitude, color.GetR(), color.GetG(), color.GetB(), lifetime, flags, beamWidth, segments);
|
||||
}
|
||||
|
||||
static void AddShockwave(GameScriptPosition pos, int innerRadius, int outerRadius, GameScriptColor color, int lifetime, int speed, int angle, int flags)
|
||||
{
|
||||
PHD_3DPOS p;
|
||||
p.xPos = pos.x;
|
||||
p.yPos = pos.y;
|
||||
p.zPos = pos.z;
|
||||
|
||||
TriggerShockwave(&p, innerRadius, outerRadius, speed, color.GetR(), color.GetG(), color.GetB(), lifetime, FROM_DEGREES(angle), flags);
|
||||
}
|
||||
|
||||
static void AddDynamicLight(GameScriptPosition pos, GameScriptColor color, int radius, int lifetime)
|
||||
{
|
||||
TriggerDynamicLight(pos.x, pos.y, pos.z, radius, color.GetR(), color.GetG(), color.GetB());
|
||||
}
|
||||
|
||||
static void AddBlood(GameScriptPosition pos, int num)
|
||||
{
|
||||
TriggerBlood(pos.x, pos.y, pos.z, -1, num);
|
||||
}
|
||||
|
||||
static void AddFireFlame(GameScriptPosition pos, int size)
|
||||
{
|
||||
AddFire(pos.x, pos.y, pos.z, size, FindRoomNumber(pos), true);
|
||||
}
|
||||
|
||||
static void Earthquake(int strength)
|
||||
{
|
||||
Camera.bounce = -strength;
|
||||
}
|
||||
|
||||
static void InventoryAdd(ItemEnumPair slot, sol::optional<int> count)
|
||||
{
|
||||
// If 0 is passed in, then the amount added will be the default amount
|
||||
// for that pickup - i.e. the amount you would get from picking up the
|
||||
// item in-game (e.g. 1 for medipacks, 12 for flares).
|
||||
PickedUpObject(slot.m_pair.first, count.value_or(0));
|
||||
}
|
||||
|
||||
static void InventoryRemove(ItemEnumPair slot, sol::optional<int> count)
|
||||
{
|
||||
// 0 is default for the same reason as in InventoryAdd.
|
||||
RemoveObjectFromInventory(slot.m_pair.first, count.value_or(0));
|
||||
}
|
||||
|
||||
static int InventoryGetCount(ItemEnumPair slot)
|
||||
{
|
||||
return GetInventoryCount(slot.m_pair.first);
|
||||
}
|
||||
|
||||
static void InventorySetCount(ItemEnumPair slot, int count)
|
||||
{
|
||||
// add the amount we'd need to add to get to count
|
||||
int currAmt = GetInventoryCount(slot.m_pair.first);
|
||||
InventoryAdd(slot, count - currAmt);
|
||||
}
|
||||
|
||||
static void InventoryCombine(int slot1, int slot2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void InventorySeparate(int slot)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int CalculateDistance(GameScriptPosition const & pos1, GameScriptPosition const & pos2)
|
||||
{
|
||||
auto result = sqrt(SQUARE(pos1.x - pos2.x) + SQUARE(pos1.y - pos2.y) + SQUARE(pos1.z - pos2.z));
|
||||
return static_cast<int>(round(result));
|
||||
}
|
||||
|
||||
static int CalculateHorizontalDistance(GameScriptPosition const & pos1, GameScriptPosition const & pos2)
|
||||
{
|
||||
auto result = sqrt(SQUARE(pos1.x - pos2.x) + SQUARE(pos1.z - pos2.z));
|
||||
return static_cast<int>(round(result));
|
||||
}
|
||||
|
||||
// A "special" table is essentially one that TEN reserves and does things with.
|
||||
template <typename funcIndex, typename funcNewindex, typename obj>
|
||||
static void MakeSpecialTable(sol::state * state, std::string const & name, funcIndex const & fi, funcNewindex const & fni, obj objPtr)
|
||||
{
|
||||
std::string metaName{ name + "Meta" };
|
||||
auto meta = sol::table{ *state, sol::create };
|
||||
state->set(metaName, meta);
|
||||
meta.set("__metatable", "\"metatable is protected\"");
|
||||
auto tab = state->create_named_table(name);
|
||||
tab[sol::metatable_key] = meta;
|
||||
state->set(metaName, sol::nil);
|
||||
meta.set_function("__index", fi, objPtr);
|
||||
meta.set_function("__newindex", fni, objPtr);
|
||||
}
|
||||
|
||||
static std::tuple<int, int> PercentToScreen(double x, double y)
|
||||
{
|
||||
auto fWidth = static_cast<double>(g_Configuration.Width);
|
||||
auto fHeight = static_cast<double>(g_Configuration.Height);
|
||||
int resX = std::round(fWidth / 100.0 * x);
|
||||
int resY = std::round(fHeight / 100.0 * y);
|
||||
//todo this still assumes a resolution of 800/600. account for this somehow
|
||||
return std::make_tuple(resX, resY);
|
||||
}
|
||||
|
||||
static std::tuple<double, double> ScreenToPercent(int x, int y)
|
||||
{
|
||||
|
||||
auto fWidth = static_cast<double>(g_Configuration.Width);
|
||||
auto fHeight = static_cast<double>(g_Configuration.Height);
|
||||
double resX = x/fWidth * 100.0;
|
||||
double resY = y/fHeight * 100.0;
|
||||
return std::make_tuple(resX, resY);
|
||||
}
|
||||
|
||||
GameScript::GameScript(sol::state* lua) : LuaHandler{ lua }
|
||||
{
|
||||
/*** Ambience and music
|
||||
@section Music
|
||||
*/
|
||||
|
||||
/*** Set and play an ambient track
|
||||
@function SetAmbientTrack
|
||||
@tparam string name of track (without file extension) to play
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_SetAmbientTrack, &SetAmbientTrack);
|
||||
|
||||
/*** Play an audio track
|
||||
@function PlayAudioTrack
|
||||
@tparam string name of track (without file extension) to play
|
||||
@tparam bool loop if true, the track will loop; if false, it won't (default: false)
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_PlayAudioTrack, &PlayAudioTrack);
|
||||
|
||||
|
||||
/*** Player inventory management
|
||||
@section Inventory
|
||||
*/
|
||||
|
||||
/*** Add x of an item to the inventory.
|
||||
A count of 0 will add the "default" amount of that item
|
||||
(i.e. the amount the player would get from a pickup of that type).
|
||||
For example, giving "zero" crossbow ammo would give the player
|
||||
10 instead, whereas giving "zero" medkits would give the player 1 medkit.
|
||||
@function GiveInvItem
|
||||
@tparam InvItem item the item to be added
|
||||
@tparam int count the number of items to add (default: 0)
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GiveInvItem, &InventoryAdd);
|
||||
|
||||
/***
|
||||
Remove x of a certain item from the inventory.
|
||||
As in @{GiveInvItem}, a count of 0 will remove the "default" amount of that item.
|
||||
@function TakeInvItem
|
||||
@tparam InvItem item the item to be removed
|
||||
@tparam int count the number of items to remove (default: 0)
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_TakeInvItem, &InventoryRemove);
|
||||
|
||||
/***
|
||||
Get the amount the player holds of an item.
|
||||
@function GetInvItemCount
|
||||
@tparam InvItem item the item to check
|
||||
@treturn int the amount of the item the player has in the inventory
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GetInvItemCount, &InventoryGetCount);
|
||||
|
||||
/***
|
||||
Set the amount of a certain item the player has in the inventory.
|
||||
Similar to @{GiveInvItem} but replaces with the new amount instead of adding it.
|
||||
@function SetInvItemCount
|
||||
@tparam @{InvItem} item the item to be set
|
||||
@tparam int count the number of items the player will have
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_SetInvItemCount, &InventorySetCount);
|
||||
|
||||
/*** Game entity getters.
|
||||
All Lua variables created with these functions will be non-owning.
|
||||
This means that the actual in-game entity (object/camera/sink/whatever)
|
||||
will _not_ be removed from the game if the Lua variable goes out of scope
|
||||
or is destroyed in some other way.
|
||||
@section getters
|
||||
*/
|
||||
|
||||
/***
|
||||
Get an ItemInfo by its name.
|
||||
@function GetItemByName
|
||||
@tparam string name the unique name of the item as set in, or generated by, Tomb Editor
|
||||
@treturn ItemInfo a non-owning ItemInfo referencing the item.
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GetItemByName, &GameScript::GetByName<GameScriptItemInfo, ScriptReserved_ItemInfo>, this);
|
||||
|
||||
/***
|
||||
Get a MeshInfo by its name.
|
||||
@function GetMeshByName
|
||||
@tparam string name the unique name of the mesh as set in, or generated by, Tomb Editor
|
||||
@treturn MeshInfo a non-owning MeshInfo referencing the mesh.
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GetMeshByName, &GameScript::GetByName<GameScriptMeshInfo, ScriptReserved_MeshInfo>, this);
|
||||
|
||||
/***
|
||||
Get a CameraInfo by its name.
|
||||
@function GetCameraByName
|
||||
@tparam string name the unique name of the camera as set in, or generated by, Tomb Editor
|
||||
@treturn CameraInfo a non-owning CameraInfo referencing the camera.
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GetCameraByName, &GameScript::GetByName<GameScriptCameraInfo, ScriptReserved_CameraInfo>, this);
|
||||
|
||||
/***
|
||||
Get a SinkInfo by its name.
|
||||
@function GetSinkByName
|
||||
@tparam string name the unique name of the sink as set in, or generated by, Tomb Editor
|
||||
@treturn SinkInfo a non-owning SinkInfo referencing the sink.
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GetSinkByName, &GameScript::GetByName<GameScriptSinkInfo, ScriptReserved_SinkInfo>, this);
|
||||
|
||||
/***
|
||||
Get a SoundSourceInfo by its name.
|
||||
@function GetSoundSourceByName
|
||||
@tparam string name the unique name of the sink as set in, or generated by, Tomb Editor
|
||||
@treturn SoundSourceInfo a non-owning SoundSourceInfo referencing the sink.
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_GetSoundSourceByName, &GameScript::GetByName<GameScriptSoundSourceInfo, ScriptReserved_SoundSourceInfo>, this);
|
||||
|
||||
/***
|
||||
Calculate the distance between two positions.
|
||||
@function CalculateDistance
|
||||
@tparam Position posA first position
|
||||
@tparam Position posB second position
|
||||
@treturn int the direct distance from one position to the other
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_CalculateDistance, &CalculateDistance);
|
||||
|
||||
/***
|
||||
Calculate the horizontal distance between two positions.
|
||||
@function CalculateHorizontalDistance
|
||||
@tparam Position posA first position
|
||||
@tparam Position posB second position
|
||||
@treturn int the direct distance on the XZ plane from one position to the other
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_CalculateHorizontalDistance, &CalculateHorizontalDistance);
|
||||
|
||||
/***
|
||||
Show some text on-screen.
|
||||
@function ShowString
|
||||
@tparam DisplayString str the string object to draw
|
||||
@tparam float time the time in seconds for which to show the string.
|
||||
If not given, the string will have an "infinite" life, and will show
|
||||
until @{HideString} is called or until the level is finished.
|
||||
Default: nil (i.e. infinite)
|
||||
*/
|
||||
|
||||
m_lua->set_function(ScriptReserved_ShowString, &GameScript::ShowString, this);
|
||||
|
||||
/***
|
||||
Hide some on-screen text.
|
||||
@function HideString
|
||||
@tparam DisplayString str the string object to hide. Must previously have been shown
|
||||
with a call to @{ShowString}, or this function will have no effect.
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_HideString, [this](GameScriptDisplayString const& s) {ShowString(s, 0.0f); });
|
||||
|
||||
/***
|
||||
Translate a pair of percentages to screen-space pixel coordinates.
|
||||
To be used with @{DisplayString:SetPos} and @{DisplayString.new}.
|
||||
@function PercentToScreen
|
||||
@tparam float x percent value to translate to x-coordinate
|
||||
@tparam float y percent value to translate to y-coordinate
|
||||
@treturn int x x coordinate in pixels
|
||||
@treturn int y y coordinate in pixels
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_PercentToScreen, &PercentToScreen);
|
||||
|
||||
/***
|
||||
Translate a pair of coordinates to percentages of window dimensions.
|
||||
To be used with @{DisplayString:GetPos}.
|
||||
@function ScreenToPercent
|
||||
@tparam int x pixel value to translate to a percentage of the window width
|
||||
@tparam int y pixel value to translate to a percentage of the window height
|
||||
@treturn float x coordinate as percentage
|
||||
@treturn float y coordinate as percentage
|
||||
*/
|
||||
m_lua->set_function(ScriptReserved_ScreenToPercent, &ScreenToPercent);
|
||||
MakeReadOnlyTable(ScriptReserved_ObjID, kObjIDs);
|
||||
MakeReadOnlyTable(ScriptReserved_DisplayStringOption, kDisplayStringOptionNames);
|
||||
|
||||
ResetLevelTables();
|
||||
|
||||
MakeSpecialTable(m_lua, ScriptReserved_GameVars, &LuaVariables::GetVariable, &LuaVariables::SetVariable, &m_globals);
|
||||
|
||||
GameScriptItemInfo::Register(m_lua);
|
||||
GameScriptItemInfo::SetNameCallbacks(
|
||||
[this](auto && ... param) { return AddName(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) { return RemoveName(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
|
||||
GameScriptMeshInfo::Register(m_lua);
|
||||
GameScriptMeshInfo::SetNameCallbacks(
|
||||
[this](auto && ... param) { return AddName(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) { return RemoveName(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
|
||||
GameScriptCameraInfo::Register(m_lua);
|
||||
GameScriptCameraInfo::SetNameCallbacks(
|
||||
[this](auto && ... param) { return AddName(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) { return RemoveName(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
|
||||
GameScriptSinkInfo::Register(m_lua);
|
||||
GameScriptSinkInfo::SetNameCallbacks(
|
||||
[this](auto && ... param) { return AddName(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) { return RemoveName(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
|
||||
GameScriptAIObject::Register(m_lua);
|
||||
GameScriptAIObject::SetNameCallbacks(
|
||||
[this](auto && ... param) { return AddName(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) { return RemoveName(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
|
||||
GameScriptSoundSourceInfo::Register(m_lua);
|
||||
GameScriptSoundSourceInfo::SetNameCallbacks(
|
||||
[this](auto && ... param) { return AddName(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) { return RemoveName(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
|
||||
GameScriptDisplayString::Register(m_lua);
|
||||
GameScriptDisplayString::SetCallbacks(
|
||||
[this](auto && ... param) {return SetDisplayString(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) {return ScheduleRemoveDisplayString(std::forward<decltype(param)>(param)...); },
|
||||
[this](auto && ... param) {return GetDisplayString(std::forward<decltype(param)>(param)...); }
|
||||
);
|
||||
GameScriptPosition::Register(m_lua);
|
||||
|
||||
m_lua->new_enum<GAME_OBJECT_ID>("Object", {
|
||||
{"LARA", ID_LARA}
|
||||
});
|
||||
}
|
||||
|
||||
void GameScript::ResetLevelTables()
|
||||
{
|
||||
MakeSpecialTable(m_lua, ScriptReserved_LevelFuncs, &GameScript::GetLevelFunc, &GameScript::SetLevelFunc, this);
|
||||
MakeSpecialTable(m_lua, ScriptReserved_LevelVars, &LuaVariables::GetVariable, &LuaVariables::SetVariable, &m_locals);
|
||||
}
|
||||
|
||||
sol::protected_function GameScript::GetLevelFunc(sol::table tab, std::string const& luaName)
|
||||
{
|
||||
if (m_levelFuncs.find(luaName) == m_levelFuncs.end())
|
||||
return sol::lua_nil;
|
||||
|
||||
return m_levelFuncs.at(luaName);
|
||||
}
|
||||
|
||||
bool GameScript::SetLevelFunc(sol::table tab, std::string const& luaName, sol::object value)
|
||||
{
|
||||
switch (value.get_type())
|
||||
{
|
||||
case sol::type::lua_nil:
|
||||
m_levelFuncs.erase(luaName);
|
||||
break;
|
||||
case sol::type::function:
|
||||
m_levelFuncs.insert_or_assign(luaName, value.as<sol::protected_function>());
|
||||
break;
|
||||
default:
|
||||
//todo When we save the game, do we save the functions or just the names?
|
||||
//todo It may be better just to save the names so that we can load the callbacks
|
||||
//todo from the level script each time (vital if the builder updates their
|
||||
//todo scripts after release -- squidshire, 31/08/2021
|
||||
std::string error{ "Could not assign LevelFuncs." };
|
||||
error += luaName + "; it must be a function (or nil).";
|
||||
return ScriptAssert(false, error);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<UserDisplayString>> GameScript::GetDisplayString(DisplayStringIDType id)
|
||||
{
|
||||
auto it = m_userDisplayStrings.find(id);
|
||||
if (std::cend(m_userDisplayStrings) == it)
|
||||
return std::nullopt;
|
||||
return std::ref(m_userDisplayStrings.at(id));
|
||||
}
|
||||
|
||||
bool GameScript::ScheduleRemoveDisplayString(DisplayStringIDType id)
|
||||
{
|
||||
auto it = m_userDisplayStrings.find(id);
|
||||
if (std::cend(m_userDisplayStrings) == it)
|
||||
return false;
|
||||
|
||||
it->second.m_deleteWhenZero = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameScript::SetDisplayString(DisplayStringIDType id, UserDisplayString const & ds)
|
||||
{
|
||||
return m_userDisplayStrings.insert_or_assign(id, ds).second;
|
||||
}
|
||||
|
||||
|
||||
void GameScript::SetCallbackDrawString(CallbackDrawString cb)
|
||||
{
|
||||
m_callbackDrawSring = cb;
|
||||
}
|
||||
|
||||
void GameScript::FreeLevelScripts()
|
||||
{
|
||||
m_nameMap.clear();
|
||||
m_levelFuncs.clear();
|
||||
m_locals = LuaVariables{};
|
||||
ResetLevelTables();
|
||||
m_onStart = sol::nil;
|
||||
m_onLoad = sol::nil;
|
||||
m_onControlPhase = sol::nil;
|
||||
m_onSave = sol::nil;
|
||||
m_onEnd = sol::nil;
|
||||
m_lua->collect_garbage();
|
||||
}
|
||||
|
||||
void JumpToLevel(int levelNum)
|
||||
{
|
||||
if (levelNum >= g_GameFlow->GetNumLevels())
|
||||
return;
|
||||
LevelComplete = levelNum;
|
||||
}
|
||||
|
||||
int GetSecretsCount()
|
||||
{
|
||||
return Statistics.Level.Secrets;
|
||||
}
|
||||
|
||||
void SetSecretsCount(int secretsNum)
|
||||
{
|
||||
if (secretsNum > 255)
|
||||
return;
|
||||
Statistics.Level.Secrets = secretsNum;
|
||||
}
|
||||
|
||||
void AddOneSecret()
|
||||
{
|
||||
if (Statistics.Level.Secrets >= 255)
|
||||
return;
|
||||
Statistics.Level.Secrets++;
|
||||
PlaySecretTrack();
|
||||
}
|
||||
|
||||
/*
|
||||
void GameScript::MakeItemInvisible(short id)
|
||||
{
|
||||
if (m_itemsMap.find(id) == m_itemsMap.end())
|
||||
return;
|
||||
|
||||
short itemNum = m_itemsMap[id];
|
||||
|
||||
ITEM_INFO* item = &g_Level.Items[itemNum];
|
||||
|
||||
if (item->active)
|
||||
{
|
||||
if (Objects[item->objectNumber].intelligent)
|
||||
{
|
||||
if (item->status == ITEM_ACTIVE)
|
||||
{
|
||||
item->touchBits = 0;
|
||||
item->status = ITEM_INVISIBLE;
|
||||
DisableBaddieAI(itemNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item->touchBits = 0;
|
||||
item->status = ITEM_INVISIBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
template <typename T>
|
||||
void GameScript::GetVariables(std::map<std::string, T>& locals, std::map<std::string, T>& globals)
|
||||
{
|
||||
for (const auto& it : m_locals.variables)
|
||||
{
|
||||
if (it.second.is<T>())
|
||||
locals.insert(std::pair<std::string, T>(it.first, it.second.as<T>()));
|
||||
}
|
||||
for (const auto& it : m_globals.variables)
|
||||
{
|
||||
if (it.second.is<T>())
|
||||
globals.insert(std::pair<std::string, T>(it.first, it.second.as<T>()));
|
||||
}
|
||||
}
|
||||
|
||||
template void GameScript::GetVariables<bool>(std::map<std::string, bool>& locals, std::map<std::string, bool>& globals);
|
||||
template void GameScript::GetVariables<float>(std::map<std::string, float>& locals, std::map<std::string, float>& globals);
|
||||
template void GameScript::GetVariables<std::string>(std::map<std::string, std::string>& locals, std::map<std::string, std::string>& globals);
|
||||
|
||||
template <typename T>
|
||||
void GameScript::SetVariables(std::map<std::string, T>& locals, std::map<std::string, T>& globals)
|
||||
{
|
||||
//TODO Look into serialising tables from these maps, too -- squidshire, 24/08/2021
|
||||
m_locals.variables.clear();
|
||||
for (const auto& it : locals)
|
||||
{
|
||||
m_locals.variables.insert(std::pair<std::string, sol::object>(it.first, sol::object(m_lua->lua_state(), sol::in_place, it.second)));
|
||||
}
|
||||
for (const auto& it : globals)
|
||||
{
|
||||
m_globals.variables.insert(std::pair<std::string, sol::object>(it.first, sol::object(m_lua->lua_state(), sol::in_place, it.second)));
|
||||
}
|
||||
}
|
||||
|
||||
template void GameScript::SetVariables<bool>(std::map<std::string, bool>& locals, std::map<std::string, bool>& globals);
|
||||
template void GameScript::SetVariables<float>(std::map<std::string, float>& locals, std::map<std::string, float>& globals);
|
||||
template void GameScript::SetVariables<std::string>(std::map<std::string, std::string>& locals, std::map<std::string, std::string>& globals);
|
||||
|
||||
template <typename R, char const * S, typename mapType>
|
||||
std::unique_ptr<R> GetByName(std::string const & type, std::string const & name, mapType const & map)
|
||||
{
|
||||
ScriptAssert(map.find(name) != map.end(), std::string{ type + " name not found: " + name }, ERROR_MODE::TERMINATE);
|
||||
return std::make_unique<R>(map.at(name), false);
|
||||
}
|
||||
|
||||
void GameScript::AssignItemsAndLara()
|
||||
{
|
||||
m_lua->set("Lara", GameScriptItemInfo(Lara.itemNumber, false));
|
||||
}
|
||||
|
||||
/*** Special objects
|
||||
@section specialobjects
|
||||
*/
|
||||
|
||||
/*** An @{ItemInfo} representing Lara herself.
|
||||
@table Lara
|
||||
*/
|
||||
void GameScript::ResetVariables()
|
||||
{
|
||||
(*m_lua)["Lara"] = NULL;
|
||||
}
|
||||
|
||||
void GameScript::ShowString(GameScriptDisplayString const & str, sol::optional<float> nSeconds)
|
||||
{
|
||||
auto it = m_userDisplayStrings.find(str.GetID());
|
||||
it->second.m_timeRemaining = nSeconds.value_or(0.0f);
|
||||
it->second.m_isInfinite = !nSeconds.has_value();
|
||||
}
|
||||
|
||||
void GameScript::ProcessDisplayStrings(float dt)
|
||||
{
|
||||
auto it = std::begin(m_userDisplayStrings);
|
||||
while (it != std::end(m_userDisplayStrings))
|
||||
{
|
||||
auto& str = it->second;
|
||||
bool endOfLife = (0.0f >= str.m_timeRemaining);
|
||||
if (str.m_deleteWhenZero && endOfLife)
|
||||
{
|
||||
ScriptAssertF(!str.m_isInfinite, "The infinite string {} (key \"{}\") went out of scope without being hidden.", it->first, str.m_key);
|
||||
it = m_userDisplayStrings.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!endOfLife || str.m_isInfinite)
|
||||
{
|
||||
char const* cstr = str.m_isTranslated ? g_GameFlow->GetString(str.m_key.c_str()) : str.m_key.c_str();
|
||||
int flags = 0;
|
||||
|
||||
if (str.m_flags[static_cast<size_t>(DisplayStringOptions::CENTER)])
|
||||
flags |= PRINTSTRING_CENTER;
|
||||
|
||||
if (str.m_flags[static_cast<size_t>(DisplayStringOptions::OUTLINE)])
|
||||
flags |= PRINTSTRING_OUTLINE;
|
||||
|
||||
m_callbackDrawSring(cstr, str.m_color, str.m_x, str.m_y, flags);
|
||||
|
||||
str.m_timeRemaining -= dt;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sol::object LuaVariables::GetVariable(sol::table tab, std::string key)
|
||||
{
|
||||
if (variables.find(key) == variables.end())
|
||||
return sol::lua_nil;
|
||||
return variables[key];
|
||||
}
|
||||
|
||||
void LuaVariables::SetVariable(sol::table tab, std::string key, sol::object value)
|
||||
{
|
||||
switch (value.get_type())
|
||||
{
|
||||
case sol::type::lua_nil:
|
||||
variables.erase(key);
|
||||
break;
|
||||
case sol::type::boolean:
|
||||
case sol::type::number:
|
||||
case sol::type::string:
|
||||
variables[key] = value;
|
||||
break;
|
||||
default:
|
||||
ScriptAssert(false, "Variable " + key + " has an unsupported type.", ERROR_MODE::TERMINATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameScript::ExecuteScriptFile(const std::string & luaFilename)
|
||||
{
|
||||
ExecuteScript(luaFilename);
|
||||
}
|
||||
|
||||
void GameScript::ExecuteFunction(std::string const & name)
|
||||
{
|
||||
sol::protected_function func = (*m_lua)["LevelFuncs"][name.c_str()];
|
||||
auto r = func();
|
||||
if (!r.valid())
|
||||
{
|
||||
sol::error err = r;
|
||||
ScriptAssertF(false, "Could not execute function {}: {}", name, err.what());
|
||||
}
|
||||
}
|
||||
|
||||
static void doCallback(sol::protected_function const & func, std::optional<float> dt = std::nullopt) {
|
||||
auto r = dt.has_value() ? func(dt) : func();
|
||||
|
||||
if (!r.valid())
|
||||
{
|
||||
sol::error err = r;
|
||||
ScriptAssert(false, err.what(), ERROR_MODE::TERMINATE);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScript::OnStart()
|
||||
{
|
||||
if (m_onStart.valid())
|
||||
doCallback(m_onStart);
|
||||
}
|
||||
|
||||
void GameScript::OnLoad()
|
||||
{
|
||||
if(m_onLoad.valid())
|
||||
doCallback(m_onLoad);
|
||||
}
|
||||
|
||||
void GameScript::OnControlPhase(float dt)
|
||||
{
|
||||
if(m_onControlPhase.valid())
|
||||
doCallback(m_onControlPhase, dt);
|
||||
}
|
||||
|
||||
void GameScript::OnSave()
|
||||
{
|
||||
if(m_onSave.valid())
|
||||
doCallback(m_onSave);
|
||||
}
|
||||
|
||||
void GameScript::OnEnd()
|
||||
{
|
||||
if(m_onEnd.valid())
|
||||
doCallback(m_onEnd);
|
||||
}
|
||||
|
||||
/*** Special tables
|
||||
|
||||
TombEngine uses the following tables for specific things.
|
||||
|
||||
@section levelandgametables
|
||||
*/
|
||||
|
||||
/*** A table with level-specific data which will be saved and loaded.
|
||||
This is for level-specific information that you want to store in saved games.
|
||||
|
||||
For example, you may have a level with a custom puzzle where Lara has
|
||||
to kill exactly seven enemies to open a door to a secret. You could use
|
||||
the following line each time an enemy is killed:
|
||||
|
||||
LevelVars.enemiesKilled = LevelVars.enemiesKilled + 1
|
||||
|
||||
If the player saves the level after killing three, saves, and then reloads the save
|
||||
some time later, the values `3` will be put back into `LevelVars.enemiesKilled.`
|
||||
|
||||
__This table is emptied when a level is finished.__ If the player needs to be able
|
||||
to return to the level (like in the Karnak and Alexandria levels in *The Last Revelation*),
|
||||
you will need to use the @{GameVars} table, below.
|
||||
@table LevelVars
|
||||
*/
|
||||
|
||||
/*** A table with game data which will be saved and loaded.
|
||||
This is for information not specific to any level, but which concerns your whole
|
||||
levelset or game, that you want to store in saved games.
|
||||
|
||||
For example, you may wish to have a final boss say a specific voice line based on
|
||||
a choice the player made in a previous level. In the level with the choice, you could
|
||||
write:
|
||||
|
||||
GameVars.playerSnoopedInDraws = true
|
||||
|
||||
And in the script file for the level with the boss, you could write:
|
||||
|
||||
if GameVars.playerSnoopedInDraws then
|
||||
PlayAudioTrack("how_dare_you.wav")
|
||||
end
|
||||
|
||||
Unlike @{LevelVars}, this table will remain intact for the entirety of the game.
|
||||
@table GameVars
|
||||
*/
|
||||
|
||||
/*** A table with level-specific functions.
|
||||
|
||||
This serves two purposes: it holds the level callbacks (listed below) as well as
|
||||
any trigger functions you might have specified. For example, if you give a trigger
|
||||
a Lua name of "my_trigger" in Tomb Editor, you will have to implement it as a member
|
||||
of this table:
|
||||
|
||||
LevelFuncs.my_trigger = function()
|
||||
-- implementation goes here
|
||||
end
|
||||
|
||||
The following are the level callbacks. They are optional; if your level has no special
|
||||
behaviour for a particular scenario, you do not need to implement the function. For
|
||||
example, if your level does not need any special initialisation when it is loaded,
|
||||
you can just leave out `LevelFuncs.OnStart`.
|
||||
|
||||
@tfield function OnStart Will be called when a level is loaded
|
||||
@tfield function OnLoad Will be called when a saved game is loaded
|
||||
@tfield function(float) OnControlPhase Will be called during the game's update loop,
|
||||
and provides the delta time (a float representing game time since last call) via its argument.
|
||||
@tfield function OnSave Will be called when the player saves the game
|
||||
@tfield function OnEnd Will be called when leaving a level. This includes finishing it, exiting to the menu, or loading a save in a different level.
|
||||
@table LevelFuncs
|
||||
*/
|
||||
|
||||
void GameScript::InitCallbacks()
|
||||
{
|
||||
auto assignCB = [this](sol::protected_function& func, std::string const & luaFunc) {
|
||||
std::string fullName = "LevelFuncs." + luaFunc;
|
||||
func = (*m_lua)["LevelFuncs"][luaFunc];
|
||||
std::string err{ "Level's script does not define callback " + fullName};
|
||||
if (!ScriptAssert(func.valid(), err)) {
|
||||
ScriptWarn("Defaulting to no " + fullName + " behaviour.");
|
||||
}
|
||||
};
|
||||
|
||||
assignCB(m_onStart, "OnStart");
|
||||
assignCB(m_onLoad, "OnLoad");
|
||||
assignCB(m_onControlPhase, "OnControlPhase");
|
||||
assignCB(m_onSave, "OnSave");
|
||||
assignCB(m_onEnd, "OnEnd");
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
#pragma once
|
||||
#include "frameworkandsol.h"
|
||||
#include "GameScriptAIObject.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "ScriptUtil.h"
|
||||
/***
|
||||
AI object
|
||||
|
||||
@entityclass AIObject
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
|
||||
constexpr auto LUA_CLASS_NAME{ "AIObject" };
|
||||
|
||||
static auto index_error = index_error_maker(GameScriptAIObject, LUA_CLASS_NAME);
|
||||
static auto newindex_error = newindex_error_maker(GameScriptAIObject, LUA_CLASS_NAME);
|
||||
|
||||
GameScriptAIObject::GameScriptAIObject(AI_OBJECT & ref, bool temp) : m_aiObject{ref}, m_temporary{ temp }
|
||||
{};
|
||||
|
||||
GameScriptAIObject::~GameScriptAIObject() {
|
||||
if (m_temporary)
|
||||
{
|
||||
s_callbackRemoveName(m_aiObject.luaName);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptAIObject::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptAIObject>(LUA_CLASS_NAME,
|
||||
sol::meta_function::index, index_error,
|
||||
sol::meta_function::new_index, newindex_error,
|
||||
|
||||
/// (@{Position}) position in level
|
||||
// @mem pos
|
||||
"pos", sol::property(&GameScriptAIObject::GetPos, &GameScriptAIObject::SetPos),
|
||||
|
||||
/// (int) y-axis rotation
|
||||
// @mem yRot
|
||||
"yRot", sol::property(&GameScriptAIObject::GetYRot, &GameScriptAIObject::SetYRot),
|
||||
|
||||
/// (string) unique string identifier.
|
||||
// e.g. "door_back_room" or "cracked_greek_statue"
|
||||
// @mem name
|
||||
"name", sol::property(&GameScriptAIObject::GetName, &GameScriptAIObject::SetName),
|
||||
|
||||
/// (int) room number
|
||||
// @mem room
|
||||
"room", sol::property(&GameScriptAIObject::GetRoom, &GameScriptAIObject::SetRoom),
|
||||
|
||||
/// (@{ObjID}) object ID
|
||||
// @mem objID
|
||||
"objID", sol::property(&GameScriptAIObject::GetObjID, &GameScriptAIObject::SetObjID),
|
||||
|
||||
/// (short) flags
|
||||
// @mem flags
|
||||
"flags", sol::property(&GameScriptAIObject::GetFlags, &GameScriptAIObject::SetFlags),
|
||||
|
||||
/// (short) trigger flags
|
||||
// @mem triggerFlags
|
||||
"triggerFlags", sol::property(&GameScriptAIObject::GetTriggerFlags, &GameScriptAIObject::SetTriggerFlags),
|
||||
|
||||
/// (short) box number
|
||||
// @mem boxNumber
|
||||
"boxNumber", sol::property(&GameScriptAIObject::GetBoxNumber, &GameScriptAIObject::SetBoxNumber)
|
||||
);
|
||||
}
|
||||
|
||||
GameScriptPosition GameScriptAIObject::GetPos() const
|
||||
{
|
||||
return GameScriptPosition{ m_aiObject.x, m_aiObject.y, m_aiObject.z };
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetPos(GameScriptPosition const& pos)
|
||||
{
|
||||
m_aiObject.x = pos.x;
|
||||
m_aiObject.y = pos.y;
|
||||
m_aiObject.z = pos.z;
|
||||
}
|
||||
|
||||
GAME_OBJECT_ID GameScriptAIObject::GetObjID() const
|
||||
{
|
||||
return m_aiObject.objectNumber;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetObjID(GAME_OBJECT_ID objNum)
|
||||
{
|
||||
m_aiObject.objectNumber = objNum;
|
||||
}
|
||||
|
||||
short GameScriptAIObject::GetYRot() const
|
||||
{
|
||||
return m_aiObject.yRot;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetYRot(short yRot)
|
||||
{
|
||||
m_aiObject.yRot = yRot;
|
||||
}
|
||||
|
||||
std::string GameScriptAIObject::GetName() const
|
||||
{
|
||||
return m_aiObject.luaName;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetName(std::string const & id)
|
||||
{
|
||||
ScriptAssert(!id.empty(), "Name cannot be blank", ERROR_MODE::TERMINATE);
|
||||
|
||||
// remove the old name if we have one
|
||||
s_callbackRemoveName(m_aiObject.luaName);
|
||||
|
||||
// un-register any other objects using this name.
|
||||
// maybe we should throw an error if another object
|
||||
// already uses the name...
|
||||
s_callbackRemoveName(id);
|
||||
m_aiObject.luaName = id;
|
||||
// todo add error checking
|
||||
s_callbackSetName(id, m_aiObject);
|
||||
}
|
||||
|
||||
short GameScriptAIObject::GetRoom() const
|
||||
{
|
||||
return m_aiObject.roomNumber;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetRoom(short room)
|
||||
{
|
||||
m_aiObject.roomNumber = room;
|
||||
}
|
||||
|
||||
short GameScriptAIObject::GetTriggerFlags() const
|
||||
{
|
||||
|
||||
return m_aiObject.triggerFlags;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetTriggerFlags(short tf)
|
||||
{
|
||||
m_aiObject.triggerFlags = tf;
|
||||
}
|
||||
|
||||
short GameScriptAIObject::GetFlags() const
|
||||
{
|
||||
return m_aiObject.flags;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetFlags(short tf)
|
||||
{
|
||||
m_aiObject.flags = tf;
|
||||
}
|
||||
|
||||
short GameScriptAIObject::GetBoxNumber() const
|
||||
{
|
||||
return m_aiObject.boxNumber;
|
||||
}
|
||||
|
||||
void GameScriptAIObject::SetBoxNumber(short bn)
|
||||
{
|
||||
m_aiObject.boxNumber = bn;
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#include "framework.h"
|
||||
#include "GameScriptAnimations.h"
|
||||
|
||||
/***
|
||||
New custom animations which Lara can perform.
|
||||
@pregameclass Animations
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptAnimations::Register(sol::state* lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptAnimations>("Animations",
|
||||
"crawlExtended", &GameScriptAnimations::CrawlExtended,
|
||||
"crouchRoll", &GameScriptAnimations::CrouchRoll,
|
||||
"crawlspaceSwandive", &GameScriptAnimations::CrawlspaceSwandive,
|
||||
"monkeyTurn180", &GameScriptAnimations::MonkeyTurn180,
|
||||
"monkeyAutoJump", &GameScriptAnimations::MonkeyAutoJump,
|
||||
"oscillateHang", &GameScriptAnimations::OscillateHang,
|
||||
"pose", &GameScriptAnimations::Pose
|
||||
);
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "ScriptAssert.h"
|
||||
#include <string>
|
||||
|
||||
namespace sol {
|
||||
class state;
|
||||
}
|
||||
|
||||
struct GameScriptAnimations
|
||||
{
|
||||
bool CrawlExtended; // Extended crawl moveset
|
||||
bool CrouchRoll; // Crouch roll
|
||||
bool CrawlspaceSwandive; // Swandive into crawlspaces
|
||||
bool MonkeyTurn180; // 180 degree turn on monkey swing
|
||||
bool MonkeyAutoJump; // Auto jump to monkey swing when pressing UP + ACTION beneath
|
||||
bool OscillateHang; // Grab thin ledge animation from TR1 and 2
|
||||
bool Pose; // Crossed arms AFK posing
|
||||
|
||||
static void Register(sol::state* lua);
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptAudioTrack.h"
|
||||
|
||||
/***
|
||||
Metadata about audio tracks (music and ambience).
|
||||
|
||||
__In progress__
|
||||
|
||||
@pregameclass AudioTrack
|
||||
@pragma nostrip
|
||||
*/
|
||||
// TODO FIXME find out what is meant to happen and whether we need this or not
|
||||
|
||||
GameScriptAudioTrack::GameScriptAudioTrack(std::string const & trackName, bool looped)
|
||||
{
|
||||
this->trackName = trackName;
|
||||
this->looped = looped;
|
||||
}
|
||||
|
||||
void GameScriptAudioTrack::Register(sol::state* lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptAudioTrack>("AudioTrack",
|
||||
sol::constructors<GameScriptAudioTrack(std::string, bool)>(),
|
||||
"trackName", &GameScriptAudioTrack::trackName,
|
||||
"looped", &GameScriptAudioTrack::looped
|
||||
);
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "GameScriptCameraInfo.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "ScriptUtil.h"
|
||||
/***
|
||||
Camera info
|
||||
|
||||
@entityclass CameraInfo
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
static constexpr auto LUA_CLASS_NAME{ "CameraInfo" };
|
||||
|
||||
static auto index_error = index_error_maker(GameScriptCameraInfo, LUA_CLASS_NAME);
|
||||
static auto newindex_error = newindex_error_maker(GameScriptCameraInfo, LUA_CLASS_NAME);
|
||||
|
||||
GameScriptCameraInfo::GameScriptCameraInfo(LEVEL_CAMERA_INFO & ref, bool temp) : m_camera{ref}, m_temporary{ temp }
|
||||
{};
|
||||
|
||||
GameScriptCameraInfo::~GameScriptCameraInfo() {
|
||||
if (m_temporary)
|
||||
{
|
||||
s_callbackRemoveName(m_camera.luaName);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptCameraInfo::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptCameraInfo>(LUA_CLASS_NAME,
|
||||
sol::meta_function::index, index_error,
|
||||
sol::meta_function::new_index, newindex_error,
|
||||
|
||||
/// (@{Position}) position in level
|
||||
// @mem pos
|
||||
"pos", sol::property(&GameScriptCameraInfo::GetPos, &GameScriptCameraInfo::SetPos),
|
||||
|
||||
/// (string) unique string identifier.
|
||||
// e.g. "flyby\_start" or "big\_door\_hint"
|
||||
// @mem name
|
||||
"name", sol::property(&GameScriptCameraInfo::GetName, &GameScriptCameraInfo::SetName),
|
||||
|
||||
/// (string) room number
|
||||
// @mem room
|
||||
"room", sol::property(&GameScriptCameraInfo::GetRoom, &GameScriptCameraInfo::SetRoom)
|
||||
);
|
||||
}
|
||||
|
||||
GameScriptPosition GameScriptCameraInfo::GetPos() const
|
||||
{
|
||||
return GameScriptPosition{ m_camera.x, m_camera.y, m_camera.z };
|
||||
}
|
||||
|
||||
void GameScriptCameraInfo::SetPos(GameScriptPosition const& pos)
|
||||
{
|
||||
m_camera.x = pos.x;
|
||||
m_camera.y = pos.y;
|
||||
m_camera.z = pos.z;
|
||||
}
|
||||
|
||||
std::string GameScriptCameraInfo::GetName() const
|
||||
{
|
||||
return m_camera.luaName;
|
||||
}
|
||||
|
||||
void GameScriptCameraInfo::SetName(std::string const & id)
|
||||
{
|
||||
ScriptAssert(!id.empty(), "Name cannot be blank", ERROR_MODE::TERMINATE);
|
||||
|
||||
// remove the old name if we have one
|
||||
s_callbackRemoveName(m_camera.luaName);
|
||||
|
||||
// un-register any other objects using this name.
|
||||
// maybe we should throw an error if another object
|
||||
// already uses the name...
|
||||
s_callbackRemoveName(id);
|
||||
m_camera.luaName = id;
|
||||
// todo add error checking
|
||||
s_callbackSetName(id, m_camera);
|
||||
}
|
||||
|
||||
short GameScriptCameraInfo::GetRoom() const
|
||||
{
|
||||
return m_camera.roomNumber;
|
||||
}
|
||||
|
||||
void GameScriptCameraInfo::SetRoom(short room)
|
||||
{
|
||||
m_camera.roomNumber = room;
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptColor.h"
|
||||
|
||||
/***
|
||||
An RGBA or RGB color.
|
||||
Components are specified in bytes; all values are clamped to [0, 255].
|
||||
|
||||
@miscclass Color
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptColor::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptColor>("Color",
|
||||
sol::constructors<GameScriptColor(byte, byte, byte), GameScriptColor(byte, byte, byte, byte)>(),
|
||||
sol::meta_function::to_string, &GameScriptColor::ToString,
|
||||
|
||||
/// (int) red component
|
||||
//@mem r
|
||||
"r", sol::property(&GameScriptColor::GetR, &GameScriptColor::SetR),
|
||||
|
||||
/// (int) green component
|
||||
//@mem g
|
||||
"g", sol::property(&GameScriptColor::GetG, &GameScriptColor::SetG),
|
||||
|
||||
/// (int) blue component
|
||||
//@mem b
|
||||
"b", sol::property(&GameScriptColor::GetB, &GameScriptColor::SetB),
|
||||
|
||||
/// (int) alpha component (255 is opaque, 0 is invisible)
|
||||
//@mem a
|
||||
"a", sol::property(&GameScriptColor::GetA, &GameScriptColor::SetA)
|
||||
);
|
||||
}
|
||||
|
||||
/***
|
||||
@int R red component
|
||||
@int G green component
|
||||
@int B blue component
|
||||
@return A Color object.
|
||||
@function Color.new
|
||||
*/
|
||||
GameScriptColor::GameScriptColor(byte r, byte g, byte b)
|
||||
{
|
||||
SetR(r);
|
||||
SetG(g);
|
||||
SetB(b);
|
||||
}
|
||||
|
||||
/***
|
||||
@int R red component
|
||||
@int G green component
|
||||
@int B blue component
|
||||
@int A alpha component (255 is opaque, 0 is invisible)
|
||||
@return A Color object.
|
||||
@function Color.new
|
||||
*/
|
||||
GameScriptColor::GameScriptColor(byte r, byte g, byte b, byte a) : GameScriptColor(r, g, b)
|
||||
{
|
||||
SetA(a);
|
||||
}
|
||||
|
||||
GameScriptColor::GameScriptColor(Vector3 const& col) : GameScriptColor{ col.x, col.y, col.z } {}
|
||||
|
||||
GameScriptColor::GameScriptColor(Vector4 const& col) : GameScriptColor{ col.x, col.y, col.z, col.w } {}
|
||||
|
||||
GameScriptColor::GameScriptColor(D3DCOLOR col)
|
||||
{
|
||||
b = col & 0xFF;
|
||||
col >>= 8;
|
||||
g = col & 0xFF;
|
||||
col >>= 8;
|
||||
r = col & 0xFF;
|
||||
col >>= 8;
|
||||
a = col & 0xFF;
|
||||
}
|
||||
|
||||
GameScriptColor::operator Vector3() const
|
||||
{
|
||||
return Vector3{ float(r), float(g), float(b) };
|
||||
}
|
||||
|
||||
GameScriptColor::operator Vector4() const
|
||||
{
|
||||
return Vector4{ float(r), float(g), float(b), float(a) };
|
||||
}
|
||||
|
||||
// D3DCOLOR is 32 bits and is layed out as ARGB.
|
||||
GameScriptColor::operator D3DCOLOR() const
|
||||
{
|
||||
D3DCOLOR col = a;
|
||||
col <<= 8;
|
||||
col += r;
|
||||
col <<= 8;
|
||||
col += g;
|
||||
col <<= 8;
|
||||
col += b;
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
byte GameScriptColor::GetR() const
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
void GameScriptColor::SetR(byte v)
|
||||
{
|
||||
r = std::clamp<byte>(v, 0, 255);
|
||||
}
|
||||
|
||||
byte GameScriptColor::GetG() const
|
||||
{
|
||||
return g;
|
||||
}
|
||||
|
||||
void GameScriptColor::SetG(byte v)
|
||||
{
|
||||
g = std::clamp<byte>(v, 0, 255);
|
||||
}
|
||||
|
||||
byte GameScriptColor::GetB() const
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
void GameScriptColor::SetB(byte v)
|
||||
{
|
||||
b = std::clamp<byte>(v, 0, 255);
|
||||
}
|
||||
|
||||
byte GameScriptColor::GetA() const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
void GameScriptColor::SetA(byte v)
|
||||
{
|
||||
a = std::clamp<byte>(v, 0, 255);
|
||||
}
|
||||
|
||||
/***
|
||||
@tparam Color color this color
|
||||
@treturn string A string showing the r, g, b, and a values of the color
|
||||
@function __tostring
|
||||
*/
|
||||
std::string GameScriptColor::ToString() const
|
||||
{
|
||||
return "{" + std::to_string(r) + ", " + std::to_string(g) + ", " + std::to_string(b) + ", " + std::to_string(a) + "}";
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptDisplayString.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "ReservedScriptNames.h"
|
||||
|
||||
/*** A string appearing on the screen.
|
||||
Can be used for subtitles and "2001, somewhere in Egypt"-style messages.
|
||||
|
||||
Uses screen-space coordinates, with x values specifying the number of pixels from the left of the window,
|
||||
and y values specifying the number of pixels from the top of the window.
|
||||
|
||||
Since different players will have different resolutions, you should work in terms of percentages where possible,
|
||||
and use @{Level-specific.ScreenToPercent|ScreenToPercent} and @{Level-specific.PercentToScreen|PercentToScreen}
|
||||
when you need to use screen-space coordinates.
|
||||
|
||||
@miscclass DisplayString
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
UserDisplayString::UserDisplayString(std::string const& key, int x, int y, D3DCOLOR col, FlagArray const & flags, bool translated) :
|
||||
m_key{ key },
|
||||
m_x{ x },
|
||||
m_y{ y },
|
||||
m_color{ col },
|
||||
m_flags{ flags },
|
||||
m_isTranslated{ translated }
|
||||
{
|
||||
}
|
||||
|
||||
GameScriptDisplayString::GameScriptDisplayString() {
|
||||
// We don't ever dereference this pointer; it's just
|
||||
// a handy way to get a unique key for a hash map.
|
||||
|
||||
//TODO Make sure to reset this when loading a save,
|
||||
//TODO because this key will have a chance to no longer
|
||||
//TODO be unique. -- squidshire, 28/08/2021
|
||||
m_id = reinterpret_cast<DisplayStringIDType>(this);
|
||||
}
|
||||
|
||||
// Helper type to allow us to more easily specify "give a value of type X or just give nil" parameters.
|
||||
// Sol doesn't (at the time of writing) have any mechanisms to do this kind of optional argument without
|
||||
// drawbacks, or at least no mechanisms that I could find.
|
||||
//
|
||||
// sol::optional doesn't distinguish between nil values and values of the wrong type
|
||||
// (so we can't provide the user with an error message to tell them they messed up).
|
||||
//
|
||||
// std::variant works better, providing an error if the user passes in an arg of the wrong type, but
|
||||
// the error isn't too helpful and exposes a lot of C++ code which will not help them fix the error.
|
||||
//
|
||||
// sol::object lets us check that the user has given the right type, but takes valuable type information
|
||||
// away from the function's C++ signature, giving us things like void func(sol::object, sol::object, sol::object),
|
||||
// even if the function's actual expected parameter types are (for example) float, sol::table, SomeUserType.
|
||||
//
|
||||
// This alias is an effort to avoid the above problems.
|
||||
template <typename ... Ts> using TypeOrNil = std::variant<Ts..., sol::nil_t, sol::object>;
|
||||
|
||||
/*** Create a DisplayString.
|
||||
For use in @{Level-specific.ShowString|ShowString} and @{Level-specific.HideString|HideString}.
|
||||
@function DisplayString.new
|
||||
@tparam string str string to print or key of translated string
|
||||
@tparam int x x-coordinate of top-left of string (or the center if DisplayStringOption.CENTER is given)
|
||||
@tparam int y y-coordinate of top-left of string (or the center if DisplayStringOption.CENTER is given)
|
||||
@tparam Color color the color of the text
|
||||
@tparam table flags a table of display options. Can be empty or omitted. The possible values and their effects are...
|
||||
DisplayStringOption.CENTER -- see x and y parameters
|
||||
DisplayStringOption.SHADOW -- will give the text a small shadow
|
||||
__Default: empty__
|
||||
@tparam bool translated if false or omitted, the str argument will be printed.
|
||||
If true, the str argument will be the key of a translated string specified in
|
||||
strings.lua. __Default: false__.
|
||||
@return A new DisplayString object.
|
||||
*/
|
||||
std::unique_ptr<GameScriptDisplayString> CreateString(std::string const & key, int x, int y, GameScriptColor col, TypeOrNil<sol::table> flags, TypeOrNil<bool> maybeTranslated)
|
||||
{
|
||||
auto ptr = std::make_unique<GameScriptDisplayString>();
|
||||
auto id = ptr->GetID();
|
||||
FlagArray f{};
|
||||
if (std::holds_alternative<sol::table>(flags))
|
||||
{
|
||||
auto tab = std::get<sol::table>(flags);
|
||||
for (auto& e : tab)
|
||||
{
|
||||
auto i = e.second.as<size_t>();
|
||||
f[i] = true;
|
||||
}
|
||||
}
|
||||
else if (!std::holds_alternative<sol::nil_t>(flags))
|
||||
{
|
||||
ScriptAssertF(false, "Wrong argument type for {}.new \"flags\" argument; must be a table or nil.", ScriptReserved_DisplayString);
|
||||
}
|
||||
|
||||
bool translated = false;
|
||||
if (std::holds_alternative<bool>(maybeTranslated))
|
||||
translated = std::get<bool>(maybeTranslated);
|
||||
else if (!std::holds_alternative<sol::nil_t>(maybeTranslated))
|
||||
ScriptAssertF(false, "Wrong argument type for {}.new \"translated\" argument; must be a bool or nil.", ScriptReserved_DisplayString);
|
||||
|
||||
UserDisplayString ds{ key, x, y, col, f, translated};
|
||||
|
||||
GameScriptDisplayString::s_setItemCallback(id, ds);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
GameScriptDisplayString::~GameScriptDisplayString()
|
||||
{
|
||||
s_removeItemCallback(m_id);
|
||||
}
|
||||
|
||||
void GameScriptDisplayString::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptDisplayString>(
|
||||
"DisplayString",
|
||||
"new", &CreateString,
|
||||
|
||||
/// (@{Color}) RBG color
|
||||
// @mem col
|
||||
"col", sol::property(&GameScriptDisplayString::GetCol, &GameScriptDisplayString::SetCol),
|
||||
|
||||
/// (string) String key to use. If `translated` is true when @{DisplayString.new}
|
||||
// is called, this will be the string key for the translation that will be displayed.
|
||||
// If false or omitted, this will be the string that's displayed.
|
||||
// @mem key
|
||||
"key", sol::property(&GameScriptDisplayString::SetKey, &GameScriptDisplayString::GetKey),
|
||||
|
||||
/// Set the position of the string.
|
||||
// Screen-space coordinates are expected.
|
||||
// @function DisplayString:SetPos
|
||||
// @tparam int x x-coordinate of the string
|
||||
// @tparam int y y-coordinate of the string
|
||||
"SetPos", &GameScriptDisplayString::SetPos,
|
||||
|
||||
/// Get the position of the string.
|
||||
// Screen-space coordinates are returned.
|
||||
// @function DisplayString:GetPos
|
||||
// @treturn int x x-coordinate of the string
|
||||
// @treturn int y y-coordinate of the string
|
||||
"GetPos", &GameScriptDisplayString::GetPos
|
||||
);
|
||||
}
|
||||
|
||||
DisplayStringIDType GameScriptDisplayString::GetID() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
void GameScriptDisplayString::SetPos(int x, int y)
|
||||
{
|
||||
UserDisplayString& s = s_getItemCallback(m_id).value();
|
||||
s.m_x = x;
|
||||
s.m_y = y;
|
||||
}
|
||||
|
||||
std::tuple<int, int> GameScriptDisplayString::GetPos() const
|
||||
{
|
||||
UserDisplayString& s = s_getItemCallback(m_id).value();
|
||||
return std::make_tuple(s.m_x, s.m_y);
|
||||
}
|
||||
|
||||
void GameScriptDisplayString::SetCol(GameScriptColor const & col)
|
||||
{
|
||||
UserDisplayString& s = s_getItemCallback(m_id).value();
|
||||
s.m_color = col;
|
||||
//todo maybe change getItemCallback to return a ref instead? or move its
|
||||
//todo UserDisplayString object? and then move back?
|
||||
//s_addItemCallback(m_id, s);
|
||||
}
|
||||
|
||||
GameScriptColor GameScriptDisplayString::GetCol()
|
||||
{
|
||||
UserDisplayString& s = s_getItemCallback(m_id).value();
|
||||
return s.m_color;
|
||||
}
|
||||
|
||||
void GameScriptDisplayString::SetKey(std::string const & key)
|
||||
{
|
||||
UserDisplayString& s = s_getItemCallback(m_id).value();
|
||||
s.m_key = key;
|
||||
}
|
||||
|
||||
std::string GameScriptDisplayString::GetKey() const
|
||||
{
|
||||
UserDisplayString& s = s_getItemCallback(m_id).value();
|
||||
return s.m_key;
|
||||
}
|
||||
|
||||
SetItemCallback GameScriptDisplayString::s_setItemCallback = [](DisplayStringIDType, UserDisplayString)
|
||||
{
|
||||
std::string err = "\"Set string\" callback is not set.";
|
||||
throw TENScriptException(err);
|
||||
return false;
|
||||
};
|
||||
|
||||
// This is called by a destructor (or will be if we forget to assign it during a refactor)
|
||||
// and destructors "must never throw", so we terminate instead.
|
||||
RemoveItemCallback GameScriptDisplayString::s_removeItemCallback = [](DisplayStringIDType)
|
||||
{
|
||||
TENLog("\"Remove string\" callback is not set.", LogLevel::Error);
|
||||
std::terminate();
|
||||
return false;
|
||||
};
|
||||
|
||||
GetItemCallback GameScriptDisplayString::s_getItemCallback = [](DisplayStringIDType)
|
||||
{
|
||||
std::string err = "\"Get string\" callback is not set.";
|
||||
throw TENScriptException(err);
|
||||
return std::nullopt;
|
||||
};
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#include "framework.h"
|
||||
#include "GameScriptFog.h"
|
||||
/*** Describes a layer of moving clouds.
|
||||
As seen in TR4's City of the Dead.
|
||||
|
||||
@pregameclass SkyLayer
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptFog::Register(sol::state* lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptFog>("Fog",
|
||||
sol::constructors<GameScriptFog(GameScriptColor const&, short, short)>(),
|
||||
|
||||
/// (@{Color}) RGB sky color
|
||||
//@mem color
|
||||
"color", sol::property(&GameScriptFog::SetColor),
|
||||
|
||||
/*** (int) min distance.
|
||||
|
||||
This is the distance at which the fog starts
|
||||
|
||||
@mem minDistance*/
|
||||
"minDistance", &GameScriptFog::MinDistance,
|
||||
|
||||
/*** (int) max distance.
|
||||
|
||||
This is the distance at which the fog reaches the maximum strength
|
||||
|
||||
@mem maxDistance*/
|
||||
"maxDistance", & GameScriptFog::MaxDistance
|
||||
);
|
||||
}
|
||||
|
||||
/***
|
||||
@tparam Color color RGB color
|
||||
@tparam int speed cloud speed
|
||||
@return A SkyLayer object.
|
||||
@function SkyLayer.new
|
||||
*/
|
||||
GameScriptFog::GameScriptFog(GameScriptColor const& col, short minDistance, short maxDistance)
|
||||
{
|
||||
SetColor(col);
|
||||
MinDistance = minDistance;
|
||||
MaxDistance = maxDistance;
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
void GameScriptFog::SetColor(GameScriptColor const& col)
|
||||
{
|
||||
R = col.GetR();
|
||||
G = col.GetG();
|
||||
B = col.GetB();
|
||||
}
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "GameScriptColor.h"
|
||||
|
||||
namespace sol {
|
||||
class state;
|
||||
}
|
||||
|
||||
struct GameScriptFog
|
||||
{
|
||||
bool Enabled{ false };
|
||||
byte R{ 0 };
|
||||
byte G{ 0 };
|
||||
byte B{ 0 };
|
||||
short MinDistance{ 0 };
|
||||
short MaxDistance{ 0 };
|
||||
|
||||
GameScriptFog() = default;
|
||||
GameScriptFog(GameScriptColor const& col, short minDistance, short maxDistance);
|
||||
void SetColor(GameScriptColor const& col);
|
||||
|
||||
static void Register(sol::state*);
|
||||
};
|
|
@ -1,123 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptInventoryObject.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include <string>
|
||||
|
||||
/***
|
||||
Represents the properties of an object as it appears in the inventory.
|
||||
|
||||
@pregameclass InventoryObject
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
/*** Create an inventoryObject item. Use this if you want to specify property values later later.
|
||||
The default property values are not disclosed here, since at the time of writing, they are subject to change.
|
||||
@function InventoryObject.new
|
||||
@return an InventoryObject
|
||||
*/
|
||||
|
||||
/*** For more information on each parameter, see the
|
||||
associated getters and setters.
|
||||
@function InventoryObject.new
|
||||
@tparam string nameKey name key
|
||||
@tparam InvItem slot slot of inventory object to change
|
||||
@tparam int yOffset y-axis offset (positive values move the item down)
|
||||
@tparam float scale item size (1 being standard size)
|
||||
@tparam Rotation rot rotation about x, y, and z axes
|
||||
@tparam RotationAxis rotAxisWhenCurrent axis to rotate around in inventory
|
||||
@tparam int meshBits not currently implemented
|
||||
@tparam ItemAction action is this usable, equippable, or examinable?
|
||||
@return an InventoryObject
|
||||
*/
|
||||
GameScriptInventoryObject::GameScriptInventoryObject(std::string const& a_name, ItemEnumPair a_slot, short a_yOffset, float a_scale, GameScriptRotation const & a_rot, RotationFlags a_rotationFlags, int a_meshBits, ItemOptions a_action) :
|
||||
name{ a_name },
|
||||
slot{ a_slot.m_pair.second },
|
||||
yOffset{ a_yOffset },
|
||||
scale{ a_scale },
|
||||
rot{ a_rot },
|
||||
rotationFlags{ a_rotationFlags },
|
||||
meshBits{ a_meshBits }
|
||||
{
|
||||
SetAction(a_action);
|
||||
}
|
||||
|
||||
void GameScriptInventoryObject::Register(sol::state * lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptInventoryObject>("InventoryObject",
|
||||
sol::constructors<GameScriptInventoryObject(std::string const &, ItemEnumPair, short, float, GameScriptRotation const &, RotationFlags, int, ItemOptions), GameScriptInventoryObject()>(),
|
||||
/*** (string) string key for the item's (localised) name. Corresponds to an entry in strings.lua.
|
||||
@mem nameKey
|
||||
*/
|
||||
"nameKey", &GameScriptInventoryObject::name,
|
||||
|
||||
/*** (@{InvItem}) slot of item whose inventory display properties you wish to change
|
||||
@mem slot
|
||||
*/
|
||||
"slot", sol::property(&GameScriptInventoryObject::SetSlot),
|
||||
|
||||
/*** (float) y-axis offset (positive values will move the item lower).
|
||||
A value of about 100 will cause the item to display directly below its usual position.
|
||||
@mem yOffset
|
||||
*/
|
||||
"yOffset", &GameScriptInventoryObject::yOffset,
|
||||
|
||||
/*** (float) Item's size when displayed in the inventory as a multiple of its "regular" size.
|
||||
A value of 0.5 will cause the item to render at half the size,
|
||||
and a value of 2 will cause the item to render at twice the size.
|
||||
@mem scale
|
||||
*/
|
||||
"scale", &GameScriptInventoryObject::scale,
|
||||
|
||||
/*** (@{Rotation}) Item's rotation about its origin when displayed in the inventory.
|
||||
@mem rot
|
||||
*/
|
||||
"rot", &GameScriptInventoryObject::rot,
|
||||
|
||||
/*** (RotationAxis) Axis to rotate about when the item is being looked at in the inventory.
|
||||
Note that this is entirely separate from the `rot` field described above.
|
||||
Must be RotationAxis.X, RotationAxis.Y or RotationAxis.Z.
|
||||
e.g. `myItem.rotAxisWhenCurrent = RotationAxis.X`
|
||||
@mem rotAxisWhenCurrent
|
||||
*/
|
||||
"rotAxisWhenCurrent", &GameScriptInventoryObject::rotationFlags,
|
||||
|
||||
/*** (int) __Not currently implemented__ (will have no effect regardless of what you set it to)
|
||||
@mem meshBits
|
||||
*/
|
||||
"meshBits", &GameScriptInventoryObject::meshBits,
|
||||
|
||||
/*** (ItemAction) What can the player do with the item?
|
||||
Must be one of:
|
||||
EQUIP
|
||||
USE
|
||||
EXAMINE
|
||||
e.g. `myItem.action = ItemAction.EXAMINE`
|
||||
@mem action
|
||||
*/
|
||||
"action", sol::property(&GameScriptInventoryObject::SetAction)
|
||||
);
|
||||
}
|
||||
|
||||
// Add validation so the user can't choose something unimplemented
|
||||
void GameScriptInventoryObject::SetAction(ItemOptions a_action)
|
||||
{
|
||||
bool isSupported = (a_action == ItemOptions::OPT_EQUIP) ||
|
||||
(a_action == ItemOptions::OPT_USE) ||
|
||||
(a_action == ItemOptions::OPT_EXAMINABLE);
|
||||
|
||||
if (!ScriptAssert(isSupported, "Unsupported item action: " + std::to_string(a_action)))
|
||||
{
|
||||
ItemOptions def = ItemOptions::OPT_USE;
|
||||
ScriptWarn("Defaulting to " + std::to_string(def));
|
||||
action = def;
|
||||
}
|
||||
else
|
||||
{
|
||||
action = a_action;
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptInventoryObject::SetSlot(ItemEnumPair a_slot)
|
||||
{
|
||||
slot = a_slot.m_pair.second;
|
||||
}
|
|
@ -1,582 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "GameScriptItemInfo.h"
|
||||
#include "ScriptUtil.h"
|
||||
#include "Game/items.h"
|
||||
#include "Objects/objectslist.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/setup.h"
|
||||
#include "Game/control/lot.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "GameScriptRotation.h"
|
||||
#include "Specific/trmath.h"
|
||||
|
||||
/***
|
||||
Represents any object inside the game world.
|
||||
Examples include statics, enemies, doors,
|
||||
pickups, and Lara herself.
|
||||
|
||||
@entityclass ItemInfo
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
constexpr auto LUA_CLASS_NAME{ "ItemInfo" };
|
||||
|
||||
static auto index_error = index_error_maker(GameScriptItemInfo, LUA_CLASS_NAME);
|
||||
static auto newindex_error = newindex_error_maker(GameScriptItemInfo, LUA_CLASS_NAME);
|
||||
|
||||
GameScriptItemInfo::GameScriptItemInfo(short num, bool temp) : m_item{ &g_Level.Items[num] }, m_num{ num }, m_initialised{ false }, m_temporary{ temp }
|
||||
{};
|
||||
|
||||
GameScriptItemInfo::GameScriptItemInfo(GameScriptItemInfo&& other) noexcept :
|
||||
m_item { std::exchange(other.m_item, nullptr) },
|
||||
m_num{ std::exchange(other.m_num, NO_ITEM) },
|
||||
m_initialised{ std::exchange(other.m_initialised, false) },
|
||||
m_temporary{ std::exchange(other.m_temporary, false) }
|
||||
{};
|
||||
|
||||
// todo.. how to check if item is killed outside of script?
|
||||
GameScriptItemInfo::~GameScriptItemInfo() {
|
||||
// todo.. see if there's a better default state than -1
|
||||
if (m_temporary && (m_num > NO_ITEM))
|
||||
{
|
||||
s_callbackRemoveName(m_item->luaName);
|
||||
KillItem(m_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** If you create items with this you NEED to give a position, room,
|
||||
and object number, and then call InitialiseItem before it will work.
|
||||
@function ItemInfo.new
|
||||
*/
|
||||
|
||||
/*** Like above, but the returned variable controls the
|
||||
lifetime of the object (it will be destroyed when the variable goes
|
||||
out of scope).
|
||||
@function ItemInfo.newTemporary
|
||||
*/
|
||||
template <bool temp> std::unique_ptr<GameScriptItemInfo> CreateEmpty()
|
||||
{
|
||||
short num = CreateItem();
|
||||
ITEM_INFO * item = &g_Level.Items[num];
|
||||
return std::make_unique<GameScriptItemInfo>(num, temp);
|
||||
}
|
||||
|
||||
/*** For more information on each parameter, see the
|
||||
associated getters and setters. If you do not know what to set for these,
|
||||
most can just be set to zero (see usage). See also the overload which
|
||||
takes no arguments.
|
||||
@function ItemInfo.new
|
||||
@tparam ObjID object ID
|
||||
@tparam string name Lua name of the item
|
||||
@tparam Position position position in level
|
||||
@tparam Rotation rotation rotation about x, y, and z axes
|
||||
@tparam int room room ID item is in
|
||||
@tparam int currentAnimState current animation state
|
||||
@tparam int requiredAnimState required animation state
|
||||
@tparam int goalAnimState goal animation state
|
||||
@tparam int animNumber anim number
|
||||
@tparam int frameNumber frame number
|
||||
@tparam int hp HP of item
|
||||
@tparam int OCB ocb of item
|
||||
@tparam int itemFlags item flags
|
||||
@tparam int AIBits byte with AI bits
|
||||
@tparam int status status of object
|
||||
@tparam bool active is item active or not?
|
||||
@tparam bool hitStatus hit status of object
|
||||
@return reference to new ItemInfo object
|
||||
@usage
|
||||
local item = ItemInfo.new(
|
||||
ObjID.PISTOLS_ITEM, -- object id
|
||||
"test", -- name
|
||||
Position.new(18907, 0, 21201),
|
||||
Rotation.new(0,0,0),
|
||||
0, -- room
|
||||
0, -- currentAnimState
|
||||
0, -- requiredAnimState
|
||||
0, -- goalAnimState
|
||||
0, -- animNumber
|
||||
0, -- frameNumber
|
||||
0, -- HP
|
||||
0, -- OCB
|
||||
{0,0,0,0,0,0,0,0}, -- itemFlags
|
||||
0, -- AIBits
|
||||
0, -- status
|
||||
false, -- active
|
||||
false, -- hitStatus
|
||||
)
|
||||
*/
|
||||
|
||||
/*** Like the above, but the returned variable controls the
|
||||
lifetime of the object (it will be destroyed when the variable goes
|
||||
out of scope).
|
||||
@function ItemInfo.newTemporary
|
||||
@param see_above same as above function
|
||||
*/
|
||||
|
||||
template <bool temp> static std::unique_ptr<GameScriptItemInfo> Create(
|
||||
GAME_OBJECT_ID objID,
|
||||
std::string name,
|
||||
GameScriptPosition pos,
|
||||
GameScriptRotation rot,
|
||||
short room,
|
||||
int currentAnimState,
|
||||
int requiredAnimState,
|
||||
int goalAnimState,
|
||||
int animNumber,
|
||||
int frameNumber,
|
||||
short hp,
|
||||
short ocb,
|
||||
sol::as_table_t<std::array<short, 8>> flags,
|
||||
byte aiBits,
|
||||
short status,
|
||||
bool active,
|
||||
bool hitStatus
|
||||
)
|
||||
{
|
||||
short num = CreateItem();
|
||||
auto ptr = std::make_unique<GameScriptItemInfo>(num, temp);
|
||||
|
||||
ITEM_INFO* item = &g_Level.Items[num];
|
||||
ptr->SetPos(pos);
|
||||
ptr->SetRot(rot);
|
||||
ptr->SetRoom(room);
|
||||
ptr->SetObjectID(objID);
|
||||
InitialiseItem(num);
|
||||
|
||||
ptr->SetName(name);
|
||||
ptr->SetCurrentAnimState(currentAnimState);
|
||||
ptr->SetRequiredAnimState(requiredAnimState);
|
||||
ptr->SetGoalAnimState(goalAnimState);
|
||||
ptr->SetAnimNumber(animNumber);
|
||||
ptr->SetFrameNumber(frameNumber);
|
||||
ptr->SetHP(hp);
|
||||
ptr->SetOCB(ocb);
|
||||
ptr->SetItemFlags(flags);
|
||||
ptr->SetAIBits(aiBits);
|
||||
ptr->SetStatus(status);
|
||||
ptr->SetActive(active);
|
||||
ptr->SetHitStatus(hitStatus);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptItemInfo>(LUA_CLASS_NAME,
|
||||
"new", sol::overload(Create<false>, CreateEmpty<false>),
|
||||
"newTemporary", sol::overload(Create<true>, CreateEmpty<true>),
|
||||
sol::meta_function::index, index_error,
|
||||
sol::meta_function::new_index, newindex_error,
|
||||
|
||||
/// Initialise an item.
|
||||
//Use this if you called new with no arguments
|
||||
// @function ItemInfo.Init
|
||||
"Init", &GameScriptItemInfo::Init,
|
||||
|
||||
/// Enable the item
|
||||
// @function ItemInfo:EnableItem
|
||||
"Enable", &GameScriptItemInfo::EnableItem,
|
||||
|
||||
/// Disable the item
|
||||
// @function ItemInfo:DisableItem
|
||||
"Disable", &GameScriptItemInfo::DisableItem,
|
||||
|
||||
/// (@{ObjID}) object ID
|
||||
// @mem objectID
|
||||
"objectID", sol::property(&GameScriptItemInfo::GetObjectID, &GameScriptItemInfo::SetObjectID),
|
||||
|
||||
/*** (int) current animation state
|
||||
|
||||
The state number of the animation the object is currently doing.
|
||||
This corresponds to "state" number shown in the animation editor of WadTool.
|
||||
@mem currentAnimState
|
||||
*/
|
||||
"currentAnimState", sol::property(&GameScriptItemInfo::GetCurrentAnimState, &GameScriptItemInfo::SetCurrentAnimState),
|
||||
|
||||
/// (int) State of required animation
|
||||
// @mem requiredAnimState
|
||||
"requiredAnimState", sol::property(&GameScriptItemInfo::GetRequiredAnimState, &GameScriptItemInfo::SetRequiredAnimState),
|
||||
|
||||
/// (int) State of goal animation
|
||||
// @mem goalAnimState
|
||||
"goalAnimState", sol::property(&GameScriptItemInfo::GetGoalAnimState, &GameScriptItemInfo::SetGoalAnimState),
|
||||
|
||||
/*** (int) animation number
|
||||
|
||||
The index of the animation the object is currently doing.
|
||||
This corresponds to the number shown in the item's animation list in WadTool.
|
||||
@mem animNumber
|
||||
*/
|
||||
"animNumber", sol::property(&GameScriptItemInfo::GetAnimNumber, &GameScriptItemInfo::SetAnimNumber),
|
||||
|
||||
/*** (int) frame number
|
||||
|
||||
Current fame of the animation the object is currently doing.
|
||||
The number of frames in an animation can be seen under the heading "End frame" in
|
||||
the WadTool animation editor.
|
||||
@mem frameNumber
|
||||
*/
|
||||
"frameNumber", sol::property(&GameScriptItemInfo::GetFrameNumber, &GameScriptItemInfo::SetFrameNumber),
|
||||
|
||||
/// (int) HP (hit points/health points) of object
|
||||
//@raise an exception if the object is intelligent and an invalid
|
||||
//hp value is given
|
||||
// @mem HP
|
||||
"HP", sol::property(&GameScriptItemInfo::GetHP, &GameScriptItemInfo::SetHP),
|
||||
|
||||
/// (int) OCB (object code bit) of object
|
||||
// @mem OCB
|
||||
"OCB", sol::property(&GameScriptItemInfo::GetOCB, &GameScriptItemInfo::SetOCB),
|
||||
|
||||
/// (table) item flags of object (table of 8 ints)
|
||||
// @mem itemFlags
|
||||
"itemFlags", sol::property(&GameScriptItemInfo::GetItemFlags, &GameScriptItemInfo::SetItemFlags),
|
||||
|
||||
/// (int) AIBits of object. Will be clamped to [0, 255]
|
||||
// @mem AIBits
|
||||
"AIBits", sol::property(&GameScriptItemInfo::GetAIBits, &GameScriptItemInfo::SetAIBits),
|
||||
|
||||
/// (int) status of object.
|
||||
// possible values:
|
||||
// 0 - not active
|
||||
// 1 - active
|
||||
// 2 - deactivated
|
||||
// 3 - invisible
|
||||
// @mem status
|
||||
"status", sol::property(&GameScriptItemInfo::GetStatus, &GameScriptItemInfo::SetStatus),
|
||||
|
||||
/// (bool) hit status of object
|
||||
// @mem hitStatus
|
||||
"hitStatus", sol::property(&GameScriptItemInfo::GetHitStatus, &GameScriptItemInfo::SetHitStatus),
|
||||
|
||||
/// (bool) whether or not the object is active
|
||||
// @mem active
|
||||
"active", sol::property(&GameScriptItemInfo::GetActive, &GameScriptItemInfo::SetActive),
|
||||
|
||||
/// (int) room the item is in
|
||||
// @mem room
|
||||
"room", sol::property(&GameScriptItemInfo::GetRoom, &GameScriptItemInfo::SetRoom),
|
||||
|
||||
/// (@{Position}) position in level
|
||||
// @mem pos
|
||||
"pos", sol::property(&GameScriptItemInfo::GetPos, &GameScriptItemInfo::SetPos),
|
||||
|
||||
/// (@{Rotation}) rotation represented as degree angles about X, Y, and Z axes
|
||||
// @mem rot
|
||||
"rot", sol::property(&GameScriptItemInfo::GetRot, &GameScriptItemInfo::SetRot),
|
||||
|
||||
/// (string) unique string identifier.
|
||||
// e.g. "door\_back\_room" or "cracked\_greek\_statue"
|
||||
// @mem name
|
||||
"name", sol::property(&GameScriptItemInfo::GetName, &GameScriptItemInfo::SetName)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void GameScriptItemInfo::Init()
|
||||
{
|
||||
bool cond = IsPointInRoom(m_item->pos, m_item->roomNumber);
|
||||
std::string err{ "Position of item \"{}\" does not match its room ID." };
|
||||
if (!ScriptAssertF(cond, err, m_item->luaName))
|
||||
{
|
||||
ScriptWarn("Resetting to the center of the room.");
|
||||
PHD_3DPOS center = GetRoomCenter(m_item->roomNumber);
|
||||
// reset position but not rotation
|
||||
m_item->pos.xPos = center.xPos;
|
||||
m_item->pos.yPos = center.yPos;
|
||||
m_item->pos.zPos = center.zPos;
|
||||
}
|
||||
InitialiseItem(m_num);
|
||||
m_initialised = true;
|
||||
}
|
||||
|
||||
GAME_OBJECT_ID GameScriptItemInfo::GetObjectID() const
|
||||
{
|
||||
return m_item->objectNumber;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetObjectID(GAME_OBJECT_ID item)
|
||||
{
|
||||
m_item->objectNumber = item;
|
||||
}
|
||||
|
||||
|
||||
std::string GameScriptItemInfo::GetName() const
|
||||
{
|
||||
return m_item->luaName;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetName(std::string const & id)
|
||||
{
|
||||
ScriptAssert(!id.empty(), "Name cannot be blank", ERROR_MODE::TERMINATE);
|
||||
|
||||
// remove the old name if we have one
|
||||
s_callbackRemoveName(m_item->luaName);
|
||||
|
||||
// un-register any other objects using this name.
|
||||
// maybe we should throw an error if another object
|
||||
// already uses the name...
|
||||
s_callbackRemoveName(id);
|
||||
m_item->luaName = id;
|
||||
// todo add error checking
|
||||
s_callbackSetName(id, m_num);
|
||||
}
|
||||
|
||||
GameScriptPosition GameScriptItemInfo::GetPos() const
|
||||
{
|
||||
return GameScriptPosition( m_item->pos );
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetPos(GameScriptPosition const& pos)
|
||||
{
|
||||
pos.StoreInPHDPos(m_item->pos);
|
||||
}
|
||||
|
||||
// This does not guarantee that the returned value will be identical
|
||||
// to a value written in via SetRot - only that the angle measures
|
||||
// will be mathematically equal
|
||||
// (e.g. 90 degrees = -270 degrees = 450 degrees)
|
||||
GameScriptRotation GameScriptItemInfo::GetRot() const
|
||||
{
|
||||
return GameScriptRotation( int(TO_DEGREES(m_item->pos.xRot)) % 360,
|
||||
int(TO_DEGREES(m_item->pos.yRot)) % 360,
|
||||
int(TO_DEGREES(m_item->pos.zRot)) % 360);
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetRot(GameScriptRotation const& rot)
|
||||
{
|
||||
m_item->pos.xRot = FROM_DEGREES(rot.x);
|
||||
m_item->pos.yRot = FROM_DEGREES(rot.y);
|
||||
m_item->pos.zRot = FROM_DEGREES(rot.z);
|
||||
}
|
||||
|
||||
short GameScriptItemInfo::GetHP() const
|
||||
{
|
||||
return(m_item->hitPoints);
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetHP(short hp)
|
||||
{
|
||||
if(Objects[m_item->objectNumber].intelligent &&
|
||||
(hp < 0 || hp > Objects[m_item->objectNumber].hitPoints))
|
||||
{
|
||||
ScriptAssert(false, "Invalid HP value: " + std::to_string(hp));
|
||||
if (hp < 0)
|
||||
{
|
||||
hp = 0;
|
||||
ScriptWarn("Setting HP to 0.");
|
||||
}
|
||||
else if (hp > Objects[m_item->objectNumber].hitPoints)
|
||||
{
|
||||
hp = Objects[m_item->objectNumber].hitPoints;
|
||||
ScriptWarn("Setting HP to default value (" + std::to_string(hp) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
m_item->hitPoints = hp;
|
||||
}
|
||||
|
||||
short GameScriptItemInfo::GetOCB() const
|
||||
{
|
||||
return m_item->triggerFlags;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetOCB(short ocb)
|
||||
{
|
||||
m_item->triggerFlags = ocb;
|
||||
}
|
||||
|
||||
byte GameScriptItemInfo::GetAIBits() const
|
||||
{
|
||||
return m_item->aiBits;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetAIBits(byte bits)
|
||||
{
|
||||
m_item->aiBits = bits;
|
||||
}
|
||||
|
||||
sol::as_table_t<std::array<short, 8>> GameScriptItemInfo::GetItemFlags() const
|
||||
{
|
||||
std::array<short, 8> ret{};
|
||||
memcpy(ret.data(), m_item->itemFlags, sizeof(m_item->itemFlags));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetItemFlags(sol::as_table_t<std::array<short, 8>> const& arr)
|
||||
{
|
||||
memcpy(m_item->itemFlags, arr.value().data(), sizeof(m_item->itemFlags));
|
||||
}
|
||||
|
||||
int GameScriptItemInfo::GetCurrentAnimState() const
|
||||
{
|
||||
return m_item->currentAnimState;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetCurrentAnimState(int animState)
|
||||
{
|
||||
m_item->currentAnimState = animState;
|
||||
}
|
||||
|
||||
int GameScriptItemInfo::GetRequiredAnimState() const
|
||||
{
|
||||
return m_item->requiredAnimState;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetRequiredAnimState(short animState)
|
||||
{
|
||||
m_item->requiredAnimState = animState;
|
||||
}
|
||||
|
||||
int GameScriptItemInfo::GetGoalAnimState() const
|
||||
{
|
||||
return m_item->goalAnimState;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetGoalAnimState(int state)
|
||||
{
|
||||
m_item->goalAnimState = state;
|
||||
}
|
||||
|
||||
int GameScriptItemInfo::GetAnimNumber() const
|
||||
{
|
||||
return m_item->animNumber - Objects[m_item->objectNumber].animIndex;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetAnimNumber(int animNumber)
|
||||
{
|
||||
//TODO fixme: we need bounds checking with an error message once it's in the level file format
|
||||
m_item->animNumber = animNumber + Objects[m_item->objectNumber].animIndex;
|
||||
}
|
||||
|
||||
int GameScriptItemInfo::GetFrameNumber() const
|
||||
{
|
||||
return m_item->frameNumber - g_Level.Anims[m_item->animNumber].frameBase;
|
||||
}
|
||||
|
||||
|
||||
void GameScriptItemInfo::SetFrameNumber(int frameNumber)
|
||||
{
|
||||
auto const fBase = g_Level.Anims[m_item->animNumber].frameBase;
|
||||
auto const fEnd = g_Level.Anims[m_item->animNumber].frameEnd;
|
||||
auto frameCount = fEnd - fBase;
|
||||
bool cond = (frameNumber < frameCount);
|
||||
const char* err = "Invalid frame number {}; max frame count for anim {} is {}.";
|
||||
if (ScriptAssertF(cond, err, frameNumber, m_item->animNumber, frameCount))
|
||||
{
|
||||
m_item->frameNumber = frameNumber + fBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptWarn("Not setting frame number.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
short GameScriptItemInfo::GetStatus() const
|
||||
{
|
||||
return m_item->status;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetStatus(short status)
|
||||
{
|
||||
m_item->status = status;
|
||||
}
|
||||
|
||||
bool GameScriptItemInfo::GetActive() const
|
||||
{
|
||||
return m_item->active;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetActive(bool active)
|
||||
{
|
||||
m_item->active = active;
|
||||
}
|
||||
|
||||
bool GameScriptItemInfo::GetHitStatus() const
|
||||
{
|
||||
return m_item->hitStatus;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetHitStatus(bool hitStatus)
|
||||
{
|
||||
m_item->hitStatus = hitStatus;
|
||||
}
|
||||
|
||||
short GameScriptItemInfo::GetRoom() const
|
||||
{
|
||||
return m_item->roomNumber;
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::SetRoom(short room)
|
||||
{
|
||||
const size_t nRooms = g_Level.Rooms.size();
|
||||
if (room < 0 || static_cast<size_t>(room) >= nRooms)
|
||||
{
|
||||
ScriptAssertF(false, "Invalid room number: {}. Value must be in range [0, {})", room, nRooms);
|
||||
TENLog("Room number will not be set", LogLevel::Warning, LogConfig::All);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_initialised)
|
||||
m_item->roomNumber = room;
|
||||
else
|
||||
ItemNewRoom(m_num, room);
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::EnableItem()
|
||||
{
|
||||
if (!m_item->active)
|
||||
{
|
||||
if (Objects[m_item->objectNumber].intelligent)
|
||||
{
|
||||
if (m_item->status == ITEM_DEACTIVATED)
|
||||
{
|
||||
m_item->touchBits = 0;
|
||||
m_item->status = ITEM_ACTIVE;
|
||||
AddActiveItem(m_num);
|
||||
EnableBaddieAI(m_num, 1);
|
||||
}
|
||||
else if (m_item->status == ITEM_INVISIBLE)
|
||||
{
|
||||
m_item->touchBits = 0;
|
||||
if (EnableBaddieAI(m_num, 0))
|
||||
m_item->status = ITEM_ACTIVE;
|
||||
else
|
||||
m_item->status = ITEM_INVISIBLE;
|
||||
AddActiveItem(m_num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_item->touchBits = 0;
|
||||
AddActiveItem(m_num);
|
||||
m_item->status = ITEM_ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptItemInfo::DisableItem()
|
||||
{
|
||||
if (m_item->active)
|
||||
{
|
||||
if (Objects[m_item->objectNumber].intelligent)
|
||||
{
|
||||
if (m_item->status == ITEM_ACTIVE)
|
||||
{
|
||||
m_item->touchBits = 0;
|
||||
m_item->status = ITEM_DEACTIVATED;
|
||||
RemoveActiveItem(m_num);
|
||||
DisableBaddieAI(m_num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_item->touchBits = 0;
|
||||
RemoveActiveItem(m_num);
|
||||
m_item->status = ITEM_DEACTIVATED;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptLevel.h"
|
||||
#include "ScriptAssert.h"
|
||||
|
||||
/***
|
||||
Stores level metadata.
|
||||
These are things things which aren't present in the compiled level file itself.
|
||||
|
||||
@pregameclass Level
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
/*** Make a new Level object.
|
||||
@function Level.new
|
||||
@return a Level object
|
||||
*/
|
||||
void GameScriptLevel::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptLevel>("Level",
|
||||
sol::constructors<GameScriptLevel()>(),
|
||||
|
||||
/// (string) string key for the level's (localised) name.
|
||||
// Corresponds to an entry in strings.lua.
|
||||
//@mem nameKey
|
||||
"nameKey", &GameScriptLevel::NameStringKey,
|
||||
|
||||
/// (string) Level-specific Lua script file.
|
||||
// Path of the Lua file holding the level's logic script, relative to the location of the tombengine executable
|
||||
//@mem scriptFile
|
||||
"scriptFile", &GameScriptLevel::ScriptFileName,
|
||||
|
||||
/// (string) Compiled file path.
|
||||
// This path is relative to the location of the TombEngine executable.
|
||||
//@mem levelFile
|
||||
"levelFile", &GameScriptLevel::FileName,
|
||||
|
||||
/// (string) Load screen image.
|
||||
// Path of the level's load screen file (.png or .jpg), relative to the location of the tombengine executable
|
||||
//@mem loadScreenFile
|
||||
"loadScreenFile", &GameScriptLevel::LoadScreenFileName,
|
||||
|
||||
/// (string) initial ambient sound track to play.
|
||||
// This is the filename of the track __without__ the .wav extension.
|
||||
//@mem ambientTrack
|
||||
"ambientTrack", &GameScriptLevel::AmbientTrack,
|
||||
|
||||
/// (@{SkyLayer}) Primary sky layer
|
||||
//@mem layer1
|
||||
"layer1", &GameScriptLevel::Layer1,
|
||||
|
||||
/// (@{SkyLayer}) Secondary sky layer
|
||||
// __(not yet implemented)__
|
||||
//@mem layer2
|
||||
"layer2", &GameScriptLevel::Layer2,
|
||||
|
||||
/// (@{Fog}) omni fog RGB color and distance.
|
||||
// As seen in TR4's Desert Railroad.
|
||||
// If not provided, distance fog will be black.
|
||||
//
|
||||
// __(not yet implemented)__
|
||||
//@mem fog
|
||||
"fog", &GameScriptLevel::Fog,
|
||||
|
||||
/// (bool) Draw sky layer? (default: false)
|
||||
//@mem horizon
|
||||
"horizon", &GameScriptLevel::Horizon,
|
||||
|
||||
/// (bool) Enable smooth transition from horizon graphic to sky layer.
|
||||
// If set to false, there will be a black band between the two.
|
||||
//
|
||||
// __(not yet implemented)__
|
||||
//@mem colAddHorizon
|
||||
"colAddHorizon", &GameScriptLevel::ColAddHorizon,
|
||||
|
||||
/// (bool) Enable flickering lightning in the sky.
|
||||
// Equivalent to classic TRLE's LIGHTNING setting. As in the TRC Ireland levels.
|
||||
//
|
||||
//@mem storm
|
||||
"storm", &GameScriptLevel::Storm,
|
||||
|
||||
/// (WeatherType) Choose weather effect.
|
||||
// Must be one of the values `WeatherType.None`, `WeatherType.Rain`, or `WeatherType.Snow`.
|
||||
//
|
||||
//@mem weather
|
||||
"weather", &GameScriptLevel::Weather,
|
||||
|
||||
/// (float) Choose weather strength.
|
||||
// Must be value between `0.1` and `1.0`.
|
||||
//
|
||||
//@mem weatherStrength
|
||||
"weatherStrength", sol::property(&GameScriptLevel::SetWeatherStrength),
|
||||
|
||||
/*** (LaraType) Must be one of the LaraType values.
|
||||
These are:
|
||||
|
||||
Normal
|
||||
Young
|
||||
Bunhead
|
||||
Catsuit
|
||||
Divesuit
|
||||
Invisible
|
||||
|
||||
e.g. `myLevel.laraType = LaraType.Divesuit`
|
||||
|
||||
__(not yet fully implemented)__
|
||||
@mem laraType*/
|
||||
"laraType", &GameScriptLevel::LaraType,
|
||||
|
||||
/// (bool) Enable occasional screen shake effect.
|
||||
// As seen in TRC's Sinking Submarine.
|
||||
//@mem rumble
|
||||
"rumble", &GameScriptLevel::Rumble,
|
||||
|
||||
/// (@{Mirror}) Location and size of the level's mirror, if present.
|
||||
//
|
||||
// __(not yet implemented)__
|
||||
//@mem mirror
|
||||
"mirror", &GameScriptLevel::Mirror,
|
||||
|
||||
/*** (byte) The maximum draw distance for level.
|
||||
Given in sectors (blocks).
|
||||
Must be in the range [1, 127], and equal to or less than the value passed to SetGameFarView.
|
||||
|
||||
This is equivalent to TRNG's LevelFarView variable.
|
||||
|
||||
__(not yet implemented)__
|
||||
@mem farView
|
||||
*/
|
||||
"farView", sol::property(&GameScriptLevel::SetLevelFarView),
|
||||
|
||||
/*** (bool) Enable unlimited oxygen supply when in water.
|
||||
|
||||
__(not yet implemented)__
|
||||
@mem unlimitedAir
|
||||
*/
|
||||
"unlimitedAir", &GameScriptLevel::UnlimitedAir,
|
||||
|
||||
/// (table of @{InventoryObject}s) table of inventory object overrides
|
||||
//@mem objects
|
||||
"objects", &GameScriptLevel::InventoryObjects
|
||||
);
|
||||
}
|
||||
|
||||
void GameScriptLevel::SetWeatherStrength(float val)
|
||||
{
|
||||
bool cond = val <= 1.0f && val >= 0.0f;
|
||||
std::string msg{ "weatherStrength value must be in the range [0.1, 1.0]." };
|
||||
if (!ScriptAssert(cond, msg))
|
||||
{
|
||||
ScriptWarn("Setting weatherStrength view to 1.");
|
||||
WeatherStrength = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
WeatherStrength = val;
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptLevel::SetLevelFarView(byte val)
|
||||
{
|
||||
bool cond = val <= 127 && val >= 1;
|
||||
std::string msg{ "levelFarView value must be in the range [1, 127]." };
|
||||
if (!ScriptAssert(cond, msg))
|
||||
{
|
||||
ScriptWarn("Setting levelFarView view to 32.");
|
||||
LevelFarView = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
LevelFarView = val;
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
#pragma once
|
||||
#include "frameworkandsol.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "GameScriptMeshInfo.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "GameScriptColor.h"
|
||||
#include "ScriptUtil.h"
|
||||
/***
|
||||
Mesh info
|
||||
|
||||
@entityclass MeshInfo
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
constexpr auto LUA_CLASS_NAME{ "MeshInfo" };
|
||||
|
||||
static auto index_error = index_error_maker(GameScriptMeshInfo, LUA_CLASS_NAME);
|
||||
static auto newindex_error = newindex_error_maker(GameScriptMeshInfo, LUA_CLASS_NAME);
|
||||
|
||||
GameScriptMeshInfo::GameScriptMeshInfo(MESH_INFO & ref, bool temp) : m_mesh{ref}, m_temporary{ temp }
|
||||
{};
|
||||
|
||||
GameScriptMeshInfo::~GameScriptMeshInfo() {
|
||||
if (m_temporary)
|
||||
{
|
||||
s_callbackRemoveName(m_mesh.luaName);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptMeshInfo>(LUA_CLASS_NAME,
|
||||
sol::meta_function::index, index_error,
|
||||
sol::meta_function::new_index, newindex_error,
|
||||
|
||||
/// (@{Position}) position in level
|
||||
// @mem pos
|
||||
"pos", sol::property(&GameScriptMeshInfo::GetPos, &GameScriptMeshInfo::SetPos),
|
||||
|
||||
/// (int) y-axis rotation
|
||||
// @mem yRot
|
||||
"yRot", sol::property(&GameScriptMeshInfo::GetRot, &GameScriptMeshInfo::SetRot),
|
||||
|
||||
/// (string) unique string identifier.
|
||||
// e.g. "my\_vase" or "oldrubble"
|
||||
// @mem name
|
||||
"name", sol::property(&GameScriptMeshInfo::GetName, &GameScriptMeshInfo::SetName),
|
||||
|
||||
/// (int) static number
|
||||
// @mem staticNumber
|
||||
"staticNumber", sol::property(&GameScriptMeshInfo::GetStaticNumber, &GameScriptMeshInfo::SetStaticNumber),
|
||||
|
||||
/// (@{Color}) color of mesh
|
||||
// @mem color
|
||||
"color", sol::property(&GameScriptMeshInfo::GetColor, &GameScriptMeshInfo::SetColor),
|
||||
|
||||
/// (int) hp
|
||||
// @mem HP
|
||||
"HP", sol::property(&GameScriptMeshInfo::GetHP, &GameScriptMeshInfo::SetHP)
|
||||
);
|
||||
}
|
||||
|
||||
GameScriptPosition GameScriptMeshInfo::GetPos() const
|
||||
{
|
||||
return GameScriptPosition{ m_mesh.pos.xPos, m_mesh.pos.yPos, m_mesh.pos.zPos };
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::SetPos(GameScriptPosition const& pos)
|
||||
{
|
||||
m_mesh.pos.xPos = pos.x;
|
||||
m_mesh.pos.yPos = pos.y;
|
||||
m_mesh.pos.zPos = pos.z;
|
||||
}
|
||||
|
||||
int GameScriptMeshInfo::GetRot() const
|
||||
{
|
||||
return m_mesh.pos.yRot;
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::SetRot(int yRot)
|
||||
{
|
||||
m_mesh.pos.yRot = yRot;
|
||||
}
|
||||
|
||||
std::string GameScriptMeshInfo::GetName() const
|
||||
{
|
||||
return m_mesh.luaName;
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::SetName(std::string const & id)
|
||||
{
|
||||
ScriptAssert(!id.empty(), "Name cannot be blank", ERROR_MODE::TERMINATE);
|
||||
|
||||
// remove the old name if we have one
|
||||
s_callbackRemoveName(m_mesh.luaName);
|
||||
|
||||
// un-register any other objects using this name.
|
||||
// maybe we should throw an error if another object
|
||||
// already uses the name...
|
||||
s_callbackRemoveName(id);
|
||||
m_mesh.luaName = id;
|
||||
// todo add error checking
|
||||
s_callbackSetName(id, m_mesh);
|
||||
}
|
||||
|
||||
int GameScriptMeshInfo::GetStaticNumber() const
|
||||
{
|
||||
return m_mesh.staticNumber;
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::SetStaticNumber(int staticNumber)
|
||||
{
|
||||
m_mesh.staticNumber = staticNumber;
|
||||
}
|
||||
|
||||
GameScriptColor GameScriptMeshInfo::GetColor() const
|
||||
{
|
||||
|
||||
return GameScriptColor{ m_mesh.color };
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::SetColor(GameScriptColor const & col)
|
||||
{
|
||||
m_mesh.color = col;
|
||||
}
|
||||
|
||||
int GameScriptMeshInfo::GetHP() const
|
||||
{
|
||||
return m_mesh.hitPoints;
|
||||
}
|
||||
|
||||
void GameScriptMeshInfo::SetHP(int hp)
|
||||
{
|
||||
m_mesh.hitPoints = hp;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptMirror.h"
|
||||
|
||||
/***
|
||||
A mirror effect.
|
||||
As seen in TR4's Coastal Ruins and Sacred Lake levels.
|
||||
|
||||
__Not currently implemented.__
|
||||
|
||||
@pregameclass Mirror
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptMirror::Register(sol::state* lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptMirror>("Mirror",
|
||||
sol::constructors<GameScriptMirror(short, int, int, int, int)>(),
|
||||
"room", &GameScriptMirror::Room,
|
||||
"startX", &GameScriptMirror::StartX,
|
||||
"endX", &GameScriptMirror::EndX,
|
||||
"startZ", &GameScriptMirror::StartZ,
|
||||
"endZ", &GameScriptMirror::EndZ
|
||||
);
|
||||
}
|
||||
|
||||
GameScriptMirror::GameScriptMirror(short room, int startX, int endX, int startZ, int endZ)
|
||||
{
|
||||
Room = room;
|
||||
StartX = startX;
|
||||
EndX = endX;
|
||||
StartZ = startZ;
|
||||
EndZ = endZ;
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "Specific/phd_global.h"
|
||||
|
||||
/***
|
||||
Represents a position in the game world.
|
||||
@miscclass Position
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptPosition::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptPosition>("Position",
|
||||
sol::constructors<GameScriptPosition(int, int, int)>(),
|
||||
sol::meta_function::to_string, &GameScriptPosition::ToString,
|
||||
|
||||
/// (int) x coordinate
|
||||
//@mem x
|
||||
"x", &GameScriptPosition::x,
|
||||
|
||||
/// (int) y coordinate
|
||||
//@mem y
|
||||
|
||||
"y", &GameScriptPosition::y,
|
||||
/// (int) z coordinate
|
||||
//@mem z
|
||||
|
||||
"z", &GameScriptPosition::z
|
||||
);
|
||||
}
|
||||
|
||||
/***
|
||||
@int X x coordinate
|
||||
@int Y y coordinate
|
||||
@int Z z coordinate
|
||||
@return A Position object.
|
||||
@function Position.new
|
||||
*/
|
||||
GameScriptPosition::GameScriptPosition(int aX, int aY, int aZ)
|
||||
{
|
||||
x = aX;
|
||||
y = aY;
|
||||
z = aZ;
|
||||
}
|
||||
|
||||
GameScriptPosition::GameScriptPosition(PHD_3DPOS const& pos)
|
||||
{
|
||||
x = pos.xPos;
|
||||
y = pos.yPos;
|
||||
z = pos.zPos;
|
||||
}
|
||||
|
||||
void GameScriptPosition::StoreInPHDPos(PHD_3DPOS& pos) const
|
||||
{
|
||||
pos.xPos = x;
|
||||
pos.yPos = y;
|
||||
pos.zPos = z;
|
||||
}
|
||||
|
||||
/***
|
||||
@tparam Position position this position
|
||||
@treturn string A string showing the x, y, and z values of the position
|
||||
@function __tostring
|
||||
*/
|
||||
std::string GameScriptPosition::ToString() const
|
||||
{
|
||||
return "{" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + "}";
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptRotation.h"
|
||||
#include "Specific/phd_global.h"
|
||||
|
||||
/*** Represents a rotation.
|
||||
Rotations are specifed as a combination of individual
|
||||
angles, in degrees, about each axis.
|
||||
All values will be clamped to [-32768, 32767].
|
||||
@miscclass Rotation
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptRotation::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptRotation>("Rotation",
|
||||
sol::constructors<GameScriptRotation(int, int, int)>(),
|
||||
sol::meta_function::to_string, &GameScriptRotation::ToString,
|
||||
|
||||
/// (int) rotation about x axis
|
||||
//@mem x
|
||||
"x", &GameScriptRotation::x,
|
||||
|
||||
/// (int) rotation about x axis
|
||||
//@mem y
|
||||
"y", &GameScriptRotation::y,
|
||||
|
||||
/// (int) rotation about x axis
|
||||
//@mem z
|
||||
"z", &GameScriptRotation::z
|
||||
);
|
||||
}
|
||||
|
||||
/***
|
||||
@int X rotation about x axis
|
||||
@int Y rotation about y axis
|
||||
@int Z rotation about z axis
|
||||
@return A Rotation object.
|
||||
@function Rotation.new
|
||||
*/
|
||||
GameScriptRotation::GameScriptRotation(int aX, int aY, int aZ)
|
||||
{
|
||||
x = aX;
|
||||
y = aY;
|
||||
z = aZ;
|
||||
}
|
||||
|
||||
void GameScriptRotation::StoreInPHDPos(PHD_3DPOS& pos) const
|
||||
{
|
||||
pos.xRot = x;
|
||||
pos.yRot = y;
|
||||
pos.zRot = z;
|
||||
}
|
||||
|
||||
GameScriptRotation::GameScriptRotation(PHD_3DPOS const & pos)
|
||||
{
|
||||
x = pos.xRot;
|
||||
y = pos.yRot;
|
||||
z = pos.zRot;
|
||||
}
|
||||
|
||||
/***
|
||||
@tparam Rotation rotation this rotation
|
||||
@treturn string A string showing the x, y, and z values of the rotation
|
||||
@function __tostring
|
||||
*/
|
||||
std::string GameScriptRotation::ToString() const
|
||||
{
|
||||
return "{" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + "}";
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptSettings.h"
|
||||
|
||||
/***
|
||||
Settings that will be run on game startup.
|
||||
@pregameclass Settings
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptSettings::Register(sol::state* lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptSettings>("Settings",
|
||||
"screenWidth", &GameScriptSettings::ScreenWidth,
|
||||
"screenHeight", &GameScriptSettings::ScreenHeight,
|
||||
"enableDynamicShadows", &GameScriptSettings::EnableDynamicShadows,
|
||||
"windowed", &GameScriptSettings::Windowed,
|
||||
"enableWaterCaustics", &GameScriptSettings::EnableWaterCaustics,
|
||||
"drawingDistance", &GameScriptSettings::DrawingDistance,
|
||||
"showRendererSteps", &GameScriptSettings::ShowRendererSteps,
|
||||
"showDebugInfo", &GameScriptSettings::ShowDebugInfo,
|
||||
|
||||
/*** How should the application respond to script errors?
|
||||
Must be one of the following:
|
||||
`ErrorMode.TERMINATE` - print to the log file and terminate the application when any script error is hit.
|
||||
This is the one you will want to go for if you want to know IMMEDIATELY if something has gone wrong.
|
||||
|
||||
`ErrorMode.WARN` - print to the log file and continue running the application when a recoverable script error is hit.
|
||||
Choose this one if terminating the application is too much for you. Note that unrecoverable errors will still terminate
|
||||
the application.
|
||||
|
||||
`ErrorMode.SILENT` - do nothing when a recoverable script error is hit.
|
||||
Think __very__ carefully before using this setting. These error modes are here to help you to keep your scripts
|
||||
working properly, but if you opt to ignore errors, you won't be alerted if you've misused a function or passed
|
||||
an invalid argument.
|
||||
|
||||
As with `ErrorMode.WARN`, unrecoverable errors will still terminate the application.
|
||||
@mem errorMode
|
||||
*/
|
||||
"errorMode", &GameScriptSettings::ErrorMode
|
||||
);
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
#pragma once
|
||||
#include "frameworkandsol.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "GameScriptSinkInfo.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "ScriptUtil.h"
|
||||
/***
|
||||
Sink info
|
||||
|
||||
@entityclass SinkInfo
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
constexpr auto LUA_CLASS_NAME{ "SinkInfo" };
|
||||
|
||||
static auto index_error = index_error_maker(GameScriptSinkInfo, LUA_CLASS_NAME);
|
||||
static auto newindex_error = newindex_error_maker(GameScriptSinkInfo, LUA_CLASS_NAME);
|
||||
|
||||
GameScriptSinkInfo::GameScriptSinkInfo(SINK_INFO & ref, bool temp) : m_sink{ref}, m_temporary{ temp }
|
||||
{};
|
||||
|
||||
GameScriptSinkInfo::~GameScriptSinkInfo() {
|
||||
if (m_temporary)
|
||||
{
|
||||
s_callbackRemoveName(m_sink.luaName);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptSinkInfo::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptSinkInfo>(LUA_CLASS_NAME,
|
||||
sol::meta_function::index, index_error,
|
||||
sol::meta_function::new_index, newindex_error,
|
||||
|
||||
/// (@{Position}) position in level
|
||||
// @mem pos
|
||||
"pos", sol::property(&GameScriptSinkInfo::GetPos, &GameScriptSinkInfo::SetPos),
|
||||
|
||||
/// (string) unique string identifier.
|
||||
// e.g. "strong\_river\_current" or "propeller\_death\_sink"
|
||||
// @mem name
|
||||
"name", sol::property(&GameScriptSinkInfo::GetName, &GameScriptSinkInfo::SetName),
|
||||
|
||||
/// (int) strength.
|
||||
// Strength of the sink, with higher numbers providing stronger currents. Will be clamped to [1, 32].
|
||||
// @mem strength
|
||||
"strength", sol::property(&GameScriptSinkInfo::GetStrength, &GameScriptSinkInfo::SetStrength),
|
||||
|
||||
/// (int) box index.
|
||||
// I don't know what this does and it's not actually in the engine yet
|
||||
// @mem boxIndex
|
||||
"boxIndex", sol::property(&GameScriptSinkInfo::GetBoxIndex, &GameScriptSinkInfo::SetBoxIndex)
|
||||
);
|
||||
}
|
||||
|
||||
GameScriptPosition GameScriptSinkInfo::GetPos() const
|
||||
{
|
||||
return GameScriptPosition{ m_sink.x, m_sink.y, m_sink.z };
|
||||
}
|
||||
|
||||
void GameScriptSinkInfo::SetPos(GameScriptPosition const& pos)
|
||||
{
|
||||
m_sink.x = pos.x;
|
||||
m_sink.y = pos.y;
|
||||
m_sink.z = pos.z;
|
||||
}
|
||||
|
||||
std::string GameScriptSinkInfo::GetName() const
|
||||
{
|
||||
return m_sink.luaName;
|
||||
}
|
||||
|
||||
void GameScriptSinkInfo::SetName(std::string const & id)
|
||||
{
|
||||
ScriptAssert(!id.empty(), "Name cannot be blank", ERROR_MODE::TERMINATE);
|
||||
|
||||
// remove the old name if we have one
|
||||
s_callbackRemoveName(m_sink.luaName);
|
||||
|
||||
// un-register any other sinks using this name.
|
||||
// maybe we should throw an error if another sink
|
||||
// already uses the name...
|
||||
s_callbackRemoveName(id);
|
||||
m_sink.luaName = id;
|
||||
// todo add error checking
|
||||
s_callbackSetName(id, m_sink);
|
||||
}
|
||||
|
||||
int GameScriptSinkInfo::GetStrength() const
|
||||
{
|
||||
return m_sink.strength;
|
||||
}
|
||||
|
||||
void GameScriptSinkInfo::SetStrength(int str)
|
||||
{
|
||||
m_sink.strength = std::clamp(str, 1, 32);
|
||||
}
|
||||
|
||||
int GameScriptSinkInfo::GetBoxIndex() const
|
||||
{
|
||||
|
||||
return m_sink.boxIndex;
|
||||
}
|
||||
|
||||
void GameScriptSinkInfo::SetBoxIndex(int b)
|
||||
{
|
||||
m_sink.boxIndex = b;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "GameScriptSkyLayer.h"
|
||||
|
||||
/*** Describes a layer of moving clouds.
|
||||
As seen in TR4's City of the Dead.
|
||||
|
||||
@pregameclass SkyLayer
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
void GameScriptSkyLayer::Register(sol::state* lua)
|
||||
{
|
||||
lua->new_usertype<GameScriptSkyLayer>("SkyLayer",
|
||||
sol::constructors<GameScriptSkyLayer(GameScriptColor const &, short)>(),
|
||||
|
||||
/// (@{Color}) RGB sky color
|
||||
//@mem color
|
||||
"color", sol::property(&GameScriptSkyLayer::SetColor),
|
||||
|
||||
/*** (int) cloud speed.
|
||||
|
||||
Values can be between [-32768, 32767], with positive numbers resulting in a sky that scrolls from
|
||||
west to east, and negative numbers resulting in one that travels east to west.
|
||||
|
||||
Please note that speeds outside of the range of about [-1000, 1000] will cause the
|
||||
sky to scroll so fast that it will no longer appear as a coherent stream of clouds.
|
||||
Less is more. City of The Dead, for example, uses a speed value of 16.
|
||||
|
||||
@mem speed*/
|
||||
"speed", &GameScriptSkyLayer::CloudSpeed
|
||||
);
|
||||
}
|
||||
|
||||
/***
|
||||
@tparam Color color RGB color
|
||||
@tparam int speed cloud speed
|
||||
@return A SkyLayer object.
|
||||
@function SkyLayer.new
|
||||
*/
|
||||
GameScriptSkyLayer::GameScriptSkyLayer(GameScriptColor const& col, short speed)
|
||||
{
|
||||
SetColor(col);
|
||||
CloudSpeed = speed;
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
void GameScriptSkyLayer::SetColor(GameScriptColor const & col)
|
||||
{
|
||||
R = col.GetR();
|
||||
G = col.GetG();
|
||||
B = col.GetB();
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#include "frameworkandsol.h"
|
||||
#include "ScriptAssert.h"
|
||||
#include "GameScriptSoundSourceInfo.h"
|
||||
#include "GameScriptPosition.h"
|
||||
#include "ScriptUtil.h"
|
||||
/***
|
||||
Sound source info
|
||||
|
||||
@entityclass SoundSourceInfo
|
||||
@pragma nostrip
|
||||
*/
|
||||
|
||||
static constexpr auto LUA_CLASS_NAME{ "SoundSourceInfo" };
|
||||
|
||||
static auto index_error = index_error_maker(GameScriptSoundSourceInfo, LUA_CLASS_NAME);
|
||||
static auto newindex_error = newindex_error_maker(GameScriptSoundSourceInfo, LUA_CLASS_NAME);
|
||||
|
||||
GameScriptSoundSourceInfo::GameScriptSoundSourceInfo(SOUND_SOURCE_INFO & ref, bool temp) : m_soundSource{ref}, m_temporary{ temp }
|
||||
{};
|
||||
|
||||
GameScriptSoundSourceInfo::~GameScriptSoundSourceInfo() {
|
||||
if (m_temporary)
|
||||
{
|
||||
s_callbackRemoveName(m_soundSource.luaName);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScriptSoundSourceInfo::Register(sol::state* state)
|
||||
{
|
||||
state->new_usertype<GameScriptSoundSourceInfo>(LUA_CLASS_NAME,
|
||||
sol::meta_function::index, index_error,
|
||||
sol::meta_function::new_index, newindex_error,
|
||||
|
||||
/// (@{Position}) position in level
|
||||
// @mem pos
|
||||
"pos", sol::property(&GameScriptSoundSourceInfo::GetPos, &GameScriptSoundSourceInfo::SetPos),
|
||||
|
||||
/// (string) unique string identifier.
|
||||
// e.g. "machine\_sound\_1" or "discordant\_humming"
|
||||
// @mem name
|
||||
"name", sol::property(&GameScriptSoundSourceInfo::GetName, &GameScriptSoundSourceInfo::SetName),
|
||||
|
||||
/// (int) sound ID
|
||||
// @mem soundID
|
||||
"soundID", sol::property(&GameScriptSoundSourceInfo::GetSoundID, &GameScriptSoundSourceInfo::SetSoundID),
|
||||
|
||||
/// (int) flags
|
||||
// @mem flags
|
||||
"flags", sol::property(&GameScriptSoundSourceInfo::GetFlags, &GameScriptSoundSourceInfo::SetFlags)
|
||||
);
|
||||
}
|
||||
|
||||
GameScriptPosition GameScriptSoundSourceInfo::GetPos() const
|
||||
{
|
||||
return GameScriptPosition{ m_soundSource.x, m_soundSource.y, m_soundSource.z };
|
||||
}
|
||||
|
||||
void GameScriptSoundSourceInfo::SetPos(GameScriptPosition const& pos)
|
||||
{
|
||||
m_soundSource.x = pos.x;
|
||||
m_soundSource.y = pos.y;
|
||||
m_soundSource.z = pos.z;
|
||||
}
|
||||
|
||||
std::string GameScriptSoundSourceInfo::GetName() const
|
||||
{
|
||||
return m_soundSource.luaName;
|
||||
}
|
||||
|
||||
void GameScriptSoundSourceInfo::SetName(std::string const & id)
|
||||
{
|
||||
ScriptAssert(!id.empty(), "Name cannot be blank", ERROR_MODE::TERMINATE);
|
||||
|
||||
// remove the old name if we have one
|
||||
s_callbackRemoveName(m_soundSource.luaName);
|
||||
|
||||
// un-register any other objects using this name.
|
||||
// maybe we should throw an error if another object
|
||||
// already uses the name...
|
||||
s_callbackRemoveName(id);
|
||||
m_soundSource.luaName = id;
|
||||
// todo add error checking
|
||||
s_callbackSetName(id, m_soundSource);
|
||||
}
|
||||
|
||||
int GameScriptSoundSourceInfo::GetSoundID() const
|
||||
{
|
||||
return m_soundSource.soundId;
|
||||
}
|
||||
|
||||
void GameScriptSoundSourceInfo::SetSoundID(int soundID)
|
||||
{
|
||||
m_soundSource.soundId = soundID;
|
||||
}
|
||||
|
||||
int GameScriptSoundSourceInfo::GetFlags() const
|
||||
{
|
||||
return m_soundSource.flags;
|
||||
}
|
||||
|
||||
void GameScriptSoundSourceInfo::SetFlags(int flags)
|
||||
{
|
||||
m_soundSource.flags = flags;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
#include "framework.h"
|
||||
#include "LuaHandler.h"
|
||||
|
||||
LuaHandler::LuaHandler(sol::state* lua) {
|
||||
m_lua = lua;
|
||||
}
|
||||
|
||||
void LuaHandler::ExecuteScript(std::string const& luaFilename) {
|
||||
auto result = m_lua->safe_script_file(luaFilename, sol::script_pass_on_error);
|
||||
if (!result.valid())
|
||||
{
|
||||
sol::error error = result;
|
||||
throw TENScriptException{ error.what() };
|
||||
}
|
||||
}
|
||||
|
||||
void LuaHandler::ExecuteString(std::string const & command) {
|
||||
auto result = m_lua->safe_script(command, sol::environment(m_lua->lua_state(), sol::create, m_lua->globals()), sol::script_pass_on_error);
|
||||
if (!result.valid())
|
||||
{
|
||||
sol::error error = result;
|
||||
throw TENScriptException{ error.what() };
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
#include "framework.h"
|
||||
#include "ScriptAssert.h"
|
||||
|
||||
static ERROR_MODE ScriptErrorMode = ERROR_MODE::WARN;
|
||||
|
||||
void ScriptWarn(std::string const& msg)
|
||||
{
|
||||
switch (ScriptErrorMode)
|
||||
{
|
||||
case ERROR_MODE::TERMINATE:
|
||||
case ERROR_MODE::WARN:
|
||||
TENLog(msg, LogLevel::Warning, LogConfig::All);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ScriptAssert(bool cond, std::string const& msg, std::optional<ERROR_MODE> forceMode)
|
||||
{
|
||||
if (!cond)
|
||||
{
|
||||
ERROR_MODE mode = forceMode ? *forceMode : ScriptErrorMode;
|
||||
switch (mode)
|
||||
{
|
||||
case ERROR_MODE::WARN:
|
||||
TENLog(msg, LogLevel::Error, LogConfig::All);
|
||||
break;
|
||||
case ERROR_MODE::TERMINATE:
|
||||
TENLog(msg, LogLevel::Error, LogConfig::All);
|
||||
throw TENScriptException(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cond;
|
||||
}
|
||||
|
||||
|
||||
void SetScriptErrorMode(ERROR_MODE mode)
|
||||
{
|
||||
ScriptErrorMode = mode;
|
||||
}
|
||||
|
||||
ERROR_MODE GetScriptErrorMode()
|
||||
{
|
||||
return ScriptErrorMode;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue