2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2018-10-01 22:22:11 +02:00
|
|
|
#include "savegame.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "Lara.h"
|
|
|
|
#include "items.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "pickup.h"
|
|
|
|
#include "lot.h"
|
|
|
|
#include "switch.h"
|
|
|
|
#include "spotcam.h"
|
2019-12-01 08:13:19 +01:00
|
|
|
#include "traps.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "laramisc.h"
|
|
|
|
#include "sound.h"
|
|
|
|
#include "level.h"
|
|
|
|
#include "setup.h"
|
2020-04-12 06:50:43 +02:00
|
|
|
#include "camera.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "quad.h"
|
2020-05-27 19:07:34 +02:00
|
|
|
#include "tr5_rats_emitter.h"
|
|
|
|
#include "tr5_bats_emitter.h"
|
|
|
|
#include "tr5_spider_emitter.h"
|
2018-10-01 22:22:11 +02:00
|
|
|
|
|
|
|
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;
|
2019-11-27 15:12:35 +01:00
|
|
|
int SaveGame::LastSaveGame;
|
2018-10-01 22:22:11 +02:00
|
|
|
|
|
|
|
ChunkId* SaveGame::m_chunkGameStatus;
|
|
|
|
ChunkId* SaveGame::m_chunkItems;
|
|
|
|
ChunkId* SaveGame::m_chunkItem;
|
|
|
|
ChunkId* SaveGame::m_chunkLara;
|
2018-10-10 22:29:40 +02:00
|
|
|
ChunkId* SaveGame::m_chunkLuaVariable;
|
2018-10-24 23:32:22 +02:00
|
|
|
ChunkId* SaveGame::m_chunkStaticFlags;
|
2018-11-01 09:10:32 +01:00
|
|
|
ChunkId* SaveGame::m_chunkVehicle;
|
2019-11-09 09:55:56 +01:00
|
|
|
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;
|
2018-10-25 23:43:58 +02:00
|
|
|
ChunkId* SaveGame::m_chunkSpecialItemBurningTorch;
|
|
|
|
ChunkId* SaveGame::m_chunkSpecialItemChaff;
|
|
|
|
ChunkId* SaveGame::m_chunkSpecialItemTorpedo;
|
|
|
|
ChunkId* SaveGame::m_chunkSpecialItemCrossbowBolt;
|
|
|
|
ChunkId* SaveGame::m_chunkSpecialItemFlare;
|
|
|
|
ChunkId* SaveGame::m_chunkItemQuadInfo;
|
2018-11-11 11:33:13 +01:00
|
|
|
ChunkId* SaveGame::m_chunkBats;
|
|
|
|
ChunkId* SaveGame::m_chunkRats;
|
|
|
|
ChunkId* SaveGame::m_chunkSpiders;
|
2020-01-12 08:02:48 +01:00
|
|
|
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
|
|
|
|
2020-05-30 17:58:09 +02:00
|
|
|
SAVEGAME_INFO Savegame;
|
2019-05-31 21:45:13 +02:00
|
|
|
extern vector<AudioTrack> g_AudioTracks;
|
2019-11-09 09:55:56 +01:00
|
|
|
extern byte SequenceUsed[6];
|
|
|
|
extern byte SequenceResults[3][3][3];
|
|
|
|
extern byte Sequences[3];
|
|
|
|
extern byte CurrentSequence;
|
2019-05-31 21:45:13 +02:00
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
void SaveGame::saveItems()
|
2018-10-01 22:22:11 +02:00
|
|
|
{
|
2018-10-24 23:32:22 +02:00
|
|
|
// Save level items
|
2019-11-27 15:12:35 +01:00
|
|
|
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...)
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = NumItems; i < NUM_ITEMS; i++)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2018-11-11 11:33:13 +01:00
|
|
|
|
|
|
|
// Save special items
|
2020-02-24 12:51:28 +01:00
|
|
|
if (Objects[ID_BATS_EMITTER].loaded)
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < NUM_BATS; i++)
|
2019-03-29 00:27:16 +01:00
|
|
|
if (Bats[i].on)
|
|
|
|
m_writer->WriteChunk(m_chunkBats, &saveBats, i, 0);
|
|
|
|
|
2020-02-24 12:51:28 +01:00
|
|
|
if (Objects[ID_RATS_EMITTER].loaded)
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < NUM_RATS; i++)
|
2019-03-29 00:27:16 +01:00
|
|
|
if (Rats[i].on)
|
|
|
|
m_writer->WriteChunk(m_chunkRats, &saveRats, i, 0);
|
|
|
|
|
2020-02-24 12:51:28 +01:00
|
|
|
if (Objects[ID_SPIDERS_EMITTER].loaded)
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < NUM_SPIDERS; i++)
|
2019-03-29 00:27:16 +01:00
|
|
|
if (Spiders[i].on)
|
|
|
|
m_writer->WriteChunk(m_chunkSpiders, &saveSpiders, i, 0);
|
2018-10-01 22:22:11 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveItem(int itemNumber, int runtimeItem)
|
2018-10-01 22:22:11 +02:00
|
|
|
{
|
|
|
|
ITEM_INFO* item = &Items[itemNumber];
|
2020-04-27 15:28:54 +02:00
|
|
|
ObjectInfo* obj = &Objects[item->objectNumber];
|
2018-10-01 22:22:11 +02:00
|
|
|
|
2018-10-10 22:29:40 +02:00
|
|
|
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;
|
|
|
|
}
|
2020-01-18 21:55:04 +01:00
|
|
|
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);
|
|
|
|
|
2020-01-12 08:02:48 +01:00
|
|
|
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);
|
|
|
|
}
|
2018-10-01 22:22:11 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveGameStatus(int arg1, int arg2)
|
2018-10-01 22:22:11 +02:00
|
|
|
{
|
2018-10-10 22:29:40 +02:00
|
|
|
LEB128::Write(m_stream, FlipStatus);
|
2019-05-06 23:48:35 +02:00
|
|
|
LEB128::Write(m_stream, LastInventoryItem);
|
2018-10-10 22:29:40 +02:00
|
|
|
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
|
2018-10-10 22:29:40 +02:00
|
|
|
if (NumberRooms > 0)
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < 6; i++)
|
2019-11-09 09:55:56 +01:00
|
|
|
m_writer->WriteChunk(m_chunkSequenceSwitch, &saveSequenceSwitch, i, SequenceUsed[i]);
|
2018-10-24 23:32:22 +02:00
|
|
|
|
2019-11-27 15:12:35 +01: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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < g_AudioTracks.size(); i++)
|
2019-05-31 21:45:13 +02:00
|
|
|
m_writer->WriteChunk(m_chunkCdFlags, &saveCdFlags, i, g_AudioTracks[i].Mask);
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < 255; i++)
|
2018-10-24 23:32:22 +02:00
|
|
|
m_writer->WriteChunk(m_chunkFlipStats, &saveFlipStats, i, FlipStats[i]);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < 255; i++)
|
2018-10-24 23:32:22 +02:00
|
|
|
m_writer->WriteChunk(m_chunkFlipMap, &saveFlipMap, i, FlipMap[i]);
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveLara(int arg1, int arg2)
|
2018-10-10 22:29:40 +02:00
|
|
|
{
|
|
|
|
// LARA_INFO struct dumped to savegame
|
2020-04-27 14:01:00 +02:00
|
|
|
LaraInfo lara;
|
2018-10-01 22:22:11 +02:00
|
|
|
memcpy(&lara, &Lara, sizeof(Lara));
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
2018-10-01 22:22:11 +02:00
|
|
|
|
2020-01-12 08:02:48 +01:00
|
|
|
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);
|
2020-04-24 19:15:05 +02:00
|
|
|
lara.generalPtr = (char *)lara.generalPtr - (ptrdiff_t)malloc_buffer;
|
2018-10-01 22:22:11 +02:00
|
|
|
|
|
|
|
m_stream->Write(reinterpret_cast<char*>(&lara), sizeof(Lara));
|
2018-10-10 22:29:40 +02:00
|
|
|
|
|
|
|
// Lara weapon data
|
2020-01-12 08:02:48 +01:00
|
|
|
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++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.Puzzles[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkPuzzle, &savePuzzle, i, Lara.Puzzles[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_PUZZLES * 2; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.PuzzlesCombo[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkPuzzleCombo, &savePuzzle, i, Lara.PuzzlesCombo[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_KEYS; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.Keys[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkKey, &savePuzzle, i, Lara.Keys[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_KEYS * 2; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.KeysCombo[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkKeyCombo, &savePuzzle, i, Lara.KeysCombo[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_PICKUPS; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.Pickups[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkPickup, &savePuzzle, i, Lara.Pickups[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_PICKUPS * 2; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.PickupsCombo[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkPickupCombo, &savePuzzle, i, Lara.PickupsCombo[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < NUM_EXAMINES; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.Examines[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkExamine, &savePuzzle, i, Lara.Examines[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2020-01-12 08:02:48 +01:00
|
|
|
for (int i = 0; i < NUM_EXAMINES * 2; i++)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.ExaminesCombo[i] > 0)
|
|
|
|
m_writer->WriteChunk(m_chunkExamineCombo, &savePuzzle, i, Lara.ExaminesCombo[i]);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGame::saveWeaponItem(int arg1, int arg2)
|
|
|
|
{
|
|
|
|
ITEM_INFO* weaponItem = &Items[arg1];
|
|
|
|
|
2018-10-10 22:29:40 +02:00
|
|
|
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);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGame::saveLaraExtraInfo(int arg1, int arg2)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
LEB128::Write(m_stream, (Lara.Binoculars ? 1 : 0));
|
|
|
|
LEB128::Write(m_stream, (Lara.Lasersight ? 1 : 0));
|
|
|
|
LEB128::Write(m_stream, (Lara.Crowbar ? 1 : 0));
|
|
|
|
LEB128::Write(m_stream, (Lara.Silencer ? 1 : 0));
|
|
|
|
LEB128::Write(m_stream, (Lara.Torch ? 1 : 0));
|
|
|
|
LEB128::Write(m_stream, Lara.Secrets);
|
|
|
|
LEB128::Write(m_stream, Lara.ExtraAnim);
|
|
|
|
LEB128::Write(m_stream, Lara.Vehicle);
|
|
|
|
LEB128::Write(m_stream, Lara.mineL);
|
|
|
|
LEB128::Write(m_stream, Lara.mineR);
|
|
|
|
LEB128::Write(m_stream, Lara.NumFlares);
|
|
|
|
LEB128::Write(m_stream, Lara.NumLargeMedipacks);
|
|
|
|
LEB128::Write(m_stream, Lara.NumSmallMedipacks);
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGame::savePuzzle(int arg1, int arg2)
|
|
|
|
{
|
|
|
|
LEB128::Write(m_stream, arg1); // ID
|
|
|
|
LEB128::Write(m_stream, arg2); // Quantity
|
|
|
|
}
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2020-01-12 08:02:48 +01:00
|
|
|
void SaveGame::saveWeaponInfo(int arg1, int arg2)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
CarriedWeaponInfo* weapon = &Lara.Weapons[arg1];
|
2020-01-12 08:02:48 +01:00
|
|
|
|
|
|
|
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-01 22:22:11 +02:00
|
|
|
}
|
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
void SaveGame::saveVariables()
|
2018-10-09 00:02:14 +02:00
|
|
|
{
|
|
|
|
m_luaVariables.clear();
|
2020-04-28 12:24:10 -03:00
|
|
|
//g_GameScript->GetVariables(&m_luaVariables);
|
2019-11-27 15:12:35 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01: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
|
|
|
|
2018-10-10 22:29:40 +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)
|
2018-10-10 22:29:40 +02:00
|
|
|
m_stream->WriteBool(variable.BoolValue);
|
2018-10-09 00:02:14 +02:00
|
|
|
else if (variable.Type == LUA_VARIABLE_TYPE_INT)
|
2018-10-10 22:29:40 +02:00
|
|
|
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)
|
2018-10-10 22:29:40 +02:00
|
|
|
m_stream->WriteFloat(variable.FloatValue);
|
2018-10-09 00:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SaveGame::Start()
|
2018-10-01 22:22:11 +02:00
|
|
|
{
|
|
|
|
m_chunkGameStatus = ChunkId::FromString("TR5MSgGameStatus");
|
|
|
|
m_chunkItems = ChunkId::FromString("TR5MSgItems");
|
|
|
|
m_chunkItem = ChunkId::FromString("TR5MSgItem");
|
|
|
|
m_chunkLara = ChunkId::FromString("TR5MSgLara");
|
2018-10-10 22:29:40 +02:00
|
|
|
m_chunkLuaVariable = ChunkId::FromString("TR5MSgLuaVar");
|
2018-10-24 23:32:22 +02:00
|
|
|
m_chunkStaticFlags = ChunkId::FromString("TR5MSgStFl");
|
2018-11-01 09:10:32 +01:00
|
|
|
m_chunkVehicle = ChunkId::FromString("TR5MSgLaraVeh");
|
2019-11-09 09:55:56 +01:00
|
|
|
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");
|
2018-10-25 23:43:58 +02:00
|
|
|
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");
|
2018-11-11 11:33:13 +01:00
|
|
|
m_chunkBats = ChunkId::FromString("TR5MSgBats");
|
|
|
|
m_chunkRats = ChunkId::FromString("TR5MSgRats");
|
|
|
|
m_chunkSpiders = ChunkId::FromString("TR5MSgSpiders");
|
2020-01-12 08:02:48 +01:00
|
|
|
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;
|
2018-10-10 22:29:40 +02:00
|
|
|
delete m_chunkLuaVariable;
|
2018-10-24 23:32:22 +02:00
|
|
|
delete m_chunkStaticFlags;
|
2018-11-01 09:10:32 +01:00
|
|
|
delete m_chunkVehicle;
|
2018-10-24 23:32:22 +02:00
|
|
|
delete m_chunkFlipMap;
|
|
|
|
delete m_chunkFlipStats;
|
|
|
|
delete m_chunkFlybyFlags;
|
2019-11-09 09:55:56 +01:00
|
|
|
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;
|
2018-10-25 23:43:58 +02:00
|
|
|
delete m_chunkSpecialItemBurningTorch;
|
|
|
|
delete m_chunkSpecialItemChaff;
|
|
|
|
delete m_chunkSpecialItemTorpedo;
|
|
|
|
delete m_chunkSpecialItemCrossbowBolt;
|
|
|
|
delete m_chunkSpecialItemFlare;
|
|
|
|
delete m_chunkItemQuadInfo;
|
2018-11-11 11:33:13 +01:00
|
|
|
delete m_chunkBats;
|
|
|
|
delete m_chunkRats;
|
|
|
|
delete m_chunkSpiders;
|
2020-01-12 08:02:48 +01:00
|
|
|
delete m_chunkLaraExtraInfo;
|
|
|
|
delete m_chunkWeaponInfo;
|
2020-01-20 07:29:37 +01:00
|
|
|
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-01 22:22:11 +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);
|
2018-10-01 22:22:11 +02:00
|
|
|
m_writer = new ChunkWriter(0x4D355254, m_stream);
|
|
|
|
|
2019-05-06 23:48:35 +02:00
|
|
|
printf("Timer: %d\n", Savegame.Game.Timer);
|
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
// The header must be here, so no chunks
|
2019-03-29 00:27:16 +01:00
|
|
|
m_stream->WriteString(g_GameFlow->GetString(g_GameFlow->GetLevel(CurrentLevel)->NameStringIndex));
|
2019-05-06 23:48:35 +02:00
|
|
|
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);
|
2018-10-25 23:43:58 +02:00
|
|
|
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();
|
|
|
|
|
2018-10-10 22:29:40 +02:00
|
|
|
// EOF
|
|
|
|
m_stream->WriteInt32(0);
|
2018-10-01 22:22:11 +02:00
|
|
|
|
|
|
|
m_stream->Close();
|
|
|
|
|
|
|
|
delete m_writer;
|
|
|
|
delete m_stream;
|
|
|
|
|
2018-10-10 22:29:40 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SaveGame::readGameStatus()
|
|
|
|
{
|
2018-10-24 23:32:22 +02:00
|
|
|
FlipStatus = LEB128::ReadInt32(m_stream);
|
2019-05-06 23:48:35 +02:00
|
|
|
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-10 22:29:40 +02:00
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
m_reader->ReadChunks(&readGameStatusChunks, 0);
|
|
|
|
|
|
|
|
return true;
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SaveGame::readLara()
|
|
|
|
{
|
|
|
|
// Read dumped LARA_INFO struct
|
2020-04-27 14:01:00 +02:00
|
|
|
char* buffer = (char*)malloc(sizeof(LaraInfo));
|
|
|
|
m_stream->Read(buffer, sizeof(LaraInfo));
|
|
|
|
LaraInfo* lara = reinterpret_cast<LaraInfo*>(buffer);
|
|
|
|
memcpy(&Lara, lara, sizeof(LaraInfo));
|
2018-10-24 23:32:22 +02:00
|
|
|
free(buffer);
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2020-05-30 17:58:09 +02:00
|
|
|
for (int i = 0; i < NUM_LARA_MESHES; i++)
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
2020-05-30 17:58:09 +02:00
|
|
|
Lara.meshPtrs[i] = AddPtr(Lara.meshPtrs[i], short, MeshBase);
|
2018-10-24 23:32:22 +02:00
|
|
|
}
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2020-05-30 17:58:09 +02:00
|
|
|
Lara.leftArm.frameBase = AddPtr(Lara.leftArm.frameBase, short, Objects[ID_LARA].frameBase);
|
|
|
|
Lara.rightArm.frameBase = AddPtr(Lara.rightArm.frameBase, short, Objects[ID_LARA].frameBase);
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
Lara.target = NULL;
|
|
|
|
Lara.spazEffect = NULL;
|
2020-05-30 17:58:09 +02:00
|
|
|
Lara.generalPtr = (void*)AddPtr(Lara.generalPtr, char, malloc_buffer);
|
2020-01-12 08:02:48 +01:00
|
|
|
Lara.weaponItem = NO_ITEM;
|
2018-10-10 22:29:40 +02:00
|
|
|
|
|
|
|
// Is Lara burning?
|
2018-10-24 23:32:22 +02:00
|
|
|
if (Lara.burn)
|
2018-10-10 22:29:40 +02:00
|
|
|
{
|
2018-10-24 23:32:22 +02:00
|
|
|
Lara.burn = false;
|
2018-10-10 22:29:40 +02:00
|
|
|
bool smokeFlag = false;
|
2018-10-24 23:32:22 +02:00
|
|
|
if (Lara.burnSmoke)
|
2018-10-10 22:29:40 +02:00
|
|
|
{
|
2018-10-24 23:32:22 +02:00
|
|
|
Lara.burnSmoke = false;
|
2018-10-10 22:29:40 +02:00
|
|
|
smokeFlag = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
LaraBurn();
|
|
|
|
if (smokeFlag)
|
2018-10-24 23:32:22 +02:00
|
|
|
Lara.burnSmoke = true;
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
m_reader->ReadChunks(&readLaraChunks, 0);
|
|
|
|
return true;
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SaveGame::readItem()
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNumber = LEB128::ReadInt16(m_stream);
|
|
|
|
short runtimeItem = LEB128::ReadByte(m_stream);
|
|
|
|
short itemKind = LEB128::ReadInt16(m_stream);
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2018-10-25 23:53:57 +02:00
|
|
|
// Runtime items must be allocated dynamically
|
|
|
|
if (runtimeItem)
|
|
|
|
itemNumber = CreateItem();
|
|
|
|
|
2018-10-10 22:29:40 +02:00
|
|
|
ITEM_INFO* item = &Items[itemNumber];
|
2018-10-25 23:53:57 +02:00
|
|
|
item->objectNumber = LEB128::ReadInt16(m_stream);
|
|
|
|
|
2020-04-27 15:28:54 +02:00
|
|
|
ObjectInfo* obj = &Objects[item->objectNumber];
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2018-10-25 23:53:57 +02:00
|
|
|
// 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)
|
|
|
|
{
|
2020-01-18 21:55:04 +01:00
|
|
|
m_reader->ReadChunks(&readItemChunks, itemNumber);
|
|
|
|
DisableBaddieAI(itemNumber);
|
2018-10-24 23:32:22 +02:00
|
|
|
KillItem(itemNumber);
|
2020-06-04 12:49:08 +02:00
|
|
|
item->status = ITEM_DEACTIVATED;
|
2020-01-18 21:55:04 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-10-25 23:43:58 +02:00
|
|
|
// Some post-processing things
|
2020-06-04 12:49:08 +02:00
|
|
|
if (obj->isPuzzleHole && (item->status == ITEM_DEACTIVATED || item->status == ITEM_ACTIVE))
|
2020-05-27 19:37:01 +02:00
|
|
|
item->objectNumber += NUM_PUZZLES;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
|
|
|
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;
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2018-10-10 22:29:40 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
bool SaveGame::readSavegameChunks(ChunkId* chunkId, int maxSize, int arg)
|
2018-10-10 22:29:40 +02:00
|
|
|
{
|
2018-10-24 23:32:22 +02:00
|
|
|
if (chunkId->EqualsTo(m_chunkGameStatus))
|
2018-10-10 22:29:40 +02:00
|
|
|
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();
|
2018-10-25 23:43:58 +02:00
|
|
|
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();
|
2018-11-11 11:33:13 +01:00
|
|
|
else if (chunkId->EqualsTo(m_chunkBats))
|
|
|
|
return readBats();
|
|
|
|
else if (chunkId->EqualsTo(m_chunkRats))
|
|
|
|
return readRats();
|
|
|
|
else if (chunkId->EqualsTo(m_chunkSpiders))
|
|
|
|
return readSpiders();
|
2018-10-10 22:29:40 +02:00
|
|
|
|
|
|
|
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);
|
2018-10-10 22:29:40 +02:00
|
|
|
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
|
2018-10-10 22:29:40 +02:00
|
|
|
m_stream->Close();
|
2018-10-24 23:32:22 +02:00
|
|
|
//delete m_writer;
|
|
|
|
//delete m_stream;
|
2018-10-10 22:29:40 +02:00
|
|
|
|
2020-04-28 12:24:10 -03:00
|
|
|
//g_GameScript->SetVariables(&m_luaVariables);
|
2018-10-10 22:29:40 +02:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
bool SaveGame::readLaraChunks(ChunkId* chunkId, int maxSize, int arg)
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
2020-01-12 08:02:48 +01:00
|
|
|
if (chunkId->EqualsTo(m_chunkLaraExtraInfo))
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Binoculars = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.Lasersight = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.Crowbar = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.Silencer = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.Torch = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.Secrets = LEB128::ReadInt32(m_stream);
|
|
|
|
Lara.ExtraAnim = LEB128::ReadInt16(m_stream);
|
|
|
|
Lara.Vehicle = LEB128::ReadInt16(m_stream);
|
|
|
|
Lara.mineL = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.mineR = LEB128::ReadByte(m_stream);
|
|
|
|
Lara.NumFlares = LEB128::ReadInt32(m_stream);
|
|
|
|
Lara.NumLargeMedipacks = LEB128::ReadInt32(m_stream);
|
|
|
|
Lara.NumSmallMedipacks = LEB128::ReadInt32(m_stream);
|
2020-01-12 08:02:48 +01:00
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
return true;
|
|
|
|
}
|
2020-01-12 08:02:48 +01:00
|
|
|
else if (chunkId->EqualsTo(m_chunkWeaponInfo))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
CarriedWeaponInfo* weapon = &Lara.Weapons[id];
|
2020-01-12 08:02:48 +01:00
|
|
|
|
|
|
|
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);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Puzzles[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkPuzzleCombo))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.PuzzlesCombo[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkKey))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Keys[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkKeyCombo))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.KeysCombo[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkPickup))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Pickups[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkPickupCombo))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.PickupsCombo[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkExamine))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Examines[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
else if (chunkId->EqualsTo(m_chunkExamineCombo))
|
|
|
|
{
|
|
|
|
int id = LEB128::ReadInt32(m_stream);
|
|
|
|
int quantity = LEB128::ReadInt32(m_stream);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.ExaminesCombo[id] = quantity;
|
2020-01-12 08:02:48 +01:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
bool SaveGame::readGameStatusChunks(ChunkId* chunkId, int maxSize, int arg)
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
|
|
|
if (chunkId->EqualsTo(m_chunkStaticFlags))
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
2019-11-27 15:12:35 +01:00
|
|
|
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))
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
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))
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
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))
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
short index = LEB128::ReadInt16(m_stream);
|
2018-10-24 23:32:22 +02:00
|
|
|
printf("Index: %d\n", index);
|
2019-11-27 15:12:35 +01:00
|
|
|
short value = LEB128::ReadInt16(m_stream);
|
2019-05-31 21:45:13 +02:00
|
|
|
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))
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
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;
|
|
|
|
}
|
2019-11-09 09:55:56 +01:00
|
|
|
else if (chunkId->EqualsTo(m_chunkSequenceSwitch))
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
2019-11-27 15:12:35 +01: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))
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short roomNumber = LEB128::ReadInt16(m_stream);
|
2018-10-24 23:32:22 +02:00
|
|
|
if (item->roomNumber != roomNumber)
|
|
|
|
ItemNewRoom(itemNumber, roomNumber);
|
|
|
|
|
2020-01-12 08:02:48 +01:00
|
|
|
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);
|
|
|
|
|
2020-04-27 15:28:54 +02:00
|
|
|
ObjectInfo* obj = &Objects[item->objectNumber];
|
2018-10-24 23:32:22 +02:00
|
|
|
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
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);
|
2020-05-30 17:58:09 +02:00
|
|
|
creature->enemy = AddPtr(enemy, ITEM_INFO, malloc_buffer);
|
2018-10-24 23:32:22 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-10-25 23:43:58 +02:00
|
|
|
else if (chunkId->EqualsTo(m_chunkItemQuadInfo))
|
|
|
|
{
|
2020-04-24 19:15:05 +02:00
|
|
|
QUAD_INFO* quadInfo = (QUAD_INFO*)game_malloc(sizeof(QUAD_INFO));
|
2018-10-25 23:43:58 +02:00
|
|
|
m_stream->ReadBytes(reinterpret_cast<byte*>(quadInfo), sizeof(QUAD_INFO));
|
|
|
|
if (item->objectNumber == ID_QUAD)
|
|
|
|
item->data = (void*)quadInfo;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2020-01-12 08:02:48 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
|
2018-10-01 22:22:11 +02:00
|
|
|
return true;
|
2018-10-24 23:32:22 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveItemFlags(int arg1, int arg2)
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
|
|
|
ITEM_INFO* item = &Items[arg1];
|
2020-04-27 15:28:54 +02:00
|
|
|
ObjectInfo* obj = &Objects[item->objectNumber];
|
2018-10-24 23:32:22 +02:00
|
|
|
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveItemIntelligentData(int arg1, int arg2)
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
|
|
|
ITEM_INFO* item = &Items[arg1];
|
2020-04-27 15:28:54 +02:00
|
|
|
ObjectInfo* obj = &Objects[item->objectNumber];
|
2018-10-24 23:32:22 +02:00
|
|
|
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
|
|
|
|
|
2020-04-24 19:15:05 +02:00
|
|
|
ITEM_INFO* enemy = (ITEM_INFO*)((char*)creature->enemy - (ptrdiff_t)malloc_buffer);
|
2018-10-24 23:32:22 +02:00
|
|
|
|
|
|
|
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);
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
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);
|
2020-01-12 08:02:48 +01:00
|
|
|
LEB128::Write(m_stream, item->speed);
|
|
|
|
LEB128::Write(m_stream, item->fallspeed);
|
2018-10-24 23:32:22 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveItemMesh(int arg1, int arg2)
|
2018-10-24 23:32:22 +02:00
|
|
|
{
|
|
|
|
ITEM_INFO* item = &Items[arg1];
|
|
|
|
|
2020-01-12 08:02:48 +01:00
|
|
|
LEB128::Write(m_stream, item->meshBits);
|
|
|
|
LEB128::Write(m_stream, item->swapMeshFlags);
|
2018-10-24 23:32:22 +02:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01: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);
|
|
|
|
}
|
2018-10-25 23:43:58 +02:00
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveBurningTorch(int itemNumber, int arg2)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveChaff(int itemNumber, int arg2)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveTorpedo(int itemNumber, int arg2)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveCrossbowBolt(int itemNumber, int arg2)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveFlare(int itemNumber, int arg2)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
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
|
2019-11-27 15:12:35 +01:00
|
|
|
LEB128::Write(m_stream, (int)item->data);
|
2018-10-25 23:43:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SaveGame::readBurningTorch()
|
|
|
|
{
|
|
|
|
LEB128::ReadInt16(m_stream);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNumber = CreateItem();
|
2018-10-25 23:43:58 +02:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short oldXrot = item->pos.xRot;
|
|
|
|
short oldYrot = item->pos.yRot;
|
|
|
|
short oldZrot = item->pos.zRot;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNumber = CreateItem();
|
2018-10-25 23:43:58 +02:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short oldXrot = item->pos.xRot;
|
|
|
|
short oldYrot = item->pos.yRot;
|
|
|
|
short oldZrot = item->pos.zRot;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNumber = CreateItem();
|
2018-10-25 23:43:58 +02:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short oldXrot = item->pos.xRot;
|
|
|
|
short oldYrot = item->pos.yRot;
|
|
|
|
short oldZrot = item->pos.zRot;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNumber = CreateItem();
|
2018-10-25 23:43:58 +02:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short oldXrot = item->pos.xRot;
|
|
|
|
short oldYrot = item->pos.yRot;
|
|
|
|
short oldZrot = item->pos.zRot;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNumber = CreateItem();
|
2018-10-25 23:43:58 +02:00
|
|
|
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);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short oldXrot = item->pos.xRot;
|
|
|
|
short oldYrot = item->pos.yRot;
|
|
|
|
short oldZrot = item->pos.zRot;
|
2018-10-25 23:43:58 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveItemQuadInfo(int itemNumber, int arg2)
|
2018-10-25 23:43:58 +02:00
|
|
|
{
|
|
|
|
m_stream->WriteBytes(reinterpret_cast<byte*>(Items[itemNumber].data), sizeof(QUAD_INFO));
|
2018-11-11 11:33:13 +01:00
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveRats(int arg1, int arg2)
|
2018-11-11 11:33:13 +01:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveBats(int arg1, int arg2)
|
2018-11-11 11:33:13 +01:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
void SaveGame::saveSpiders(int arg1, int arg2)
|
2018-11-11 11:33:13 +01:00
|
|
|
{
|
|
|
|
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()
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
int index = LEB128::ReadInt16(m_stream);
|
2018-11-11 11:33:13 +01:00
|
|
|
|
|
|
|
BAT_STRUCT* bats = &Bats[index];
|
|
|
|
|
|
|
|
char* buffer = (char*)malloc(sizeof(BAT_STRUCT));
|
|
|
|
m_stream->Read(buffer, sizeof(BAT_STRUCT));
|
2020-01-12 08:02:48 +01:00
|
|
|
memcpy(bats, buffer, sizeof(BAT_STRUCT));
|
2018-11-11 11:33:13 +01:00
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SaveGame::readRats()
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
int index = LEB128::ReadInt16(m_stream);
|
2018-11-11 11:33:13 +01:00
|
|
|
|
|
|
|
RAT_STRUCT* rats = &Rats[index];
|
|
|
|
|
|
|
|
char* buffer = (char*)malloc(sizeof(RAT_STRUCT));
|
|
|
|
m_stream->Read(buffer, sizeof(RAT_STRUCT));
|
2020-01-12 08:02:48 +01:00
|
|
|
memcpy(rats, buffer, sizeof(RAT_STRUCT));
|
2018-11-11 11:33:13 +01:00
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SaveGame::readSpiders()
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
int index = LEB128::ReadInt16(m_stream);
|
2018-11-11 11:33:13 +01:00
|
|
|
|
|
|
|
SPIDER_STRUCT* spiders = &Spiders[index];
|
|
|
|
|
|
|
|
char* buffer = (char*)malloc(sizeof(SPIDER_STRUCT));
|
|
|
|
m_stream->Read(buffer, sizeof(SPIDER_STRUCT));
|
2020-01-12 08:02:48 +01:00
|
|
|
memcpy(spiders, buffer, sizeof(SPIDER_STRUCT));
|
2018-11-11 11:33:13 +01:00
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return true;
|
2018-10-25 23:43:58 +02:00
|
|
|
}
|