TombEngine/TR5Main/Game/floordata.cpp

448 lines
11 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
using namespace T5M::Floordata;
int FLOOR_INFO::SectorPlane(int x, int z) const
2020-09-14 00:19:05 -03:00
{
const auto point = GetSectorPoint(x, z);
auto vector = Vector2(point.x, point.y);
const auto matrix = Matrix::CreateRotationZ(FloorCollision.SplitAngle);
Vector2::Transform(vector, matrix, vector);
2020-09-17 00:08:10 -03:00
return vector.x < 0 ? 0 : 1;
}
2020-09-17 00:08:10 -03:00
std::optional<int> FLOOR_INFO::RoomBelow(int plane) const
{
const auto room = FloorCollision.Portals[plane];
return room != -1 ? std::optional{room} : std::nullopt;
}
2020-09-17 00:08:10 -03:00
std::optional<int> FLOOR_INFO::RoomBelow(int x, int z) const
{
return RoomBelow(SectorPlane(x, z));
2020-09-14 00:19:05 -03:00
}
2021-01-06 17:53:13 -03:00
std::optional<int> FLOOR_INFO::RoomBelow(int x, int z, int y) const
{
for (const auto itemNumber : BridgeItem)
{
const auto& item = g_Level.Items[itemNumber];
const auto itemHeight = Objects[item.objectNumber].floor(itemNumber, x, y, z);
if (itemHeight && *itemHeight >= y)
return std::nullopt;
}
return RoomBelow(x, z);
}
std::optional<int> FLOOR_INFO::RoomAbove(int plane) const
2020-09-15 11:01:24 -03:00
{
const auto room = CeilingCollision.Portals[plane];
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) const
2020-09-15 11:01:24 -03:00
{
return RoomAbove(SectorPlane(x, z));
2020-09-15 11:01:24 -03:00
}
2021-01-06 17:53:13 -03:00
std::optional<int> FLOOR_INFO::RoomAbove(int x, int z, int y) const
{
for (const auto itemNumber : BridgeItem)
{
const auto& item = g_Level.Items[itemNumber];
const auto itemHeight = Objects[item.objectNumber].ceiling(itemNumber, x, y, z);
if (itemHeight && *itemHeight <= y)
return std::nullopt;
}
return RoomAbove(x, z);
}
std::optional<int> FLOOR_INFO::RoomSide() const
2020-09-15 11:01:24 -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) const
{
const auto plane = SectorPlane(x, z);
const auto vector = GetSectorPoint(x, z);
2020-09-15 11:01:24 -03:00
return FloorCollision.Planes[plane].x * vector.x + FloorCollision.Planes[plane].y * vector.y + FloorCollision.Planes[plane].z;
2020-09-15 11:01:24 -03:00
}
2021-01-06 17:53:13 -03:00
int FLOOR_INFO::FloorHeight(int x, int z, int y) const
{
auto height = FloorHeight(x, z);
for (const auto itemNumber : BridgeItem)
{
const auto& item = g_Level.Items[itemNumber];
const auto itemHeight = Objects[item.objectNumber].floor(itemNumber, x, y, z);
if (itemHeight && *itemHeight >= y && *itemHeight < height)
height = *itemHeight;
}
return height;
}
int FLOOR_INFO::CeilingHeight(int x, int z) const
2020-09-14 00:19:05 -03:00
{
const auto plane = SectorPlane(x, z);
const auto vector = GetSectorPoint(x, z);
2020-09-15 11:01:24 -03:00
return CeilingCollision.Planes[plane].x * vector.x + CeilingCollision.Planes[plane].y * vector.y + CeilingCollision.Planes[plane].z;
}
2020-09-15 11:01:24 -03:00
2021-01-06 17:53:13 -03:00
int FLOOR_INFO::CeilingHeight(int x, int z, int y) const
{
auto height = CeilingHeight(x, z);
for (const auto itemNumber : BridgeItem)
{
const auto& item = g_Level.Items[itemNumber];
const auto itemHeight = Objects[item.objectNumber].ceiling(itemNumber, x, y, z);
if (itemHeight && *itemHeight <= y && *itemHeight > height)
height = *itemHeight;
}
return height;
}
Vector2 FLOOR_INFO::FloorSlope(int plane) const
{
return Vector2{FloorCollision.Planes[plane].x, FloorCollision.Planes[plane].y};
2020-09-17 00:08:10 -03:00
}
Vector2 FLOOR_INFO::FloorSlope(int x, int z) const
2020-09-17 00:08:10 -03:00
{
return FloorSlope(SectorPlane(x, z));
}
2020-09-22 23:38:48 -03:00
Vector2 FLOOR_INFO::CeilingSlope(int plane) const
{
return Vector2{CeilingCollision.Planes[plane].x, CeilingCollision.Planes[plane].y};
}
2020-09-22 23:38:48 -03:00
Vector2 FLOOR_INFO::CeilingSlope(int x, int z) const
{
return CeilingSlope(SectorPlane(x, z));
}
2020-09-17 00:08:10 -03:00
bool FLOOR_INFO::IsWall(int plane) const
{
return FloorCollision.SplitAngle == CeilingCollision.SplitAngle && FloorCollision.Planes[plane] == CeilingCollision.Planes[plane];
2020-09-17 00:08:10 -03:00
}
bool FLOOR_INFO::IsWall(int x, int z) const
2020-09-17 00:08:10 -03:00
{
return IsWall(SectorPlane(x, z));
}
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
std::optional<int> FLOOR_INFO::InsideBridge(int x, int z, int y, bool floor) const
{
for (const auto itemNumber : BridgeItem)
{
const auto& item = g_Level.Items[itemNumber];
const auto floorHeight = Objects[item.objectNumber].floor(itemNumber, x, y, z);
const auto ceilingHeight = Objects[item.objectNumber].ceiling(itemNumber, x, y, z);
if (floorHeight && ceilingHeight && (y > *floorHeight && y < *ceilingHeight || y == (floor ? *ceilingHeight : *floorHeight)))
return floor ? floorHeight : ceilingHeight;
}
return std::nullopt;
}
int FLOOR_INFO::LogicalHeight(int x, int z, int y, bool floor) const
{
auto height = InsideBridge(x, z, y, floor);
while (height)
{
y = *height;
height = InsideBridge(x, z, y, floor);
}
return y;
}
void FLOOR_INFO::AddItem(short itemNumber)
{
BridgeItem.insert(itemNumber);
}
void FLOOR_INFO::RemoveItem(short itemNumber)
{
BridgeItem.erase(itemNumber);
}
namespace T5M::Floordata
2020-12-21 13:16:29 -03:00
{
2021-01-03 15:21:32 -03:00
VectorInt2 GetSectorPoint(int x, int z)
{
const auto xPoint = x % SECTOR(1) - SECTOR(1) / 2;
const auto yPoint = z % SECTOR(1) - SECTOR(1) / 2;
return VectorInt2{xPoint, yPoint};
}
VectorInt2 GetRoomPosition(int roomNumber, int x, int z)
2020-09-22 23:38:48 -03:00
{
const auto& room = g_Level.Rooms[roomNumber];
const auto xRoom = (z - room.z) / SECTOR(1);
const auto yRoom = (x - room.x) / SECTOR(1);
auto pos = VectorInt2{xRoom, yRoom};
if (pos.x < 0)
{
pos.x = 0;
}
else if (pos.x > room.xSize - 1)
{
pos.x = room.xSize - 1;
}
if (pos.y < 0)
{
pos.y = 0;
}
else if (pos.y > room.ySize - 1)
{
pos.y = room.ySize - 1;
}
return pos;
2020-09-22 23:38:48 -03:00
}
2021-01-03 15:21:32 -03:00
FLOOR_INFO& GetFloor(int roomNumber, const VectorInt2& pos)
2020-09-17 00:08:10 -03:00
{
auto& room = g_Level.Rooms[roomNumber];
return room.floor[room.xSize * pos.y + pos.x];
2020-09-17 00:08:10 -03:00
}
FLOOR_INFO& GetFloor(int roomNumber, int x, int z)
2020-09-17 00:08:10 -03:00
{
return GetFloor(roomNumber, GetRoomPosition(roomNumber, x, z));
2020-09-17 00:08:10 -03:00
}
2021-01-03 15:21:32 -03:00
FLOOR_INFO& GetFloorSide(int roomNumber, int x, int z, int* sideRoomNumber)
{
auto floor = &GetFloor(roomNumber, x, z);
2021-01-03 15:21:32 -03:00
const auto roomSide = floor->RoomSide();
if (roomSide)
{
roomNumber = *roomSide;
floor = &GetFloor(roomNumber, x, z);
}
if (sideRoomNumber)
*sideRoomNumber = roomNumber;
return *floor;
}
2021-01-06 17:53:13 -03:00
FLOOR_INFO& GetBottomFloor(const ROOM_VECTOR& location, int x, int z, int& y, bool firstOutside)
2021-01-03 15:21:32 -03:00
{
2021-01-06 17:53:13 -03:00
auto floor = &GetFloorSide(location.roomNumber, x, z);
auto wall = floor->IsWall(x, z);
y = location.yNumber;
if (!wall)
y = std::clamp(y, floor->CeilingHeight(x, z), floor->FloorHeight(x, z));
auto roomBelow = floor->RoomBelow(x, z, y);
while ((firstOutside && wall || !firstOutside && !floor->InsideBridge(x, z, y, true)) && roomBelow)
{
2021-01-06 17:53:13 -03:00
floor = &GetFloorSide(*roomBelow, x, z);
wall = floor->IsWall(x, z);
if (!wall)
y = floor->CeilingHeight(x, z);
roomBelow = floor->RoomBelow(x, z, y);
}
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
return *floor;
}
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
FLOOR_INFO& GetTopFloor(const ROOM_VECTOR& location, int x, int z, int& y, bool firstOutside)
2020-09-15 11:01:24 -03:00
{
2021-01-06 17:53:13 -03:00
auto floor = &GetFloorSide(location.roomNumber, x, z);
auto wall = floor->IsWall(x, z);
y = location.yNumber;
if (!wall)
y = std::clamp(y, floor->CeilingHeight(x, z), floor->FloorHeight(x, z));
auto roomAbove = floor->RoomAbove(x, z, y);
while ((firstOutside && wall || !firstOutside && !floor->InsideBridge(x, z, y, false)) && roomAbove)
2020-09-15 11:01:24 -03:00
{
2021-01-06 17:53:13 -03:00
floor = &GetFloorSide(*roomAbove, x, z);
wall = floor->IsWall(x, z);
if (!wall)
y = floor->FloorHeight(x, z);
roomAbove = floor->RoomAbove(x, z, y);
2020-09-20 23:16:21 -03:00
}
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
return *floor;
2020-09-22 23:38:48 -03:00
}
2021-01-06 17:53:13 -03:00
std::optional<int> GetFloorHeight(const ROOM_VECTOR& location, int x, int z)
{
2021-01-06 17:53:13 -03:00
auto floor = &GetFloorSide(location.roomNumber, x, z);
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
int y;
floor = floor->IsWall(x, z) ? &GetTopFloor(location, x, z, y, true) : &GetBottomFloor(location, x, z, y);
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
if (!floor->IsWall(x, z))
2020-09-20 23:16:21 -03:00
{
2021-01-06 17:53:13 -03:00
y = floor->LogicalHeight(x, z, y, true);
return std::optional{floor->FloorHeight(x, z, y)};
2020-09-15 11:01:24 -03:00
}
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
return std::nullopt;
2020-09-22 23:38:48 -03:00
}
2021-01-06 17:53:13 -03:00
std::optional<int> GetCeilingHeight(const ROOM_VECTOR& location, int x, int z)
2020-09-22 23:38:48 -03:00
{
2021-01-06 17:53:13 -03:00
auto floor = &GetFloorSide(location.roomNumber, x, z);
2020-09-22 23:38:48 -03:00
2021-01-06 17:53:13 -03:00
int y;
floor = floor->IsWall(x, z) ? &GetBottomFloor(location, x, z, y, true) : &GetTopFloor(location, x, z, y);
2020-09-15 11:01:24 -03:00
2021-01-06 17:53:13 -03:00
if (!floor->IsWall(x, z))
{
2021-01-06 17:53:13 -03:00
y = floor->LogicalHeight(x, z, y, false);
return std::optional{floor->CeilingHeight(x, z, y)};
}
2020-09-14 00:19:05 -03:00
return std::nullopt;
}
2020-09-21 23:59:57 -03:00
2021-01-06 17:53:13 -03:00
std::optional<ROOM_VECTOR> GetBottomRoom(ROOM_VECTOR location, int x, int y, int z)
2020-09-21 23:59:57 -03:00
{
2021-01-06 17:53:13 -03:00
auto floor = &GetFloorSide(location.roomNumber, x, z, &location.roomNumber);
2021-01-06 17:53:13 -03:00
if (!floor->IsWall(x, z))
{
location.yNumber = floor->LogicalHeight(x, z, std::clamp(location.yNumber, floor->CeilingHeight(x, z), floor->FloorHeight(x, z)), false);
const auto floorHeight = floor->FloorHeight(x, z, location.yNumber);
const auto ceilingHeight = floor->CeilingHeight(x, z, location.yNumber);
2021-01-07 17:47:09 -03:00
if (y < ceilingHeight)
2021-01-06 17:53:13 -03:00
return std::nullopt;
if (y <= floorHeight && y >= ceilingHeight)
2021-01-07 11:16:21 -03:00
{
location.yNumber = y;
2021-01-06 17:53:13 -03:00
return std::optional{location};
2021-01-07 11:16:21 -03:00
}
2021-01-06 17:53:13 -03:00
}
2021-01-06 17:53:13 -03:00
auto roomBelow = floor->RoomBelow(x, z, location.yNumber);
2021-01-06 17:53:13 -03:00
while (roomBelow)
2020-09-21 23:59:57 -03:00
{
2021-01-06 17:53:13 -03:00
floor = &GetFloorSide(*roomBelow, x, z, &location.roomNumber);
2021-01-06 17:53:13 -03:00
if (!floor->IsWall(x, z))
{
location.yNumber = floor->LogicalHeight(x, z, floor->CeilingHeight(x, z), false);
const auto floorHeight = floor->FloorHeight(x, z, location.yNumber);
const auto ceilingHeight = floor->CeilingHeight(x, z, location.yNumber);
2021-01-07 17:47:09 -03:00
if (y < ceilingHeight)
2021-01-06 17:53:13 -03:00
return std::nullopt;
if (y <= floorHeight && y >= ceilingHeight)
2021-01-07 11:16:21 -03:00
{
location.yNumber = y;
2021-01-06 17:53:13 -03:00
return std::optional{location};
2021-01-07 11:16:21 -03:00
}
2021-01-06 17:53:13 -03:00
}
2021-01-06 17:53:13 -03:00
roomBelow = floor->RoomBelow(x, z, location.yNumber);
2020-09-21 23:59:57 -03:00
}
return std::nullopt;
2020-09-21 23:59:57 -03:00
}
2021-01-06 17:53:13 -03:00
std::optional<ROOM_VECTOR> GetTopRoom(ROOM_VECTOR location, int x, int y, int z)
{
2021-01-06 17:53:13 -03:00
auto floor = &GetFloorSide(location.roomNumber, x, z, &location.roomNumber);
2021-01-06 17:53:13 -03:00
if (!floor->IsWall(x, z))
{
2021-01-06 17:53:13 -03:00
location.yNumber = floor->LogicalHeight(x, z, std::clamp(location.yNumber, floor->CeilingHeight(x, z), floor->FloorHeight(x, z)), true);
const auto floorHeight = floor->FloorHeight(x, z, location.yNumber);
const auto ceilingHeight = floor->CeilingHeight(x, z, location.yNumber);
2021-01-07 17:47:09 -03:00
if (y > floorHeight)
2021-01-06 17:53:13 -03:00
return std::nullopt;
if (y <= floorHeight && y >= ceilingHeight)
2021-01-07 11:16:21 -03:00
{
location.yNumber = y;
2021-01-06 17:53:13 -03:00
return std::optional{location};
2021-01-07 11:16:21 -03:00
}
2020-09-21 23:59:57 -03:00
}
2021-01-06 17:53:13 -03:00
auto roomAbove = floor->RoomAbove(x, z, location.yNumber);
2020-09-21 23:59:57 -03:00
2021-01-06 17:53:13 -03:00
while (roomAbove)
{
2021-01-06 17:53:13 -03:00
floor = &GetFloorSide(*roomAbove, x, z, &location.roomNumber);
2020-12-20 14:04:27 -03:00
2021-01-06 17:53:13 -03:00
if (!floor->IsWall(x, z))
{
2021-01-06 17:53:13 -03:00
location.yNumber = floor->LogicalHeight(x, z, floor->FloorHeight(x, z), true);
const auto floorHeight = floor->FloorHeight(x, z, location.yNumber);
const auto ceilingHeight = floor->CeilingHeight(x, z, location.yNumber);
2021-01-07 17:47:09 -03:00
if (y > floorHeight)
2021-01-06 17:53:13 -03:00
return std::nullopt;
if (y <= floorHeight && y >= ceilingHeight)
2021-01-07 11:16:21 -03:00
{
location.yNumber = y;
2021-01-06 17:53:13 -03:00
return std::optional{location};
2021-01-07 11:16:21 -03:00
}
}
2020-09-21 23:59:57 -03:00
2021-01-06 17:53:13 -03:00
roomAbove = floor->RoomAbove(x, z, location.yNumber);
}
2020-09-17 00:08:10 -03:00
return std::nullopt;
}
2020-09-15 11:01:24 -03:00
2021-01-06 17:53:13 -03:00
ROOM_VECTOR GetRoom(ROOM_VECTOR location, int x, int y, int z)
{
2021-01-06 17:53:13 -03:00
const auto locationBelow = GetBottomRoom(location, x, y, z);
const auto locationAbove = GetTopRoom(location, x, y, z);
2020-09-15 11:01:24 -03:00
2021-01-06 17:53:13 -03:00
if (locationBelow)
{
2021-01-06 17:53:13 -03:00
location = *locationBelow;
}
2021-01-06 17:53:13 -03:00
else if (locationAbove)
{
2021-01-06 17:53:13 -03:00
location = *locationAbove;
}
2021-01-06 17:53:13 -03:00
return location;
}
2020-09-15 11:01:24 -03:00
2021-01-06 17:53:13 -03:00
void AddBridge(short itemNumber)
{
2021-01-06 17:53:13 -03:00
const auto& item = g_Level.Items[itemNumber];
auto& floor = GetFloor(item.roomNumber, item.pos.xPos, item.pos.zPos);
floor.AddItem(itemNumber);
}
2020-09-17 00:08:10 -03:00
2021-01-06 17:53:13 -03:00
void RemoveBridge(short itemNumber)
{
2021-01-06 17:53:13 -03:00
const auto& item = g_Level.Items[itemNumber];
auto& floor = GetFloor(item.roomNumber, item.pos.xPos, item.pos.zPos);
floor.RemoveItem(itemNumber);
}
2020-09-17 00:08:10 -03:00
}