TombEngine/TR5Main/Specific/roomload.cpp

742 lines
18 KiB
C++
Raw Normal View History

2018-08-19 09:46:58 +02:00
#include "roomload.h"
#include "..\Global\global.h"
#include "..\Game\items.h"
#include "..\Specific\setup.h"
#include "..\Game\draw.h"
2018-08-30 22:51:16 +02:00
#include "..\Game\lot.h"
2019-11-21 07:43:34 +01:00
#include "..\Game\Lara.h"
#include "..\Game\savegame.h"
#include "..\Game\spotcam.h"
2018-10-28 11:45:53 +01:00
#include "..\Scripting\GameFlowScript.h"
#include "IO/ChunkId.h"
#include "IO/ChunkReader.h"
#include "IO/ChunkWriter.h"
#include "IO/LEB128.h"
2018-08-19 09:46:58 +02:00
#include <process.h>
#include <stdio.h>
#include <vector>
#include <map>
#include "IO/Streams.h"
ChunkId* ChunkTriggersList = ChunkId::FromString("Tr5Triggers");
ChunkId* ChunkTrigger = ChunkId::FromString("Tr5Trigger");
ChunkId* ChunkLuaIds = ChunkId::FromString("Tr5LuaIds");
ChunkId* ChunkLuaId = ChunkId::FromString("Tr5LuaId");
2018-08-19 09:46:58 +02:00
extern GameScript* g_GameScript;
2018-08-19 09:46:58 +02:00
byte* Texture32;
byte* Texture16;
byte* MiscTextures;
2019-12-02 09:11:21 +01:00
short* RawMeshData;
int MeshDataSize;
int* MeshTrees;
int* RawMeshPointers;
int NumObjects;
int NumStaticObjects;
int NumMeshPointers;
int NumObjectTextures;
int NumTextureTiles;
2018-08-19 09:46:58 +02:00
uintptr_t hLoadLevel;
2019-12-02 09:11:21 +01:00
unsigned int ThreadId;
int IsLevelLoading;
bool g_FirstLevel = true;
2018-08-19 09:46:58 +02:00
using namespace std;
2019-12-02 09:11:21 +01:00
vector<int> MoveablesIds;
vector<int> StaticObjectsIds;
2018-08-19 09:46:58 +02:00
extern GameFlow* g_GameFlow;
extern LaraExtraInfo g_LaraExtra;
char* LevelDataPtr;
2019-12-02 09:11:21 +01:00
int g_NumSprites;
int g_NumSpritesSequences;
ChunkReader* g_levelChunkIO;
2019-12-02 09:11:21 +01:00
short ReadInt8()
{
byte value = *(byte*)LevelDataPtr;
LevelDataPtr += 1;
return value;
}
2019-12-02 09:11:21 +01:00
short ReadInt16()
2018-08-19 09:46:58 +02:00
{
2019-12-02 09:11:21 +01:00
short value = *(short*)LevelDataPtr;
2018-08-19 09:46:58 +02:00
LevelDataPtr += 2;
return value;
}
2019-12-02 09:11:21 +01:00
int ReadInt32()
2018-08-19 09:46:58 +02:00
{
2019-12-02 09:11:21 +01:00
int value = *(int*)LevelDataPtr;
2018-08-19 09:46:58 +02:00
LevelDataPtr += 4;
return value;
}
2019-12-02 09:11:21 +01:00
void ReadBytes(void* dest, int count)
2018-08-19 09:46:58 +02:00
{
memcpy(dest, LevelDataPtr, count);
LevelDataPtr += count;
}
int LoadItems()
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "LoadItems - DLL");
NumItems = ReadInt32();
if (NumItems == 0)
return false;
Items = (ITEM_INFO*)GameMalloc(sizeof(ITEM_INFO) * NUM_ITEMS);
LevelItems = NumItems;
InitialiseClosedDoors();
FreeItemsStuff(NUM_ITEMS);
if (NumItems > 0)
{
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumItems; i++)
2018-08-19 09:46:58 +02:00
{
ITEM_INFO* item = &Items[i];
item->objectNumber = ReadInt16();
item->roomNumber = ReadInt16();
item->pos.xPos = ReadInt32();
item->pos.yPos = ReadInt32();
item->pos.zPos = ReadInt32();
item->pos.yRot = ReadInt16();
item->shade = ReadInt16();
item->triggerFlags = ReadInt16();
item->flags = ReadInt16();
// DEBUG: set Lara position
/*if (item->objectNumber == ID_LARA)
{
item->pos.xPos = 33050;
item->pos.yPos = 10000;
item->pos.zPos = 21162;
item->roomNumber = 0;
}*/
2018-08-30 22:51:16 +02:00
// ANDREA2
/*if (item->objectNumber == ID_LARA)
{
item->pos.xPos = 58*1024;
item->pos.yPos = 0;
item->pos.zPos = 39*1024;
item->roomNumber = 144;
2018-08-30 22:51:16 +02:00
}*/
2018-08-19 09:46:58 +02:00
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumItems; i++)
2018-08-19 09:46:58 +02:00
InitialiseItem(i);
}
for (int r = 0; r < NumberRooms; r++)
{
MESH_INFO* mesh = Rooms[r].mesh;
for (int m = 0; m < Rooms[r].numMeshes; m++)
{
FLOOR_INFO* floor = &Rooms[r].floor[((mesh->z - Rooms[r].z) >> 10) + Rooms[r].xSize * ((mesh->x - Rooms[r].x) >> 10)];
2018-08-19 09:46:58 +02:00
if (!(Boxes[floor->box].overlapIndex & 0x4000)
&& !(CurrentLevel == 5 && (r == 19 || r == 23 || r == 16)))
{
int fl = floor->floor << 2;
STATIC_INFO* st = &StaticObjects[mesh->staticNumber];
if (fl <= mesh->y - st->yMaxc + 512 && fl < mesh->y - st->yMinc)
{
if (st->xMaxc == 0 || st->xMinc == 0 ||
st->zMaxc == 0 || st->zMinc == 0 ||
(st->xMaxc ^ st->xMinc) & 0x8000 &&
(st->xMaxc ^ st->zMinc) & 0x8000)
{
floor->box |= 8;
2018-08-19 09:46:58 +02:00
}
}
}
}
}
return true;
}
void LoadObjects()
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "LoadObjects - DLL");
2018-09-01 15:46:37 +02:00
memset(Objects, 0, sizeof(OBJECT_INFO) * ID_NUMBER_OBJECTS);
2018-08-19 09:46:58 +02:00
memset(StaticObjects, 0, sizeof(STATIC_INFO) * NUM_STATICS);
2019-12-02 09:11:21 +01:00
int numMeshDataWords = ReadInt32();
int numMeshDataBytes = 2 * numMeshDataWords;
2018-08-19 09:46:58 +02:00
2019-12-02 09:11:21 +01:00
MeshBase = (short*)GameMalloc(numMeshDataBytes);
2018-08-19 09:46:58 +02:00
ReadBytes(MeshBase, numMeshDataBytes);
2019-12-02 09:11:21 +01:00
RawMeshData = (short*)malloc(numMeshDataBytes);
2018-08-19 09:46:58 +02:00
memcpy(RawMeshData, MeshBase, numMeshDataBytes);
MeshDataSize = numMeshDataBytes;
// TR5 functions do something strange with meshes so I save just for me raw meshes and raw mesh pointers
2019-12-02 09:11:21 +01:00
int numMeshPointers = ReadInt32();
Meshes = (short**)GameMalloc(8 * numMeshPointers);
RawMeshPointers = (int*)malloc(4 * numMeshPointers);
2018-08-19 09:46:58 +02:00
ReadBytes(RawMeshPointers, 4 * numMeshPointers);
memcpy(Meshes, RawMeshPointers, 4 * numMeshPointers);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numMeshPointers; i++)
Meshes[i] = &MeshBase[(int)Meshes[i] / 2];
2018-08-19 09:46:58 +02:00
2019-12-02 09:11:21 +01:00
int numMeshes = numMeshPointers;
2018-08-19 09:46:58 +02:00
NumMeshPointers = numMeshes;
2019-12-02 09:11:21 +01:00
int numAnimations = ReadInt32();
2018-08-19 09:46:58 +02:00
Anims = (ANIM_STRUCT*)GameMalloc(sizeof(ANIM_STRUCT) * numAnimations);
ReadBytes(Anims, sizeof(ANIM_STRUCT) * numAnimations);
2019-12-02 09:11:21 +01:00
int numChanges = ReadInt32();
2018-08-19 09:46:58 +02:00
Changes = (CHANGE_STRUCT*)GameMalloc(sizeof(CHANGE_STRUCT) * numChanges);
ReadBytes(Changes, sizeof(CHANGE_STRUCT) * numChanges);
2019-12-02 09:11:21 +01:00
int numRanges = ReadInt32();
2018-08-19 09:46:58 +02:00
Ranges = (RANGE_STRUCT*)GameMalloc(sizeof(RANGE_STRUCT) * numRanges);
ReadBytes(Ranges, sizeof(RANGE_STRUCT) * numRanges);
2019-12-02 09:11:21 +01:00
int numCommands = ReadInt32();
Commands = (short*)GameMalloc(2 * numCommands);
2018-08-19 09:46:58 +02:00
ReadBytes(Commands, 2 * numCommands);
2019-12-02 09:11:21 +01:00
int numBones = ReadInt32();
Bones = (int*)GameMalloc(4 * numBones);
2018-08-19 09:46:58 +02:00
ReadBytes(Bones, 4 * numBones);
2019-12-02 09:11:21 +01:00
int* bone = Bones;
2018-08-19 09:46:58 +02:00
for (int i = 0; i < 15; i++)
{
2019-12-02 09:11:21 +01:00
int opcode = *(bone++);
2018-08-19 09:46:58 +02:00
int linkX = *(bone++);
int linkY = *(bone++);
int linkZ = *(bone++);
}
2019-12-02 09:11:21 +01:00
MeshTrees = (int*)GameMalloc(4 * numBones);
2018-08-19 09:46:58 +02:00
memcpy(MeshTrees, Bones, 4 * numBones);
2019-12-02 09:11:21 +01:00
int numFrames = ReadInt32();
Frames = (short*)GameMalloc(2 * numFrames);
2018-08-19 09:46:58 +02:00
ReadBytes(Frames, 2 * numFrames);
AnimationsCount = numAnimations;
if (AnimationsCount > 0)
{
2019-12-02 09:11:21 +01:00
int i = 0;
for (int i = 0; i < AnimationsCount; i++)
ADD_PTR(Anims[i].framePtr, short, Frames);
2018-08-19 09:46:58 +02:00
}
2019-12-02 09:11:21 +01:00
int numModels = ReadInt32();
2018-08-19 09:46:58 +02:00
NumObjects = numModels;
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numModels; i++)
2018-08-19 09:46:58 +02:00
{
int objNum = ReadInt32();
MoveablesIds.push_back(objNum);
Objects[objNum].loaded = true;
Objects[objNum].nmeshes = ReadInt16();
Objects[objNum].meshIndex = ReadInt16();
Objects[objNum].boneIndex = ReadInt32();
2019-12-02 09:11:21 +01:00
Objects[objNum].frameBase = (short*)(ReadInt32() + (int)Frames);
2018-08-19 09:46:58 +02:00
Objects[objNum].animIndex = ReadInt16();
ReadInt16();
Objects[objNum].loaded = true;
}
2019-12-30 19:21:47 +01:00
// TODO: this functions seems to not be useful anymore. Hairs and skinning works fine without it.
//if (LaraDrawType != LARA_DIVESUIT)
// CreateSkinningData();
2018-08-19 09:46:58 +02:00
2019-12-02 09:11:21 +01:00
for (int i = 0; i < ID_NUMBER_OBJECTS; i++)
2018-08-19 09:46:58 +02:00
{
Objects[i].meshIndex *= 2;
}
memcpy(&Meshes[numMeshes], &Meshes[0], sizeof(short*) * numMeshes);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < numMeshes; i++)
2018-08-19 09:46:58 +02:00
{
Meshes[2 * i] = Meshes[numMeshes + i];
Meshes[2 * i + 1] = Meshes[numMeshes + i];
}
InitialiseObjects();
InitialiseClosedDoors();
int numStatics = ReadInt32();
NumStaticObjects = numStatics;
for (int i = 0; i < numStatics; i++)
{
2019-12-02 09:11:21 +01:00
int meshID = ReadInt32();
2018-08-19 09:46:58 +02:00
StaticObjectsIds.push_back(meshID);
StaticObjects[meshID].meshNumber = ReadInt16();
StaticObjects[meshID].yMinp = ReadInt16();
StaticObjects[meshID].xMaxp = ReadInt16();
StaticObjects[meshID].yMinp = ReadInt16();
StaticObjects[meshID].yMaxp = ReadInt16();
StaticObjects[meshID].zMinp = ReadInt16();
StaticObjects[meshID].zMaxp = ReadInt16();
StaticObjects[meshID].xMinc = ReadInt16();
StaticObjects[meshID].xMaxc = ReadInt16();
StaticObjects[meshID].yMinc = ReadInt16();
StaticObjects[meshID].yMaxc = ReadInt16();
StaticObjects[meshID].zMinc = ReadInt16();
StaticObjects[meshID].zMaxc = ReadInt16();
StaticObjects[meshID].flags = ReadInt16();
}
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NUM_STATICS; i++)
2018-08-19 09:46:58 +02:00
{
StaticObjects[i].meshNumber *= 2;
}
ProcessMeshData(2 * numMeshes);
// HACK: to remove after decompiling LoadSprites
MoveablesIds.push_back(ID_DEFAULT_SPRITES);
}
void LoadCameras()
{
NumberCameras = ReadInt32();
if (NumberCameras != 0)
{
Cameras = (OBJECT_VECTOR*)GameMalloc(NumberCameras * sizeof(OBJECT_VECTOR));
ReadBytes(Cameras, NumberCameras * sizeof(OBJECT_VECTOR));
}
NumberSpotcams = ReadInt32();
if (NumberSpotcams != 0)
{
ReadBytes(SpotCam, NumberSpotcams * sizeof(SPOTCAM));
}
}
void LoadTextures()
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "LoadTextures - DLL");
printf("LoadTextures\n");
2019-12-02 09:11:21 +01:00
int uncompressedSize = 0;
int compressedSize = 0;
2018-08-19 09:46:58 +02:00
// Read 32 bit textures
ReadFileEx(&uncompressedSize, 1, 4, LevelFilePtr);
ReadFileEx(&compressedSize, 1, 4, LevelFilePtr);
Texture32 = (byte*)malloc(uncompressedSize);
byte* buffer = (byte*)malloc(compressedSize);
ReadFileEx(buffer, compressedSize, 1, LevelFilePtr);
Decompress(Texture32, buffer, compressedSize, uncompressedSize);
free(buffer);
// Read 16 bit textures
ReadFileEx(&uncompressedSize, 1, 4, LevelFilePtr);
ReadFileEx(&compressedSize, 1, 4, LevelFilePtr);
Texture16 = (byte*)malloc(uncompressedSize);
buffer = (byte*)malloc(compressedSize);
ReadFileEx(buffer, compressedSize, 1u, LevelFilePtr);
Decompress(Texture16, buffer, compressedSize, uncompressedSize);
free(buffer);
// Read misc textures
ReadFileEx(&uncompressedSize, 1, 4, LevelFilePtr);
ReadFileEx(&compressedSize, 1, 4, LevelFilePtr);
printf("%d\n", uncompressedSize);
MiscTextures = (byte*)malloc(uncompressedSize);
buffer = (byte*)malloc(compressedSize);
ReadFileEx(buffer, compressedSize, 1u, LevelFilePtr);
Decompress(MiscTextures, buffer, compressedSize, uncompressedSize);
free(buffer);
}
void ReadRoom(ROOM_INFO* room, ROOM_INFO* roomData)
2018-08-19 09:46:58 +02:00
{
2019-12-02 09:11:21 +01:00
/*ADD_PTR(roomData->door, short, roomData + 1);
2018-08-19 09:46:58 +02:00
ADD_PTR(roomData->floor, FLOOR_INFO, roomData + 1);
ADD_PTR(roomData->light, LIGHTINFO, roomData + 1);
ADD_PTR(roomData->mesh, MESH_INFO, roomData + 1);
ADD_PTR(roomData->Separator4, void, roomData + 1);
ADD_PTR(roomData->LayerOffset, tr5_room_layer, roomData + 1);
ADD_PTR(roomData->PolyOffset, void, roomData + 1);
ADD_PTR(roomData->PolyOffset2, void, roomData + 1);
ADD_PTR(roomData->VerticesOffset, tr5_room_vertex, roomData + 1);
2019-12-02 09:11:21 +01:00
roomData->LightDataSize += (int)(roomData + 1);
2018-08-19 09:46:58 +02:00
if ((byte)roomData->door & 1)
{
//DB_Log(0, "%X", roomData->door);
roomData->door = 0;
}
byte* polyOff = (byte*)roomData->PolyOffset;
byte* polyOff2 = (byte*)roomData->PolyOffset2;
byte* vertOff = (byte*)roomData->VerticesOffset;
for (int i = 0; i < roomData->NumLayers; i++)
{
roomData->LayerOffset[i].PolyOffset = polyOff;
roomData->LayerOffset[i].PolyOffset2 = polyOff2;
roomData->LayerOffset[i].VerticesOffset = vertOff;
polyOff += sizeof(tr4_mesh_face3) * roomData->LayerOffset[i].NumLayerTriangles +
sizeof(tr4_mesh_face4) * roomData->LayerOffset[i].NumLayerRectangles;
polyOff2 += 4 * roomData->LayerOffset[i].NumLayerVertices; // todo find what struct this is
vertOff += sizeof(tr5_room_vertex) * roomData->LayerOffset[i].NumLayerVertices;
}
memcpy(room, roomData, sizeof(ROOM_INFO));*/
}
void ReadRooms()
2018-08-19 09:46:58 +02:00
{
ReadInt32();
2019-12-02 09:11:21 +01:00
int numRooms = ReadInt32();
2018-08-19 09:46:58 +02:00
NumberRooms = numRooms;
Rooms = (ROOM_INFO*)GameMalloc(NumberRooms * sizeof(ROOM_INFO));
printf("NumRooms: %d\n", numRooms);
2019-12-02 09:11:21 +01:00
for (int i = 0; i < NumberRooms; i++)
2018-08-19 09:46:58 +02:00
{
// Ignore XELA
2019-12-02 09:11:21 +01:00
int xela = ReadInt32();
2018-08-19 09:46:58 +02:00
// Read room data
2019-12-02 09:11:21 +01:00
int roomDataSize = ReadInt32();
2018-08-19 09:46:58 +02:00
byte* roomData = (byte*)GameMalloc(roomDataSize);
ReadBytes(roomData, roomDataSize);
// Put the room data in the struct
ReadRoom(&Rooms[i], (ROOM_INFO*)roomData);
}
}
int LoadRoomsNew()
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "LoadRooms - DLL");
printf("LoadRooms\n");
Wibble = 0;
RoomLightsCount = 0;
Unk_007E7FE8 = 0;
ReadRooms();
DoSomethingWithRooms();
2019-12-02 09:11:21 +01:00
int numFloorData = ReadInt32();
FloorData = (short*)GameMalloc(numFloorData * 2);
2018-08-19 09:46:58 +02:00
ReadBytes(FloorData, numFloorData * 2);
return true;
}
void FreeLevel()
2018-08-19 09:46:58 +02:00
{
MallocPtr = MallocBuffer;
MallocFree = MallocSize;
2018-09-02 09:29:36 +02:00
g_Renderer->FreeRendererData();
g_GameScript->FreeLevelScripts();
2018-08-19 09:46:58 +02:00
}
unsigned __stdcall LoadLevel(void* data)
{
DB_Log(5, "LoadLevel - DLL");
printf("LoadLevel\n");
char* filename = (char*)data;
LevelDataPtr = NULL;
LevelFilePtr = 0;
g_Renderer->UpdateProgress(0);
2018-08-19 09:46:58 +02:00
LevelFilePtr = FileOpen(filename);
if (LevelFilePtr)
{
2019-12-02 09:11:21 +01:00
int version;
short numRoomTextureTiles;
short numObjectsTextureTiles;
short numBumpTextureTiles;
2018-08-19 09:46:58 +02:00
ReadFileEx(&version, 1, 4, LevelFilePtr);
ReadFileEx(&numRoomTextureTiles, 1, 2, LevelFilePtr);
ReadFileEx(&numObjectsTextureTiles, 1, 2, LevelFilePtr);
ReadFileEx(&numBumpTextureTiles, 1, 2, LevelFilePtr);
g_Renderer->NumTexturePages = numRoomTextureTiles + numObjectsTextureTiles + numBumpTextureTiles;
LoadTextures();
g_Renderer->UpdateProgress(20);
2019-12-02 09:11:21 +01:00
short buffer[32];
2018-08-19 09:46:58 +02:00
ReadFileEx(&buffer, 2, 16, LevelFilePtr);
WeatherType = buffer[0];
LaraDrawType = buffer[1];
2019-12-02 09:11:21 +01:00
int uncompressedSize;
int compressedSize;
2018-08-19 09:46:58 +02:00
ReadFileEx(&uncompressedSize, 1, 4, LevelFilePtr);
ReadFileEx(&compressedSize, 1, 4, LevelFilePtr);
LevelDataPtr = (char*)malloc(uncompressedSize);
ReadFileEx(LevelDataPtr, uncompressedSize, 1, LevelFilePtr);
LoadRooms();
g_Renderer->UpdateProgress(40);
2018-08-19 09:46:58 +02:00
LoadObjects();
g_Renderer->UpdateProgress(50);
2018-08-30 22:51:16 +02:00
InitialiseLOTarray(true);
2018-08-19 09:46:58 +02:00
LoadSprites();
LoadCameras();
LoadSoundEffects();
g_Renderer->UpdateProgress(60);
2018-08-19 09:46:58 +02:00
LoadBoxes();
LoadAnimatedTextures();
LoadTextureInfos();
g_Renderer->UpdateProgress(70);
2018-08-19 09:46:58 +02:00
LoadItems();
LoadAIObjects();
LoadDemoData();
LoadSamples();
g_Renderer->UpdateProgress(80);
2018-08-19 09:46:58 +02:00
2019-12-02 09:11:21 +01:00
int extraSize = 0;
ReadFileEx(&extraSize, 1, 4, LevelFilePtr);
if (extraSize > 0)
{
ReadFileEx(&extraSize, 1, 4, LevelFilePtr);
LevelDataPtr = (char*)malloc(extraSize);
ReadFileEx(LevelDataPtr, extraSize, 1, LevelFilePtr);
LoadNewData(extraSize);
}
2018-08-19 09:46:58 +02:00
LevelDataPtr = NULL;
FileClose(LevelFilePtr);
}
else
{
return false;
}
g_Renderer->UpdateProgress(80);
2018-08-19 09:46:58 +02:00
g_Renderer->PrepareDataForTheRenderer();
// Initialise the game
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
2018-09-09 22:07:28 +02:00
SeedRandomDraw(0xD371F947);
SeedRandomControl(0xD371F947);
2018-09-09 21:58:38 +02:00
Wibble = 0;
TorchRoom = -1;
InitialiseGameFlags();
InitialiseLara(!(InitialiseGame || CurrentLevel == 1 || level->ResetHub));
GetCarriedItems();
GetAIPickups();
SeedRandomDraw(0xD371F947);
SeedRandomControl(0xD371F947);
g_LaraExtra.Vehicle = -1;
2018-10-09 00:02:14 +02:00
g_GameScript->AssignItemsAndLara();
// Level loaded
2018-08-19 09:46:58 +02:00
IsLevelLoading = false;
g_Renderer->UpdateProgress(100);
2018-08-19 09:46:58 +02:00
_endthreadex(1);
return true;
}
int S_LoadLevelFile(int levelIndex)
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "S_LoadLevelFile - DLL");
printf("S_LoadLevelFile\n");
2018-10-28 14:11:00 +01:00
SOUND_Stop();
Sound_FreeSamples();
if (!g_FirstLevel)
FreeLevel();
g_FirstLevel = false;
2018-08-19 09:46:58 +02:00
RenderLoadBar = false;
char filename[80];
GameScriptLevel* level = g_GameFlow->Levels[levelIndex];
strcpy_s(filename, level->FileName.c_str());
2018-10-28 11:45:53 +01:00
// Loading level is done is two threads, one for loading level and one for drawing loading screen
2018-08-19 09:46:58 +02:00
IsLevelLoading = true;
hLoadLevel = _beginthreadex(0, 0, LoadLevel, filename, 0, &ThreadId);
// This function loops until progress is 100%. Not very thread safe, but behaviour should be predictable.
2018-10-28 11:45:53 +01:00
g_Renderer->DrawLoadingScreen((char*)(level->LoadScreenFileName.c_str()));
2019-01-13 21:57:16 +01:00
while (IsLevelLoading);
2018-08-19 09:46:58 +02:00
return true;
}
void AdjustUV(int num)
2018-08-19 09:46:58 +02:00
{
// Dummy function
NumObjectTextures = num;
}
bool ReadLuaIds(ChunkId* chunkId, int maxSize, int arg)
{
if (chunkId->EqualsTo(ChunkLuaId))
{
2019-12-02 09:11:21 +01:00
int luaId = 0;
g_levelChunkIO->GetRawStream()->ReadInt32(&luaId);
2019-12-02 09:11:21 +01:00
int itemId = 0;
g_levelChunkIO->GetRawStream()->ReadInt32(&itemId);
g_GameScript->AddLuaId(luaId, itemId);
return true;
}
else
return false;
}
bool ReadLuaTriggers(ChunkId* chunkId, int maxSize, int arg)
{
if (chunkId->EqualsTo(ChunkTrigger))
{
char* functionName = NULL;
g_levelChunkIO->GetRawStream()->ReadString(&functionName);
char* functionCode = NULL;
g_levelChunkIO->GetRawStream()->ReadString(&functionCode);
LuaFunction* function = new LuaFunction();
function->Name = string(functionName);
function->Code = string(functionCode);
function->Executed = false;
g_GameScript->AddTrigger(function);
delete functionName;
delete functionCode;
return true;
}
else
return false;
}
bool ReadNewDataChunks(ChunkId* chunkId, int maxSize, int arg)
{
if (chunkId->EqualsTo(ChunkTriggersList))
return g_levelChunkIO->ReadChunks(ReadLuaTriggers, 0);
else if (chunkId->EqualsTo(ChunkLuaIds))
return g_levelChunkIO->ReadChunks(ReadLuaIds, 0);
return false;
}
void LoadNewData(int size)
{
// Free old level scripts
MemoryStream stream(LevelDataPtr, size);
g_levelChunkIO = new ChunkReader(0x4D355254, &stream);
if (!g_levelChunkIO->IsValid())
return;
g_levelChunkIO->ReadChunks(ReadNewDataChunks, 0);
}
void LoadSprites()
{
DB_Log(2, "LoadSprites");
ReadInt32(); // SPR\0
g_NumSprites = ReadInt32();
Sprites = (SPRITE*)GameMalloc(g_NumSprites * sizeof(SPRITE));
2019-12-02 09:11:21 +01:00
for (int i = 0; i < g_NumSprites; i++)
{
Sprites[i].tile = ReadInt16() + 1;
Sprites[i].x = ReadInt8();
Sprites[i].y = ReadInt8();
Sprites[i].width = ReadInt16();
Sprites[i].height = ReadInt16();
Sprites[i].left = (ReadInt16() + 1) / 256.0;
Sprites[i].top = (ReadInt16() + 1) / 256.0;
Sprites[i].right = (ReadInt16() - 1) / 256.0;
Sprites[i].bottom = (ReadInt16() - 1) / 256.0;
}
g_NumSpritesSequences = ReadInt32();
2019-12-02 09:11:21 +01:00
for (int i = 0; i < g_NumSpritesSequences; i++)
{
2019-12-02 09:11:21 +01:00
int spriteID = ReadInt32();
short negLength = ReadInt16();
short offset = ReadInt16();
if (spriteID >= ID_NUMBER_OBJECTS)
{
StaticObjects[spriteID - ID_NUMBER_OBJECTS].meshNumber = offset;
}
else
{
Objects[spriteID].nmeshes = negLength;
Objects[spriteID].meshIndex = offset;
Objects[spriteID].loaded = true;
}
}
}
2018-08-19 09:46:58 +02:00
void Inject_RoomLoad()
{
INJECT(0x004A6380, LoadItems);
INJECT(0x004A4E60, LoadObjects);
INJECT(0x004A3FC0, LoadTextures);
INJECT(0x0040130C, S_LoadLevelFile);
INJECT(0x004A7130, FreeLevel);
INJECT(0x004A5430, AdjustUV);
INJECT(0x004A5CA0, LoadCameras);
2018-08-19 09:46:58 +02:00
}