TombEngine/TR5Main/Game/floordata.cpp

419 lines
9.8 KiB
C++
Raw Normal View History

2020-09-17 00:08:10 -03:00
#include "framework.h"
#include "trmath.h"
#include "floordata.h"
#include "room.h"
#include "level.h"
2020-09-21 23:59:57 -03:00
#include "setup.h"
2020-09-17 00:08:10 -03:00
2020-09-15 11:01:24 -03:00
VectorInt2 FLOOR_INFO::GetRoomPosition(int roomNumber, int x, int z)
2020-09-14 00:19:05 -03:00
{
2020-09-19 20:09:57 -03:00
auto room = &g_Level.Rooms[roomNumber];
auto xRoom = (z - room->z) / WALL_SIZE;
auto yRoom = (x - room->x) / WALL_SIZE;
auto pos = VectorInt2{xRoom, yRoom};
2020-09-17 00:08:10 -03:00
if (pos.x < 0)
{
pos.x = 0;
}
2020-09-19 20:09:57 -03:00
else if (pos.x > room->xSize - 1)
2020-09-17 00:08:10 -03:00
{
2020-09-19 20:09:57 -03:00
pos.x = room->xSize - 1;
2020-09-17 00:08:10 -03:00
}
if (pos.y < 0)
{
pos.y = 0;
}
2020-09-19 20:09:57 -03:00
else if (pos.y > room->ySize - 1)
2020-09-17 00:08:10 -03:00
{
2020-09-19 20:09:57 -03:00
pos.y = room->ySize - 1;
2020-09-17 00:08:10 -03:00
}
return pos;
2020-09-14 00:19:05 -03:00
}
2020-09-19 20:09:57 -03:00
FLOOR_INFO* FLOOR_INFO::GetFloor(int roomNumber, VectorInt2 pos)
2020-09-15 11:01:24 -03:00
{
2020-09-19 20:09:57 -03:00
auto room = &g_Level.Rooms[roomNumber];
return &room->floor[room->xSize * pos.y + pos.x];
2020-09-15 11:01:24 -03:00
}
2020-09-19 20:09:57 -03:00
FLOOR_INFO* FLOOR_INFO::GetFloor(int roomNumber, int x, int z)
2020-09-15 11:01:24 -03:00
{
return GetFloor(roomNumber, GetRoomPosition(roomNumber, x, z));
}
2020-09-19 20:09:57 -03:00
FLOOR_INFO* FLOOR_INFO::GetBottomFloor(int startRoomNumber, int x, int z, bool first)
2020-09-15 11:01:24 -03:00
{
auto roomNumber = startRoomNumber;
2020-09-17 00:08:10 -03:00
auto floor = GetFloor(roomNumber, x, z);
2020-09-19 20:09:57 -03:00
auto plane = floor->SectorPlane(x, z);
auto roomBelow = floor->RoomBelow(plane);
2020-09-15 11:01:24 -03:00
2020-09-19 20:09:57 -03:00
while ((!first || floor->IsWall(plane)) && roomBelow)
2020-09-15 11:01:24 -03:00
{
2020-09-22 23:38:48 -03:00
roomNumber = *roomBelow;
2020-09-17 00:08:10 -03:00
floor = GetFloor(roomNumber, x, z);
2020-09-22 23:38:48 -03:00
auto roomSide = floor->RoomSide();
if (roomSide)
{
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
}
2020-09-19 20:09:57 -03:00
plane = floor->SectorPlane(x, z);
roomBelow = floor->RoomBelow(plane);
2020-09-15 11:01:24 -03:00
}
2020-09-17 00:08:10 -03:00
return floor;
2020-09-15 11:01:24 -03:00
}
2020-09-19 20:09:57 -03:00
FLOOR_INFO* FLOOR_INFO::GetTopFloor(int startRoomNumber, int x, int z, bool first)
2020-09-14 00:19:05 -03:00
{
2020-09-15 11:01:24 -03:00
auto roomNumber = startRoomNumber;
2020-09-17 00:08:10 -03:00
auto floor = GetFloor(roomNumber, x, z);
2020-09-19 20:09:57 -03:00
auto plane = floor->SectorPlane(x, z);
auto roomAbove = floor->RoomAbove(plane);
2020-09-15 11:01:24 -03:00
2020-09-19 20:09:57 -03:00
while ((!first || floor->IsWall(plane)) && roomAbove)
2020-09-15 11:01:24 -03:00
{
2020-09-22 23:38:48 -03:00
roomNumber = *roomAbove;
2020-09-17 00:08:10 -03:00
floor = GetFloor(roomNumber, x, z);
2020-09-22 23:38:48 -03:00
auto roomSide = floor->RoomSide();
if (roomSide)
{
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
}
2020-09-19 20:09:57 -03:00
plane = floor->SectorPlane(x, z);
roomAbove = floor->RoomAbove(plane);
2020-09-15 11:01:24 -03:00
}
2020-09-17 00:08:10 -03:00
return floor;
}
2020-09-18 23:11:04 -03:00
FLOOR_INFO* FLOOR_INFO::GetNearBottomFloor(int startRoomNumber, int x, int z)
2020-09-17 00:08:10 -03:00
{
2020-09-22 23:38:48 -03:00
auto roomNumber = startRoomNumber;
2020-09-17 00:08:10 -03:00
auto floor = GetFloor(roomNumber, x, z);
2020-09-22 23:38:48 -03:00
auto roomSide = floor->RoomSide();
if (roomSide)
{
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
}
2020-09-19 20:09:57 -03:00
if (floor->IsWall(x, z))
2020-09-17 00:08:10 -03:00
{
floor = GetTopFloor(roomNumber, x, z, true);
}
else
{
floor = GetBottomFloor(roomNumber, x, z);
}
2020-09-19 20:09:57 -03:00
return floor->IsWall(x, z) ? nullptr : floor;
2020-09-17 00:08:10 -03:00
}
2020-09-18 23:11:04 -03:00
FLOOR_INFO* FLOOR_INFO::GetNearTopFloor(int startRoomNumber, int x, int z)
2020-09-17 00:08:10 -03:00
{
2020-09-22 23:38:48 -03:00
auto roomNumber = startRoomNumber;
2020-09-17 00:08:10 -03:00
auto floor = GetFloor(roomNumber, x, z);
2020-09-22 23:38:48 -03:00
auto roomSide = floor->RoomSide();
if (roomSide)
{
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
}
2020-09-19 20:09:57 -03:00
if (floor->IsWall(x, z))
2020-09-17 00:08:10 -03:00
{
floor = GetBottomFloor(roomNumber, x, z, true);
}
else
{
floor = GetTopFloor(roomNumber, x, z);
}
2020-09-19 20:09:57 -03:00
return floor->IsWall(x, z) ? nullptr : floor;
2020-09-15 11:01:24 -03:00
}
2020-09-22 23:38:48 -03:00
std::optional<int> FLOOR_INFO::GetBottomRoom(int startRoomNumber, int x, int y, int z)
2020-09-15 11:01:24 -03:00
{
2020-09-22 23:38:48 -03:00
auto roomNumber = startRoomNumber;
2020-09-20 23:16:21 -03:00
auto floor = GetFloor(roomNumber, x, z);
auto plane = floor->SectorPlane(x, z);
2020-09-15 11:01:24 -03:00
2020-10-14 20:01:20 -03:00
if (!floor->IsWall(plane) && y <= floor->FloorHeight(x, z) && y >= floor->CeilingHeight(x, z))
2020-09-22 23:38:48 -03:00
return std::nullopt;
auto roomBelow = floor->RoomBelow(plane);
while (roomBelow)
2020-09-15 11:01:24 -03:00
{
2020-09-22 23:38:48 -03:00
roomNumber = *roomBelow;
floor = GetFloor(roomNumber, x, z);
auto roomSide = floor->RoomSide();
if (roomSide)
2020-09-15 11:01:24 -03:00
{
2020-09-22 23:38:48 -03:00
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
2020-09-20 23:16:21 -03:00
}
2020-09-22 23:38:48 -03:00
plane = floor->SectorPlane(x, z);
2020-10-14 20:01:20 -03:00
if (!floor->IsWall(plane) && y <= floor->FloorHeight(x, z) && y >= floor->CeilingHeight(x, z))
2020-09-22 23:38:48 -03:00
return std::optional{roomNumber};
roomBelow = floor->RoomBelow(plane);
}
return std::nullopt;
}
std::optional<int> FLOOR_INFO::GetTopRoom(int startRoomNumber, int x, int y, int z)
{
auto roomNumber = startRoomNumber;
auto floor = GetFloor(roomNumber, x, z);
auto plane = floor->SectorPlane(x, z);
2020-10-14 20:01:20 -03:00
if (!floor->IsWall(plane) && y <= floor->FloorHeight(x, z) && y >= floor->CeilingHeight(x, z))
2020-09-22 23:38:48 -03:00
return std::nullopt;
auto roomAbove = floor->RoomAbove(plane);
while (roomAbove)
{
roomNumber = *roomAbove;
floor = GetFloor(roomNumber, x, z);
auto roomSide = floor->RoomSide();
if (roomSide)
2020-09-20 23:16:21 -03:00
{
2020-09-22 23:38:48 -03:00
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
2020-09-15 11:01:24 -03:00
}
2020-09-22 23:38:48 -03:00
plane = floor->SectorPlane(x, z);
2020-10-14 20:01:20 -03:00
if (!floor->IsWall(plane) && y <= floor->FloorHeight(x, z) && y >= floor->CeilingHeight(x, z))
2020-09-22 23:38:48 -03:00
return std::optional{roomNumber};
roomAbove = floor->RoomAbove(plane);
}
return std::nullopt;
}
int FLOOR_INFO::GetRoom(int startRoomNumber, int x, int y, int z)
{
auto roomNumber = startRoomNumber;
auto floor = GetFloor(roomNumber, x, z);
auto roomSide = floor->RoomSide();
if (roomSide)
{
roomNumber = *roomSide;
floor = GetFloor(roomNumber, x, z);
}
auto roomBelow = GetBottomRoom(roomNumber, x, y, z);
auto roomAbove = GetTopRoom(roomNumber, x, y, z);
if (roomBelow)
{
roomNumber = *roomBelow;
}
else if (roomAbove)
{
roomNumber = *roomAbove;
2020-09-15 11:01:24 -03:00
}
return roomNumber;
}
VectorInt2 FLOOR_INFO::GetSectorPoint(int x, int z)
{
auto xPoint = x % WALL_SIZE - WALL_SIZE / 2;
auto yPoint = z % WALL_SIZE - WALL_SIZE / 2;
return VectorInt2{xPoint, yPoint};
2020-09-14 00:19:05 -03:00
}
2020-09-21 23:59:57 -03:00
std::optional<int> FLOOR_INFO::GetFloorHeight(int startRoomNumber, int x, int y, int z, bool raw)
2020-09-17 00:08:10 -03:00
{
2020-09-18 23:11:04 -03:00
auto floor = GetNearBottomFloor(startRoomNumber, x, z);
2020-09-21 23:59:57 -03:00
if (floor)
{
auto height = floor->FloorHeight(x, z);
if (!raw)
{
for (auto itemNumber : floor->FloorItem)
{
auto item = &g_Level.Items[itemNumber];
auto itemHeight = Objects[item->objectNumber].floor(itemNumber, x, y, z);
if (itemHeight && *itemHeight >= y && *itemHeight < height)
height = *itemHeight;
2020-09-21 23:59:57 -03:00
}
}
2020-09-22 23:38:48 -03:00
return std::optional{height};
2020-09-21 23:59:57 -03:00
}
return std::nullopt;
2020-09-17 00:08:10 -03:00
}
2020-09-21 23:59:57 -03:00
std::optional<int> FLOOR_INFO::GetCeilingHeight(int startRoomNumber, int x, int y, int z, bool raw)
2020-09-17 00:08:10 -03:00
{
2020-09-18 23:11:04 -03:00
auto floor = GetNearTopFloor(startRoomNumber, x, z);
2020-09-21 23:59:57 -03:00
if (floor)
{
auto height = floor->CeilingHeight(x, z);
if (!raw)
{
for (auto itemNumber : floor->CeilingItem)
{
auto item = &g_Level.Items[itemNumber];
auto itemHeight = Objects[item->objectNumber].ceiling(itemNumber, x, y, z);
if (itemHeight && *itemHeight <= y && *itemHeight > height)
height = *itemHeight;
2020-09-21 23:59:57 -03:00
}
}
2020-09-22 23:38:48 -03:00
return std::optional{height};
2020-09-21 23:59:57 -03:00
}
return std::nullopt;
}
void FLOOR_INFO::AddFloor(short itemNumber)
{
auto item = &g_Level.Items[itemNumber];
auto floor = GetNearBottomFloor(item->roomNumber, item->pos.xPos, item->pos.zPos);
auto begin = floor->FloorItem.cbegin();
auto end = floor->FloorItem.cend();
auto position = std::find(begin, end, itemNumber);
if (position == end)
floor->FloorItem.push_back(itemNumber);
}
void FLOOR_INFO::RemoveFloor(short itemNumber)
{
auto item = &g_Level.Items[itemNumber];
auto floor = GetNearBottomFloor(item->roomNumber, item->pos.xPos, item->pos.zPos);
auto begin = floor->FloorItem.cbegin();
auto end = floor->FloorItem.cend();
auto position = std::find(begin, end, itemNumber);
if (position != end)
floor->FloorItem.erase(position);
}
void FLOOR_INFO::AddCeiling(short itemNumber)
{
auto item = &g_Level.Items[itemNumber];
auto floor = GetNearTopFloor(item->roomNumber, item->pos.xPos, item->pos.zPos);
auto begin = floor->CeilingItem.cbegin();
auto end = floor->CeilingItem.cend();
auto position = std::find(begin, end, itemNumber);
if (position == end)
floor->CeilingItem.push_back(itemNumber);
}
void FLOOR_INFO::RemoveCeiling(short itemNumber)
{
auto item = &g_Level.Items[itemNumber];
auto floor = GetNearTopFloor(item->roomNumber, item->pos.xPos, item->pos.zPos);
auto begin = floor->CeilingItem.cbegin();
auto end = floor->CeilingItem.cend();
auto position = std::find(begin, end, itemNumber);
if (position != end)
floor->CeilingItem.erase(position);
2020-09-17 00:08:10 -03:00
}
2020-09-15 11:01:24 -03:00
int FLOOR_INFO::SectorPlane(int x, int z)
2020-09-14 00:19:05 -03:00
{
2020-09-15 11:01:24 -03:00
auto vector = GetSectorPoint(x, z);
auto matrix = Matrix::CreateRotationZ(FloorCollision.SplitAngle);
auto result = Vector2::Transform(Vector2(vector.x, vector.y), matrix);
return result.x < 0 ? 0 : 1;
}
std::optional<int> FLOOR_INFO::RoomBelow(int plane)
2020-09-17 00:08:10 -03:00
{
2020-09-15 11:01:24 -03:00
auto room = FloorCollision.Portals[plane];
2020-09-22 23:38:48 -03:00
return room != -1 ? std::optional{room} : std::nullopt;
2020-09-15 11:01:24 -03:00
}
std::optional<int> FLOOR_INFO::RoomBelow(int x, int z)
{
return RoomBelow(SectorPlane(x, z));
}
std::optional<int> FLOOR_INFO::RoomAbove(int plane)
2020-09-17 00:08:10 -03:00
{
2020-09-15 11:01:24 -03:00
auto room = CeilingCollision.Portals[plane];
2020-09-22 23:38:48 -03:00
return room != -1 ? std::optional{room} : std::nullopt;
2020-09-15 11:01:24 -03:00
}
std::optional<int> FLOOR_INFO::RoomAbove(int x, int z)
{
return RoomAbove(SectorPlane(x, z));
}
std::optional<int> FLOOR_INFO::RoomSide()
{
2020-09-22 23:38:48 -03:00
return WallPortal != -1 ? std::optional{WallPortal} : std::nullopt;
2020-09-15 11:01:24 -03:00
}
int FLOOR_INFO::FloorHeight(int x, int z)
{
auto plane = SectorPlane(x, z);
auto vector = GetSectorPoint(x, z);
return FloorCollision.Planes[plane].x * vector.x + FloorCollision.Planes[plane].y * vector.y + FloorCollision.Planes[plane].z;
}
int FLOOR_INFO::CeilingHeight(int x, int z)
{
auto plane = SectorPlane(x, z);
auto vector = GetSectorPoint(x, z);
return CeilingCollision.Planes[plane].x * vector.x + CeilingCollision.Planes[plane].y * vector.y + CeilingCollision.Planes[plane].z;
2020-09-14 00:19:05 -03:00
}
2020-09-17 00:08:10 -03:00
Vector2 FLOOR_INFO::FloorSlope(int plane)
{
return Vector2{FloorCollision.Planes[plane].x, FloorCollision.Planes[plane].y};
}
Vector2 FLOOR_INFO::FloorSlope(int x, int z)
{
return FloorSlope(SectorPlane(x, z));
}
Vector2 FLOOR_INFO::CeilingSlope(int plane)
{
return Vector2{CeilingCollision.Planes[plane].x, CeilingCollision.Planes[plane].y};
}
Vector2 FLOOR_INFO::CeilingSlope(int x, int z)
{
return CeilingSlope(SectorPlane(x, z));
}
bool FLOOR_INFO::IsWall(int plane)
{
return FloorCollision.SplitAngle == CeilingCollision.SplitAngle && FloorCollision.Planes[plane] == CeilingCollision.Planes[plane];
}
bool FLOOR_INFO::IsWall(int x, int z)
{
return IsWall(SectorPlane(x, z));
}