TombEngine/TR5Main/Game/savegame.cpp

1584 lines
49 KiB
C++
Raw Normal View History

#include "savegame.h"
#include "..\Global\global.h"
2019-11-21 07:43:34 +01:00
#include "..\Game\Lara.h"
#include "..\Game\items.h"
2018-10-24 23:32:22 +02:00
#include "..\Game\box.h"
#include "..\Game\pickup.h"
2018-10-24 23:32:22 +02:00
#include "..\Game\lot.h"
#include "..\Game\switch.h"
#include "..\Game\spotcam.h"
2019-12-01 08:13:19 +01:00
#include "traps.h"
#include "..\Game\laramisc.h"
2018-11-24 18:00:27 +01:00
#include "..\Objects\newobjects.h"
#include "..\Objects\oldobjects.h"
#include "..\Game\sound.h"
2020-03-17 21:47:37 -03:00
#include "..\Specific\roomload.h"
2020-04-01 13:09:14 +02:00
#include "../Specific/setup.h"
#include "camera.h"
FileStream* SaveGame::m_stream;
ChunkReader* SaveGame::m_reader;
ChunkWriter* SaveGame::m_writer;
2018-10-09 00:02:14 +02:00
vector<LuaVariable> SaveGame::m_luaVariables;
int SaveGame::LastSaveGame;
ChunkId* SaveGame::m_chunkGameStatus;
ChunkId* SaveGame::m_chunkItems;
ChunkId* SaveGame::m_chunkItem;
ChunkId* SaveGame::m_chunkLara;
ChunkId* SaveGame::m_chunkLuaVariable;
2018-10-24 23:32:22 +02:00
ChunkId* SaveGame::m_chunkStaticFlags;
ChunkId* SaveGame::m_chunkVehicle;
ChunkId* SaveGame::m_chunkSequenceSwitch;
2018-10-24 23:32:22 +02:00
ChunkId* SaveGame::m_chunkFlybyFlags;
ChunkId* SaveGame::m_chunkCdFlags;
ChunkId* SaveGame::m_chunkCamera;
ChunkId* SaveGame::m_chunkFlipStats;
ChunkId* SaveGame::m_chunkFlipMap;
ChunkId* SaveGame::m_chunkItemDummy;
ChunkId* SaveGame::m_chunkStatistics;
ChunkId* SaveGame::m_chunkItemAnims;
ChunkId* SaveGame::m_chunkItemMeshes;
ChunkId* SaveGame::m_chunkItemFlags;
ChunkId* SaveGame::m_chunkItemHitPoints;
ChunkId* SaveGame::m_chunkItemPosition;
ChunkId* SaveGame::m_chunkItemIntelligentData;
ChunkId* SaveGame::m_chunkSpecialItemBurningTorch;
ChunkId* SaveGame::m_chunkSpecialItemChaff;
ChunkId* SaveGame::m_chunkSpecialItemTorpedo;
ChunkId* SaveGame::m_chunkSpecialItemCrossbowBolt;
ChunkId* SaveGame::m_chunkSpecialItemFlare;
ChunkId* SaveGame::m_chunkItemQuadInfo;
ChunkId* SaveGame::m_chunkBats;
ChunkId* SaveGame::m_chunkRats;
ChunkId* SaveGame::m_chunkSpiders;
ChunkId* SaveGame::m_chunkLaraExtraInfo;
ChunkId* SaveGame::m_chunkWeaponInfo;
ChunkId* SaveGame::m_chunkPuzzle;
ChunkId* SaveGame::m_chunkKey;
ChunkId* SaveGame::m_chunkPickup;
ChunkId* SaveGame::m_chunkExamine;
ChunkId* SaveGame::m_chunkPuzzleCombo;
ChunkId* SaveGame::m_chunkKeyCombo;
ChunkId* SaveGame::m_chunkPickupCombo;
ChunkId* SaveGame::m_chunkExamineCombo;
ChunkId* SaveGame::m_chunkWeaponItem;
2018-10-24 23:32:22 +02:00
extern vector<AudioTrack> g_AudioTracks;
extern byte SequenceUsed[6];
extern byte SequenceResults[3][3][3];
extern byte Sequences[3];
extern byte CurrentSequence;
2018-10-24 23:32:22 +02:00
void SaveGame::saveItems()
{
2018-10-24 23:32:22 +02:00
// Save level items
for (int i = 0; i < NumItems; i++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunkWithChildren(m_chunkItem, &saveItem, i, 0);
// Save items created at runtime (flares, missiles...)
for (int i = NumItems; i < NUM_ITEMS; i++)
{
ITEM_INFO* item = &Items[i];
if (item->active)
{
// Some items are very special and are saved in specific functions, all the others use the general function
if (item->objectNumber == ID_BURNING_TORCH_ITEM)
m_writer->WriteChunk(m_chunkSpecialItemBurningTorch, &saveBurningTorch, i, 1);
else if (item->objectNumber == ID_CHAFF)
m_writer->WriteChunk(m_chunkSpecialItemChaff, &saveChaff, i, 1);
else if (item->objectNumber == ID_TORPEDO)
m_writer->WriteChunk(m_chunkSpecialItemTorpedo, &saveTorpedo, i, 1);
else if (item->objectNumber == ID_CROSSBOW_BOLT)
m_writer->WriteChunk(m_chunkSpecialItemCrossbowBolt, &saveCrossbowBolt, i, 1);
else if (item->objectNumber == ID_FLARE_ITEM)
m_writer->WriteChunk(m_chunkSpecialItemFlare, &saveFlare, i, 1);
else
m_writer->WriteChunkWithChildren(m_chunkItem, &saveItem, i, 1);
}
}
// Save special items
if (Objects[ID_BATS_EMITTER].loaded)
for (int i = 0; i < NUM_BATS; i++)
if (Bats[i].on)
m_writer->WriteChunk(m_chunkBats, &saveBats, i, 0);
if (Objects[ID_RATS_EMITTER].loaded)
for (int i = 0; i < NUM_RATS; i++)
if (Rats[i].on)
m_writer->WriteChunk(m_chunkRats, &saveRats, i, 0);
if (Objects[ID_SPIDERS_EMITTER].loaded)
for (int i = 0; i < NUM_SPIDERS; i++)
if (Spiders[i].on)
m_writer->WriteChunk(m_chunkSpiders, &saveSpiders, i, 0);
}
void SaveGame::saveItem(int itemNumber, int runtimeItem)
{
ITEM_INFO* item = &Items[itemNumber];
OBJECT_INFO* obj = &Objects[item->objectNumber];
LEB128::Write(m_stream, itemNumber);
2018-10-24 23:32:22 +02:00
LEB128::Write(m_stream, runtimeItem);
bool hasData = true;
if (item->flags & IFLAG_KILLED)
{
LEB128::Write(m_stream, 0x2000);
hasData = false;
}
else if (item->flags & (IFLAG_ACTIVATION_MASK | IFLAG_INVISIBLE | 0x20)
|| item->objectNumber == ID_LARA)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, 0x8000);
hasData = true;
}
else
{
LEB128::Write(m_stream, 0x0000);
hasData = false;
}
LEB128::Write(m_stream, item->objectNumber);
if (hasData)
{
m_writer->WriteChunkInt(m_chunkItemDummy, 1);
if (obj->saveAnim)
m_writer->WriteChunk(m_chunkItemAnims, &saveItemAnims, itemNumber, 0);
if (obj->savePosition)
m_writer->WriteChunk(m_chunkItemPosition, &saveItemPosition, itemNumber, 0);
if (obj->saveHitpoints)
m_writer->WriteChunk(m_chunkItemHitPoints, &saveItemHitPoints, itemNumber, 0);
if (obj->saveFlags)
m_writer->WriteChunkWithChildren(m_chunkItemFlags, &saveItemFlags, itemNumber, 0);
if (obj->saveMesh)
m_writer->WriteChunk(m_chunkItemMeshes, &saveItemMesh, itemNumber, 0);
2018-10-24 23:32:22 +02:00
if (obj->intelligent && item->data != NULL)
m_writer->WriteChunk(m_chunkItemIntelligentData, &saveItemIntelligentData, itemNumber, 0);
}
else
{
m_writer->WriteChunkInt(m_chunkItemDummy, 1);
}
}
void SaveGame::saveGameStatus(int arg1, int arg2)
{
LEB128::Write(m_stream, FlipStatus);
LEB128::Write(m_stream, LastInventoryItem);
LEB128::Write(m_stream, FlipEffect);
LEB128::Write(m_stream, FlipTimer);
LEB128::Write(m_stream, CurrentAtmosphere);
2018-10-24 23:32:22 +02:00
LEB128::Write(m_stream, CurrentSequence);
// Now the sub-chunks
if (NumberRooms > 0)
{
for (int i = 0; i < NumberRooms; i++)
for (int j = 0; j < Rooms[i].numMeshes; j++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunk(m_chunkStaticFlags, &saveStaticFlag, i, j);
}
for (int i = 0; i < 6; i++)
m_writer->WriteChunk(m_chunkSequenceSwitch, &saveSequenceSwitch, i, SequenceUsed[i]);
2018-10-24 23:32:22 +02:00
for (int i = 0; i < NumberSpotcams; i++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunk(m_chunkFlybyFlags, &saveFlybyFlags, i, SpotCam[i].flags);
for (int i = 0; i < g_AudioTracks.size(); i++)
m_writer->WriteChunk(m_chunkCdFlags, &saveCdFlags, i, g_AudioTracks[i].Mask);
for (int i = 0; i < NumberCameras; i++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunk(m_chunkCamera, &saveCamera, i, Camera.fixed[i].flags);
for (int i = 0; i < 255; i++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunk(m_chunkFlipStats, &saveFlipStats, i, FlipStats[i]);
for (int i = 0; i < 255; i++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunk(m_chunkFlipMap, &saveFlipMap, i, FlipMap[i]);
}
void SaveGame::saveLara(int arg1, int arg2)
{
// LARA_INFO struct dumped to savegame
LARA_INFO lara;
memcpy(&lara, &Lara, sizeof(Lara));
for (int i = 0; i < 15; i++)
2019-12-11 07:48:27 +01:00
lara.meshPtrs[i] = (short*)((char*)lara.meshPtrs[i] - (ptrdiff_t)MeshBase);
lara.leftArm.frameBase = (short*)((char *)lara.leftArm.frameBase - (ptrdiff_t)Objects[ID_LARA].frameBase);
lara.rightArm.frameBase = (short*)((char *)lara.rightArm.frameBase - (ptrdiff_t)Objects[ID_LARA].frameBase);
2019-12-11 07:48:27 +01:00
lara.generalPtr = (char *)lara.generalPtr - (ptrdiff_t)MallocBuffer;
m_stream->Write(reinterpret_cast<char*>(&lara), sizeof(Lara));
// Lara weapon data
if (Lara.weaponItem != NO_ITEM)
m_writer->WriteChunk(m_chunkWeaponItem, &saveWeaponItem, Lara.weaponItem, 0);
// Save Lara extra info
m_writer->WriteChunk(m_chunkLaraExtraInfo, &saveLaraExtraInfo, 0, 0);
// Save carried weapons
for (int i = 0; i < NUM_WEAPONS; i++)
{
m_writer->WriteChunk(m_chunkWeaponInfo, &saveWeaponInfo, i, 0);
}
// Save carried puzzles, keys, pickups and examines
for (int i = 0; i < NUM_PUZZLES; i++)
{
if (g_LaraExtra.Puzzles[i] > 0)
m_writer->WriteChunk(m_chunkPuzzle, &savePuzzle, i, g_LaraExtra.Puzzles[i]);
}
for (int i = 0; i < NUM_PUZZLES * 2; i++)
{
if (g_LaraExtra.PuzzlesCombo[i] > 0)
m_writer->WriteChunk(m_chunkPuzzleCombo, &savePuzzle, i, g_LaraExtra.PuzzlesCombo[i]);
}
for (int i = 0; i < NUM_KEYS; i++)
{
if (g_LaraExtra.Keys[i] > 0)
m_writer->WriteChunk(m_chunkKey, &savePuzzle, i, g_LaraExtra.Keys[i]);
}
for (int i = 0; i < NUM_KEYS * 2; i++)
{
if (g_LaraExtra.KeysCombo[i] > 0)
m_writer->WriteChunk(m_chunkKeyCombo, &savePuzzle, i, g_LaraExtra.KeysCombo[i]);
}
for (int i = 0; i < NUM_PICKUPS; i++)
{
if (g_LaraExtra.Pickups[i] > 0)
m_writer->WriteChunk(m_chunkPickup, &savePuzzle, i, g_LaraExtra.Pickups[i]);
}
for (int i = 0; i < NUM_PICKUPS * 2; i++)
{
if (g_LaraExtra.PickupsCombo[i] > 0)
m_writer->WriteChunk(m_chunkPickupCombo, &savePuzzle, i, g_LaraExtra.PickupsCombo[i]);
}
for (int i = 0; i < NUM_EXAMINES; i++)
{
if (g_LaraExtra.Examines[i] > 0)
m_writer->WriteChunk(m_chunkExamine, &savePuzzle, i, g_LaraExtra.Examines[i]);
}
for (int i = 0; i < NUM_EXAMINES * 2; i++)
{
if (g_LaraExtra.ExaminesCombo[i] > 0)
m_writer->WriteChunk(m_chunkExamineCombo, &savePuzzle, i, g_LaraExtra.ExaminesCombo[i]);
}
}
void SaveGame::saveWeaponItem(int arg1, int arg2)
{
ITEM_INFO* weaponItem = &Items[arg1];
LEB128::Write(m_stream, weaponItem->objectNumber);
LEB128::Write(m_stream, weaponItem->animNumber);
LEB128::Write(m_stream, weaponItem->frameNumber);
LEB128::Write(m_stream, weaponItem->currentAnimState);
LEB128::Write(m_stream, weaponItem->goalAnimState);
LEB128::Write(m_stream, weaponItem->requiredAnimState);
}
void SaveGame::saveLaraExtraInfo(int arg1, int arg2)
{
LEB128::Write(m_stream, (g_LaraExtra.Binoculars ? 1 : 0));
LEB128::Write(m_stream, (g_LaraExtra.Lasersight ? 1 : 0));
LEB128::Write(m_stream, (g_LaraExtra.Crowbar ? 1 : 0));
LEB128::Write(m_stream, (g_LaraExtra.Silencer ? 1 : 0));
LEB128::Write(m_stream, (g_LaraExtra.Torch ? 1 : 0));
LEB128::Write(m_stream, g_LaraExtra.Secrets);
LEB128::Write(m_stream, g_LaraExtra.ExtraAnim);
LEB128::Write(m_stream, g_LaraExtra.Vehicle);
LEB128::Write(m_stream, g_LaraExtra.mineL);
LEB128::Write(m_stream, g_LaraExtra.mineR);
LEB128::Write(m_stream, g_LaraExtra.NumFlares);
LEB128::Write(m_stream, g_LaraExtra.NumLargeMedipacks);
LEB128::Write(m_stream, g_LaraExtra.NumSmallMedipacks);
}
void SaveGame::savePuzzle(int arg1, int arg2)
{
LEB128::Write(m_stream, arg1); // ID
LEB128::Write(m_stream, arg2); // Quantity
}
void SaveGame::saveWeaponInfo(int arg1, int arg2)
{
CarriedWeaponInfo* weapon = &g_LaraExtra.Weapons[arg1];
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, weapon->Present);
LEB128::Write(m_stream, weapon->SelectedAmmo);
LEB128::Write(m_stream, weapon->Ammo[WEAPON_AMMO1]);
LEB128::Write(m_stream, weapon->Ammo[WEAPON_AMMO2]);
LEB128::Write(m_stream, weapon->Ammo[WEAPON_AMMO3]);
LEB128::Write(m_stream, weapon->HasSilencer);
LEB128::Write(m_stream, weapon->HasLasersight);
}
2018-10-24 23:32:22 +02:00
void SaveGame::saveVariables()
2018-10-09 00:02:14 +02:00
{
m_luaVariables.clear();
g_GameScript->GetVariables(&m_luaVariables);
for (int i = 0; i < m_luaVariables.size(); i++)
2018-10-24 23:32:22 +02:00
m_writer->WriteChunk(m_chunkLuaVariable, &saveVariable, i, 0);
2018-10-09 00:02:14 +02:00
}
void SaveGame::saveVariable(int arg1, int arg2)
2018-10-09 00:02:14 +02:00
{
2018-10-24 23:32:22 +02:00
LuaVariable variable = m_luaVariables[arg1];
2018-10-09 00:02:14 +02:00
LEB128::Write(m_stream, variable.IsGlobal == 1);
LEB128::Write(m_stream, variable.Type);
2018-10-09 00:02:14 +02:00
m_stream->WriteString((char*)variable.Name.c_str());
if (variable.Type == LUA_VARIABLE_TYPE_BOOL)
m_stream->WriteBool(variable.BoolValue);
2018-10-09 00:02:14 +02:00
else if (variable.Type == LUA_VARIABLE_TYPE_INT)
m_stream->WriteInt32(variable.IntValue);
2018-10-09 00:02:14 +02:00
else if (variable.Type == LUA_VARIABLE_TYPE_STRING)
m_stream->WriteString((char*)variable.StringValue.c_str());
else if (variable.Type == LUA_VARIABLE_TYPE_FLOAT)
m_stream->WriteFloat(variable.FloatValue);
2018-10-09 00:02:14 +02:00
}
void SaveGame::Start()
{
m_chunkGameStatus = ChunkId::FromString("TR5MSgGameStatus");
m_chunkItems = ChunkId::FromString("TR5MSgItems");
m_chunkItem = ChunkId::FromString("TR5MSgItem");
m_chunkLara = ChunkId::FromString("TR5MSgLara");
m_chunkLuaVariable = ChunkId::FromString("TR5MSgLuaVar");
2018-10-24 23:32:22 +02:00
m_chunkStaticFlags = ChunkId::FromString("TR5MSgStFl");
m_chunkVehicle = ChunkId::FromString("TR5MSgLaraVeh");
m_chunkSequenceSwitch = ChunkId::FromString("TR5MSgSeqSw");
2018-10-24 23:32:22 +02:00
m_chunkFlybyFlags = ChunkId::FromString("TR5MSgFlybyF");
m_chunkCdFlags = ChunkId::FromString("TR5MSgCdF");
m_chunkCamera = ChunkId::FromString("TR5MSgCam");
m_chunkFlipStats = ChunkId::FromString("TR5MSgFlS");
m_chunkFlipMap = ChunkId::FromString("TR5MSgFlM");
m_chunkItemDummy = ChunkId::FromString("TR5MSgItemDummy");
m_chunkStatistics = ChunkId::FromString("TR5MSgStats");
m_chunkItemAnims = ChunkId::FromString("TR5MSgItAnms");
m_chunkItemMeshes = ChunkId::FromString("TR5MSgItMsh");
m_chunkItemFlags = ChunkId::FromString("TR5MSgItFl");
m_chunkItemHitPoints = ChunkId::FromString("TR5MSgItHP");
m_chunkItemPosition = ChunkId::FromString("TR5MSgItPos");
m_chunkItemIntelligentData = ChunkId::FromString("TR5MSgItIntell");
m_chunkSpecialItemBurningTorch = ChunkId::FromString("TR5MSgItTorch");
m_chunkSpecialItemChaff = ChunkId::FromString("TR5MSgItChaff");
m_chunkSpecialItemTorpedo = ChunkId::FromString("TR5MSgItTorpedo");
m_chunkSpecialItemCrossbowBolt = ChunkId::FromString("TR5MSgItBolt");
m_chunkSpecialItemFlare = ChunkId::FromString("TR5MSgItFlare");
m_chunkItemQuadInfo = ChunkId::FromString("TR5MSgQuadInfo");
m_chunkBats = ChunkId::FromString("TR5MSgBats");
m_chunkRats = ChunkId::FromString("TR5MSgRats");
m_chunkSpiders = ChunkId::FromString("TR5MSgSpiders");
m_chunkLaraExtraInfo = ChunkId::FromString("TR5MSgLaraExtraInfo");
m_chunkWeaponInfo = ChunkId::FromString("TR5MSgWeapon");
m_chunkPuzzle = ChunkId::FromString("TR5MSgPuzzle");
m_chunkPuzzleCombo = ChunkId::FromString("TR5MSgPuzzleC");
m_chunkKey = ChunkId::FromString("TR5MSgKey");
m_chunkKeyCombo = ChunkId::FromString("TR5MSgKeyC");
m_chunkPickup = ChunkId::FromString("TR5MSgPickup");
m_chunkPickupCombo = ChunkId::FromString("TR5MSgPickupC");
m_chunkExamine = ChunkId::FromString("TR5MSgExamine");
m_chunkExamineCombo = ChunkId::FromString("TR5MSgExamineC");
m_chunkWeaponItem = ChunkId::FromString("TR5MSgWeaponItem");
2018-10-24 23:32:22 +02:00
LastSaveGame = 0;
2018-10-09 00:02:14 +02:00
}
void SaveGame::End()
{
delete m_chunkGameStatus;
delete m_chunkItems;
delete m_chunkItem;
delete m_chunkLara;
delete m_chunkLuaVariable;
2018-10-24 23:32:22 +02:00
delete m_chunkStaticFlags;
delete m_chunkVehicle;
2018-10-24 23:32:22 +02:00
delete m_chunkFlipMap;
delete m_chunkFlipStats;
delete m_chunkFlybyFlags;
delete m_chunkSequenceSwitch;
2018-10-24 23:32:22 +02:00
delete m_chunkCdFlags;
delete m_chunkCamera;
delete m_chunkItemDummy;
delete m_chunkStatistics;
delete m_chunkItemAnims;
delete m_chunkItemMeshes;
delete m_chunkItemFlags;
delete m_chunkItemHitPoints;
delete m_chunkItemPosition;
delete m_chunkItemIntelligentData;
delete m_chunkSpecialItemBurningTorch;
delete m_chunkSpecialItemChaff;
delete m_chunkSpecialItemTorpedo;
delete m_chunkSpecialItemCrossbowBolt;
delete m_chunkSpecialItemFlare;
delete m_chunkItemQuadInfo;
delete m_chunkBats;
delete m_chunkRats;
delete m_chunkSpiders;
delete m_chunkLaraExtraInfo;
delete m_chunkWeaponInfo;
delete m_chunkPuzzle;
delete m_chunkKey;
delete m_chunkPickup;
delete m_chunkExamine;
delete m_chunkPuzzleCombo;
delete m_chunkKeyCombo;
delete m_chunkPickupCombo;
delete m_chunkExamineCombo;
delete m_chunkWeaponItem;
2018-10-09 00:02:14 +02:00
}
2018-10-09 00:02:14 +02:00
bool SaveGame::Save(char* fileName)
{
2018-10-24 23:32:22 +02:00
m_stream = new FileStream(fileName, true, true);
m_writer = new ChunkWriter(0x4D355254, m_stream);
printf("Timer: %d\n", Savegame.Game.Timer);
2018-10-24 23:32:22 +02:00
// The header must be here, so no chunks
m_stream->WriteString(g_GameFlow->GetString(g_GameFlow->GetLevel(CurrentLevel)->NameStringIndex));
LEB128::Write(m_stream, (GameTimer / 30) / 86400);
LEB128::Write(m_stream, ((GameTimer / 30) % 86400) / 3600);
LEB128::Write(m_stream, ((GameTimer / 30) / 60) % 60);
LEB128::Write(m_stream, (GameTimer / 30) % 60);
2018-10-24 23:32:22 +02:00
LEB128::Write(m_stream, CurrentLevel);
LEB128::Write(m_stream, GameTimer);
LEB128::Write(m_stream, ++LastSaveGame);
2018-10-24 23:32:22 +02:00
// Now we write chunks
m_writer->WriteChunk(m_chunkStatistics, &saveStatistics, 0, 0);
m_writer->WriteChunkWithChildren(m_chunkGameStatus, &saveGameStatus, 0, 0);
m_writer->WriteChunkWithChildren(m_chunkLara, &saveLara, 0, 0);
saveItems();
saveVariables();
// EOF
m_stream->WriteInt32(0);
m_stream->Close();
delete m_writer;
delete m_stream;
return true;
}
bool SaveGame::readGameStatus()
{
2018-10-24 23:32:22 +02:00
FlipStatus = LEB128::ReadInt32(m_stream);
LastInventoryItem = LEB128::ReadInt32(m_stream);
2018-10-24 23:32:22 +02:00
FlipEffect = LEB128::ReadInt32(m_stream);
FlipTimer = LEB128::ReadInt32(m_stream);
CurrentAtmosphere = LEB128::ReadByte(m_stream);
CurrentSequence = LEB128::ReadByte(m_stream);
2018-10-24 23:32:22 +02:00
m_reader->ReadChunks(&readGameStatusChunks, 0);
return true;
}
bool SaveGame::readLara()
{
// Read dumped LARA_INFO struct
char* buffer = (char*)malloc(sizeof(LARA_INFO));
m_stream->Read(buffer, sizeof(LARA_INFO));
LARA_INFO* lara = reinterpret_cast<LARA_INFO*>(buffer);
2018-10-24 23:32:22 +02:00
memcpy(&Lara, lara, sizeof(LARA_INFO));
free(buffer);
for (int i = 0; i < 15; i++)
2018-10-24 23:32:22 +02:00
{
Lara.meshPtrs[i] = ADD_PTR(Lara.meshPtrs[i], short, MeshBase);
//printf("MeshPtr: %d\n", Lara.meshPtrs[i]);
2018-10-24 23:32:22 +02:00
}
Lara.leftArm.frameBase = ADD_PTR(Lara.leftArm.frameBase, short, Objects[ID_LARA].frameBase);
Lara.rightArm.frameBase = ADD_PTR(Lara.rightArm.frameBase, short, Objects[ID_LARA].frameBase);
2018-10-24 23:32:22 +02:00
Lara.target = NULL;
Lara.spazEffect = NULL;
Lara.generalPtr = ADD_PTR(Lara.generalPtr, char, MallocBuffer);
Lara.weaponItem = NO_ITEM;
// Is Lara burning?
2018-10-24 23:32:22 +02:00
if (Lara.burn)
{
2018-10-24 23:32:22 +02:00
Lara.burn = false;
bool smokeFlag = false;
2018-10-24 23:32:22 +02:00
if (Lara.burnSmoke)
{
2018-10-24 23:32:22 +02:00
Lara.burnSmoke = false;
smokeFlag = true;
}
LaraBurn();
if (smokeFlag)
2018-10-24 23:32:22 +02:00
Lara.burnSmoke = true;
}
2018-10-24 23:32:22 +02:00
m_reader->ReadChunks(&readLaraChunks, 0);
2018-10-24 23:32:22 +02:00
return true;
}
bool SaveGame::readItem()
{
short itemNumber = LEB128::ReadInt16(m_stream);
short runtimeItem = LEB128::ReadByte(m_stream);
short itemKind = LEB128::ReadInt16(m_stream);
// Runtime items must be allocated dynamically
if (runtimeItem)
itemNumber = CreateItem();
ITEM_INFO* item = &Items[itemNumber];
item->objectNumber = LEB128::ReadInt16(m_stream);
OBJECT_INFO* obj = &Objects[item->objectNumber];
// Runtime items must be initialised
// TODO: test test test!!!
if (runtimeItem)
{
InitialiseItem(itemNumber);
AddActiveItem(itemNumber);
}
2018-10-24 23:32:22 +02:00
if (itemKind == 0x2000)
{
m_reader->ReadChunks(&readItemChunks, itemNumber);
DisableBaddieAI(itemNumber);
2018-10-24 23:32:22 +02:00
KillItem(itemNumber);
item->status = ITEM_DEACTIVATED;
item->flags |= ONESHOT;
item->afterDeath = 128;
2018-10-24 23:32:22 +02:00
}
else if (itemKind == 0x8000)
{
m_reader->ReadChunks(&readItemChunks, itemNumber);
}
else
{
m_reader->ReadChunks(&readItemChunks, itemNumber);
}
// Some post-processing things
if (obj->collision == PuzzleHoleCollision && (item->status == ITEM_DEACTIVATED || item->status == ITEM_ACTIVE))
{
item->objectNumber += 8;
2019-12-01 08:13:19 +01:00
//*((_WORD *)pItem - 28) = v55 + Objects[*((_WORD *)pItem - 32)].anim_index;
}
if (item->objectNumber >= ID_SMASH_OBJECT1 && item->objectNumber <= ID_SMASH_OBJECT8 && (item->flags & ONESHOT))
item->meshBits = 0x100;
if (item->objectNumber == ID_RAISING_BLOCK1 && item->itemFlags[1])
{
if (item->triggerFlags == -1)
AlterFloorHeight(item, -255);
else if (item->triggerFlags == -3)
AlterFloorHeight(item, -1023);
else
AlterFloorHeight(item, -1024);
}
if (item->objectNumber == ID_RAISING_BLOCK2 && item->itemFlags[1])
AlterFloorHeight(item, -2048);
2018-10-24 23:32:22 +02:00
return true;
}
bool SaveGame::readVariable()
{
LuaVariable variable;
variable.IsGlobal = LEB128::ReadByte(m_stream) == 1;
variable.Type = LEB128::ReadInt32(m_stream);
char* variableName;
m_stream->ReadString(&variableName);
variable.Name = string(variableName);
free(variableName);
if (variable.Type == LUA_VARIABLE_TYPE_BOOL)
m_stream->ReadBool(&variable.BoolValue);
else if (variable.Type == LUA_VARIABLE_TYPE_INT)
m_stream->ReadInt32(&variable.IntValue);
else if (variable.Type == LUA_VARIABLE_TYPE_FLOAT)
m_stream->ReadFloat(&variable.FloatValue);
else if (variable.Type == LUA_VARIABLE_TYPE_STRING)
{
char* variableValue;
m_stream->ReadString(&variableValue);
variable.StringValue = string(variableValue);
free(variableValue);
}
2018-10-24 23:32:22 +02:00
return true;
}
bool SaveGame::readSavegameChunks(ChunkId* chunkId, int maxSize, int arg)
{
2018-10-24 23:32:22 +02:00
if (chunkId->EqualsTo(m_chunkGameStatus))
return readGameStatus();
else if (chunkId->EqualsTo(m_chunkLara))
return readLara();
else if (chunkId->EqualsTo(m_chunkItem))
return readItem();
else if (chunkId->EqualsTo(m_chunkLuaVariable))
return readVariable();
2018-10-24 23:32:22 +02:00
else if (chunkId->EqualsTo(m_chunkStatistics))
return readStatistics();
else if (chunkId->EqualsTo(m_chunkSpecialItemBurningTorch))
return readBurningTorch();
else if (chunkId->EqualsTo(m_chunkSpecialItemChaff))
return readChaff();
else if (chunkId->EqualsTo(m_chunkSpecialItemTorpedo))
return readTorpedo();
else if (chunkId->EqualsTo(m_chunkSpecialItemCrossbowBolt))
return readCrossbowBolt();
else if (chunkId->EqualsTo(m_chunkSpecialItemFlare))
return readFlare();
else if (chunkId->EqualsTo(m_chunkBats))
return readBats();
else if (chunkId->EqualsTo(m_chunkRats))
return readRats();
else if (chunkId->EqualsTo(m_chunkSpiders))
return readSpiders();
return false;
}
bool SaveGame::Load(char* fileName)
{
m_luaVariables.clear();
2018-10-24 23:32:22 +02:00
m_stream = new FileStream(fileName, true, false);
m_reader = new ChunkReader(0x4D355254, m_stream);
2018-10-24 23:32:22 +02:00
// Header must be here
char* levelName;
m_stream->ReadString(&levelName);
// Skip timer
LEB128::ReadInt32(m_stream);
LEB128::ReadInt32(m_stream);
LEB128::ReadInt32(m_stream);
LEB128::ReadInt32(m_stream);
CurrentLevel = LEB128::ReadByte(m_stream);
GameTimer = LEB128::ReadInt32(m_stream);
LastSaveGame = LEB128::ReadInt32(m_stream);
// Read chunks
m_reader->ReadChunks(&readSavegameChunks, 0);
// Close the stream
m_stream->Close();
2018-10-24 23:32:22 +02:00
//delete m_writer;
//delete m_stream;
g_GameScript->SetVariables(&m_luaVariables);
2018-10-24 23:32:22 +02:00
JustLoaded = true;
return true;
}
bool SaveGame::LoadHeader(char* fileName, SaveGameHeader* header)
{
m_stream = new FileStream(fileName, true, false);
m_reader = new ChunkReader(0x4D355254, m_stream);
// Header must be here
char* levelName;
m_stream->ReadString(&levelName);
header->LevelName = string(levelName);
free(levelName);
// Skip timer
header->Days = LEB128::ReadInt32(m_stream);
header->Hours = LEB128::ReadInt32(m_stream);
header->Minutes = LEB128::ReadInt32(m_stream);
header->Seconds = LEB128::ReadInt32(m_stream);
header->Level = LEB128::ReadByte(m_stream);
header->Timer = LEB128::ReadInt32(m_stream);
header->Count = LEB128::ReadInt32(m_stream);
// Close the stream
m_stream->Close();
//delete m_writer;
//delete m_stream;
return true;
}
void SaveGame::saveStaticFlag(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
LEB128::Write(m_stream, Rooms[arg1].mesh[arg2].Flags);
}
bool SaveGame::readLaraChunks(ChunkId* chunkId, int maxSize, int arg)
2018-10-24 23:32:22 +02:00
{
if (chunkId->EqualsTo(m_chunkLaraExtraInfo))
2018-10-24 23:32:22 +02:00
{
g_LaraExtra.Binoculars = LEB128::ReadByte(m_stream);
g_LaraExtra.Lasersight = LEB128::ReadByte(m_stream);
g_LaraExtra.Crowbar = LEB128::ReadByte(m_stream);
g_LaraExtra.Silencer = LEB128::ReadByte(m_stream);
g_LaraExtra.Torch = LEB128::ReadByte(m_stream);
g_LaraExtra.Secrets = LEB128::ReadInt32(m_stream);
g_LaraExtra.ExtraAnim = LEB128::ReadInt16(m_stream);
g_LaraExtra.Vehicle = LEB128::ReadInt16(m_stream);
g_LaraExtra.mineL = LEB128::ReadByte(m_stream);
g_LaraExtra.mineR = LEB128::ReadByte(m_stream);
g_LaraExtra.NumFlares = LEB128::ReadInt32(m_stream);
g_LaraExtra.NumLargeMedipacks = LEB128::ReadInt32(m_stream);
g_LaraExtra.NumSmallMedipacks = LEB128::ReadInt32(m_stream);
2018-10-24 23:32:22 +02:00
return true;
}
else if (chunkId->EqualsTo(m_chunkWeaponInfo))
{
int id = LEB128::ReadInt32(m_stream);
CarriedWeaponInfo* weapon = &g_LaraExtra.Weapons[id];
weapon->Present = LEB128::ReadByte(m_stream);
weapon->SelectedAmmo = LEB128::ReadByte(m_stream);
weapon->Ammo[WEAPON_AMMO1] = LEB128::ReadInt16(m_stream);
weapon->Ammo[WEAPON_AMMO2] = LEB128::ReadInt16(m_stream);
weapon->Ammo[WEAPON_AMMO3] = LEB128::ReadInt16(m_stream);
weapon->HasSilencer = LEB128::ReadByte(m_stream);
weapon->HasLasersight = LEB128::ReadByte(m_stream);
}
else if (chunkId->EqualsTo(m_chunkPuzzle))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.Puzzles[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkPuzzleCombo))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.PuzzlesCombo[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkKey))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.Keys[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkKeyCombo))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.KeysCombo[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkPickup))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.Pickups[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkPickupCombo))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.PickupsCombo[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkExamine))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.Examines[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkExamineCombo))
{
int id = LEB128::ReadInt32(m_stream);
int quantity = LEB128::ReadInt32(m_stream);
g_LaraExtra.ExaminesCombo[id] = quantity;
}
else if (chunkId->EqualsTo(m_chunkWeaponItem))
{
short weaponItemNum = CreateItem();
Lara.weaponItem = weaponItemNum;
ITEM_INFO* weaponItem = &Items[Lara.weaponItem];
weaponItem->objectNumber = LEB128::ReadInt16(m_stream);
weaponItem->animNumber = LEB128::ReadInt16(m_stream);
weaponItem->frameNumber = LEB128::ReadInt16(m_stream);
weaponItem->currentAnimState = LEB128::ReadInt16(m_stream);
weaponItem->goalAnimState = LEB128::ReadInt16(m_stream);
weaponItem->requiredAnimState = LEB128::ReadInt16(m_stream);
weaponItem->roomNumber = 255;
}
2018-10-24 23:32:22 +02:00
return false;
}
bool SaveGame::readGameStatusChunks(ChunkId* chunkId, int maxSize, int arg)
2018-10-24 23:32:22 +02:00
{
if (chunkId->EqualsTo(m_chunkStaticFlags))
{
short roomIndex = LEB128::ReadInt16(m_stream);
short staticIndex = LEB128::ReadInt16(m_stream);
short flags = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
Rooms[roomIndex].mesh[staticIndex].Flags = flags;
if (!flags)
{
FLOOR_INFO* floor = GetFloor(Rooms[roomIndex].mesh[staticIndex].x,
Rooms[roomIndex].mesh[staticIndex].y,
Rooms[roomIndex].mesh[staticIndex].z,
&roomIndex);
int height = GetFloorHeight(floor, Rooms[roomIndex].mesh[staticIndex].x,
2018-10-24 23:32:22 +02:00
Rooms[roomIndex].mesh[staticIndex].y,
Rooms[roomIndex].mesh[staticIndex].z);
TestTriggers(TriggerIndex, 1, 0);
floor->stopper = false;
}
return true;
}
else if (chunkId->EqualsTo(m_chunkFlipStats))
{
short index = LEB128::ReadInt16(m_stream);
short value = LEB128::ReadInt16(m_stream);
2020-01-14 00:26:44 -03:00
//FlipStats[index] = value;
2018-10-24 23:32:22 +02:00
return true;
}
else if (chunkId->EqualsTo(m_chunkFlipMap))
{
short index = LEB128::ReadInt16(m_stream);
short value = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
FlipMap[index] = value;
2020-01-14 00:26:44 -03:00
if ((value & 0x3E00) == 0x3E00)
DoFlipMap(index);
2018-10-24 23:32:22 +02:00
return true;
}
else if (chunkId->EqualsTo(m_chunkCdFlags))
{
short index = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
printf("Index: %d\n", index);
short value = LEB128::ReadInt16(m_stream);
if (index < g_AudioTracks.size())
g_AudioTracks[index].Mask = value;
2018-10-24 23:32:22 +02:00
return true;
}
else if (chunkId->EqualsTo(m_chunkCamera))
{
short index = LEB128::ReadInt16(m_stream);
short value = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
Camera.fixed[index].flags = value;
return true;
}
else if (chunkId->EqualsTo(m_chunkSequenceSwitch))
2018-10-24 23:32:22 +02:00
{
short index = LEB128::ReadInt16(m_stream);
short value = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
SequenceUsed[index] = value;
return true;
}
else if (chunkId->EqualsTo(m_chunkFlybyFlags))
{
int index = LEB128::ReadInt16(m_stream);
int value = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
SpotCam[index].flags = value;
return true;
}
return false;
}
void SaveGame::saveCamera(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
}
void SaveGame::saveSequenceSwitch(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
}
void SaveGame::saveFlybyFlags(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
}
void SaveGame::saveFlipMap(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
}
void SaveGame::saveFlipStats(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
}
void SaveGame::saveCdFlags(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, arg1);
LEB128::Write(m_stream, arg2);
}
bool SaveGame::readItemChunks(ChunkId* chunkId, int maxSize, int itemNumber)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[itemNumber];
if (chunkId->EqualsTo(m_chunkItemDummy))
return m_reader->ReadChunkInt32(maxSize);
else if (chunkId->EqualsTo(m_chunkItemAnims))
{
item->currentAnimState = LEB128::ReadInt16(m_stream);
item->goalAnimState = LEB128::ReadInt16(m_stream);
item->requiredAnimState = LEB128::ReadInt16(m_stream);
item->animNumber = LEB128::ReadInt16(m_stream);
item->frameNumber = LEB128::ReadInt16(m_stream);
return true;
}
else if (chunkId->EqualsTo(m_chunkItemPosition))
{
item->pos.xPos = LEB128::ReadInt32(m_stream);
item->pos.yPos = LEB128::ReadInt32(m_stream);
item->pos.zPos = LEB128::ReadInt32(m_stream);
item->pos.xRot = LEB128::ReadInt16(m_stream);
item->pos.yRot = LEB128::ReadInt16(m_stream);
item->pos.zRot = LEB128::ReadInt16(m_stream);
short roomNumber = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
if (item->roomNumber != roomNumber)
ItemNewRoom(itemNumber, roomNumber);
item->speed = LEB128::ReadInt16(m_stream);
item->fallspeed = LEB128::ReadInt16(m_stream);
2018-10-24 23:32:22 +02:00
return true;
}
else if (chunkId->EqualsTo(m_chunkItemHitPoints))
{
item->hitPoints = LEB128::ReadInt16(m_stream);
return true;
}
else if (chunkId->EqualsTo(m_chunkItemFlags))
{
item->flags = LEB128::ReadInt16(m_stream);
byte active = LEB128::ReadByte(m_stream);
item->status = LEB128::ReadByte(m_stream);
item->gravityStatus = LEB128::ReadByte(m_stream);
item->hitStatus = LEB128::ReadByte(m_stream);
item->collidable = LEB128::ReadByte(m_stream);
item->lookedAt = LEB128::ReadByte(m_stream);
item->dynamicLight = LEB128::ReadByte(m_stream);
item->poisoned = LEB128::ReadByte(m_stream);
item->aiBits = LEB128::ReadByte(m_stream);
item->reallyActive = LEB128::ReadByte(m_stream);
item->triggerFlags = LEB128::ReadInt16(m_stream);
item->timer = LEB128::ReadByte(m_stream);
item->itemFlags[0] = LEB128::ReadInt16(m_stream);
item->itemFlags[1] = LEB128::ReadInt16(m_stream);
item->itemFlags[2] = LEB128::ReadInt16(m_stream);
item->itemFlags[3] = LEB128::ReadInt16(m_stream);
if (active && !item->active)
AddActiveItem(itemNumber);
return true;
}
else if (chunkId->EqualsTo(m_chunkItemIntelligentData))
{
EnableBaddieAI(itemNumber, 1);
OBJECT_INFO* obj = &Objects[item->objectNumber];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
2018-10-24 23:32:22 +02:00
creature->jointRotation[0] = LEB128::ReadInt16(m_stream);
creature->jointRotation[1] = LEB128::ReadInt16(m_stream);
creature->jointRotation[2] = LEB128::ReadInt16(m_stream);
creature->jointRotation[3] = LEB128::ReadInt16(m_stream);
creature->maximumTurn = LEB128::ReadInt16(m_stream);
creature->flags = LEB128::ReadInt16(m_stream);
creature->alerted = LEB128::ReadByte(m_stream);
creature->headLeft = LEB128::ReadByte(m_stream);
creature->headRight = LEB128::ReadByte(m_stream);
creature->reachedGoal = LEB128::ReadByte(m_stream);
creature->hurtByLara = LEB128::ReadByte(m_stream);
creature->patrol2 = LEB128::ReadByte(m_stream);
creature->jumpAhead = LEB128::ReadByte(m_stream);
creature->monkeyAhead = LEB128::ReadByte(m_stream);
creature->mood = (MOOD_TYPE)LEB128::ReadInt32(m_stream);
ITEM_INFO* enemy = (ITEM_INFO*)LEB128::ReadLong(m_stream);
creature->enemy = ADD_PTR(enemy, ITEM_INFO, MallocBuffer);
creature->aiTarget.objectNumber = LEB128::ReadInt16(m_stream);
creature->aiTarget.roomNumber = LEB128::ReadInt16(m_stream);
creature->aiTarget.boxNumber = LEB128::ReadInt16(m_stream);
creature->aiTarget.flags = LEB128::ReadInt16(m_stream);
creature->aiTarget.pos.xPos = LEB128::ReadInt32(m_stream);
creature->aiTarget.pos.yPos = LEB128::ReadInt32(m_stream);
creature->aiTarget.pos.zPos = LEB128::ReadInt32(m_stream);
creature->aiTarget.pos.xRot = LEB128::ReadInt16(m_stream);
creature->aiTarget.pos.yRot = LEB128::ReadInt16(m_stream);
creature->aiTarget.pos.zRot = LEB128::ReadInt16(m_stream);
creature->LOT.canJump = LEB128::ReadByte(m_stream);
creature->LOT.canMonkey = LEB128::ReadByte(m_stream);
creature->LOT.isAmphibious = LEB128::ReadByte(m_stream);
creature->LOT.isJumping = LEB128::ReadByte(m_stream);
creature->LOT.isMonkeying = LEB128::ReadByte(m_stream);
return true;
}
else if (chunkId->EqualsTo(m_chunkItemQuadInfo))
{
QUAD_INFO* quadInfo = (QUAD_INFO*)GameMalloc(sizeof(QUAD_INFO));
m_stream->ReadBytes(reinterpret_cast<byte*>(quadInfo), sizeof(QUAD_INFO));
if (item->objectNumber == ID_QUAD)
item->data = (void*)quadInfo;
return true;
}
else if (chunkId->EqualsTo(m_chunkItemMeshes))
{
item->meshBits = LEB128::ReadInt32(m_stream);
item->swapMeshFlags = LEB128::ReadInt32(m_stream);
return true;
}
2018-10-24 23:32:22 +02:00
return false;
}
void SaveGame::saveStatistics(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
LEB128::Write(m_stream, Savegame.Game.AmmoHits);
LEB128::Write(m_stream, Savegame.Game.AmmoUsed);
LEB128::Write(m_stream, Savegame.Game.Distance);
LEB128::Write(m_stream, Savegame.Game.HealthUsed);
LEB128::Write(m_stream, Savegame.Game.Kills);
LEB128::Write(m_stream, Savegame.Game.Secrets);
LEB128::Write(m_stream, Savegame.Game.Timer);
LEB128::Write(m_stream, Savegame.Level.AmmoHits);
LEB128::Write(m_stream, Savegame.Level.AmmoUsed);
LEB128::Write(m_stream, Savegame.Level.Distance);
LEB128::Write(m_stream, Savegame.Level.HealthUsed);
LEB128::Write(m_stream, Savegame.Level.Kills);
LEB128::Write(m_stream, Savegame.Level.Secrets);
LEB128::Write(m_stream, Savegame.Level.Timer);
}
bool SaveGame::readStatistics()
{
Savegame.Game.AmmoHits = LEB128::ReadInt32(m_stream);
Savegame.Game.AmmoUsed = LEB128::ReadInt32(m_stream);
Savegame.Game.Distance = LEB128::ReadInt32(m_stream);
Savegame.Game.HealthUsed = LEB128::ReadByte(m_stream);
Savegame.Game.Kills = LEB128::ReadInt16(m_stream);
Savegame.Game.Secrets = LEB128::ReadByte(m_stream);
Savegame.Game.Timer = LEB128::ReadInt32(m_stream);
Savegame.Level.AmmoHits = LEB128::ReadInt32(m_stream);
Savegame.Level.AmmoUsed = LEB128::ReadInt32(m_stream);
Savegame.Level.Distance = LEB128::ReadInt32(m_stream);
Savegame.Level.HealthUsed = LEB128::ReadByte(m_stream);
Savegame.Level.Kills = LEB128::ReadInt16(m_stream);
Savegame.Level.Secrets = LEB128::ReadByte(m_stream);
Savegame.Level.Timer = LEB128::ReadInt32(m_stream);
return true;
2018-10-24 23:32:22 +02:00
}
void SaveGame::saveItemFlags(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[arg1];
OBJECT_INFO* obj = &Objects[item->objectNumber];
LEB128::Write(m_stream, item->flags);
LEB128::Write(m_stream, item->active);
LEB128::Write(m_stream, item->status);
LEB128::Write(m_stream, item->gravityStatus);
LEB128::Write(m_stream, item->hitStatus);
LEB128::Write(m_stream, item->collidable);
LEB128::Write(m_stream, item->lookedAt);
LEB128::Write(m_stream, item->dynamicLight);
LEB128::Write(m_stream, item->poisoned);
LEB128::Write(m_stream, item->aiBits);
LEB128::Write(m_stream, item->reallyActive);
LEB128::Write(m_stream, item->triggerFlags);
LEB128::Write(m_stream, item->timer);
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]);
}
void SaveGame::saveItemIntelligentData(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[arg1];
OBJECT_INFO* obj = &Objects[item->objectNumber];
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
ITEM_INFO* enemy = (ITEM_INFO*)((char*)creature->enemy - (ptrdiff_t)MallocBuffer);
LEB128::Write(m_stream, creature->jointRotation[0]);
LEB128::Write(m_stream, creature->jointRotation[1]);
LEB128::Write(m_stream, creature->jointRotation[2]);
LEB128::Write(m_stream, creature->jointRotation[3]);
LEB128::Write(m_stream, creature->maximumTurn);
LEB128::Write(m_stream, creature->flags);
LEB128::Write(m_stream, creature->alerted);
LEB128::Write(m_stream, creature->headLeft);
LEB128::Write(m_stream, creature->headRight);
LEB128::Write(m_stream, creature->reachedGoal);
LEB128::Write(m_stream, creature->hurtByLara);
LEB128::Write(m_stream, creature->patrol2);
LEB128::Write(m_stream, creature->jumpAhead);
LEB128::Write(m_stream, creature->monkeyAhead);
LEB128::Write(m_stream, creature->mood);
LEB128::Write(m_stream, (int)enemy);
2018-10-24 23:32:22 +02:00
LEB128::Write(m_stream, creature->aiTarget.objectNumber);
LEB128::Write(m_stream, creature->aiTarget.roomNumber);
LEB128::Write(m_stream, creature->aiTarget.boxNumber);
LEB128::Write(m_stream, creature->aiTarget.flags);
LEB128::Write(m_stream, creature->aiTarget.pos.xPos);
LEB128::Write(m_stream, creature->aiTarget.pos.yPos);
LEB128::Write(m_stream, creature->aiTarget.pos.zPos);
LEB128::Write(m_stream, creature->aiTarget.pos.xRot);
LEB128::Write(m_stream, creature->aiTarget.pos.yRot);
LEB128::Write(m_stream, creature->aiTarget.pos.zRot);
LEB128::Write(m_stream, creature->LOT.canJump);
LEB128::Write(m_stream, creature->LOT.canMonkey);
LEB128::Write(m_stream, creature->LOT.isAmphibious);
LEB128::Write(m_stream, creature->LOT.isJumping);
LEB128::Write(m_stream, creature->LOT.isMonkeying);
}
void SaveGame::saveItemHitPoints(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[arg1];
LEB128::Write(m_stream, item->hitPoints);
}
void SaveGame::saveItemPosition(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[arg1];
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->speed);
LEB128::Write(m_stream, item->fallspeed);
2018-10-24 23:32:22 +02:00
}
void SaveGame::saveItemMesh(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[arg1];
LEB128::Write(m_stream, item->meshBits);
LEB128::Write(m_stream, item->swapMeshFlags);
2018-10-24 23:32:22 +02:00
}
void SaveGame::saveItemAnims(int arg1, int arg2)
2018-10-24 23:32:22 +02:00
{
ITEM_INFO* item = &Items[arg1];
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);
}
void SaveGame::saveBurningTorch(int itemNumber, int arg2)
{
ITEM_INFO* item = &Items[itemNumber];
LEB128::Write(m_stream, itemNumber);
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->speed);
LEB128::Write(m_stream, item->fallspeed);
LEB128::Write(m_stream, item->itemFlags[2]);
}
void SaveGame::saveChaff(int itemNumber, int arg2)
{
ITEM_INFO* item = &Items[itemNumber];
LEB128::Write(m_stream, itemNumber);
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->speed);
LEB128::Write(m_stream, item->fallspeed);
LEB128::Write(m_stream, item->itemFlags[0]);
LEB128::Write(m_stream, item->itemFlags[1]);
}
void SaveGame::saveTorpedo(int itemNumber, int arg2)
{
ITEM_INFO* item = &Items[itemNumber];
LEB128::Write(m_stream, itemNumber);
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->speed);
LEB128::Write(m_stream, item->fallspeed);
LEB128::Write(m_stream, item->itemFlags[0]);
LEB128::Write(m_stream, item->itemFlags[1]);
LEB128::Write(m_stream, item->currentAnimState);
LEB128::Write(m_stream, item->goalAnimState);
LEB128::Write(m_stream, item->requiredAnimState);
}
void SaveGame::saveCrossbowBolt(int itemNumber, int arg2)
{
ITEM_INFO* item = &Items[itemNumber];
LEB128::Write(m_stream, itemNumber);
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->speed);
LEB128::Write(m_stream, item->fallspeed);
}
void SaveGame::saveFlare(int itemNumber, int arg2)
{
ITEM_INFO* item = &Items[itemNumber];
LEB128::Write(m_stream, itemNumber);
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->speed);
LEB128::Write(m_stream, item->fallspeed);
// Flare age
LEB128::Write(m_stream, (int)item->data);
}
bool SaveGame::readBurningTorch()
{
LEB128::ReadInt16(m_stream);
short itemNumber = CreateItem();
ITEM_INFO* item = &Items[itemNumber];
item->objectNumber = ID_BURNING_TORCH_ITEM;
item->pos.xPos = LEB128::ReadInt32(m_stream);
item->pos.yPos = LEB128::ReadInt32(m_stream);
item->pos.zPos = LEB128::ReadInt32(m_stream);
item->pos.xRot = LEB128::ReadInt16(m_stream);
item->pos.yRot = LEB128::ReadInt16(m_stream);
item->pos.zRot = LEB128::ReadInt16(m_stream);
item->roomNumber = LEB128::ReadInt16(m_stream);
short oldXrot = item->pos.xRot;
short oldYrot = item->pos.yRot;
short oldZrot = item->pos.zRot;
InitialiseItem(itemNumber);
item->pos.xRot = oldXrot;
item->pos.yRot = oldYrot;
item->pos.zRot = oldZrot;
item->speed = LEB128::ReadInt16(m_stream);
item->fallspeed = LEB128::ReadInt16(m_stream);
AddActiveItem(itemNumber);
item->itemFlags[2] = LEB128::ReadInt16(m_stream);
return true;
}
bool SaveGame::readChaff()
{
LEB128::ReadInt16(m_stream);
short itemNumber = CreateItem();
ITEM_INFO* item = &Items[itemNumber];
item->objectNumber = ID_CHAFF;
item->pos.xPos = LEB128::ReadInt32(m_stream);
item->pos.yPos = LEB128::ReadInt32(m_stream);
item->pos.zPos = LEB128::ReadInt32(m_stream);
item->pos.xRot = LEB128::ReadInt16(m_stream);
item->pos.yRot = LEB128::ReadInt16(m_stream);
item->pos.zRot = LEB128::ReadInt16(m_stream);
item->roomNumber = LEB128::ReadInt16(m_stream);
short oldXrot = item->pos.xRot;
short oldYrot = item->pos.yRot;
short oldZrot = item->pos.zRot;
InitialiseItem(itemNumber);
item->pos.xRot = oldXrot;
item->pos.yRot = oldYrot;
item->pos.zRot = oldZrot;
item->speed = LEB128::ReadInt16(m_stream);
item->fallspeed = LEB128::ReadInt16(m_stream);
AddActiveItem(itemNumber);
item->itemFlags[0] = LEB128::ReadInt16(m_stream);
item->itemFlags[1] = LEB128::ReadInt16(m_stream);
return true;
}
bool SaveGame::readCrossbowBolt()
{
LEB128::ReadInt16(m_stream);
short itemNumber = CreateItem();
ITEM_INFO* item = &Items[itemNumber];
item->objectNumber = ID_CROSSBOW_BOLT;
item->pos.xPos = LEB128::ReadInt32(m_stream);
item->pos.yPos = LEB128::ReadInt32(m_stream);
item->pos.zPos = LEB128::ReadInt32(m_stream);
item->pos.xRot = LEB128::ReadInt16(m_stream);
item->pos.yRot = LEB128::ReadInt16(m_stream);
item->pos.zRot = LEB128::ReadInt16(m_stream);
item->roomNumber = LEB128::ReadInt16(m_stream);
short oldXrot = item->pos.xRot;
short oldYrot = item->pos.yRot;
short oldZrot = item->pos.zRot;
InitialiseItem(itemNumber);
item->pos.xRot = oldXrot;
item->pos.yRot = oldYrot;
item->pos.zRot = oldZrot;
item->speed = LEB128::ReadInt16(m_stream);
item->fallspeed = LEB128::ReadInt16(m_stream);
AddActiveItem(itemNumber);
return true;
}
bool SaveGame::readFlare()
{
LEB128::ReadInt16(m_stream);
short itemNumber = CreateItem();
ITEM_INFO* item = &Items[itemNumber];
item->objectNumber = ID_FLARE_ITEM;
item->pos.xPos = LEB128::ReadInt32(m_stream);
item->pos.yPos = LEB128::ReadInt32(m_stream);
item->pos.zPos = LEB128::ReadInt32(m_stream);
item->pos.xRot = LEB128::ReadInt16(m_stream);
item->pos.yRot = LEB128::ReadInt16(m_stream);
item->pos.zRot = LEB128::ReadInt16(m_stream);
item->roomNumber = LEB128::ReadInt16(m_stream);
short oldXrot = item->pos.xRot;
short oldYrot = item->pos.yRot;
short oldZrot = item->pos.zRot;
InitialiseItem(itemNumber);
item->pos.xRot = oldXrot;
item->pos.yRot = oldYrot;
item->pos.zRot = oldZrot;
item->speed = LEB128::ReadInt16(m_stream);
item->fallspeed = LEB128::ReadInt16(m_stream);
AddActiveItem(itemNumber);
// Flare age
item->data = (void*)LEB128::ReadInt32(m_stream);
return true;
}
bool SaveGame::readTorpedo()
{
LEB128::ReadInt16(m_stream);
short itemNumber = CreateItem();
ITEM_INFO* item = &Items[itemNumber];
item->objectNumber = ID_TORPEDO;
item->pos.xPos = LEB128::ReadInt32(m_stream);
item->pos.yPos = LEB128::ReadInt32(m_stream);
item->pos.zPos = LEB128::ReadInt32(m_stream);
item->pos.xRot = LEB128::ReadInt16(m_stream);
item->pos.yRot = LEB128::ReadInt16(m_stream);
item->pos.zRot = LEB128::ReadInt16(m_stream);
item->roomNumber = LEB128::ReadInt16(m_stream);
short oldXrot = item->pos.xRot;
short oldYrot = item->pos.yRot;
short oldZrot = item->pos.zRot;
InitialiseItem(itemNumber);
item->pos.xRot = oldXrot;
item->pos.yRot = oldYrot;
item->pos.zRot = oldZrot;
item->speed = LEB128::ReadInt16(m_stream);
item->fallspeed = LEB128::ReadInt16(m_stream);
AddActiveItem(itemNumber);
item->itemFlags[0] = LEB128::ReadInt16(m_stream);
item->itemFlags[1] = LEB128::ReadInt16(m_stream);
item->currentAnimState = LEB128::ReadInt16(m_stream);
item->goalAnimState = LEB128::ReadInt16(m_stream);
item->requiredAnimState = LEB128::ReadInt16(m_stream);
return true;
}
void SaveGame::saveItemQuadInfo(int itemNumber, int arg2)
{
m_stream->WriteBytes(reinterpret_cast<byte*>(Items[itemNumber].data), sizeof(QUAD_INFO));
}
void SaveGame::saveRats(int arg1, int arg2)
{
RAT_STRUCT buffer;
memcpy(&buffer, &Rats[arg1], sizeof(RAT_STRUCT));
LEB128::Write(m_stream, arg1);
m_stream->Write(reinterpret_cast<char*>(&buffer), sizeof(RAT_STRUCT));
}
void SaveGame::saveBats(int arg1, int arg2)
{
BAT_STRUCT buffer;
memcpy(&buffer, &Bats[arg1], sizeof(BAT_STRUCT));
LEB128::Write(m_stream, arg1);
m_stream->Write(reinterpret_cast<char*>(&buffer), sizeof(BAT_STRUCT));
}
void SaveGame::saveSpiders(int arg1, int arg2)
{
SPIDER_STRUCT buffer;
memcpy(&buffer, &Spiders[arg1], sizeof(SPIDER_STRUCT));
LEB128::Write(m_stream, arg1);
m_stream->Write(reinterpret_cast<char*>(&buffer), sizeof(SPIDER_STRUCT));
}
bool SaveGame::readBats()
{
int index = LEB128::ReadInt16(m_stream);
BAT_STRUCT* bats = &Bats[index];
char* buffer = (char*)malloc(sizeof(BAT_STRUCT));
m_stream->Read(buffer, sizeof(BAT_STRUCT));
memcpy(bats, buffer, sizeof(BAT_STRUCT));
free(buffer);
return true;
}
bool SaveGame::readRats()
{
int index = LEB128::ReadInt16(m_stream);
RAT_STRUCT* rats = &Rats[index];
char* buffer = (char*)malloc(sizeof(RAT_STRUCT));
m_stream->Read(buffer, sizeof(RAT_STRUCT));
memcpy(rats, buffer, sizeof(RAT_STRUCT));
free(buffer);
return true;
}
bool SaveGame::readSpiders()
{
int index = LEB128::ReadInt16(m_stream);
SPIDER_STRUCT* spiders = &Spiders[index];
char* buffer = (char*)malloc(sizeof(SPIDER_STRUCT));
m_stream->Read(buffer, sizeof(SPIDER_STRUCT));
memcpy(spiders, buffer, sizeof(SPIDER_STRUCT));
free(buffer);
return true;
}