New streams class; Refactored chunk IO; Added chunk writer; Started new savegame system;

This commit is contained in:
MontyTRC89 2018-10-01 22:22:11 +02:00
parent c7995dae7f
commit 5c376c0f95
22 changed files with 1312 additions and 118 deletions

Binary file not shown.

View file

@ -224,14 +224,6 @@ GAME_STATUS __cdecl ControlPhase(__int32 numFrames, __int32 demoMode)
return GAME_STATUS::GAME_STATUS_NONE; return GAME_STATUS::GAME_STATUS_NONE;
} }
void __cdecl j_AnimateItem(ITEM_INFO* item)
{
if (item != LaraItem)
printf("AnimateItem\n");
AnimateItem(item);
}
unsigned __stdcall GameMain(void*) unsigned __stdcall GameMain(void*)
{ {
DB_Log(2, "GameMain - DLL"); DB_Log(2, "GameMain - DLL");
@ -875,5 +867,5 @@ void __cdecl TestTriggers(__int16* data, __int32 heavy, __int32 HeavyFlags)
void Inject_Control() void Inject_Control()
{ {
INJECT(0x0040261C, j_AnimateItem);
} }

View file

@ -2,24 +2,12 @@
#include "..\Global\global.h" #include "..\Global\global.h"
typedef enum GAME_STATUS {
GAME_STATUS_NONE,
GAME_STATUS_NEW_GAME,
GAME_STATUS_LOAD_GAME,
GAME_STATUS_SAVE_GAME,
GAME_STATUS_EXIT_TO_TITLE,
GAME_STATUS_EXIT_GAME,
GAME_STATUS_LARA_DEAD,
GAME_STATUS_LEVEL_COMPLETED
};
#define GetFloor ((FLOOR_INFO* (__cdecl*)(int, int, int, short*)) 0x00415B20) #define GetFloor ((FLOOR_INFO* (__cdecl*)(int, int, int, short*)) 0x00415B20)
#define GetCeiling ((int (__cdecl*)(FLOOR_INFO*, int, int, int)) 0x00417640) #define GetCeiling ((int (__cdecl*)(FLOOR_INFO*, int, int, int)) 0x00417640)
#define GetFloorHeight ((int (__cdecl*)(FLOOR_INFO*, int, int, int)) 0x00415FB0) #define GetFloorHeight ((int (__cdecl*)(FLOOR_INFO*, int, int, int)) 0x00415FB0)
#define GetRandomControl ((int (__cdecl*)()) 0x004A7C10) #define GetRandomControl ((int (__cdecl*)()) 0x004A7C10)
#define AnimateItem ((void (__cdecl*)(ITEM_INFO*)) 0x00415300) #define AnimateItem ((void (__cdecl*)(ITEM_INFO*)) 0x00415300)
#define GetWaterHeight ((__int32 (__cdecl*)(__int32, __int32, __int32, __int16)) 0x00415DA0) #define GetWaterHeight ((__int32 (__cdecl*)(__int32, __int32, __int32, __int16)) 0x00415DA0)
//#define TestTriggers ((void (__cdecl*)(__int16*, __int32, __int32)) 0x00416760)
#define TriggerActive ((__int32 (__cdecl*)(ITEM_INFO*)) 0x004175B0) #define TriggerActive ((__int32 (__cdecl*)(ITEM_INFO*)) 0x004175B0)
#define GetChange ((__int32 (__cdecl*)(ITEM_INFO*, ANIM_STRUCT*)) 0x00415890) #define GetChange ((__int32 (__cdecl*)(ITEM_INFO*, ANIM_STRUCT*)) 0x00415890)
#define KillMoveItems ((void (__cdecl*)()) 0x00414620) #define KillMoveItems ((void (__cdecl*)()) 0x00414620)
@ -55,7 +43,6 @@ GAME_STATUS __cdecl DoLevel(__int32 index, __int32 ambient, bool loadFromSavegam
GAME_STATUS __cdecl ControlPhase(__int32 numFrames, __int32 demoMode); GAME_STATUS __cdecl ControlPhase(__int32 numFrames, __int32 demoMode);
unsigned __stdcall GameMain(void*); unsigned __stdcall GameMain(void*);
void __cdecl j_AnimateItem(ITEM_INFO* item);
void __cdecl TestTriggers(__int16* data, __int32 heavy, __int32 HeavyFlags); void __cdecl TestTriggers(__int16* data, __int32 heavy, __int32 HeavyFlags);
void Inject_Control(); void Inject_Control();

View file

@ -0,0 +1,117 @@
#include "savegame.h"
#include "..\Global\global.h"
FileStream* SaveGame::m_stream;
ChunkReader* SaveGame::m_reader;
ChunkWriter* SaveGame::m_writer;
ChunkId* SaveGame::m_chunkHeader;
ChunkId* SaveGame::m_chunkGameStatus;
ChunkId* SaveGame::m_chunkItems;
ChunkId* SaveGame::m_chunkItem;
ChunkId* SaveGame::m_chunkLara;
ChunkId* SaveGame::m_chunkLuaVariables;
ChunkId* SaveGame::m_chunkLuaLocal;
ChunkId* SaveGame::m_chunkLuaGlobal;
void SaveGame::SaveHeader(__int32 param)
{
m_stream->WriteString(g_GameFlow->GetString(g_GameFlow->GetLevel(CurrentLevel)->Name));
LEB128::Write(m_stream, (Savegame.Game.Timer / 30) / 86400);
LEB128::Write(m_stream, ((Savegame.Game.Timer / 30) % 86400) / 3600);
LEB128::Write(m_stream, ((Savegame.Game.Timer / 30) / 60) % 60);
LEB128::Write(m_stream, (Savegame.Game.Timer / 30) % 60);
LEB128::Write(m_stream, CurrentLevel);
}
void SaveGame::SaveGameStatus(__int32 param)
{
}
void SaveGame::SaveItems(__int32 param)
{
for (__int32 i = 0; i < NumItems; i++)
{
m_writer->WriteChunk(m_chunkItem, &SaveItem, i);
}
}
void SaveGame::SaveItem(__int32 itemNumber)
{
ITEM_INFO* item = &Items[itemNumber];
OBJECT_INFO* obj = &Objects[item->objectNumber];
LEB128::Write(m_stream, item->flags);
LEB128::Write(m_stream, item->pos.xPos);
LEB128::Write(m_stream, item->pos.yPos);
LEB128::Write(m_stream, item->pos.zPos);
LEB128::Write(m_stream, item->pos.xRot);
LEB128::Write(m_stream, item->pos.yRot);
LEB128::Write(m_stream, item->pos.zRot);
LEB128::Write(m_stream, item->roomNumber);
LEB128::Write(m_stream, item->itemFlags[0]);
LEB128::Write(m_stream, item->itemFlags[1]);
LEB128::Write(m_stream, item->itemFlags[2]);
LEB128::Write(m_stream, item->itemFlags[3]);
LEB128::Write(m_stream, item->triggerFlags);
LEB128::Write(m_stream, item->timer);
LEB128::Write(m_stream, item->speed);
LEB128::Write(m_stream, item->fallspeed);
LEB128::Write(m_stream, item->currentAnimState);
LEB128::Write(m_stream, item->goalAnimState);
LEB128::Write(m_stream, item->requiredAnimState);
LEB128::Write(m_stream, item->animNumber);
LEB128::Write(m_stream, item->frameNumber);
LEB128::Write(m_stream, item->objectNumber);
LEB128::Write(m_stream, item->hitPoints);
}
void SaveGame::SaveLara(__int32 param)
{
LARA_INFO lara;
memcpy(&lara, &Lara, sizeof(Lara));
for (__int32 i = 0; i < 15; i++)
lara.meshPtrs[i] = (__int16*)(lara.meshPtrs[i] - MeshBase);
lara.leftArm.frameBase = (__int16*)(lara.leftArm.frameBase - Objects[ID_PISTOLS_ANIM].frameBase);
lara.rightArm.frameBase = (__int16*)(lara.rightArm.frameBase - Objects[ID_PISTOLS_ANIM].frameBase);
m_stream->Write(reinterpret_cast<char*>(&lara), sizeof(Lara));
}
bool SaveGame::Save(char* fileName)
{
m_chunkHeader = ChunkId::FromString("TR5MSgHeader");
m_chunkGameStatus = ChunkId::FromString("TR5MSgGameStatus");
m_chunkItems = ChunkId::FromString("TR5MSgItems");
m_chunkItem = ChunkId::FromString("TR5MSgItem");
m_chunkLara = ChunkId::FromString("TR5MSgLara");
m_chunkLuaVariables = ChunkId::FromString("TR5MSgLuaVars");
m_chunkLuaLocal = ChunkId::FromString("TR5MSgLuaL");
m_chunkLuaGlobal = ChunkId::FromString("TR5MSgLuaG");
m_stream = new FileStream(fileName);
m_writer = new ChunkWriter(0x4D355254, m_stream);
m_writer->WriteChunk(m_chunkHeader, &SaveHeader, 0);
m_writer->WriteChunk(m_chunkLara, &SaveLara, 0);
m_writer->WriteChunkWithChildren(m_chunkItems, &SaveItems, 0);
m_stream->Close();
delete m_writer;
delete m_stream;
delete m_chunkHeader;
delete m_chunkGameStatus;
delete m_chunkItems;
delete m_chunkItem;
delete m_chunkLara;
delete m_chunkLuaVariables;
delete m_chunkLuaLocal;
delete m_chunkLuaGlobal;
return true;
}

View file

@ -1,8 +1,45 @@
#pragma once #pragma once
#include "..\Global\global.h"
#include "..\Specific\IO\ChunkId.h"
#include "..\Specific\IO\ChunkReader.h"
#include "..\Specific\IO\ChunkWriter.h"
#include "..\Specific\IO\LEB128.h"
#include "..\Specific\IO\Streams.h"
#include "..\Scripting\GameFlowScript.h"
#include "..\Scripting\GameLogicScript.h"
#define RestoreGame ((__int32 (__cdecl*)()) 0x00472060) #define RestoreGame ((__int32 (__cdecl*)()) 0x00472060)
#define ReadSavegame ((__int32 (__cdecl*)(__int32)) 0x004A8E10) #define ReadSavegame ((__int32 (__cdecl*)(__int32)) 0x004A8E10)
#define CreateSavegame ((void (__cdecl*)()) 0x00470FA0) #define CreateSavegame ((void (__cdecl*)()) 0x00470FA0)
#define WriteSavegame ((__int32 (__cdecl*)(__int32)) 0x004A8BC0) #define WriteSavegame ((__int32 (__cdecl*)(__int32)) 0x004A8BC0)
#define SAVEGAME_BUFFER_SIZE 1048576
extern GameFlow* g_GameFlow;
extern GameScript* g_GameScript;
class SaveGame {
private:
static FileStream* m_stream;
static ChunkReader* m_reader;
static ChunkWriter* m_writer;
static ChunkId* m_chunkHeader;
static ChunkId* m_chunkGameStatus;
static ChunkId* m_chunkItems;
static ChunkId* m_chunkItem;
static ChunkId* m_chunkLara;
static ChunkId* m_chunkLuaVariables;
static ChunkId* m_chunkLuaLocal;
static ChunkId* m_chunkLuaGlobal;
static void SaveHeader(__int32 param);
static void SaveGameStatus(__int32 param);
static void SaveLara(__int32 param);
static void SaveItem(__int32 param);
static void SaveItems(__int32 param);
public:
static bool Save(char* fileName);
};

View file

@ -17,7 +17,7 @@
#define BOX_BLOCKED (1 << 14) // unpassable for other enemies, always set for movable blocks & closed doors #define BOX_BLOCKED (1 << 14) // unpassable for other enemies, always set for movable blocks & closed doors
#define BOX_LAST (1 << 15) // unpassable by large enemies (T-Rex, Centaur, etc), always set behind doors #define BOX_LAST (1 << 15) // unpassable by large enemies (T-Rex, Centaur, etc), always set behind doors
#define NUM_OBJECTS 488 #define NUM_OBJECTS 518
#define UNIT_SHADOW 256 #define UNIT_SHADOW 256
#define DEFAULT_RADIUS 10 #define DEFAULT_RADIUS 10

View file

@ -897,3 +897,14 @@ enum WEATHER_TYPES
WEATHER_RAIN = 1, WEATHER_RAIN = 1,
WEATHER_SNOW = 2 WEATHER_SNOW = 2
}; };
enum GAME_STATUS {
GAME_STATUS_NONE,
GAME_STATUS_NEW_GAME,
GAME_STATUS_LOAD_GAME,
GAME_STATUS_SAVE_GAME,
GAME_STATUS_EXIT_TO_TITLE,
GAME_STATUS_EXIT_GAME,
GAME_STATUS_LARA_DEAD,
GAME_STATUS_LEVEL_COMPLETED
};

View file

@ -11,6 +11,7 @@
#define ONE_DEGREE 182 #define ONE_DEGREE 182
#define ANGLE(x) ((x) * 65536.0 / 360.0) #define ANGLE(x) ((x) * 65536.0 / 360.0)
#define TR_ANGLE_TO_DEGREES(x) ((x) / 65536.0 * 360.0)
#define TR_ANGLE_TO_RAD(x) ((x) / 65536.0 * 360.0 * RADIAN) #define TR_ANGLE_TO_RAD(x) ((x) / 65536.0 * 360.0 * RADIAN)
#define SQRT_ASM ((int (__cdecl*)(int)) 0x0048F980) #define SQRT_ASM ((int (__cdecl*)(int)) 0x0048F980)

View file

@ -489,5 +489,35 @@ typedef enum object_types {
ID_NEW_SLOT_485, ID_NEW_SLOT_485,
ID_NEW_SLOT_486, ID_NEW_SLOT_486,
ID_NEW_SLOT_487, ID_NEW_SLOT_487,
ID_NEW_SLOT_488 ID_NEW_SLOT_488,
ID_NEW_SLOT_489,
ID_NEW_SLOT_490,
ID_NEW_SLOT_491,
ID_NEW_SLOT_492,
ID_NEW_SLOT_493,
ID_NEW_SLOT_494,
ID_NEW_SLOT_495,
ID_NEW_SLOT_496,
ID_NEW_SLOT_497,
ID_NEW_SLOT_498,
ID_NEW_SLOT_499,
ID_NEW_SLOT_500,
ID_NEW_SLOT_501,
ID_NEW_SLOT_502,
ID_NEW_SLOT_503,
ID_NEW_SLOT_504,
ID_NEW_SLOT_505,
ID_NEW_SLOT_506,
ID_NEW_SLOT_507,
ID_NEW_SLOT_508,
ID_NEW_SLOT_509,
ID_NEW_SLOT_510,
ID_NEW_SLOT_511,
ID_NEW_SLOT_512,
ID_NEW_SLOT_513,
ID_NEW_SLOT_514,
ID_NEW_SLOT_515,
ID_NEW_SLOT_516,
ID_NEW_SLOT_517,
ID_NEW_SLOT_518
} GAME_OBJECT_ID; } GAME_OBJECT_ID;

View file

@ -52,11 +52,14 @@
#define FloorData VAR_U_(0x00875168, __int16*) #define FloorData VAR_U_(0x00875168, __int16*)
#define ObjectTextures VAR_U_(0x008751B0, OBJECT_TEXTURE*) #define ObjectTextures VAR_U_(0x008751B0, OBJECT_TEXTURE*)
#define RoomLightsCount VAR_U_(0x0087B0EC, __int32) #define RoomLightsCount VAR_U_(0x0087B0EC, __int32)
#define LevelDataPtr VAR_U_(0x00874964, char*) //#define LevelDataPtr VAR_U_(0x00874964, char*)
#define NumberRooms VAR_U_(0x0087514C, __int16) #define NumberRooms VAR_U_(0x0087514C, __int16)
#define nAnimUVRanges VAR_U_(0x0087495C, __int32) #define nAnimUVRanges VAR_U_(0x0087495C, __int32)
#define LevelFilePtr VAR_U_(0x00875164, FILE*) #define LevelFilePtr VAR_U_(0x00875164, FILE*)
//#define StaticObjects ARRAY_(0x00874988, STATIC_INFO, [70]) //#define StaticObjects ARRAY_(0x00874988, STATIC_INFO, [70])
#define NumberCameras VAR_U_(0x00EEFAC0, __int32)
#define Cameras VAR_U_(0x00EEF9A2, OBJECT_VECTOR*)
#define NumberSpotcams VAR_U_(0x00E4F428, __int32)
// Lara // Lara
#define LaraItem VAR_U_(0x00E5BF08, ITEM_INFO*) #define LaraItem VAR_U_(0x00E5BF08, ITEM_INFO*)
@ -122,8 +125,8 @@
#define AllStringsOffsets VAR_U_(0x00E5C2B8, __int16*) #define AllStringsOffsets VAR_U_(0x00E5C2B8, __int16*)
#define RenderLoadBar VAR_U_(0x008FBDC0, __int32) #define RenderLoadBar VAR_U_(0x008FBDC0, __int32)
#define IsLevelLoading VAR_U_(0x00874968, __int32) //#define IsLevelLoading VAR_U_(0x00874968, __int32)
#define ThreadId VAR_U_(0x00874978, unsigned int) //#define ThreadId VAR_U_(0x00874978, unsigned int)
#define WeatherType VAR_U_(0x00EEF4A0, byte) #define WeatherType VAR_U_(0x00EEF4A0, byte)
#define CreditsDone VAR_U_(0x00E6D838, byte) #define CreditsDone VAR_U_(0x00E6D838, byte)
#define CanLoad VAR_U_(0x0051CE54, byte) #define CanLoad VAR_U_(0x0051CE54, byte)

View file

@ -10,14 +10,37 @@ GameScript::GameScript(sol::state* lua)
{ {
m_lua = lua; m_lua = lua;
// Add constants
(*m_lua)["HIT_POINTS"] = ITEM_PARAM_HIT_POINTS; (*m_lua)["HIT_POINTS"] = ITEM_PARAM_HIT_POINTS;
(*m_lua)["CURRENT_ANIM_STATE"] = ITEM_PARAM_CURRENT_ANIM_STATE; (*m_lua)["CURRENT_ANIM_STATE"] = ITEM_PARAM_CURRENT_ANIM_STATE;
(*m_lua)["ANIM_NUMBER"] = ITEM_PARAM_ANIM_NUMBER; (*m_lua)["ANIM_NUMBER"] = ITEM_PARAM_ANIM_NUMBER;
(*m_lua)["GOAL_ANIM_STATE"] = ITEM_PARAM_GOAL_ANIM_STATE;
(*m_lua)["REQUIRED_ANIM_STATE"] = ITEM_PARAM_REQUIRED_ANIM_STATE;
(*m_lua)["FRAME_NUMBER"] = ITEM_PARAM_FRAME_NUMBER;
(*m_lua)["HIT_POINTS"] = ITEM_PARAM_HIT_POINTS;
(*m_lua)["HIT_STATUS"] = ITEM_PARAM_HIT_STATUS;
(*m_lua)["GRAVITY_STATUS"] = ITEM_PARAM_GRAVITY_STATUS;
(*m_lua)["COLLIDABLE"] = ITEM_PARAM_COLLIDABLE;
(*m_lua)["POISONED"] = ITEM_PARAM_POISONED;
(*m_lua)["ROOM_NUMBER"] = ITEM_PARAM_ROOM_NUMBER;
// Add the item type
m_lua->new_usertype<GameScriptItemPosition>("ItemPosition",
"x", &GameScriptItemPosition::x,
"y", &GameScriptItemPosition::y,
"z", &GameScriptItemPosition::z,
"xRot", &GameScriptItemPosition::xRot,
"yRot", &GameScriptItemPosition::yRot,
"zRot", &GameScriptItemPosition::zRot,
"room", &GameScriptItemPosition::room
);
m_lua->new_usertype<GameScriptItem>("Item", m_lua->new_usertype<GameScriptItem>("Item",
sol::constructors<GameScriptItem(ITEM_INFO*)>(),
"Get", &GameScriptItem::Get, "Get", &GameScriptItem::Get,
"Set", &GameScriptItem::Set "Set", &GameScriptItem::Set,
"GetPosition", &GameScriptItem::GetItemPosition,
"SetPosition", &GameScriptItem::SetItemPosition,
"SetRotation", &GameScriptItem::SetItemRotation
); );
// GameScript type // GameScript type
@ -31,22 +54,16 @@ GameScript::GameScript(sol::state* lua)
"SetSecretsCount", &GameScript::SetSecretsCount, "SetSecretsCount", &GameScript::SetSecretsCount,
"AddOneSecret", &GameScript::AddOneSecret, "AddOneSecret", &GameScript::AddOneSecret,
"JumpToLevel", &GameScript::JumpToLevel, "JumpToLevel", &GameScript::JumpToLevel,
"GetItem", &GameScript::GetItem "GetItem", &GameScript::GetItem,
"PlaySoundEffect", &GameScript::PlaySoundEffect,
"PlaySoundEffectAtPosition", &GameScript::PlaySoundEffectAtPosition
); );
// Add global variables and namespaces
(*m_lua)["TR"] = this; (*m_lua)["TR"] = this;
// DEBUG: just for testing m_locals = (*m_lua).create_table("Locals");
LuaFunction* function = new LuaFunction(); m_globals = (*m_lua).create_table("Globals");
function->Name = "Trigger_0";
function->Code = "function Trigger_0() \n TR:EnableItem(2); \n TR:PlayAudioTrack(15); \n item = TR:GetItem(2); \n item:Set(HIT_POINTS, -16384); \n return true; \n end";
m_lua->script(function->Code);
Triggers.push_back(function);
m_itemsMap.insert(pair<__int16, __int16>(0, 0));
m_itemsMap.insert(pair<__int16, __int16>(9, 9));
m_itemsMap.insert(pair<__int16, __int16>(10, 10));
m_itemsMap.insert(pair<__int16, __int16>(2, 8));
} }
GameScript::~GameScript() GameScript::~GameScript()
@ -56,22 +73,32 @@ GameScript::~GameScript()
void GameScript::AddTrigger(LuaFunction* function) void GameScript::AddTrigger(LuaFunction* function)
{ {
Triggers.push_back(function); m_triggers.push_back(function);
(*m_lua).script(function->Code); (*m_lua).script(function->Code);
} }
void GameScript::AddLuaId(int luaId, int itemId)
{
m_itemsMap.insert(pair<__int32, __int32>(luaId, itemId));
}
void GameScript::FreeLevelScripts() void GameScript::FreeLevelScripts()
{ {
// Delete all triggers // Delete all triggers
for (__int32 i = 0; i < Triggers.size(); i++) for (__int32 i = 0; i < m_triggers.size(); i++)
{ {
LuaFunction* trigger = Triggers[i]; LuaFunction* trigger = m_triggers[i];
char* name = (char*)trigger->Name.c_str(); char* name = (char*)trigger->Name.c_str();
(*m_lua)[name] = NULL; (*m_lua)[name] = NULL;
delete Triggers[i]; delete m_triggers[i];
} }
m_triggers.clear();
Triggers.clear(); // Clear the items mapping
m_itemsMap.clear();
(*m_lua)["Lara"] = NULL;
//delete m_Lara;
} }
string GameScript::loadScriptFromFile(char* luaFilename) string GameScript::loadScriptFromFile(char* luaFilename)
@ -98,10 +125,10 @@ bool GameScript::ExecuteScript(char* luaFilename)
bool GameScript::ExecuteTrigger(__int16 index) bool GameScript::ExecuteTrigger(__int16 index)
{ {
// Is this a valid trigger? // Is this a valid trigger?
if (index >= Triggers.size()) if (index >= m_triggers.size())
return true; return true;
LuaFunction* trigger = Triggers[index]; LuaFunction* trigger = m_triggers[index];
// We want to execute a trigger just one time // We want to execute a trigger just one time
// TODO: implement in the future continoous trigger? // TODO: implement in the future continoous trigger?
@ -115,7 +142,16 @@ bool GameScript::ExecuteTrigger(__int16 index)
bool result = (*m_lua)[name](); bool result = (*m_lua)[name]();
// Trigger was executed, don't execute it anymore // Trigger was executed, don't execute it anymore
Triggers[index]->Executed = result; trigger->Executed = result;
m_locals.for_each([&](sol::object const& key, sol::object const& value) {
if (value.is<bool>())
std::cout << key.as<string>() << " " << value.as<bool>() << std::endl;
else if (value.is<string>())
std::cout << key.as<string>() << " " << value.as<string>() << std::endl;
else
std::cout << key.as<string>() << " " << value.as<int>() << std::endl;
});
return result; return result;
} }
@ -259,13 +295,52 @@ void GameScript::MakeItemInvisible(__int16 id)
GameScriptItem GameScript::GetItem(__int16 id) GameScriptItem GameScript::GetItem(__int16 id)
{ {
if (m_itemsMap.find(id) == m_itemsMap.end()) if (m_itemsMap.find(id) == m_itemsMap.end())
return NULL; throw "Item not found";
__int16 itemNum = m_itemsMap[id]; __int16 itemNum = m_itemsMap[id];
ITEM_INFO* item = &Items[itemNum]; return m_items[itemNum];
GameScriptItem scriptItem = GameScriptItem(item); }
return scriptItem; void GameScript::PlaySoundEffectAtPosition(__int16 id, __int32 x, __int32 y, __int32 z, __int32 flags)
{
PHD_3DPOS pos;
pos.xPos = x;
pos.yPos = y;
pos.zPos = z;
pos.xRot = 0;
pos.yRot = 0;
pos.zRot = 0;
SoundEffect(id, &pos, flags);
}
void GameScript::PlaySoundEffect(__int16 id, __int32 flags)
{
SoundEffect(id, NULL, flags);
}
void GameScript::AssignVariables()
{
for (__int32 i = 0; i < NUM_ITEMS; i++)
m_items[i].NativeItem = NULL;
for (__int32 i = 0; i < NumItems; i++)
m_items[i].NativeItem = &Items[i];
(*m_lua)["Lara"] = m_items[Lara.itemNumber];
}
void GameScript::ResetVariables()
{
(*m_lua)["Lara"] = NULL;
}
void GameScript::SetItem(__int32 index, ITEM_INFO* item)
{
if (index >= NUM_ITEMS)
return;
m_items[index].NativeItem = item;
} }
GameScript* g_GameScript; GameScript* g_GameScript;

View file

@ -20,6 +20,7 @@ using namespace std;
#define ITEM_PARAM_GRAVITY_STATUS 7 #define ITEM_PARAM_GRAVITY_STATUS 7
#define ITEM_PARAM_COLLIDABLE 8 #define ITEM_PARAM_COLLIDABLE 8
#define ITEM_PARAM_POISONED 9 #define ITEM_PARAM_POISONED 9
#define ITEM_PARAM_ROOM_NUMBER 10
typedef struct LuaFunction { typedef struct LuaFunction {
string Name; string Name;
@ -27,40 +28,48 @@ typedef struct LuaFunction {
bool Executed; bool Executed;
}; };
typedef struct GameScriptItem { typedef struct GameScriptItemPosition {
private: __int32 x;
ITEM_INFO* m_item; __int32 y;
__int32 z;
__int16 xRot;
__int16 yRot;
__int16 zRot;
__int16 room;
};
public: typedef struct GameScriptItem {
GameScriptItem(ITEM_INFO* item) ITEM_INFO* NativeItem;
{
m_item = item;
}
__int16 Get(__int32 param) __int16 Get(__int32 param)
{ {
if (NativeItem == NULL)
return 0;
switch (param) switch (param)
{ {
case ITEM_PARAM_CURRENT_ANIM_STATE: case ITEM_PARAM_CURRENT_ANIM_STATE:
return m_item->currentAnimState; return NativeItem->currentAnimState;
case ITEM_PARAM_REQUIRED_ANIM_STATE: case ITEM_PARAM_REQUIRED_ANIM_STATE:
return m_item->requiredAnimState; return NativeItem->requiredAnimState;
case ITEM_PARAM_GOAL_ANIM_STATE: case ITEM_PARAM_GOAL_ANIM_STATE:
return m_item->goalAnimState; return NativeItem->goalAnimState;
case ITEM_PARAM_ANIM_NUMBER: case ITEM_PARAM_ANIM_NUMBER:
return m_item->animNumber; return NativeItem->animNumber;
case ITEM_PARAM_FRAME_NUMBER: case ITEM_PARAM_FRAME_NUMBER:
return m_item->frameNumber; return NativeItem->frameNumber;
case ITEM_PARAM_HIT_POINTS: case ITEM_PARAM_HIT_POINTS:
return m_item->hitPoints; return NativeItem->hitPoints;
case ITEM_PARAM_HIT_STATUS: case ITEM_PARAM_HIT_STATUS:
return m_item->hitStatus; return NativeItem->hitStatus;
case ITEM_PARAM_GRAVITY_STATUS: case ITEM_PARAM_GRAVITY_STATUS:
return m_item->gravityStatus; return NativeItem->gravityStatus;
case ITEM_PARAM_COLLIDABLE: case ITEM_PARAM_COLLIDABLE:
return m_item->collidable; return NativeItem->collidable;
case ITEM_PARAM_POISONED: case ITEM_PARAM_POISONED:
return m_item->poisoned; return NativeItem->poisoned;
case ITEM_PARAM_ROOM_NUMBER:
return NativeItem->roomNumber;
default: default:
return 0; return 0;
} }
@ -68,53 +77,102 @@ public:
void Set(__int32 param, __int16 value) void Set(__int32 param, __int16 value)
{ {
if (NativeItem == NULL)
return;
switch (param) switch (param)
{ {
case ITEM_PARAM_CURRENT_ANIM_STATE: case ITEM_PARAM_CURRENT_ANIM_STATE:
m_item->currentAnimState = value; break; NativeItem->currentAnimState = value; break;
case ITEM_PARAM_REQUIRED_ANIM_STATE: case ITEM_PARAM_REQUIRED_ANIM_STATE:
m_item->requiredAnimState = value; break; NativeItem->requiredAnimState = value; break;
case ITEM_PARAM_GOAL_ANIM_STATE: case ITEM_PARAM_GOAL_ANIM_STATE:
m_item->goalAnimState = value; break; NativeItem->goalAnimState = value; break;
case ITEM_PARAM_ANIM_NUMBER: case ITEM_PARAM_ANIM_NUMBER:
m_item->animNumber = value; NativeItem->animNumber = value;
m_item->frameNumber = Anims[m_item->animNumber].frameBase; NativeItem->frameNumber = Anims[NativeItem->animNumber].frameBase;
break; break;
case ITEM_PARAM_FRAME_NUMBER: case ITEM_PARAM_FRAME_NUMBER:
m_item->frameNumber = value; break; NativeItem->frameNumber = value; break;
case ITEM_PARAM_HIT_POINTS: case ITEM_PARAM_HIT_POINTS:
m_item->hitPoints = value; break; NativeItem->hitPoints = value; break;
case ITEM_PARAM_HIT_STATUS: case ITEM_PARAM_HIT_STATUS:
m_item->hitStatus = value; break; NativeItem->hitStatus = value; break;
case ITEM_PARAM_GRAVITY_STATUS: case ITEM_PARAM_GRAVITY_STATUS:
m_item->gravityStatus = value; break; NativeItem->gravityStatus = value; break;
case ITEM_PARAM_COLLIDABLE: case ITEM_PARAM_COLLIDABLE:
m_item->collidable = value; break; NativeItem->collidable = value; break;
case ITEM_PARAM_POISONED: case ITEM_PARAM_POISONED:
m_item->poisoned = value; break; NativeItem->poisoned = value; break;
case ITEM_PARAM_ROOM_NUMBER:
NativeItem->roomNumber = value; break;
default: default:
break; break;
} }
} }
GameScriptItemPosition GetItemPosition()
{
GameScriptItemPosition pos;
//if (m_item == NULL)
// return pos;
pos.x = NativeItem->pos.xPos;
pos.y = NativeItem->pos.yPos;
pos.z = NativeItem->pos.zPos;
pos.xRot = TR_ANGLE_TO_DEGREES(NativeItem->pos.xRot);
pos.yRot = TR_ANGLE_TO_DEGREES(NativeItem->pos.yRot);
pos.zRot = TR_ANGLE_TO_DEGREES(NativeItem->pos.zRot);
pos.room = NativeItem->roomNumber;
return pos;
}
void SetItemPosition(__int32 x, __int32 y, __int32 z)
{
if (NativeItem == NULL)
return;
NativeItem->pos.xPos = x;
NativeItem->pos.yPos = y;
NativeItem->pos.zPos = z;
}
void SetItemRotation(__int32 x, __int32 y, __int32 z)
{
if (NativeItem == NULL)
return;
NativeItem->pos.xRot = ANGLE(x);
NativeItem->pos.yRot = ANGLE(y);
NativeItem->pos.zRot = ANGLE(z);
}
}; };
class GameScript class GameScript
{ {
private: private:
sol::state* m_lua; sol::state* m_lua;
sol::table m_globals;
sol::table m_locals;
map<__int32, __int32> m_itemsMap;
vector<LuaFunction*> m_triggers;
GameScriptItem m_items[NUM_ITEMS];
string loadScriptFromFile(char* luaFilename); string loadScriptFromFile(char* luaFilename);
map<__int16, __int16> m_itemsMap;
public: public:
vector<LuaFunction*> Triggers;
GameScript(sol::state* lua); GameScript(sol::state* lua);
~GameScript(); ~GameScript();
bool ExecuteScript(char* luaFilename); bool ExecuteScript(char* luaFilename);
void FreeLevelScripts(); void FreeLevelScripts();
void AddTrigger(LuaFunction* function); void AddTrigger(LuaFunction* function);
void AddLuaId(int luaId, int itemId);
void SetItem(__int32 index, ITEM_INFO* item);
void AssignVariables();
void ResetVariables();
void EnableItem(__int16 id); void EnableItem(__int16 id);
void DisableItem(__int16 id); void DisableItem(__int16 id);
@ -127,4 +185,6 @@ public:
void AddOneSecret(); void AddOneSecret();
void MakeItemInvisible(__int16 id); void MakeItemInvisible(__int16 id);
GameScriptItem GetItem(__int16 id); GameScriptItem GetItem(__int16 id);
void PlaySoundEffectAtPosition(__int16 id, __int32 x, __int32 y, __int32 z, __int32 flags);
void PlaySoundEffect(__int16 id, __int32 flags);
}; };

View file

@ -0,0 +1,84 @@
#pragma once
#include <Windows.h>
#include <stdlib.h>
#include <memory>
#include <string>
#include "LEB128.h"
#include "Streams.h"
using namespace std;
typedef struct ChunkId
{
private:
byte* m_chunkBytes;
__int32 m_length;
public:
ChunkId(char* bytes, __int32 length)
{
if (length == 0)
{
m_chunkBytes = NULL;
m_length = 0;
}
else
{
m_chunkBytes = (byte*)malloc(length);
memcpy(m_chunkBytes, bytes, length);
m_length = length;
}
}
~ChunkId()
{
if (m_chunkBytes != NULL)
delete m_chunkBytes;
}
static ChunkId* FromString(char* str)
{
return new ChunkId(str, strlen(str));
}
static ChunkId* FromString(string* str)
{
return new ChunkId((char*)str->c_str(), str->length());
}
static ChunkId* FromStream(BaseStream* stream)
{
__int32 idLength = LEB128::ReadInt32(stream);
char* buffer = (char*)malloc(idLength);
stream->Read(buffer, idLength);
ChunkId* chunk = new ChunkId(buffer, idLength);
free(buffer);
return chunk;
}
void ToStream(BaseStream* stream)
{
LEB128::Write(stream, m_length);
stream->WriteBytes(m_chunkBytes, m_length);
}
byte* GetBytes()
{
return m_chunkBytes;
}
__int32 GetLength()
{
return m_length;
}
bool EqualsTo(ChunkId* other)
{
if (m_length != other->GetLength())
return false;
return (strncmp((const char*)m_chunkBytes, (const char*)other->GetBytes(), m_length) == 0);
}
};

View file

@ -0,0 +1,144 @@
#pragma once
#include <stdlib.h>
#include <memory>
#include "ChunkId.h"
#include "LEB128.h"
#include "Streams.h"
class ChunkReader
{
private:
bool m_isValid;
ChunkId* m_emptyChunk;
BaseStream* m_stream;
__int32 readInt32()
{
__int32 value = 0;
m_stream->Read(reinterpret_cast<char *>(&value), 4);
return value;
}
__int16 readInt16()
{
__int16 value = 0;
m_stream->Read(reinterpret_cast<char *>(&value), 2);
return value;
}
public:
ChunkReader(__int32 expectedMagicNumber, BaseStream* stream)
{
m_isValid = false;
if (stream == NULL)
return;
m_stream = stream;
// Check the magic number
__int32 magicNumber = readInt32();
if (magicNumber != expectedMagicNumber)
return;
// TODO: future use for compression
m_stream->Seek(4, SEEK_ORIGIN::CURRENT);
m_emptyChunk = new ChunkId(NULL, 0);
m_isValid = true;
}
~ChunkReader()
{
delete m_emptyChunk;
}
bool ChunkReader::IsValid()
{
return m_isValid;
}
bool ChunkReader::ReadChunks(bool(*func)(ChunkId* parentChunkId, __int32 maxSize))
{
do
{
ChunkId* chunkId = ChunkId::FromStream(m_stream);
if (chunkId->EqualsTo(m_emptyChunk)) // End reached
break;
// Read up to a 64 bit number for the chunk size
__int64 chunkSize = LEB128::ReadLong(m_stream);
// Try loading chunk content
bool chunkRecognized = false;
__int32 startPos = m_stream->GetCurrentPosition();
chunkRecognized = func(chunkId, chunkSize);
__int32 readDataCount = m_stream->GetCurrentPosition() - startPos;
// Adjust _stream position if necessary
if (readDataCount != chunkSize)
m_stream->Seek(chunkSize, SEEK_ORIGIN::CURRENT);
} while (true);
return true;
}
char* ReadChunkArrayOfBytes(__int64 length)
{
char* value = (char*)malloc(length);
m_stream->Read(value, length);
return value;
}
bool ReadChunkBool(__int64 length)
{
return (LEB128::ReadByte(m_stream) != 0);
}
__int64 ReadChunkLong(__int64 length)
{
return LEB128::ReadLong(m_stream);
}
__int32 ReadChunkInt32(__int64 length)
{
return LEB128::ReadInt32(m_stream);
}
unsigned __int32 ReadChunkUInt32(__int64 length)
{
return LEB128::ReadUInt32(m_stream);
}
__int16 ReadChunkInt16(__int64 length)
{
return LEB128::ReadInt16(m_stream);
}
unsigned __int16 ReadChunkUInt16(__int64 length)
{
return LEB128::ReadUInt16(m_stream);
}
byte ReadChunkByte(__int64 length)
{
return LEB128::ReadByte(m_stream);
}
char* ReadChunkString(long length)
{
char* value = (char*)malloc(length);
memcpy(value, LevelDataPtr, length);
return value;
}
BaseStream* GetRawStream()
{
return m_stream;
}
};

View file

@ -0,0 +1,109 @@
#pragma once
#include "Streams.h"
#include "LEB128.h"
#include "ChunkId.h"
typedef struct ChunkWritingState
{
private:
BaseStream* m_stream;
__int64 m_chunkSizePosition;
__int64 m_previousPosition;
__int64 m_maximumSize;
public:
ChunkWritingState(BaseStream* stream, ChunkId* chunkID, __int64 maximumSize)
{
m_stream = stream;
// Write chunk ID
chunkID->ToStream(m_stream);
// Write chunk size
m_chunkSizePosition = m_stream->GetCurrentPosition();
LEB128::Write(m_stream, 0, maximumSize);
// Prepare for writeing chunk content
m_previousPosition = m_stream->GetCurrentPosition();
m_maximumSize = maximumSize;
}
void EndWrite()
{
// Update chunk size
long newPosition = m_stream->GetCurrentPosition();
long chunkSize = newPosition - m_previousPosition;
m_stream->Seek(m_chunkSizePosition, SEEK_ORIGIN::BEGIN);
LEB128::Write(m_stream, chunkSize, m_maximumSize);
m_stream->Seek(newPosition, SEEK_ORIGIN::BEGIN);
}
};
class ChunkWriter {
private:
BaseStream* m_stream;
public:
ChunkWriter(__int32 magicNumber, BaseStream* stream)
{
m_stream = stream;
__int32 value = 0;
m_stream->WriteInt32(&magicNumber);
m_stream->WriteInt32(&value);
}
BaseStream* GetRawStream()
{
return m_stream;
}
void WriteChunkEnd()
{
byte value = 0;
m_stream->WriteByte(&value);
}
void WriteChunkEmpty(ChunkId* chunkID)
{
chunkID->ToStream(m_stream);
LEB128::Write(m_stream, 0);
}
void WriteChunkArrayOfBytes(ChunkId* chunkID, byte* value, __int32 length)
{
chunkID->ToStream(m_stream);
LEB128::Write(m_stream, length);
m_stream->WriteBytes(value, length);
}
void WriteChunkInt(ChunkId* chunkID, __int64 value)
{
chunkID->ToStream(m_stream);
LEB128::Write(m_stream, LEB128::GetLength(m_stream, value));
LEB128::Write(m_stream, value);
}
ChunkWritingState* WriteChunk(ChunkId* chunkID, __int64 maximumSize = LEB128::MaximumSize4Byte)
{
return new ChunkWritingState(m_stream, chunkID, maximumSize);
}
void WriteChunk(ChunkId* chunkID, void(*writeChunk)(__int32), __int32 arg, __int64 maximumSize = LEB128::MaximumSize4Byte)
{
ChunkWritingState* state = WriteChunk(chunkID, maximumSize);
writeChunk(arg);
state->EndWrite();
delete state;
}
void WriteChunkWithChildren(ChunkId* chunkID, void(*writeChunk)(__int32), __int32 arg, __int64 maximumSize = LEB128::MaximumSize4Byte)
{
ChunkWritingState* state = WriteChunk(chunkID, maximumSize);
writeChunk(arg);
WriteChunkEnd();
state->EndWrite();
delete state;
}
};

View file

@ -0,0 +1,116 @@
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <windows.h>
#include "Streams.h"
extern char* LevelDataPtr;
typedef struct LEB128 {
static const __int64 MaximumSize1Byte = 64L - 1;
static const __int64 MaximumSize2Byte = 64L * 128 - 1;
static const __int64 MaximumSize3Byte = 64L * 128 * 128 - 1;
static const __int64 MaximumSize4Byte = 64L * 128 * 128 * 128 - 1;
static const __int64 MaximumSize5Byte = 64L * 128 * 128 * 128 * 128 - 1;
static const __int64 MaximumSize6Byte = 64L * 128 * 128 * 128 * 128 * 128 - 1;
static const __int64 MaximumSize7Byte = 64L * 128 * 128 * 128 * 128 * 128 * 128 - 1;
static const __int64 MaximumSize8Byte = 64L * 128 * 128 * 128 * 128 * 128 * 128 * 128 - 1;
static const __int64 MaximumSize9Byte = 64L * 128 * 128 * 128 * 128 * 128 * 128 * 128 * 128 - 1;
static const __int64 MaximumSize10Byte = UINT64_MAX;
static __int64 ReadLong(BaseStream* stream)
{
__int64 result = 0;
__int32 currentShift = 0;
byte currentByte;
do
{
stream->Read(reinterpret_cast<char *>(&currentByte), 1);
result |= (__int64)(currentByte & 0x7F) << currentShift;
currentShift += 7;
} while ((currentByte & 0x80) != 0);
// Sign extend
__int32 shift = 64 - currentShift;
if (shift > 0)
result = (result << shift) >> shift;
return result;
}
static __int32 ReadInt32(BaseStream* stream)
{
__int64 value = ReadLong(stream);
return (__int32)min(max(value, INT32_MIN), INT32_MAX);
}
static __int16 ReadInt16(BaseStream* stream)
{
__int64 value = ReadLong(stream);
return (__int16)min(max(value, INT16_MIN), INT16_MAX);
}
static byte ReadByte(BaseStream* stream)
{
__int64 value = ReadLong(stream);
return (byte)min(max(value, 0), UINT8_MAX);
}
static unsigned __int32 ReadUInt32(BaseStream* stream)
{
__int64 value = ReadLong(stream);
return (unsigned __int32)min(max(value, 0), UINT32_MAX);
}
static unsigned __int16 ReadUInt16(BaseStream* stream)
{
__int64 value = ReadLong(stream);
return (unsigned __int16)min(max(value, 0), UINT16_MAX);
}
static void Write(BaseStream* stream, __int64 value, __int64 maximumSize)
{
do
{
// Write byte
byte currentByte = ((byte)(value & 0x7F));
if (maximumSize >> 6 == 0 || maximumSize >> 6 == -1)
{
stream->WriteByte(&currentByte);
if (value >> 6 != 0 && value >> 6 != -1)
throw "Unable to write integer because the available space overflowed.";
return;
}
byte b = currentByte | 0x80;
stream->WriteByte(&b);
// Move data to next byte
value >>= 7;
maximumSize >>= 7;
} while (true);
}
static void Write(BaseStream* stream, __int64 value)
{
Write(stream, value, value);
}
static __int32 GetLength(BaseStream* stream, __int64 value)
{
__int32 length = 1;
value >>= 6;
while (value > 0)
{
value >>= 7;
length += 1;
}
return length;
}
};

View file

@ -0,0 +1,200 @@
#pragma once
#include <istream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <stdlib.h>
using namespace std;
enum SEEK_ORIGIN {
BEGIN,
CURRENT
};
class BaseStream {
public:
virtual bool Read(char* buffer, __int32 length) = 0;
virtual bool Write(char* buffer, __int32 length) = 0;
virtual __int32 GetCurrentPosition() = 0;
virtual bool Seek(__int32 seek, SEEK_ORIGIN origin) = 0;
virtual bool IsEOF() = 0;
virtual bool Close() = 0;
bool ReadBytes(byte* value, __int32 length)
{
return Read(reinterpret_cast<char*>(value), length);
}
bool ReadByte(byte* value)
{
return Read(reinterpret_cast<char*>(value), 1);
}
bool ReadInt16(__int16* value)
{
return Read(reinterpret_cast<char*>(value), 2);
}
bool ReadInt32(__int32* value)
{
return Read(reinterpret_cast<char*>(value), 4);
}
bool ReadString(char** value)
{
__int32 length;
ReadInt32(&length);
*value = (char*)malloc(length + 1);
Read(*value, length);
(*value)[length] = NULL;
return true;
}
bool WriteBytes(byte* value, __int32 length)
{
return Write(reinterpret_cast<char*>(value), length);
}
bool WriteByte(byte* value)
{
return Write(reinterpret_cast<char*>(value), 1);
}
bool WriteInt16(__int16* value)
{
return Write(reinterpret_cast<char*>(value), 3);
}
bool WriteInt32(__int32* value)
{
return Write(reinterpret_cast<char*>(value), 4);
}
bool WriteString(char* str)
{
__int32 length = (__int32)strlen(str);
WriteInt32(&length);
Write(str, length);
return true;
}
};
class MemoryStream : public BaseStream {
private:
char* m_startBuffer;
char* m_buffer;
__int32 m_size;
public:
MemoryStream(char* buffer, __int32 size)
{
m_buffer = (char*)malloc(size);
m_startBuffer = m_buffer;
memcpy(m_buffer, buffer, size);
m_size = size;
}
MemoryStream(__int32 size)
{
m_buffer = (char*)malloc(size);
m_startBuffer = m_buffer;
m_size = size;
}
~MemoryStream()
{
free(m_startBuffer);
}
bool Read(char* buffer, __int32 length)
{
memcpy(buffer, m_buffer, length);
m_buffer += length;
return true;
}
bool Write(char* buffer, __int32 length)
{
memcpy(m_buffer, buffer, length);
m_buffer += length;
return true;
}
__int32 GetCurrentPosition()
{
return (m_buffer - m_startBuffer);
}
bool Seek(__int32 seek, SEEK_ORIGIN origin)
{
if (origin == SEEK_ORIGIN::BEGIN)
m_buffer = m_startBuffer + seek;
else
m_buffer += seek;
return true;
}
bool IsEOF()
{
return (GetCurrentPosition() > m_size);
}
bool Close()
{
return true;
}
};
class FileStream : public BaseStream {
private:
fstream m_stream;
public:
FileStream(char* fileName)
{
m_stream.open(fileName, fstream::in | fstream::out | fstream::trunc);
}
~FileStream()
{
m_stream.close();
}
bool Read(char* buffer, __int32 length)
{
m_stream.read(buffer, length);
return true;
}
bool Write(char* buffer, __int32 length)
{
m_stream.write(buffer, length);
return true;
}
__int32 GetCurrentPosition()
{
return (__int32)(m_stream.tellg());
}
bool Seek(__int32 seek, SEEK_ORIGIN origin)
{
m_stream.seekg(seek, (origin == SEEK_ORIGIN::BEGIN ? m_stream.beg : m_stream.cur));
return true;
}
bool IsEOF()
{
return (m_stream.eof());
}
bool Close()
{
m_stream.flush();
m_stream.close();
return true;
}
};

View file

@ -1,6 +1,7 @@
#include "patch.h" #include "patch.h"
#include "..\Global\global.h"1 #include "..\Global\global.h"
#include <stdio.h> #include <stdio.h>
#include "roomload.h"
// Remapped variables. Some variables must be moved from EXE space to DLL space for having free space for bigger arrays // Remapped variables. Some variables must be moved from EXE space to DLL space for having free space for bigger arrays
__int32 NumItems; __int32 NumItems;
@ -97,6 +98,106 @@ void PatchGameCode()
newValue = (__int32)&StaticObjects[0] + 16; newValue = (__int32)&StaticObjects[0] + 16;
WriteProcessMemory(gameHandle, (LPVOID)0x4192B0, &newValue, 4, NULL); // ObjectOnLOS2 WriteProcessMemory(gameHandle, (LPVOID)0x4192B0, &newValue, 4, NULL); // ObjectOnLOS2
//newValue = 0xFF; // Move LevelDataPtr for having more space for Objects[]
//WriteProcessMemory(gameHandle, (LPVOID)0x004A7385, &newValue, 4, NULL); // ObjectOnLOS2 newValue = (__int32)&LevelDataPtr;
// LoadRooms
WriteProcessMemory(gameHandle, (LPVOID)0x004916C4, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004916CE, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004916DA, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x00491706, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x00491710, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x0049171B, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x00491726, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x00491745, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x0049175B, &newValue, 4, NULL);
// LoadRooms
WriteProcessMemory(gameHandle, (LPVOID)0x004A4DCF, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A4DDA, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A4DEA, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A4E0C, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A4E1C, &newValue, 4, NULL);
// LoadSprites
WriteProcessMemory(gameHandle, (LPVOID)0x004A59E2, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A59EC, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A59F6, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5A20, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5A4B, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5B61, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5B6E, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5B8C, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5B9D, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5BBF, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5BE4, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5BF7, &newValue, 4, NULL);
// LoadSoundEffects
WriteProcessMemory(gameHandle, (LPVOID)0x004A5D9D, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5DB5, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5DE2, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5E08, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5E13, &newValue, 4, NULL);
// LoadBoxes
WriteProcessMemory(gameHandle, (LPVOID)0x004A5E62, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5E6E, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5E8D, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5EB2, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5EBA, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5EC4, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5ED3, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5EF7, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5F04, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5F26, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5F4D, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5F5C, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5F79, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5F9F, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A5FAE, &newValue, 4, NULL);
//LoadAnimatedTextures
WriteProcessMemory(gameHandle, (LPVOID)0x004A6061, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6070, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A607F, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A609E, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A60A7, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A60B3, &newValue, 4, NULL);
// LoadTextureInfos
WriteProcessMemory(gameHandle, (LPVOID)0x004A60F1, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A60F9, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A610B, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A613D, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6159, &newValue, 4, NULL);
// Sub_4A6760
WriteProcessMemory(gameHandle, (LPVOID)0x004A6761, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6771, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A677C, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A679B, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A67A4, &newValue, 4, NULL);
// LoadDemoData
WriteProcessMemory(gameHandle, (LPVOID)0x004A67D1, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A67D9, &newValue, 4, NULL);
// LoadAIObjects
WriteProcessMemory(gameHandle, (LPVOID)0x004A67F2, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A67FF, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A681E, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A683D, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6846, &newValue, 4, NULL);
// LoadSamples
WriteProcessMemory(gameHandle, (LPVOID)0x004A689F, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A68B2, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A68BC, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A68D4, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6913, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6939, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A6941, &newValue, 4, NULL);
WriteProcessMemory(gameHandle, (LPVOID)0x004A694D, &newValue, 4, NULL);
} }

View file

@ -4,11 +4,23 @@
#include "..\Specific\setup.h" #include "..\Specific\setup.h"
#include "..\Game\draw.h" #include "..\Game\draw.h"
#include "..\Game\lot.h" #include "..\Game\lot.h"
#include "..\Game\savegame.h"
#include "IO/ChunkId.h"
#include "IO/ChunkReader.h"
#include "IO/ChunkWriter.h"
#include "IO/LEB128.h"
#include <process.h> #include <process.h>
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
#include <map> #include <map>
#include "IO/Streams.h"
ChunkId* ChunkTriggersList = ChunkId::FromString("Tr5Triggers");
ChunkId* ChunkTrigger = ChunkId::FromString("Tr5Trigger");
ChunkId* ChunkLuaIds = ChunkId::FromString("Tr5LuaIds");
ChunkId* ChunkLuaId = ChunkId::FromString("Tr5LuaId");
extern GameScript* g_GameScript; extern GameScript* g_GameScript;
@ -25,6 +37,8 @@ __int32 NumMeshPointers;
__int32 NumObjectTextures; __int32 NumObjectTextures;
uintptr_t hLoadLevel; uintptr_t hLoadLevel;
unsigned __int32 ThreadId;
__int32 IsLevelLoading;
using namespace std; using namespace std;
@ -33,6 +47,9 @@ vector<__int32> StaticObjectsIds;
extern GameFlow* g_GameFlow; extern GameFlow* g_GameFlow;
extern __int16 LaraVehicle; extern __int16 LaraVehicle;
char* LevelDataPtr;
ChunkReader* chunkIO;
__int16 ReadInt16() __int16 ReadInt16()
{ {
@ -287,6 +304,23 @@ void __cdecl LoadObjects()
MoveablesIds.push_back(ID_DEFAULT_SPRITES); MoveablesIds.push_back(ID_DEFAULT_SPRITES);
} }
void __cdecl LoadCameras()
{
NumberCameras = ReadInt32();
if (NumberCameras != 0)
{
Cameras = (OBJECT_VECTOR*)GameMalloc(NumberCameras * sizeof(OBJECT_VECTOR));
ReadBytes(Cameras, NumberCameras * sizeof(OBJECT_VECTOR));
}
NumberSpotcams = ReadInt32();
if (NumberSpotcams != 0)
{
ReadBytes(SpotCam, NumberSpotcams * sizeof(SPOTCAM));
}
}
void __cdecl LoadTextures() void __cdecl LoadTextures()
{ {
DB_Log(2, "LoadTextures - DLL"); DB_Log(2, "LoadTextures - DLL");
@ -422,6 +456,7 @@ void __cdecl FreeLevel()
MallocPtr = MallocBuffer; MallocPtr = MallocBuffer;
MallocFree = MallocSize; MallocFree = MallocSize;
g_Renderer->FreeRendererData(); g_Renderer->FreeRendererData();
g_GameScript->FreeLevelScripts();
} }
unsigned __stdcall LoadLevel(void* data) unsigned __stdcall LoadLevel(void* data)
@ -480,8 +515,19 @@ unsigned __stdcall LoadLevel(void* data)
LoadDemoData(); LoadDemoData();
LoadSamples(); LoadSamples();
LoadNewData(); __int32 extraSize = 0;
ReadFileEx(&extraSize, 1, 4, LevelFilePtr);
if (extraSize > 0)
{
ReadFileEx(&extraSize, 1, 4, LevelFilePtr);
//free(LevelDataPtr);
LevelDataPtr = (char*)malloc(extraSize);
ReadFileEx(LevelDataPtr, extraSize, 1, LevelFilePtr);
LoadNewData(extraSize);
}
//free(LevelDataPtr);
LevelDataPtr = NULL; LevelDataPtr = NULL;
FileClose(LevelFilePtr); FileClose(LevelFilePtr);
} }
@ -506,6 +552,7 @@ unsigned __stdcall LoadLevel(void* data)
SeedRandomDraw(0xD371F947); SeedRandomDraw(0xD371F947);
SeedRandomControl(0xD371F947); SeedRandomControl(0xD371F947);
LaraVehicle = -1; LaraVehicle = -1;
g_GameScript->AssignVariables();
// Level loaded // Level loaded
IsLevelLoading = false; IsLevelLoading = false;
@ -545,32 +592,33 @@ void __cdecl AdjustUV(__int32 num)
NumObjectTextures = num; NumObjectTextures = num;
} }
void __cdecl LoadNewData() bool __cdecl ReadLuaIds(ChunkId* chunkId, __int32 maxSize)
{ {
// Free old level scripts if (chunkId->EqualsTo(ChunkLuaId))
g_GameScript->FreeLevelScripts();
// Check for magic word
__int32 magicWord;
ReadFileEx(&magicWord, 1, 4, LevelFilePtr);
if (magicWord != 0x5455354D)
return;
// Load LUA triggers
__int32 numTriggers;
ReadFileEx(&numTriggers, 1, 4, LevelFilePtr);
for (__int32 i = 0; i < numTriggers; i++)
{ {
__int32 strSize; __int32 luaId = 0;
ReadFileEx(&strSize, 1, 4, LevelFilePtr); chunkIO->GetRawStream()->ReadInt32(&luaId);
char* functionName = (char*)malloc(strSize + 1);
ZeroMemory(functionName, strSize + 1);
ReadFileEx(functionName, strSize, 1, LevelFilePtr);
ReadFileEx(&strSize, 1, 4, LevelFilePtr); __int32 itemId = 0;
char* functionCode = (char*)malloc(strSize + 1); chunkIO->GetRawStream()->ReadInt32(&itemId);
ZeroMemory(functionCode, strSize + 1);
ReadFileEx(functionCode, strSize, 1, LevelFilePtr); g_GameScript->AddLuaId(luaId, itemId);
return true;
}
else
return false;
}
bool __cdecl ReadLuaTriggers(ChunkId* chunkId, __int32 maxSize)
{
if (chunkId->EqualsTo(ChunkTrigger))
{
char* functionName = NULL;
chunkIO->GetRawStream()->ReadString(&functionName);
char* functionCode = NULL;
chunkIO->GetRawStream()->ReadString(&functionCode);
LuaFunction* function = new LuaFunction(); LuaFunction* function = new LuaFunction();
function->Name = string(functionName); function->Name = string(functionName);
@ -581,7 +629,51 @@ void __cdecl LoadNewData()
delete functionName; delete functionName;
delete functionCode; delete functionCode;
return true;
} }
else
return false;
}
bool __cdecl ReadNewDataChunks(ChunkId* chunkId, __int32 maxSize)
{
if (chunkId->EqualsTo(ChunkTriggersList))
return chunkIO->ReadChunks(ReadLuaTriggers);
else if (chunkId->EqualsTo(ChunkLuaIds))
return chunkIO->ReadChunks(ReadLuaIds);
return false;
}
//ChunkWriter* writer;
void __cdecl SaveTest()
{
}
void __cdecl LoadNewData(__int32 size)
{
// Free old level scripts
//g_GameScript->FreeLevelScripts();
MemoryStream stream(LevelDataPtr, size);
chunkIO = new ChunkReader(0x4D355254, &stream);
if (!chunkIO->IsValid())
return;
chunkIO->ReadChunks(ReadNewDataChunks);
/*ChunkId* testChunkId = ChunkId::FromString("TR5MSavItems");
FileStream fs("H:\\test.sav");
writer = new ChunkWriter(0x4D355254, &fs);
writer->WriteChunkInt(testChunkId, 1234);
fs.Close();*/
SaveGame::Save((char*)"H:\\test.sav");
/*SaveGame* sg = new SaveGame();
sg->Save("H:\\test.sav");
delete sg;*/
} }
void Inject_RoomLoad() void Inject_RoomLoad()
@ -593,4 +685,5 @@ void Inject_RoomLoad()
INJECT(0x0040130C, S_LoadLevelFile); INJECT(0x0040130C, S_LoadLevelFile);
INJECT(0x004A7130, FreeLevel); INJECT(0x004A7130, FreeLevel);
INJECT(0x004A5430, AdjustUV); INJECT(0x004A5430, AdjustUV);
INJECT(0x004A5CA0, LoadCameras);
} }

View file

@ -5,6 +5,13 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include "IO/ChunkId.h"
#include "IO/ChunkReader.h"
#include "IO/LEB128.h"
struct ChunkId;
struct LEB128;
#define DoSomethingWithRooms ((void (__cdecl*)()) 0x004774D0) #define DoSomethingWithRooms ((void (__cdecl*)()) 0x004774D0)
#define FreeItemsStuff ((void (__cdecl*)(__int32)) 0x00440590) #define FreeItemsStuff ((void (__cdecl*)(__int32)) 0x00440590)
#define InitialiseClosedDoors ((void (__cdecl*)()) 0x00473600) #define InitialiseClosedDoors ((void (__cdecl*)()) 0x00473600)
@ -17,7 +24,7 @@
#define FileOpen ((FILE* (__cdecl*)(char*)) 0x004A3CD0) #define FileOpen ((FILE* (__cdecl*)(char*)) 0x004A3CD0)
#define FileClose ((void (__cdecl*)(FILE*)) 0x004A3DA0) #define FileClose ((void (__cdecl*)(FILE*)) 0x004A3DA0)
#define LoadSprites ((void (__cdecl*)()) 0x004A59D0) #define LoadSprites ((void (__cdecl*)()) 0x004A59D0)
#define LoadCameras ((void (__cdecl*)()) 0x004A5CA0) //#define LoadCameras ((void (__cdecl*)()) 0x004A5CA0)
#define LoadSoundEffects ((void (__cdecl*)()) 0x004A5D90) #define LoadSoundEffects ((void (__cdecl*)()) 0x004A5D90)
#define LoadBoxes ((void (__cdecl*)()) 0x004A5E50) #define LoadBoxes ((void (__cdecl*)()) 0x004A5E50)
#define LoadAnimatedTextures ((void (__cdecl*)()) 0x004A6060) #define LoadAnimatedTextures ((void (__cdecl*)()) 0x004A6060)
@ -53,6 +60,7 @@ extern vector<__int32> StaticObjectsIds;
extern __int32* RawMeshPointers; extern __int32* RawMeshPointers;
extern __int16* RawMeshData; extern __int16* RawMeshData;
extern __int32 NumObjectTextures; extern __int32 NumObjectTextures;
extern char* LevelDataPtr;
void __cdecl LoadTextures(); void __cdecl LoadTextures();
__int32 __cdecl LoadRoomsNew(); __int32 __cdecl LoadRoomsNew();
@ -61,8 +69,14 @@ void __cdecl LoadObjects();
__int32 __cdecl S_LoadLevelFile(__int32 levelIndex); __int32 __cdecl S_LoadLevelFile(__int32 levelIndex);
void __cdecl FreeLevel(); void __cdecl FreeLevel();
void __cdecl AdjustUV(__int32 num); void __cdecl AdjustUV(__int32 num);
void __cdecl LoadNewData(); void __cdecl LoadCameras();
unsigned __stdcall LoadLevel(void* data); unsigned __stdcall LoadLevel(void* data);
// New functions for loading data from TR5M footer
bool __cdecl ReadLuaIds(ChunkId* chunkId, __int32 maxSize);
bool __cdecl ReadLuaTriggers(ChunkId* chunkId, __int32 maxSize);
bool __cdecl ReadNewDataChunks(ChunkId* chunkId, __int32 maxSize);
void __cdecl LoadNewData(__int32 size);
void Inject_RoomLoad(); void Inject_RoomLoad();

View file

@ -169,6 +169,10 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts"</Command>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Specific\IO\ChunkId.h" />
<ClInclude Include="Specific\IO\ChunkWriter.h" />
<ClInclude Include="Specific\IO\LEB128.h" />
<ClInclude Include="Specific\IO\ChunkReader.h" />
<ClInclude Include="CustomObjects\bear.h" /> <ClInclude Include="CustomObjects\bear.h" />
<ClInclude Include="CustomObjects\customtraps.h" /> <ClInclude Include="CustomObjects\customtraps.h" />
<ClInclude Include="CustomObjects\dino.h" /> <ClInclude Include="CustomObjects\dino.h" />
@ -259,6 +263,7 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts"</Command>
<ClInclude Include="Specific\directx.h" /> <ClInclude Include="Specific\directx.h" />
<ClInclude Include="Specific\init.h" /> <ClInclude Include="Specific\init.h" />
<ClInclude Include="Specific\input.h" /> <ClInclude Include="Specific\input.h" />
<ClInclude Include="Specific\IO\Streams.h" />
<ClInclude Include="Specific\patch.h" /> <ClInclude Include="Specific\patch.h" />
<ClInclude Include="Specific\roomload.h" /> <ClInclude Include="Specific\roomload.h" />
<ClInclude Include="Specific\setup.h" /> <ClInclude Include="Specific\setup.h" />

View file

@ -300,6 +300,21 @@
<ClInclude Include="Scripting\GameLogicScript.h"> <ClInclude Include="Scripting\GameLogicScript.h">
<Filter>File di intestazione</Filter> <Filter>File di intestazione</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Specific\IO\ChunkReader.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="Specific\IO\LEB128.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="Specific\IO\ChunkId.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="Specific\IO\Streams.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="Specific\IO\ChunkWriter.h">
<Filter>File di intestazione</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="TR5Main.cpp"> <ClCompile Include="TR5Main.cpp">