2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2021-12-22 16:23:57 +03:00
|
|
|
#include "Game/misc.h"
|
2021-12-24 03:32:19 +03:00
|
|
|
|
2021-12-22 16:23:57 +03:00
|
|
|
#include "Game/animation.h"
|
2024-04-16 16:50:49 +10:00
|
|
|
#include "Game/collision/Point.h"
|
2021-12-24 03:32:19 +03:00
|
|
|
#include "Game/Lara/lara.h"
|
2021-12-22 16:23:57 +03:00
|
|
|
#include "Game/itemdata/creature_info.h"
|
|
|
|
#include "Game/items.h"
|
2023-05-01 11:24:48 +01:00
|
|
|
#include "Game/Setup.h"
|
2021-12-24 03:32:19 +03:00
|
|
|
#include "Specific/level.h"
|
2024-08-08 21:57:12 +10:00
|
|
|
#include "Specific/trutils.h"
|
2021-09-25 11:27:47 +02:00
|
|
|
|
2024-04-16 16:50:49 +10:00
|
|
|
using namespace TEN::Collision::Point;
|
2024-08-08 21:57:12 +10:00
|
|
|
using namespace TEN::Utils;
|
2021-12-19 05:24:12 +03:00
|
|
|
|
2022-05-05 07:08:14 +02:00
|
|
|
CreatureInfo* GetCreatureInfo(ItemInfo* item)
|
2020-05-19 19:01:11 +02:00
|
|
|
{
|
2023-06-15 10:11:47 +02:00
|
|
|
return (CreatureInfo*)item->Data;
|
2020-05-19 19:01:11 +02:00
|
|
|
}
|
|
|
|
|
2024-08-08 22:12:50 +10:00
|
|
|
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature, const std::vector<GAME_OBJECT_ID>& keyObjectIds, bool ignoreKeyObjectIds)
|
2020-06-10 21:38:25 +02:00
|
|
|
{
|
2024-08-08 22:12:50 +10:00
|
|
|
float closestDistSqr = INFINITY;
|
|
|
|
for (int itemNumber = 0; itemNumber < g_Level.NumItems; itemNumber++)
|
2020-06-10 21:38:25 +02:00
|
|
|
{
|
2024-08-08 22:12:50 +10:00
|
|
|
auto* targetItem = &g_Level.Items[itemNumber];
|
2024-08-08 21:57:12 +10:00
|
|
|
if (targetItem == nullptr || targetItem->Index == item->Index)
|
2021-12-19 05:24:12 +03:00
|
|
|
continue;
|
2019-12-17 17:37:53 +01:00
|
|
|
|
2024-08-08 22:12:50 +10:00
|
|
|
// Ignore or specifically target key object IDs.
|
|
|
|
if (ignoreKeyObjectIds ? Contains(keyObjectIds, targetItem->ObjectNumber) : !Contains(keyObjectIds, targetItem->ObjectNumber))
|
2024-08-08 21:57:12 +10:00
|
|
|
continue;
|
2024-08-08 01:07:06 +02:00
|
|
|
|
2024-08-08 21:57:12 +10:00
|
|
|
if (targetItem != item && targetItem->HitPoints > 0 && targetItem->Status != ITEM_INVISIBLE)
|
2019-12-17 17:37:53 +01:00
|
|
|
{
|
2024-08-08 22:12:50 +10:00
|
|
|
float distSqr = Vector3i::DistanceSquared(item->Pose.Position, targetItem->Pose.Position);
|
|
|
|
if (distSqr < closestDistSqr)
|
2019-12-17 17:37:53 +01:00
|
|
|
{
|
2024-08-08 21:57:12 +10:00
|
|
|
creature->Enemy = targetItem;
|
2024-08-08 22:12:50 +10:00
|
|
|
closestDistSqr = distSqr;
|
2019-12-17 17:37:53 +01:00
|
|
|
}
|
2020-06-26 07:06:18 +02:00
|
|
|
}
|
2019-12-17 17:37:53 +01:00
|
|
|
}
|
2022-02-08 01:26:59 +11:00
|
|
|
}
|
2024-04-16 16:50:49 +10:00
|
|
|
|
2024-04-27 20:48:39 +02:00
|
|
|
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat)
|
2024-04-16 16:50:49 +10:00
|
|
|
{
|
|
|
|
auto projectedPos = Geometry::TranslatePoint(item.Pose.Position, dir, dist);
|
|
|
|
auto pointColl = GetPointCollision(item.Pose.Position, item.RoomNumber, dir, dist);
|
|
|
|
int height = GameBoundingBox(&item).GetHeight();
|
|
|
|
|
|
|
|
// TODO: Use floor normal directly.
|
|
|
|
auto floorTilt = GetSurfaceTilt(pointColl.GetFloorNormal(), true);
|
|
|
|
|
|
|
|
// Test for wall.
|
|
|
|
if (pointColl.GetSector().IsWall(projectedPos.x, projectedPos.z))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Test for slippery slope.
|
2024-04-26 17:51:53 +10:00
|
|
|
if (pointColl.IsSteepFloor())
|
2024-04-16 16:50:49 +10:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Flat floor.
|
|
|
|
if ((abs(floorTilt.x) == 0 && abs(floorTilt.y) == 0))
|
|
|
|
{
|
|
|
|
// Test for step.
|
|
|
|
int relFloorHeight = abs(pointColl.GetFloorHeight() - item.Pose.Position.y);
|
2024-05-01 15:29:19 +10:00
|
|
|
if (relFloorHeight >= CLICK(1) && item.Pose.Position.y >= pointColl.GetFloorHeight() && canFloat)
|
2024-04-27 20:48:39 +02:00
|
|
|
{
|
2024-04-06 09:06:48 +02:00
|
|
|
return false;
|
2024-04-27 20:48:39 +02:00
|
|
|
}
|
|
|
|
else if (relFloorHeight >= CLICK(1) && !canFloat)
|
|
|
|
{
|
2024-04-16 16:50:49 +10:00
|
|
|
return false;
|
2024-04-27 20:48:39 +02:00
|
|
|
}
|
2024-04-16 16:50:49 +10:00
|
|
|
}
|
|
|
|
// Sloped floor.
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Half block.
|
|
|
|
int relFloorHeight = abs(pointColl.GetFloorHeight() - item.Pose.Position.y);
|
2024-04-27 20:48:39 +02:00
|
|
|
if (relFloorHeight > CLICK(1) && canFloat)
|
|
|
|
{
|
2024-04-16 16:50:49 +10:00
|
|
|
return false;
|
2024-04-27 20:48:39 +02:00
|
|
|
}
|
|
|
|
else if (relFloorHeight > CLICK(2) && !canFloat)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-16 16:50:49 +10:00
|
|
|
|
|
|
|
short slopeAngle = ANGLE(0.0f);
|
|
|
|
if (floorTilt.x > 0)
|
|
|
|
{
|
|
|
|
slopeAngle = ANGLE(-90.0f);
|
|
|
|
}
|
|
|
|
else if (floorTilt.x < 0)
|
|
|
|
{
|
|
|
|
slopeAngle = ANGLE(90.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (floorTilt.y > 0 && floorTilt.y > abs(floorTilt.x))
|
|
|
|
{
|
|
|
|
slopeAngle = ANGLE(180.0f);
|
|
|
|
}
|
|
|
|
else if (floorTilt.y < 0 && -floorTilt.y > abs(floorTilt.x))
|
|
|
|
{
|
|
|
|
slopeAngle = ANGLE(0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
short dirAngle = phd_atan(dir.z, dir.x);
|
|
|
|
short alignAngle = Geometry::GetShortestAngle(slopeAngle, dirAngle);
|
|
|
|
|
|
|
|
// Test if slope aspect is aligned with direction.
|
|
|
|
if (alignAngle != 0 && alignAngle != ANGLE(180.0f))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for diagonal split.
|
|
|
|
if (pointColl.IsDiagonalFloorStep())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Test ceiling height.
|
|
|
|
int relCeilHeight = abs(pointColl.GetCeilingHeight() - pointColl.GetFloorHeight());
|
|
|
|
|
2024-04-27 20:48:39 +02:00
|
|
|
if (canFloat)
|
|
|
|
{
|
|
|
|
if (relCeilHeight <= height)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (relCeilHeight < BLOCK(1))
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-16 16:50:49 +10:00
|
|
|
|
2024-05-17 12:30:14 +02:00
|
|
|
// Check for inaccessible sector.
|
2024-06-25 17:32:02 +10:00
|
|
|
if (pointColl.GetSector().PathfindingBoxID == NO_VALUE)
|
2024-05-17 12:30:14 +02:00
|
|
|
return false;
|
|
|
|
|
2024-04-16 16:50:49 +10:00
|
|
|
// Check for blocked grey box.
|
2024-06-25 17:32:02 +10:00
|
|
|
if (g_Level.PathfindingBoxes[pointColl.GetSector().PathfindingBoxID].flags & BLOCKABLE)
|
2024-04-16 16:50:49 +10:00
|
|
|
{
|
2024-06-25 17:32:02 +10:00
|
|
|
if (g_Level.PathfindingBoxes[pointColl.GetSector().PathfindingBoxID].flags & BLOCKED)
|
2024-04-16 16:50:49 +10:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for stopper flag.
|
|
|
|
if (pointColl.GetSector().Stopper)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
2024-04-27 20:48:39 +02:00
|
|
|
}
|