mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-02 17:57:59 +03:00
218 lines
4.9 KiB
C++
218 lines
4.9 KiB
C++
#include "framework.h"
|
|
#include "Game/room.h"
|
|
|
|
#include "Game/collision/collide_room.h"
|
|
#include "Game/control/control.h"
|
|
#include "Game/control/lot.h"
|
|
#include "Game/control/volume.h"
|
|
#include "Game/items.h"
|
|
#include "Renderer/Renderer11.h"
|
|
|
|
using namespace TEN::Renderer;
|
|
using namespace TEN::Floordata;
|
|
|
|
byte FlipStatus = 0;
|
|
int FlipStats[MAX_FLIPMAP];
|
|
int FlipMap[MAX_FLIPMAP];
|
|
|
|
std::vector<short> OutsideRoomTable[OUTSIDE_SIZE][OUTSIDE_SIZE];
|
|
|
|
void DoFlipMap(short group)
|
|
{
|
|
ROOM_INFO temp;
|
|
|
|
for (size_t i = 0; i < g_Level.Rooms.size(); i++)
|
|
{
|
|
auto* room = &g_Level.Rooms[i];
|
|
|
|
if (room->flippedRoom >= 0 && room->flipNumber == group)
|
|
{
|
|
RemoveRoomFlipItems(room);
|
|
|
|
auto* flipped = &g_Level.Rooms[room->flippedRoom];
|
|
|
|
temp = *room;
|
|
*room = *flipped;
|
|
*flipped = temp;
|
|
|
|
room->flippedRoom = flipped->flippedRoom;
|
|
flipped->flippedRoom = -1;
|
|
|
|
room->itemNumber = flipped->itemNumber;
|
|
room->fxNumber = flipped->fxNumber;
|
|
|
|
AddRoomFlipItems(room);
|
|
|
|
g_Renderer.flipRooms(static_cast<short>(i), room->flippedRoom);
|
|
|
|
for (auto& fd : room->floor)
|
|
fd.Room = i;
|
|
for (auto& fd : flipped->floor)
|
|
fd.Room = room->flippedRoom;
|
|
}
|
|
}
|
|
|
|
FlipStatus = FlipStats[group] = !FlipStats[group];
|
|
|
|
for (int i = 0; i < ActiveCreatures.size(); i++)
|
|
ActiveCreatures[i]->LOT.TargetBox = NO_BOX;
|
|
}
|
|
|
|
void AddRoomFlipItems(ROOM_INFO* room)
|
|
{
|
|
for (short linkNumber = room->itemNumber; linkNumber != NO_ITEM; linkNumber = g_Level.Items[linkNumber].NextItem)
|
|
{
|
|
auto* item = &g_Level.Items[linkNumber];
|
|
|
|
if (Objects[item->ObjectNumber].floor != nullptr)
|
|
UpdateBridgeItem(linkNumber);
|
|
}
|
|
}
|
|
|
|
void RemoveRoomFlipItems(ROOM_INFO* room)
|
|
{
|
|
for (short linkNumber = room->itemNumber; linkNumber != NO_ITEM; linkNumber = g_Level.Items[linkNumber].NextItem)
|
|
{
|
|
auto* item = &g_Level.Items[linkNumber];
|
|
|
|
if (item->Flags & ONESHOT &&
|
|
Objects[item->ObjectNumber].intelligent &&
|
|
item->HitPoints <= 0 &&
|
|
item->HitPoints != NOT_TARGETABLE)
|
|
{
|
|
KillItem(linkNumber);
|
|
}
|
|
|
|
if (Objects[item->ObjectNumber].floor != nullptr)
|
|
UpdateBridgeItem(linkNumber, true);
|
|
}
|
|
}
|
|
|
|
bool IsObjectInRoom(short roomNumber, short objectNumber)
|
|
{
|
|
short itemNumber = g_Level.Rooms[roomNumber].itemNumber;
|
|
|
|
if (itemNumber == NO_ITEM)
|
|
return false;
|
|
|
|
while (true)
|
|
{
|
|
auto* item = &g_Level.Items[itemNumber];
|
|
|
|
if (item->ObjectNumber == objectNumber)
|
|
break;
|
|
|
|
itemNumber = item->NextItem;
|
|
|
|
if (itemNumber == NO_ITEM)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int IsRoomOutside(int x, int y, int z)
|
|
{
|
|
if (x < 0 || z < 0)
|
|
return NO_ROOM;
|
|
|
|
int xTable = x / SECTOR(1);
|
|
int zTable = z / SECTOR(1);
|
|
|
|
if (OutsideRoomTable[xTable][zTable].size() == 0)
|
|
return NO_ROOM;
|
|
|
|
for (size_t i = 0; i < OutsideRoomTable[xTable][zTable].size(); i++)
|
|
{
|
|
short roomNumber = OutsideRoomTable[xTable][zTable][i];
|
|
auto* room = &g_Level.Rooms[roomNumber];
|
|
|
|
if (y > room->maxceiling &&
|
|
y < room->minfloor &&
|
|
(z > (room->z + SECTOR(1)) &&
|
|
z < (room->z + (room->zSize - 1) * SECTOR(1))) &&
|
|
(x > (room->x + SECTOR(1)) &&
|
|
x < (room->x + (room->xSize - 1) * SECTOR(1))))
|
|
{
|
|
auto probe = GetCollision(x, y, z, roomNumber);
|
|
|
|
if (probe.Position.Floor == NO_HEIGHT || y > probe.Position.Floor)
|
|
return NO_ROOM;
|
|
|
|
if (y < probe.Position.Ceiling)
|
|
return NO_ROOM;
|
|
|
|
return ((room->flags & (ENV_FLAG_WIND | ENV_FLAG_WATER)) != 0 ? probe.RoomNumber : NO_ROOM);
|
|
}
|
|
}
|
|
|
|
return NO_ROOM;
|
|
}
|
|
|
|
FLOOR_INFO* GetSector(ROOM_INFO* room, int x, int z)
|
|
{
|
|
int sectorX = std::clamp(x / SECTOR(1), 0, room->xSize - 1);
|
|
int sectorZ = std::clamp(z / SECTOR(1), 0, room->zSize - 1);
|
|
|
|
int index = sectorZ + sectorX * room->zSize;
|
|
if (index > room->floor.size())
|
|
return nullptr;
|
|
|
|
return &room->floor[index];
|
|
}
|
|
|
|
bool IsPointInRoom(PHD_3DPOS const& pos, int roomNumber)
|
|
{
|
|
int x = pos.xPos;
|
|
int y = pos.yPos;
|
|
int z = pos.zPos;
|
|
auto* room = &g_Level.Rooms[roomNumber];
|
|
int xSector = (x - room->x) / SECTOR(1);
|
|
int zSector = (z - room->z) / SECTOR(1);
|
|
|
|
if ((xSector >= 0 && xSector <= room->xSize - 1) &&
|
|
(zSector >= 0 && zSector <= room->zSize - 1) &&
|
|
(y <= room->minfloor && y >= room->maxceiling)) // up is negative y axis, hence y should be "less" than floor
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
PHD_3DPOS GetRoomCenter(int roomNumber)
|
|
{
|
|
auto* room = &g_Level.Rooms[roomNumber];
|
|
auto halfLength = SECTOR(room->xSize)/2;
|
|
auto halfDepth = SECTOR(room->zSize)/2;
|
|
auto halfHeight = (room->maxceiling - room->minfloor) / 2;
|
|
|
|
PHD_3DPOS center;
|
|
center.xPos = room->x + halfLength;
|
|
center.yPos = room->minfloor + halfHeight;
|
|
center.zPos = room->z + halfDepth;
|
|
return center;
|
|
}
|
|
|
|
std::set<int> GetRoomList(int roomNumber)
|
|
{
|
|
std::set<int> result;
|
|
|
|
if (g_Level.Rooms.size() <= roomNumber)
|
|
return result;
|
|
|
|
result.insert(roomNumber);
|
|
|
|
auto* room = &g_Level.Rooms[roomNumber];
|
|
for (int i = 0; i < room->doors.size(); i++)
|
|
result.insert(room->doors[i].room);
|
|
|
|
for (auto i : result)
|
|
{
|
|
room = &g_Level.Rooms[i];
|
|
for (int j = 0; j < room->doors.size(); j++)
|
|
result.insert(room->doors[j].room);
|
|
}
|
|
|
|
return result;
|
|
}
|