2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2021-09-19 18:29:25 +03:00
|
|
|
#include "animation.h"
|
2020-04-22 14:12:10 +02:00
|
|
|
#include "level.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "setup.h"
|
2021-09-16 05:06:03 +03:00
|
|
|
#include "animation.h"
|
2021-09-19 23:41:26 +03:00
|
|
|
#include "control/lot.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "Lara.h"
|
|
|
|
#include "savegame.h"
|
|
|
|
#include "spotcam.h"
|
|
|
|
#include "camera.h"
|
2021-09-19 23:41:26 +03:00
|
|
|
#include "control/control.h"
|
2021-09-11 10:13:04 +03:00
|
|
|
#include "pickup.h"
|
2021-09-19 23:41:26 +03:00
|
|
|
#include "control/volume.h"
|
2021-09-05 05:52:50 +02:00
|
|
|
#include "generic_doors.h"
|
2021-09-19 23:41:26 +03:00
|
|
|
#include "control/box.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "sound.h"
|
2020-05-30 15:55:23 +02:00
|
|
|
#include "GameFlowScript.h"
|
2020-09-29 21:40:02 +02:00
|
|
|
#include <process.h>
|
|
|
|
#include <zlib.h>
|
2021-08-28 13:27:58 +02:00
|
|
|
#include "Renderer11.h"
|
2021-09-25 16:00:30 +03:00
|
|
|
#include "items.h"
|
2021-09-25 11:27:47 +02:00
|
|
|
|
|
|
|
|
2021-08-30 18:03:21 +03:00
|
|
|
using TEN::Renderer::g_Renderer;
|
2020-06-20 23:39:08 +02:00
|
|
|
using std::vector;
|
|
|
|
using std::string;
|
2021-09-05 05:52:50 +02:00
|
|
|
using namespace TEN::Entities::Doors;
|
2020-07-03 07:05:33 +02:00
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
FILE* LevelFilePtr;
|
|
|
|
uintptr_t hLoadLevel;
|
|
|
|
unsigned int ThreadId;
|
|
|
|
int IsLevelLoading;
|
|
|
|
bool g_FirstLevel = true;
|
|
|
|
vector<int> MoveablesIds;
|
|
|
|
vector<int> StaticObjectsIds;
|
|
|
|
char* LevelDataPtr;
|
|
|
|
ChunkReader* g_levelChunkIO;
|
2020-07-21 09:56:47 +02:00
|
|
|
LEVEL g_Level;
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
short ReadInt8()
|
|
|
|
{
|
|
|
|
byte value = *(byte*)LevelDataPtr;
|
|
|
|
LevelDataPtr += 1;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
short ReadInt16()
|
|
|
|
{
|
|
|
|
short value = *(short*)LevelDataPtr;
|
|
|
|
LevelDataPtr += 2;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-06-26 07:06:18 +02:00
|
|
|
unsigned short ReadUInt16()
|
|
|
|
{
|
|
|
|
unsigned short value = *(unsigned short*)LevelDataPtr;
|
|
|
|
LevelDataPtr += 2;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
int ReadInt32()
|
|
|
|
{
|
|
|
|
int value = *(int*)LevelDataPtr;
|
|
|
|
LevelDataPtr += 4;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-06-20 21:20:36 +02:00
|
|
|
float ReadFloat()
|
|
|
|
{
|
|
|
|
float value = *(float*)LevelDataPtr;
|
|
|
|
LevelDataPtr += 4;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
Vector2 ReadVector2()
|
|
|
|
{
|
|
|
|
Vector2 value;
|
|
|
|
value.x = ReadFloat();
|
|
|
|
value.y = ReadFloat();
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 ReadVector3()
|
|
|
|
{
|
|
|
|
Vector3 value;
|
|
|
|
value.x = ReadFloat();
|
|
|
|
value.y = ReadFloat();
|
|
|
|
value.z = ReadFloat();
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
void ReadBytes(void* dest, int count)
|
|
|
|
{
|
|
|
|
memcpy(dest, LevelDataPtr, count);
|
|
|
|
LevelDataPtr += count;
|
|
|
|
}
|
|
|
|
|
2021-10-04 03:09:32 +03:00
|
|
|
void LoadItems()
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.NumItems = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num items: ", g_Level.NumItems);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.NumItems == 0)
|
2021-10-04 03:09:32 +03:00
|
|
|
return;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Items.resize(NUM_ITEMS);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
InitialiseItemArray(NUM_ITEMS);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.NumItems > 0)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
for (int i = 0; i < g_Level.NumItems; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[i];
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-07-11 16:55:20 +01:00
|
|
|
item->objectNumber = from_underlying(ReadInt16());
|
2020-04-22 14:12:10 +02:00
|
|
|
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();
|
2021-07-10 06:55:37 +02:00
|
|
|
|
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-10 06:55:37 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
item->luaName = std::string(buffer, buffer + numBytes);
|
2021-07-10 06:55:37 +02:00
|
|
|
|
2021-08-27 18:49:14 +01:00
|
|
|
g_GameScript->AddName(item->luaName, i);
|
2021-07-19 05:52:21 +02:00
|
|
|
|
2020-08-04 21:53:58 +02:00
|
|
|
memcpy(&item->startPos, &item->pos, sizeof(PHD_3DPOS));
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
for (int i = 0; i < g_Level.NumItems; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
InitialiseItem(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadObjects()
|
|
|
|
{
|
2020-09-29 21:40:02 +02:00
|
|
|
std::memset(Objects, 0, sizeof(OBJECT_INFO) * ID_NUMBER_OBJECTS);
|
|
|
|
std::memset(StaticObjects, 0, sizeof(STATIC_INFO) * MAX_STATICS);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-03 07:05:33 +02:00
|
|
|
int numMeshes = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num meshes: ", numMeshes);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Meshes.reserve(numMeshes);
|
2020-07-03 07:05:33 +02:00
|
|
|
for (int i = 0; i < numMeshes; i++)
|
|
|
|
{
|
|
|
|
MESH mesh;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
mesh.sphere.Center.x = ReadFloat();
|
|
|
|
mesh.sphere.Center.y = ReadFloat();
|
|
|
|
mesh.sphere.Center.z = ReadFloat();
|
|
|
|
mesh.sphere.Radius = ReadFloat();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-03 07:05:33 +02:00
|
|
|
int numVertices = ReadInt32();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
mesh.positions.resize(numVertices);
|
|
|
|
ReadBytes(mesh.positions.data(), 12 * numVertices);
|
|
|
|
|
|
|
|
mesh.colors.resize(numVertices);
|
|
|
|
ReadBytes(mesh.colors.data(), 12 * numVertices);
|
|
|
|
|
2021-07-30 20:55:03 +03:00
|
|
|
mesh.effects.resize(numVertices);
|
2021-07-31 18:51:30 +03:00
|
|
|
ReadBytes(mesh.effects.data(), 12 * numVertices);
|
2021-07-30 20:55:03 +03:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
mesh.bones.resize(numVertices);
|
|
|
|
ReadBytes(mesh.bones.data(), 4 * numVertices);
|
|
|
|
|
2020-07-03 07:05:33 +02:00
|
|
|
int numBuckets = ReadInt32();
|
|
|
|
mesh.buckets.reserve(numBuckets);
|
|
|
|
for (int j = 0; j < numBuckets; j++)
|
|
|
|
{
|
|
|
|
BUCKET bucket;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-03 07:05:33 +02:00
|
|
|
bucket.texture = ReadInt32();
|
|
|
|
bucket.blendMode = ReadInt8();
|
|
|
|
bucket.animated = ReadInt8();
|
2020-07-05 06:20:36 +02:00
|
|
|
bucket.numQuads = 0;
|
|
|
|
bucket.numTriangles = 0;
|
|
|
|
|
|
|
|
int numPolygons = ReadInt32();
|
|
|
|
bucket.polygons.reserve(numPolygons);
|
|
|
|
for (int k = 0; k < numPolygons; k++)
|
|
|
|
{
|
|
|
|
POLYGON poly;
|
|
|
|
|
|
|
|
poly.shape = ReadInt32();
|
2021-03-27 07:33:40 +01:00
|
|
|
poly.animatedSequence = ReadInt32();
|
|
|
|
poly.animatedFrame = ReadInt32();
|
2020-07-05 06:20:36 +02:00
|
|
|
int count = (poly.shape == 0 ? 4 : 3);
|
|
|
|
poly.indices.resize(count);
|
|
|
|
poly.textureCoordinates.resize(count);
|
2020-07-18 06:58:44 +02:00
|
|
|
poly.normals.resize(count);
|
|
|
|
poly.tangents.resize(count);
|
|
|
|
poly.bitangents.resize(count);
|
|
|
|
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.indices[n] = ReadInt32();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.textureCoordinates[n] = ReadVector2();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.normals[n] = ReadVector3();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.tangents[n] = ReadVector3();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.bitangents[n] = ReadVector3();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
bucket.polygons.push_back(poly);
|
|
|
|
|
|
|
|
if (poly.shape == 0)
|
|
|
|
bucket.numQuads++;
|
|
|
|
else
|
|
|
|
bucket.numTriangles++;
|
|
|
|
}
|
2020-07-03 07:05:33 +02:00
|
|
|
|
|
|
|
mesh.buckets.push_back(bucket);
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Meshes.push_back(mesh);
|
2020-07-03 07:05:33 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numAnimations = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num animations: ", numAnimations);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Anims.resize(numAnimations);
|
2020-07-25 18:02:35 +02:00
|
|
|
for (int i = 0; i < numAnimations; i++)
|
|
|
|
{
|
2021-07-24 19:08:17 +01:00
|
|
|
ANIM_STRUCT* anim = &g_Level.Anims[i];
|
2020-07-25 18:02:35 +02:00
|
|
|
|
|
|
|
anim->framePtr = ReadInt32();
|
|
|
|
anim->interpolation = ReadInt16();
|
|
|
|
anim->currentAnimState = ReadInt16();
|
|
|
|
anim->velocity = ReadInt32();
|
|
|
|
anim->acceleration = ReadInt32();
|
|
|
|
anim->Xvelocity = ReadInt32();
|
|
|
|
anim->Xacceleration = ReadInt32();
|
|
|
|
anim->frameBase = ReadInt16();
|
|
|
|
anim->frameEnd = ReadInt16();
|
|
|
|
anim->jumpAnimNum = ReadInt16();
|
|
|
|
anim->jumpFrameNum = ReadInt16();
|
|
|
|
anim->numberChanges = ReadInt16();
|
|
|
|
anim->changeIndex = ReadInt16();
|
|
|
|
anim->numberCommands = ReadInt16();
|
|
|
|
anim->commandIndex = ReadInt16();
|
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numChanges = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Changes.resize(numChanges);
|
|
|
|
ReadBytes(g_Level.Changes.data(), sizeof(CHANGE_STRUCT) * numChanges);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numRanges = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Ranges.resize(numRanges);
|
|
|
|
ReadBytes(g_Level.Ranges.data(), sizeof(RANGE_STRUCT) * numRanges);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numCommands = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Commands.resize(numCommands);
|
|
|
|
ReadBytes(g_Level.Commands.data(), sizeof(short) * numCommands);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numBones = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Bones.resize(numBones);
|
|
|
|
ReadBytes(g_Level.Bones.data(), 4 * numBones);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numFrames = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Frames.resize(numFrames);
|
2020-07-25 18:02:35 +02:00
|
|
|
for (int i = 0; i < numFrames; i++)
|
|
|
|
{
|
|
|
|
ANIM_FRAME* frame = &g_Level.Frames[i];
|
|
|
|
frame->boundingBox.X1 = ReadInt16();
|
|
|
|
frame->boundingBox.X2 = ReadInt16();
|
|
|
|
frame->boundingBox.Y1 = ReadInt16();
|
|
|
|
frame->boundingBox.Y2 = ReadInt16();
|
|
|
|
frame->boundingBox.Z1 = ReadInt16();
|
|
|
|
frame->boundingBox.Z2 = ReadInt16();
|
2020-07-26 07:21:38 +02:00
|
|
|
frame->offsetX = ReadInt16();
|
|
|
|
frame->offsetY = ReadInt16();
|
|
|
|
frame->offsetZ = ReadInt16();
|
2020-07-25 18:02:35 +02:00
|
|
|
int numAngles = ReadInt16();
|
|
|
|
frame->angles.resize(numAngles);
|
|
|
|
for (int j = 0; j < numAngles; j++)
|
|
|
|
{
|
|
|
|
Quaternion* q = &frame->angles[j];
|
|
|
|
q->x = ReadFloat();
|
|
|
|
q->y = ReadFloat();
|
|
|
|
q->z = ReadFloat();
|
|
|
|
q->w = ReadFloat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//ReadBytes(g_Level.Frames.data(), sizeof(ANIM_FRAME) * numFrames);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
int numModels = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num models: ", numModels);
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
for (int i = 0; i < numModels; i++)
|
|
|
|
{
|
|
|
|
int objNum = ReadInt32();
|
|
|
|
MoveablesIds.push_back(objNum);
|
|
|
|
|
|
|
|
Objects[objNum].loaded = true;
|
2020-07-03 07:05:33 +02:00
|
|
|
Objects[objNum].nmeshes = (short)ReadInt16();
|
|
|
|
Objects[objNum].meshIndex = (short)ReadInt16();
|
2020-04-22 14:12:10 +02:00
|
|
|
Objects[objNum].boneIndex = ReadInt32();
|
2020-07-25 18:02:35 +02:00
|
|
|
Objects[objNum].frameBase = ReadInt32();
|
2020-07-03 07:05:33 +02:00
|
|
|
Objects[objNum].animIndex = (short)ReadInt16();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
ReadInt16();
|
|
|
|
|
|
|
|
Objects[objNum].loaded = true;
|
|
|
|
}
|
|
|
|
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Initializing objects...");
|
2020-04-22 14:12:10 +02:00
|
|
|
InitialiseObjects();
|
|
|
|
|
|
|
|
int numStatics = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num statics: ", numStatics);
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
for (int i = 0; i < numStatics; i++)
|
|
|
|
{
|
|
|
|
int meshID = ReadInt32();
|
|
|
|
StaticObjectsIds.push_back(meshID);
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
StaticObjects[meshID].meshNumber = (short)ReadInt32();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-25 18:02:35 +02:00
|
|
|
StaticObjects[meshID].visibilityBox.X1 = ReadInt16();
|
|
|
|
StaticObjects[meshID].visibilityBox.X2 = ReadInt16();
|
|
|
|
StaticObjects[meshID].visibilityBox.Y1 = ReadInt16();
|
|
|
|
StaticObjects[meshID].visibilityBox.Y2 = ReadInt16();
|
|
|
|
StaticObjects[meshID].visibilityBox.Z1 = ReadInt16();
|
|
|
|
StaticObjects[meshID].visibilityBox.Z2 = ReadInt16();
|
|
|
|
|
|
|
|
StaticObjects[meshID].collisionBox.X1 = ReadInt16();
|
|
|
|
StaticObjects[meshID].collisionBox.X2 = ReadInt16();
|
|
|
|
StaticObjects[meshID].collisionBox.Y1 = ReadInt16();
|
|
|
|
StaticObjects[meshID].collisionBox.Y2 = ReadInt16();
|
|
|
|
StaticObjects[meshID].collisionBox.Z1 = ReadInt16();
|
|
|
|
StaticObjects[meshID].collisionBox.Z2 = ReadInt16();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-03 07:05:33 +02:00
|
|
|
StaticObjects[meshID].flags = (short)ReadInt16();
|
2020-08-16 21:06:35 +02:00
|
|
|
|
|
|
|
StaticObjects[meshID].shatterType = (short)ReadInt16();
|
|
|
|
StaticObjects[meshID].shatterSound = (short)ReadInt16();
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// HACK: to remove after decompiling LoadSprites
|
|
|
|
MoveablesIds.push_back(ID_DEFAULT_SPRITES);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadCameras()
|
|
|
|
{
|
2020-07-11 21:16:04 +02:00
|
|
|
int numCameras = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num cameras: ", numCameras);
|
|
|
|
|
2021-08-03 01:30:44 +03:00
|
|
|
g_Level.Cameras.reserve(numCameras);
|
2021-07-10 06:55:37 +02:00
|
|
|
for (int i = 0; i < numCameras; i++)
|
|
|
|
{
|
2021-07-24 19:08:17 +01:00
|
|
|
auto & camera = g_Level.Cameras.emplace_back();
|
2021-07-10 06:55:37 +02:00
|
|
|
camera.x = ReadInt32();
|
|
|
|
camera.y = ReadInt32();
|
|
|
|
camera.z = ReadInt32();
|
|
|
|
camera.roomNumber = ReadInt32();
|
|
|
|
camera.flags = ReadInt32();
|
2021-09-11 18:59:14 +03:00
|
|
|
camera.speed = ReadInt32();
|
2021-07-10 06:55:37 +02:00
|
|
|
|
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-10 06:55:37 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
camera.luaName = std::string(buffer, buffer + numBytes);
|
2021-07-10 06:55:37 +02:00
|
|
|
|
2021-08-27 18:49:14 +01:00
|
|
|
g_GameScript->AddName(camera.luaName, camera);
|
2021-07-10 06:55:37 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
NumberSpotcams = ReadInt32();
|
|
|
|
|
|
|
|
if (NumberSpotcams != 0)
|
|
|
|
{
|
|
|
|
ReadBytes(SpotCam, NumberSpotcams * sizeof(SPOTCAM));
|
|
|
|
}
|
2021-07-10 06:55:37 +02:00
|
|
|
|
|
|
|
int numSinks = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num sinks: ", numSinks);
|
|
|
|
|
2021-08-03 01:30:44 +03:00
|
|
|
g_Level.Sinks.reserve(numSinks);
|
2021-07-10 06:55:37 +02:00
|
|
|
for (int i = 0; i < numSinks; i++)
|
|
|
|
{
|
2021-07-24 19:08:17 +01:00
|
|
|
auto & sink = g_Level.Sinks.emplace_back();
|
2021-07-10 06:55:37 +02:00
|
|
|
sink.x = ReadInt32();
|
|
|
|
sink.y = ReadInt32();
|
|
|
|
sink.z = ReadInt32();
|
|
|
|
sink.strength = ReadInt32();
|
|
|
|
sink.boxIndex = ReadInt32();
|
|
|
|
|
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-10 06:55:37 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
sink.luaName = std::string(buffer, buffer+numBytes);
|
2021-07-10 06:55:37 +02:00
|
|
|
|
2021-08-27 18:49:14 +01:00
|
|
|
g_GameScript->AddName(sink.luaName, sink);
|
2021-07-10 06:55:37 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void LoadTextures()
|
|
|
|
{
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Loading textures");
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-18 06:58:44 +02:00
|
|
|
int size;
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
int numTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num room textures: ", numTextures);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.RoomTextures.reserve(numTextures);
|
2020-06-20 21:20:36 +02:00
|
|
|
for (int i = 0; i < numTextures; i++)
|
|
|
|
{
|
|
|
|
TEXTURE texture;
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
texture.width = ReadInt32();
|
|
|
|
texture.height = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.colorMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.colorMapData.data(), size);
|
2020-07-18 06:58:44 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
byte hasNormalMap = ReadInt8();
|
2020-07-18 06:58:44 +02:00
|
|
|
if (hasNormalMap)
|
|
|
|
{
|
2020-07-26 07:21:38 +02:00
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.normalMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.normalMapData.data(), size);
|
2020-07-18 06:58:44 +02:00
|
|
|
}
|
2020-06-20 21:20:36 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.RoomTextures.push_back(texture);
|
2020-06-20 21:20:36 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
numTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num object textures: ", numTextures);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.MoveablesTextures.reserve(numTextures);
|
2020-06-20 21:20:36 +02:00
|
|
|
for (int i = 0; i < numTextures; i++)
|
|
|
|
{
|
|
|
|
TEXTURE texture;
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
texture.width = ReadInt32();
|
|
|
|
texture.height = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.colorMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.colorMapData.data(), size);
|
2020-07-18 06:58:44 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
bool hasNormalMap = ReadInt8();
|
2020-07-18 06:58:44 +02:00
|
|
|
if (hasNormalMap)
|
|
|
|
{
|
2020-07-26 07:21:38 +02:00
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.normalMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.normalMapData.data(), size);
|
2020-07-18 06:58:44 +02:00
|
|
|
}
|
2020-06-20 21:20:36 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.MoveablesTextures.push_back(texture);
|
2020-06-20 21:20:36 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
numTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num static textures: ", numTextures);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.StaticsTextures.reserve(numTextures);
|
2020-06-20 21:20:36 +02:00
|
|
|
for (int i = 0; i < numTextures; i++)
|
|
|
|
{
|
|
|
|
TEXTURE texture;
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
texture.width = ReadInt32();
|
|
|
|
texture.height = ReadInt32();
|
|
|
|
|
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.colorMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.colorMapData.data(), size);
|
2020-07-18 06:58:44 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
bool hasNormalMap = ReadInt8();
|
2020-07-18 06:58:44 +02:00
|
|
|
if (hasNormalMap)
|
|
|
|
{
|
2020-07-26 07:21:38 +02:00
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.normalMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.normalMapData.data(), size);
|
2020-07-18 06:58:44 +02:00
|
|
|
}
|
2020-06-20 21:20:36 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.StaticsTextures.push_back(texture);
|
2020-06-20 21:20:36 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-03-27 07:33:40 +01:00
|
|
|
numTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num anim textures: ", numTextures);
|
|
|
|
|
2021-03-27 07:33:40 +01:00
|
|
|
g_Level.AnimatedTextures.reserve(numTextures);
|
|
|
|
for (int i = 0; i < numTextures; i++)
|
|
|
|
{
|
|
|
|
TEXTURE texture;
|
|
|
|
|
|
|
|
texture.width = ReadInt32();
|
|
|
|
texture.height = ReadInt32();
|
|
|
|
|
|
|
|
size = ReadInt32();
|
|
|
|
texture.colorMapData.resize(size);
|
|
|
|
ReadBytes(texture.colorMapData.data(), size);
|
|
|
|
|
|
|
|
bool hasNormalMap = ReadInt8();
|
|
|
|
if (hasNormalMap)
|
|
|
|
{
|
|
|
|
size = ReadInt32();
|
|
|
|
texture.normalMapData.resize(size);
|
|
|
|
ReadBytes(texture.normalMapData.data(), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_Level.AnimatedTextures.push_back(texture);
|
|
|
|
}
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
numTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num sprite textures: ", numTextures);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.SpritesTextures.reserve(numTextures);
|
2020-06-20 21:20:36 +02:00
|
|
|
for (int i = 0; i < numTextures; i++)
|
|
|
|
{
|
|
|
|
TEXTURE texture;
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
texture.width = ReadInt32();
|
|
|
|
texture.height = ReadInt32();
|
|
|
|
|
|
|
|
size = ReadInt32();
|
2020-07-18 06:58:44 +02:00
|
|
|
texture.colorMapData.resize(size);
|
2020-07-26 07:21:38 +02:00
|
|
|
ReadBytes(texture.colorMapData.data(), size);
|
2020-06-20 21:20:36 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.SpritesTextures.push_back(texture);
|
2020-06-20 21:20:36 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-09-09 13:39:25 +03:00
|
|
|
g_Level.SkyTexture.width = ReadInt32();
|
|
|
|
g_Level.SkyTexture.height = ReadInt32();
|
2020-07-26 07:21:38 +02:00
|
|
|
size = ReadInt32();
|
2021-09-09 13:39:25 +03:00
|
|
|
g_Level.SkyTexture.colorMapData.resize(size);
|
|
|
|
ReadBytes(g_Level.SkyTexture.colorMapData.data(), size);
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
2020-06-26 07:06:18 +02:00
|
|
|
void ReadRooms()
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-06-26 07:06:18 +02:00
|
|
|
int numRooms = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num rooms: ", numRooms);
|
2021-07-23 02:41:39 +01:00
|
|
|
|
2020-06-26 07:06:18 +02:00
|
|
|
for (int i = 0; i < numRooms; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2021-07-24 19:08:17 +01:00
|
|
|
auto & room = g_Level.Rooms.emplace_back();
|
2020-06-26 07:06:18 +02:00
|
|
|
room.x = ReadInt32();
|
|
|
|
room.y = 0;
|
|
|
|
room.z = ReadInt32();
|
|
|
|
room.minfloor = ReadInt32();
|
|
|
|
room.maxceiling = ReadInt32();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
int numVertices = ReadInt32();
|
2021-07-30 20:55:03 +03:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
room.positions.reserve(numVertices);
|
2020-06-26 07:06:18 +02:00
|
|
|
for (int j = 0; j < numVertices; j++)
|
2020-07-05 06:20:36 +02:00
|
|
|
room.positions.push_back(ReadVector3());
|
2021-07-30 20:55:03 +03:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
room.colors.reserve(numVertices);
|
|
|
|
for (int j = 0; j < numVertices; j++)
|
|
|
|
room.colors.push_back(ReadVector3());
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-07-30 20:55:03 +03:00
|
|
|
room.effects.reserve(numVertices);
|
|
|
|
for (int j = 0; j < numVertices; j++)
|
2021-07-31 18:51:30 +03:00
|
|
|
room.effects.push_back(ReadVector3());
|
2021-07-30 20:55:03 +03:00
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
int numBuckets = ReadInt32();
|
|
|
|
room.buckets.reserve(numBuckets);
|
|
|
|
for (int j = 0; j < numBuckets; j++)
|
2020-06-26 07:06:18 +02:00
|
|
|
{
|
2020-06-28 15:51:33 +02:00
|
|
|
BUCKET bucket;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
bucket.texture = ReadInt32();
|
|
|
|
bucket.blendMode = ReadInt8();
|
|
|
|
bucket.animated = ReadInt8();
|
2020-07-05 06:20:36 +02:00
|
|
|
bucket.numQuads = 0;
|
|
|
|
bucket.numTriangles = 0;
|
2020-06-28 15:51:33 +02:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
int numPolygons = ReadInt32();
|
|
|
|
bucket.polygons.reserve(numPolygons);
|
|
|
|
for (int k = 0; k < numPolygons; k++)
|
|
|
|
{
|
|
|
|
POLYGON poly;
|
2020-10-07 09:08:23 +02:00
|
|
|
|
2020-07-05 06:20:36 +02:00
|
|
|
poly.shape = ReadInt32();
|
2021-03-27 07:33:40 +01:00
|
|
|
poly.animatedSequence = ReadInt32();
|
|
|
|
poly.animatedFrame = ReadInt32();
|
2020-07-05 06:20:36 +02:00
|
|
|
int count = (poly.shape == 0 ? 4 : 3);
|
2020-07-18 06:58:44 +02:00
|
|
|
poly.indices.resize(count);
|
|
|
|
poly.textureCoordinates.resize(count);
|
|
|
|
poly.normals.resize(count);
|
|
|
|
poly.tangents.resize(count);
|
|
|
|
poly.bitangents.resize(count);
|
2020-07-05 06:20:36 +02:00
|
|
|
|
|
|
|
for (int n = 0; n < count; n++)
|
2020-07-18 06:58:44 +02:00
|
|
|
poly.indices[n] = ReadInt32();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.textureCoordinates[n] = ReadVector2();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.normals[n] = ReadVector3();
|
|
|
|
for (int n = 0; n < count; n++)
|
|
|
|
poly.tangents[n] = ReadVector3();
|
2020-07-05 06:20:36 +02:00
|
|
|
for (int n = 0; n < count; n++)
|
2020-07-18 06:58:44 +02:00
|
|
|
poly.bitangents[n] = ReadVector3();
|
2020-07-05 06:20:36 +02:00
|
|
|
|
|
|
|
bucket.polygons.push_back(poly);
|
|
|
|
|
|
|
|
if (poly.shape == 0)
|
|
|
|
bucket.numQuads++;
|
|
|
|
else
|
|
|
|
bucket.numTriangles++;
|
|
|
|
}
|
2020-06-28 15:51:33 +02:00
|
|
|
|
|
|
|
room.buckets.push_back(bucket);
|
2020-06-26 07:06:18 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
int numPortals = ReadInt32();
|
2020-06-26 07:06:18 +02:00
|
|
|
for (int j = 0; j < numPortals; j++)
|
|
|
|
{
|
|
|
|
ROOM_DOOR door;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-26 07:06:18 +02:00
|
|
|
door.room = ReadInt16();
|
|
|
|
door.normal.x = ReadInt16();
|
|
|
|
door.normal.y = ReadInt16();
|
|
|
|
door.normal.z = ReadInt16();
|
|
|
|
for (int k = 0; k < 4; k++)
|
|
|
|
{
|
|
|
|
door.vertices[k].x = ReadInt16();
|
|
|
|
door.vertices[k].y = ReadInt16();
|
|
|
|
door.vertices[k].z = ReadInt16();
|
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-26 07:06:18 +02:00
|
|
|
room.doors.push_back(door);
|
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
room.xSize = ReadInt32();
|
|
|
|
room.ySize = ReadInt32();
|
2020-06-26 07:06:18 +02:00
|
|
|
room.floor.reserve(room.xSize * room.ySize);
|
|
|
|
for (int j = 0; j < room.xSize * room.ySize; j++)
|
|
|
|
{
|
|
|
|
FLOOR_INFO floor;
|
|
|
|
|
2021-09-13 02:07:42 +03:00
|
|
|
floor.TriggerIndex = ReadInt32();
|
2021-09-13 02:46:48 +03:00
|
|
|
floor.Box = ReadInt32();
|
2021-09-13 02:07:42 +03:00
|
|
|
floor.Material = ReadInt32();
|
|
|
|
floor.Stopper = ReadInt32();
|
2021-08-20 02:01:50 +03:00
|
|
|
|
2020-09-14 00:19:05 -03:00
|
|
|
floor.FloorCollision.SplitAngle = ReadFloat();
|
|
|
|
floor.FloorCollision.Portals[0] = ReadInt32();
|
|
|
|
floor.FloorCollision.Portals[1] = ReadInt32();
|
|
|
|
floor.FloorCollision.Planes[0].x = ReadFloat();
|
|
|
|
floor.FloorCollision.Planes[0].y = ReadFloat();
|
|
|
|
floor.FloorCollision.Planes[0].z = ReadFloat();
|
|
|
|
floor.FloorCollision.Planes[1].x = ReadFloat();
|
|
|
|
floor.FloorCollision.Planes[1].y = ReadFloat();
|
|
|
|
floor.FloorCollision.Planes[1].z = ReadFloat();
|
|
|
|
floor.CeilingCollision.SplitAngle = ReadFloat();
|
|
|
|
floor.CeilingCollision.Portals[0] = ReadInt32();
|
|
|
|
floor.CeilingCollision.Portals[1] = ReadInt32();
|
|
|
|
floor.CeilingCollision.Planes[0].x = ReadFloat();
|
|
|
|
floor.CeilingCollision.Planes[0].y = ReadFloat();
|
|
|
|
floor.CeilingCollision.Planes[0].z = ReadFloat();
|
|
|
|
floor.CeilingCollision.Planes[1].x = ReadFloat();
|
|
|
|
floor.CeilingCollision.Planes[1].y = ReadFloat();
|
|
|
|
floor.CeilingCollision.Planes[1].z = ReadFloat();
|
|
|
|
floor.WallPortal = ReadInt32();
|
2021-08-20 02:01:50 +03:00
|
|
|
|
|
|
|
floor.Flags.Death = ReadInt8();
|
|
|
|
floor.Flags.Monkeyswing = ReadInt8();
|
|
|
|
floor.Flags.ClimbNorth = ReadInt8();
|
|
|
|
floor.Flags.ClimbSouth = ReadInt8();
|
|
|
|
floor.Flags.ClimbEast = ReadInt8();
|
|
|
|
floor.Flags.ClimbWest = ReadInt8();
|
|
|
|
floor.Flags.MarkTriggerer = ReadInt8();
|
|
|
|
floor.Flags.MarkTriggererActive = 0; // TODO: IT NEEDS TO BE WRITTEN/READ FROM SAVEGAMES!
|
|
|
|
floor.Flags.MarkBeetle = ReadInt8();
|
|
|
|
|
2020-09-19 20:09:57 -03:00
|
|
|
floor.Room = i;
|
2020-06-26 07:06:18 +02:00
|
|
|
|
|
|
|
room.floor.push_back(floor);
|
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-26 20:51:59 +02:00
|
|
|
room.ambient.x = ReadFloat();
|
|
|
|
room.ambient.y = ReadFloat();
|
|
|
|
room.ambient.z = ReadFloat();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
int numLights = ReadInt32();
|
2020-06-26 07:06:18 +02:00
|
|
|
room.lights.reserve(numLights);
|
|
|
|
for (int j = 0; j < numLights; j++)
|
|
|
|
{
|
|
|
|
ROOM_LIGHT light;
|
|
|
|
|
2020-07-26 16:17:54 +02:00
|
|
|
light.x = ReadInt32();
|
|
|
|
light.y = ReadInt32();
|
|
|
|
light.z = ReadInt32();
|
|
|
|
light.dx = ReadFloat();
|
|
|
|
light.dy = ReadFloat();
|
|
|
|
light.dz = ReadFloat();
|
2020-06-26 07:06:18 +02:00
|
|
|
light.r = ReadFloat();
|
|
|
|
light.g = ReadFloat();
|
|
|
|
light.b = ReadFloat();
|
2020-07-26 16:17:54 +02:00
|
|
|
light.intensity = ReadFloat();
|
2020-06-26 07:06:18 +02:00
|
|
|
light.in = ReadFloat();
|
|
|
|
light.out = ReadFloat();
|
2020-07-26 16:17:54 +02:00
|
|
|
light.length = ReadFloat();
|
|
|
|
light.cutoff = ReadFloat();
|
2020-06-26 07:06:18 +02:00
|
|
|
light.type = ReadInt8();
|
2020-07-26 16:17:54 +02:00
|
|
|
light.castShadows = ReadInt8();
|
2020-06-26 07:06:18 +02:00
|
|
|
|
|
|
|
room.lights.push_back(light);
|
|
|
|
}
|
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
int numStatics = ReadInt32();
|
2020-06-26 07:06:18 +02:00
|
|
|
room.mesh.reserve(numStatics);
|
|
|
|
for (int j = 0; j < numStatics; j++)
|
|
|
|
{
|
2021-07-24 19:14:23 +01:00
|
|
|
auto & mesh = room.mesh.emplace_back();
|
2021-09-10 13:49:45 +03:00
|
|
|
mesh.pos.xPos = ReadInt32();
|
|
|
|
mesh.pos.yPos = ReadInt32();
|
|
|
|
mesh.pos.zPos = ReadInt32();
|
|
|
|
mesh.pos.xRot = 0;
|
|
|
|
mesh.pos.yRot = ReadUInt16();
|
|
|
|
mesh.pos.zRot = 0;
|
2020-06-26 07:06:18 +02:00
|
|
|
mesh.flags = ReadUInt16();
|
2020-10-07 09:08:23 +02:00
|
|
|
Vector3 rgb = ReadVector3();
|
|
|
|
float a = ReadFloat();
|
2020-06-26 07:06:18 +02:00
|
|
|
mesh.staticNumber = ReadUInt16();
|
2020-10-07 09:08:23 +02:00
|
|
|
mesh.color = Vector4(rgb.x, rgb.y, rgb.z, a);
|
2020-08-16 21:06:35 +02:00
|
|
|
mesh.hitPoints = ReadInt16();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-07-14 05:29:23 +02:00
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-14 05:29:23 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
mesh.luaName = std::string(buffer, buffer + numBytes);
|
2021-07-14 05:29:23 +02:00
|
|
|
|
2021-08-27 18:49:14 +01:00
|
|
|
g_GameScript->AddName(mesh.luaName, mesh);
|
2020-06-26 07:06:18 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-07-05 16:33:50 +02:00
|
|
|
int numTriggerVolumes = ReadInt32();
|
|
|
|
for (int j = 0; j < numTriggerVolumes; j++)
|
|
|
|
{
|
|
|
|
TRIGGER_VOLUME volume;
|
|
|
|
|
2021-08-05 15:46:03 +03:00
|
|
|
volume.type = (TriggerVolumeType)ReadInt32();
|
|
|
|
|
2021-07-15 10:56:03 +02:00
|
|
|
volume.position.x = ReadFloat();
|
|
|
|
volume.position.y = ReadFloat();
|
|
|
|
volume.position.z = ReadFloat();
|
|
|
|
|
|
|
|
volume.rotation.x = ReadFloat();
|
|
|
|
volume.rotation.y = ReadFloat();
|
|
|
|
volume.rotation.z = ReadFloat();
|
|
|
|
volume.rotation.w = ReadFloat();
|
|
|
|
|
|
|
|
volume.scale.x = ReadFloat();
|
|
|
|
volume.scale.y = ReadFloat();
|
|
|
|
volume.scale.z = ReadFloat();
|
|
|
|
|
2021-07-05 16:33:50 +02:00
|
|
|
volume.activators = ReadInt32();
|
|
|
|
|
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-05 16:33:50 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
volume.onEnter = std::string(buffer, buffer+numBytes);
|
2021-07-05 16:33:50 +02:00
|
|
|
|
|
|
|
numBytes = ReadInt8();
|
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
volume.onInside = std::string(buffer, buffer+numBytes);
|
2021-07-05 16:33:50 +02:00
|
|
|
|
|
|
|
numBytes = ReadInt8();
|
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
volume.onLeave = std::string(buffer, buffer+numBytes);
|
2021-07-05 16:33:50 +02:00
|
|
|
|
|
|
|
volume.oneShot = ReadInt8();
|
|
|
|
volume.status = TS_OUTSIDE;
|
|
|
|
|
2021-08-05 15:46:03 +03:00
|
|
|
volume.box = BoundingOrientedBox(volume.position, volume.scale, volume.rotation);
|
|
|
|
volume.sphere = BoundingSphere(volume.position, volume.scale.x);
|
2021-07-05 16:33:50 +02:00
|
|
|
|
|
|
|
room.triggerVolumes.push_back(volume);
|
|
|
|
}
|
|
|
|
|
2020-06-28 15:51:33 +02:00
|
|
|
room.flippedRoom = ReadInt32();
|
|
|
|
room.flags = ReadInt32();
|
|
|
|
room.meshEffect = ReadInt32();
|
|
|
|
room.reverbType = ReadInt32();
|
|
|
|
room.flipNumber = ReadInt32();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-06-26 07:06:18 +02:00
|
|
|
room.itemNumber = NO_ITEM;
|
|
|
|
room.fxNumber = NO_ITEM;
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadRooms()
|
|
|
|
{
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Loading rooms...");
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
Wibble = 0;
|
|
|
|
//RoomLightsCount = 0;
|
2020-04-24 19:15:05 +02:00
|
|
|
//Unk_007E7FE8 = 0;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
ReadRooms();
|
|
|
|
BuildOutsideRoomsTable();
|
|
|
|
|
|
|
|
int numFloorData = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.FloorData.resize(numFloorData);
|
|
|
|
ReadBytes(g_Level.FloorData.data(), numFloorData * sizeof(short));
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void FreeLevel()
|
|
|
|
{
|
2021-08-30 17:28:26 +02:00
|
|
|
g_Level.RoomTextures.resize(0);
|
|
|
|
g_Level.MoveablesTextures.resize(0);
|
|
|
|
g_Level.StaticsTextures.resize(0);
|
|
|
|
g_Level.AnimatedTextures.resize(0);
|
|
|
|
g_Level.SpritesTextures.resize(0);
|
|
|
|
g_Level.AnimatedTexturesSequences.resize(0);
|
|
|
|
g_Level.Rooms.resize(0);
|
|
|
|
g_Level.ObjectTextures.resize(0);
|
|
|
|
g_Level.Bones.resize(0);
|
|
|
|
g_Level.Meshes.resize(0);
|
|
|
|
MoveablesIds.resize(0);
|
|
|
|
g_Level.Boxes.resize(0);
|
|
|
|
g_Level.Overlaps.resize(0);
|
|
|
|
g_Level.Anims.resize(0);
|
|
|
|
g_Level.Changes.resize(0);
|
|
|
|
g_Level.Ranges.resize(0);
|
|
|
|
g_Level.Commands.resize(0);
|
|
|
|
g_Level.Frames.resize(0);
|
|
|
|
g_Level.Sprites.resize(0);
|
|
|
|
g_Level.SoundDetails.resize(0);
|
|
|
|
g_Level.SoundMap.resize(0);
|
|
|
|
g_Level.FloorData.resize(0);
|
|
|
|
g_Level.Cameras.resize(0);
|
|
|
|
g_Level.Sinks.resize(0);
|
|
|
|
g_Level.SoundSources.resize(0);
|
|
|
|
g_Level.AIObjects.resize(0);
|
2021-08-03 13:23:51 +03:00
|
|
|
|
2020-07-11 21:16:04 +02:00
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Zones[j][i].clear();
|
2020-07-11 21:16:04 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.freeRendererData();
|
2020-04-22 14:12:10 +02:00
|
|
|
g_GameScript->FreeLevelScripts();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ReadFileEx(void* ptr, size_t size, size_t count, FILE* stream)
|
|
|
|
{
|
|
|
|
_lock_file(stream);
|
|
|
|
size_t result = fread(ptr, size, count, stream);
|
|
|
|
_unlock_file(stream);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-10-04 03:09:32 +03:00
|
|
|
void LoadSoundSources()
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2021-07-10 06:55:37 +02:00
|
|
|
int numSoundSources = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num sound sources: ", numSoundSources);
|
|
|
|
|
2021-08-03 01:30:44 +03:00
|
|
|
g_Level.SoundSources.reserve(numSoundSources);
|
2021-07-10 06:55:37 +02:00
|
|
|
for (int i = 0; i < numSoundSources; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2021-07-24 19:08:17 +01:00
|
|
|
auto & source = g_Level.SoundSources.emplace_back(SOUND_SOURCE_INFO{});
|
2021-07-10 06:55:37 +02:00
|
|
|
|
|
|
|
source.x = ReadInt32();
|
|
|
|
source.y = ReadInt32();
|
|
|
|
source.z = ReadInt32();
|
|
|
|
source.soundId = ReadInt32();
|
|
|
|
source.flags = ReadInt32();
|
|
|
|
|
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-10 06:55:37 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
source.luaName = std::string(buffer, buffer+numBytes);
|
2021-07-10 06:55:37 +02:00
|
|
|
|
2021-08-27 18:49:14 +01:00
|
|
|
g_GameScript->AddName(source.luaName, source);
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadAnimatedTextures()
|
|
|
|
{
|
2021-09-15 21:09:09 +03:00
|
|
|
int numAnimatedTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num anim textures: ", numAnimatedTextures);
|
|
|
|
|
2021-09-15 21:09:09 +03:00
|
|
|
for (int i = 0; i < numAnimatedTextures; i++)
|
2021-03-27 07:33:40 +01:00
|
|
|
{
|
|
|
|
ANIMATED_TEXTURES_SEQUENCE sequence;
|
|
|
|
sequence.atlas = ReadInt32();
|
|
|
|
sequence.numFrames = ReadInt32();
|
|
|
|
for (int j = 0; j < sequence.numFrames; j++)
|
|
|
|
{
|
|
|
|
ANIMATED_TEXTURES_FRAME frame;
|
|
|
|
frame.x1 = ReadFloat();
|
|
|
|
frame.y1 = ReadFloat();
|
|
|
|
frame.x2 = ReadFloat();
|
|
|
|
frame.y2 = ReadFloat();
|
|
|
|
frame.x3 = ReadFloat();
|
|
|
|
frame.y3 = ReadFloat();
|
|
|
|
frame.x4 = ReadFloat();
|
|
|
|
frame.y4 = ReadFloat();
|
|
|
|
sequence.frames.push_back(frame);
|
|
|
|
}
|
|
|
|
g_Level.AnimatedTexturesSequences.push_back(sequence);
|
|
|
|
}
|
2021-09-15 21:09:09 +03:00
|
|
|
|
|
|
|
// Unused for now
|
|
|
|
int nAnimUVRanges = ReadInt8();
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void LoadTextureInfos()
|
|
|
|
{
|
|
|
|
ReadInt32(); // TEX/0
|
2020-07-21 09:56:47 +02:00
|
|
|
|
|
|
|
int numObjectTextures = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num texinfos: ", numObjectTextures);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
for (int i = 0; i < numObjectTextures; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
OBJECT_TEXTURE texture;
|
|
|
|
texture.attribute = ReadInt32();
|
|
|
|
texture.tileAndFlag = ReadInt32();
|
|
|
|
texture.newFlags = ReadInt32();
|
|
|
|
for (int j = 0; j < 4; j++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
texture.vertices[j].x = ReadFloat();
|
|
|
|
texture.vertices[j].y = ReadFloat();
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
2020-07-21 09:56:47 +02:00
|
|
|
texture.destination = ReadInt32();
|
|
|
|
g_Level.ObjectTextures.push_back(texture);
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadAIObjects()
|
|
|
|
{
|
2020-07-11 21:16:04 +02:00
|
|
|
int nAIObjects = ReadInt32();
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Num AI objects: ", nAIObjects);
|
|
|
|
|
2021-08-03 01:30:44 +03:00
|
|
|
g_Level.AIObjects.reserve(nAIObjects);
|
2021-07-10 06:55:37 +02:00
|
|
|
for (int i = 0; i < nAIObjects; i++)
|
|
|
|
{
|
2021-07-24 19:08:17 +01:00
|
|
|
auto & obj = g_Level.AIObjects.emplace_back();
|
2021-07-10 06:55:37 +02:00
|
|
|
|
2021-07-14 05:48:42 +02:00
|
|
|
obj.objectNumber = (GAME_OBJECT_ID)ReadInt16();
|
2021-07-10 06:55:37 +02:00
|
|
|
obj.roomNumber = ReadInt16();
|
|
|
|
obj.x = ReadInt32();
|
|
|
|
obj.y = ReadInt32();
|
|
|
|
obj.z = ReadInt32();
|
|
|
|
obj.triggerFlags = ReadInt16();
|
|
|
|
obj.flags = ReadInt16();
|
|
|
|
obj.yRot = ReadInt16();
|
|
|
|
obj.boxNumber = ReadInt16();
|
|
|
|
|
|
|
|
byte numBytes = ReadInt8();
|
2021-07-24 19:08:17 +01:00
|
|
|
char buffer[255];
|
2021-07-10 06:55:37 +02:00
|
|
|
ReadBytes(buffer, numBytes);
|
2021-07-24 19:08:17 +01:00
|
|
|
obj.luaName = std::string(buffer, buffer+numBytes);
|
|
|
|
|
2021-08-27 18:49:14 +01:00
|
|
|
g_GameScript->AddName(obj.luaName, obj);
|
2021-07-10 06:55:37 +02:00
|
|
|
}
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FILE* FileOpen(const char* fileName)
|
|
|
|
{
|
|
|
|
FILE* ptr = fopen(fileName, "rb");
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileClose(FILE* ptr)
|
|
|
|
{
|
|
|
|
fclose(ptr);
|
|
|
|
}
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
bool Decompress(byte* dest, byte* src, unsigned long compressedSize, unsigned long uncompressedSize)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-26 07:21:38 +02:00
|
|
|
z_stream strm;
|
|
|
|
ZeroMemory(&strm, sizeof(z_stream));
|
|
|
|
strm.avail_in = compressedSize;
|
|
|
|
strm.avail_out = uncompressedSize;
|
|
|
|
strm.next_out = (BYTE*)dest;
|
|
|
|
strm.next_in = (BYTE*)src;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
inflateInit(&strm);
|
|
|
|
inflate(&strm, Z_FULL_FLUSH);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
if (strm.total_out == uncompressedSize)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-26 07:21:38 +02:00
|
|
|
inflateEnd(&strm);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-31 09:39:32 +02:00
|
|
|
bool replace(std::string& str, const std::string& from, const std::string& to) {
|
|
|
|
size_t start_pos = str.find(from);
|
|
|
|
if (start_pos == std::string::npos)
|
|
|
|
return false;
|
|
|
|
str.replace(start_pos, from.length(), to);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-27 13:01:32 +02:00
|
|
|
unsigned CALLBACK LoadLevel(void* data)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
|
|
|
char* filename = (char*)data;
|
|
|
|
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Loading Level flie: ", filename);
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
LevelDataPtr = NULL;
|
|
|
|
LevelFilePtr = NULL;
|
2020-07-26 07:21:38 +02:00
|
|
|
char* baseLevelDataPtr = NULL;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(0);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
LevelFilePtr = FileOpen(filename);
|
|
|
|
if (LevelFilePtr)
|
|
|
|
{
|
|
|
|
int version;
|
|
|
|
int uncompressedSize;
|
|
|
|
int compressedSize;
|
2020-07-26 07:21:38 +02:00
|
|
|
char* compressedBuffer;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
// Read file header
|
|
|
|
ReadFileEx(&version, 1, 4, LevelFilePtr);
|
2020-04-22 14:12:10 +02:00
|
|
|
ReadFileEx(&uncompressedSize, 1, 4, LevelFilePtr);
|
|
|
|
ReadFileEx(&compressedSize, 1, 4, LevelFilePtr);
|
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
// The entire level is ZLIB compressed
|
|
|
|
compressedBuffer = (char*)malloc(compressedSize);
|
2020-04-22 14:12:10 +02:00
|
|
|
LevelDataPtr = (char*)malloc(uncompressedSize);
|
2020-07-26 07:21:38 +02:00
|
|
|
baseLevelDataPtr = LevelDataPtr;
|
|
|
|
|
|
|
|
ReadFileEx(compressedBuffer, compressedSize, 1, LevelFilePtr);
|
|
|
|
Decompress((byte*)LevelDataPtr, (byte*)compressedBuffer, compressedSize, uncompressedSize);
|
|
|
|
|
|
|
|
// Now the entire level is decompressed
|
|
|
|
free(compressedBuffer);
|
|
|
|
|
|
|
|
LoadTextures();
|
|
|
|
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(20);
|
2020-07-26 07:21:38 +02:00
|
|
|
|
|
|
|
WeatherType = ReadInt8();
|
|
|
|
LaraDrawType = ReadInt8();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
LoadRooms();
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(40);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
LoadObjects();
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(50);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
LoadSprites();
|
|
|
|
LoadCameras();
|
2021-10-04 03:09:32 +03:00
|
|
|
LoadSoundSources();
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(60);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
LoadBoxes();
|
2020-07-11 21:16:04 +02:00
|
|
|
|
2021-09-03 09:37:42 +02:00
|
|
|
//InitialiseLOTarray(true);
|
2020-07-11 21:16:04 +02:00
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
LoadAnimatedTextures();
|
|
|
|
LoadTextureInfos();
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(70);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
LoadItems();
|
|
|
|
LoadAIObjects();
|
|
|
|
LoadSamples();
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(80);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-26 07:21:38 +02:00
|
|
|
free(baseLevelDataPtr);
|
2020-04-22 14:12:10 +02:00
|
|
|
LevelDataPtr = NULL;
|
|
|
|
FileClose(LevelFilePtr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-26 07:21:38 +02:00
|
|
|
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(90);
|
2020-06-21 14:27:12 +02:00
|
|
|
g_Renderer.PrepareDataForTheRenderer();
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
// Initialise the game
|
|
|
|
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
|
|
|
|
|
|
|
|
InitialiseGameFlags();
|
2021-08-09 00:07:08 +01:00
|
|
|
InitialiseLara(!(InitialiseGame || CurrentLevel == 1));
|
2020-04-22 14:12:10 +02:00
|
|
|
GetCarriedItems();
|
|
|
|
GetAIPickups();
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Vehicle = -1;
|
2020-04-22 14:12:10 +02:00
|
|
|
g_GameScript->AssignItemsAndLara();
|
|
|
|
|
|
|
|
// Level loaded
|
|
|
|
IsLevelLoading = false;
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.updateProgress(100);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
_endthreadex(1);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadSamples()
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
int SoundMapSize = ReadInt16();
|
|
|
|
g_Level.SoundMap.resize(SoundMapSize);
|
|
|
|
ReadBytes(g_Level.SoundMap.data(), SoundMapSize * sizeof(short));
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
int numSamplesInfos = ReadInt32();
|
|
|
|
if (numSamplesInfos)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.SoundDetails.resize(numSamplesInfos);
|
|
|
|
ReadBytes(g_Level.SoundDetails.data(), numSamplesInfos * sizeof(SAMPLE_INFO));
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-09-08 19:50:19 +02:00
|
|
|
int numSamples = ReadInt32();
|
|
|
|
if (numSamples <= 0)
|
|
|
|
return;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-09-08 19:50:19 +02:00
|
|
|
int uncompressedSize;
|
|
|
|
int compressedSize;
|
|
|
|
char* buffer = (char*)malloc(2 * 1048576);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-09-08 19:50:19 +02:00
|
|
|
for (int i = 0; i < numSamples; i++)
|
|
|
|
{
|
|
|
|
uncompressedSize = ReadInt32();
|
|
|
|
compressedSize = ReadInt32();
|
|
|
|
ReadBytes(buffer, compressedSize);
|
|
|
|
Sound_LoadSample(buffer, compressedSize, uncompressedSize, i);
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
2020-09-08 19:50:19 +02:00
|
|
|
|
|
|
|
free(buffer);
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
//Log(1, aNog_Level.SoundDetailss);
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadBoxes()
|
|
|
|
{
|
|
|
|
// Read boxes
|
2020-07-11 21:16:04 +02:00
|
|
|
int numBoxes = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Boxes.resize(numBoxes);
|
|
|
|
ReadBytes(g_Level.Boxes.data(), numBoxes * sizeof(BOX_INFO));
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
// Read overlaps
|
2020-07-11 21:16:04 +02:00
|
|
|
int numOverlaps = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Overlaps.resize(numOverlaps);
|
|
|
|
ReadBytes(g_Level.Overlaps.data(), numOverlaps * sizeof(OVERLAP));
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
// Read zones
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
// Ground zones
|
2020-09-01 07:06:31 +02:00
|
|
|
for (int j = 0; j < MAX_ZONES - 1; j++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Zones[j][i].resize(numBoxes * sizeof(int));
|
|
|
|
ReadBytes(g_Level.Zones[j][i].data(), numBoxes * sizeof(int));
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fly zone
|
2020-09-01 07:06:31 +02:00
|
|
|
g_Level.Zones[MAX_ZONES - 1][i].resize(numBoxes * sizeof(int));
|
|
|
|
ReadBytes(g_Level.Zones[MAX_ZONES - 1][i].data(), numBoxes * sizeof(int));
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// By default all blockable boxes are blocked
|
2020-07-11 21:16:04 +02:00
|
|
|
for (int i = 0; i < numBoxes; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Boxes[i].flags & BLOCKABLE)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Boxes[i].flags |= BLOCKED;
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-04 03:09:32 +03:00
|
|
|
int LoadLevelFile(int levelIndex)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2021-10-04 03:09:32 +03:00
|
|
|
logD("Loading level file...");
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2021-09-16 05:06:03 +03:00
|
|
|
Sound_Stop();
|
2020-04-22 14:12:10 +02:00
|
|
|
Sound_FreeSamples();
|
|
|
|
if (!g_FirstLevel)
|
|
|
|
FreeLevel();
|
|
|
|
g_FirstLevel = false;
|
|
|
|
|
|
|
|
char filename[80];
|
|
|
|
GameScriptLevel* level = g_GameFlow->Levels[levelIndex];
|
|
|
|
strcpy_s(filename, level->FileName.c_str());
|
|
|
|
|
|
|
|
// Loading level is done is two threads, one for loading level and one for drawing loading screen
|
|
|
|
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.
|
2020-06-21 11:51:46 +02:00
|
|
|
wchar_t loadscreenFileName[80];
|
|
|
|
std::mbstowcs(loadscreenFileName, level->LoadScreenFileName.c_str(),80);
|
|
|
|
std::wstring loadScreenFile = std::wstring(loadscreenFileName);
|
2020-08-09 15:25:56 +02:00
|
|
|
g_Renderer.renderLoadingScreen(loadScreenFile);
|
2020-04-22 14:12:10 +02:00
|
|
|
|
|
|
|
while (IsLevelLoading);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadSprites()
|
|
|
|
{
|
|
|
|
//DB_Log(2, "LoadSprites");
|
|
|
|
|
|
|
|
ReadInt32(); // SPR\0
|
|
|
|
|
2020-07-11 21:16:04 +02:00
|
|
|
int numSprites = ReadInt32();
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Sprites.resize(numSprites);
|
2020-07-11 21:16:04 +02:00
|
|
|
for (int i = 0; i < numSprites; i++)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
SPRITE* spr = &g_Level.Sprites[i];
|
|
|
|
spr->tile = ReadInt32();
|
|
|
|
spr->x1 = ReadFloat();
|
|
|
|
spr->y1 = ReadFloat();
|
|
|
|
spr->x2 = ReadFloat();
|
|
|
|
spr->y2 = ReadFloat();
|
|
|
|
spr->x3 = ReadFloat();
|
|
|
|
spr->y3 = ReadFloat();
|
|
|
|
spr->x4 = ReadFloat();
|
|
|
|
spr->y4 = ReadFloat();
|
2020-04-22 14:12:10 +02:00
|
|
|
}
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.NumSpritesSequences = ReadInt32();
|
|
|
|
for (int i = 0; i < g_Level.NumSpritesSequences; i++)
|
2020-04-22 14:12:10 +02: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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GetCarriedItems()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
ITEM_INFO* item, *item2;
|
|
|
|
short linknum;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
for (i = 0; i < g_Level.NumItems; ++i)
|
|
|
|
g_Level.Items[i].carriedItem = NO_ITEM;
|
2020-07-11 21:16:04 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
for (i = 0; i < g_Level.NumItems; ++i)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
item = &g_Level.Items[i];
|
2020-04-22 14:12:10 +02:00
|
|
|
if (Objects[item->objectNumber].intelligent || item->objectNumber >= ID_SEARCH_OBJECT1 && item->objectNumber <= ID_SEARCH_OBJECT3)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
for (linknum = g_Level.Rooms[item->roomNumber].itemNumber; linknum != NO_ITEM; linknum = g_Level.Items[linknum].nextItem)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
item2 = &g_Level.Items[linknum];
|
2020-04-22 14:12:10 +02:00
|
|
|
if (abs(item2->pos.xPos - item->pos.xPos) < 512
|
|
|
|
&& abs(item2->pos.zPos - item->pos.zPos) < 512
|
|
|
|
&& abs(item2->pos.yPos - item->pos.yPos) < 256
|
2020-05-27 19:07:34 +02:00
|
|
|
&& Objects[item2->objectNumber].isPickup)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
|
|
|
item2->carriedItem = item->carriedItem;
|
|
|
|
item->carriedItem = linknum;
|
|
|
|
RemoveDrawnItem(linknum);
|
|
|
|
item2->roomNumber = NO_ROOM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GetAIPickups()
|
|
|
|
{
|
|
|
|
int i, num;
|
|
|
|
ITEM_INFO* item;
|
2021-07-10 06:55:37 +02:00
|
|
|
AI_OBJECT* object;
|
2020-04-22 14:12:10 +02:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
for (i = 0; i < g_Level.NumItems; ++i)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
item = &g_Level.Items[i];
|
2020-04-22 14:12:10 +02:00
|
|
|
if (Objects[item->objectNumber].intelligent)
|
|
|
|
{
|
|
|
|
item->aiBits = 0;
|
2020-07-21 09:56:47 +02:00
|
|
|
for (num = 0; num < g_Level.AIObjects.size(); ++num)
|
2020-04-22 14:12:10 +02:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
object = &g_Level.AIObjects[num];
|
2020-04-22 14:12:10 +02:00
|
|
|
if (abs(object->x - item->pos.xPos) < 512
|
|
|
|
&& abs(object->z - item->pos.zPos) < 512
|
|
|
|
&& object->roomNumber == item->roomNumber
|
|
|
|
&& object->objectNumber < ID_AI_PATROL2)
|
|
|
|
{
|
|
|
|
item->aiBits = (1 << object->objectNumber - ID_AI_GUARD) & 0x1F;
|
|
|
|
item->itemFlags[3] = object->triggerFlags;
|
|
|
|
if (object->objectNumber != ID_AI_GUARD)
|
|
|
|
object->roomNumber = NO_ROOM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
item->TOSSPAD |= item->aiBits << 8 | (char) item->itemFlags[3];
|
|
|
|
}
|
|
|
|
}
|
2020-08-02 19:39:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void BuildOutsideRoomsTable()
|
|
|
|
{
|
|
|
|
for (int x = 0; x < OUTSIDE_SIZE; x++)
|
|
|
|
for (int z = 0; z < OUTSIDE_SIZE; z++)
|
|
|
|
OutsideRoomTable[x][z].clear();
|
|
|
|
|
2020-08-04 21:53:58 +02:00
|
|
|
for (int x = 0; x < OUTSIDE_SIZE; x++)
|
2020-08-02 19:39:55 +02:00
|
|
|
{
|
2020-08-04 21:53:58 +02:00
|
|
|
for (int z = 0; z < OUTSIDE_SIZE; z++)
|
2020-08-02 19:39:55 +02:00
|
|
|
{
|
|
|
|
for (int i = 0; i < g_Level.Rooms.size(); i++)
|
|
|
|
{
|
|
|
|
ROOM_INFO* r = &g_Level.Rooms[i];
|
|
|
|
|
2020-08-04 21:53:58 +02:00
|
|
|
int rx = (r->x / 1024);
|
|
|
|
int rz = (r->z / 1024);
|
2020-08-02 19:39:55 +02:00
|
|
|
|
2020-08-04 21:53:58 +02:00
|
|
|
if (x >= rx + 1 && z >= rz + 1 && x <= (rx + r->ySize - 2) && z <= (rz + r->xSize - 2))
|
|
|
|
OutsideRoomTable[x][z].push_back(i);
|
2020-08-02 19:39:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|