mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-02 09:47:58 +03:00
Vertical pole fix (#707)
* Partially revise vertical pole detection * Refine vertical pole mount logic * Cleanup * Cleanup * Partially fix grabbing vertical poles while airborne * Dump a maths function from another branch * Use const argument * Fix wrong sphere collisions with vertical poles in edge cases * Cleanup * Update vector struct methods * Fix Lara alignment on narrow distances * Revert removal of static keyword; update IsPointInFront() Co-authored-by: Lwmte <3331699+Lwmte@users.noreply.github.com>
This commit is contained in:
parent
2b0e019963
commit
b8fd52554d
12 changed files with 330 additions and 251 deletions
|
@ -50,7 +50,7 @@ constexpr int LARA_RADIUS = 100;
|
|||
constexpr int LARA_RADIUS_CRAWL = 200;
|
||||
constexpr int LARA_RADIUS_UNDERWATER = 300;
|
||||
constexpr int LARA_RADIUS_DEATH = 400;
|
||||
constexpr int LARA_VELOCITY = 12; // TODO: Float.
|
||||
constexpr int LARA_ALIGN_VELOCITY = 12; // TODO: Float.
|
||||
|
||||
constexpr auto LARA_FREEFALL_VELOCITY = 131.0f;
|
||||
constexpr auto LARA_DAMAGE_VELOCITY = 141.0f;
|
||||
|
|
|
@ -562,9 +562,9 @@ void ModulateLaraSlideVelocity(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
void AlignLaraToSurface(ItemInfo* item, float alpha)
|
||||
{
|
||||
auto probe = GetCollision(item);
|
||||
short aspectAngle = GetSurfaceAspectAngle(probe.FloorTilt);
|
||||
short steepnessAngle = std::min(GetSurfaceSteepnessAngle(probe.FloorTilt), ANGLE(70.0f));
|
||||
auto floorTilt = GetCollision(item).FloorTilt;
|
||||
short aspectAngle = GetSurfaceAspectAngle(floorTilt);
|
||||
short steepnessAngle = std::min(GetSurfaceSteepnessAngle(floorTilt), ANGLE(70.0f));
|
||||
|
||||
short deltaAngle = GetShortestAngularDistance(item->Pose.Orientation.y, aspectAngle);
|
||||
float sinDeltaAngle = phd_sin(deltaAngle);
|
||||
|
|
|
@ -1113,22 +1113,22 @@ void GetTightropeFallOff(ItemInfo* item, int regularity)
|
|||
#endif
|
||||
|
||||
// TODO: Organise all of this properly. -- Sezz 2022.07.28
|
||||
bool CheckLaraState(LaraState state, std::vector<LaraState> stateList)
|
||||
bool CheckLaraState(LaraState referenceState, const std::vector<LaraState>& stateList)
|
||||
{
|
||||
for (auto listedState : stateList)
|
||||
for (auto& state : stateList)
|
||||
{
|
||||
if (state == listedState)
|
||||
if (state == referenceState)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckLaraWeaponType(LaraWeaponType weaponType, std::vector<LaraWeaponType> weaponTypeList)
|
||||
bool CheckLaraWeaponType(LaraWeaponType referenceWeaponType, const std::vector<LaraWeaponType>& weaponTypeList)
|
||||
{
|
||||
for (auto listedWeaponType : weaponTypeList)
|
||||
for (auto& weaponType : weaponTypeList)
|
||||
{
|
||||
if (weaponType == listedWeaponType)
|
||||
if (weaponType == referenceWeaponType)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2519,25 +2519,33 @@ bool TestLaraTightropeDismount(ItemInfo* item, CollisionInfo* coll)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool up, float offset)
|
||||
bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, float offset)
|
||||
{
|
||||
static constexpr auto poleProbeCollRadius = 16.0f;
|
||||
|
||||
bool atLeastOnePoleCollided = false;
|
||||
|
||||
if (GetCollidedObjects(item, SECTOR(1), true, CollidedItems, nullptr, 0) && CollidedItems[0])
|
||||
if (GetCollidedObjects(item, SECTOR(1), true, CollidedItems, nullptr, false) &&
|
||||
CollidedItems[0] != nullptr)
|
||||
{
|
||||
auto laraBox = TO_DX_BBOX(item->Pose, GetBoundsAccurate(item));
|
||||
|
||||
// HACK: because Core implemented upward pole movement as SetPosition command, we can't precisely
|
||||
// HACK: Because Core implemented upward pole movement as a SetPosition command, we can't precisely
|
||||
// check her position. So we add a fixed height offset.
|
||||
|
||||
auto sphere = BoundingSphere(laraBox.Center + Vector3(0, (laraBox.Extents.y + poleProbeCollRadius + offset) * (up ? -1 : 1), 0), poleProbeCollRadius);
|
||||
// Offset a sphere when jumping toward pole.
|
||||
auto sphereOffset2D = Vector3::Zero;
|
||||
sphereOffset2D = TranslateVector(sphereOffset2D, item->Pose.Orientation.y, coll->Setup.Radius + item->Animation.Velocity.z);
|
||||
|
||||
auto spherePos = laraBox.Center + Vector3(0.0f, (laraBox.Extents.y + poleProbeCollRadius + offset) * (goingUp ? -1 : 1), 0.0f);
|
||||
|
||||
auto sphere = BoundingSphere(spherePos, poleProbeCollRadius);
|
||||
auto offsetSphere = BoundingSphere(spherePos + sphereOffset2D, poleProbeCollRadius);
|
||||
|
||||
//g_Renderer.AddDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
|
||||
|
||||
int i = 0;
|
||||
while (CollidedItems[i] != NULL)
|
||||
while (CollidedItems[i] != nullptr)
|
||||
{
|
||||
auto*& object = CollidedItems[i];
|
||||
i++;
|
||||
|
@ -2546,11 +2554,11 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool up, float o
|
|||
continue;
|
||||
|
||||
auto poleBox = TO_DX_BBOX(object->Pose, GetBoundsAccurate(object));
|
||||
poleBox.Extents = poleBox.Extents + Vector3(coll->Setup.Radius, 0, coll->Setup.Radius);
|
||||
poleBox.Extents = poleBox.Extents + Vector3(coll->Setup.Radius, 0.0f, coll->Setup.Radius);
|
||||
|
||||
//g_Renderer.AddDebugBox(poleBox, Vector4(0, 0, 1, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
|
||||
|
||||
if (poleBox.Intersects(sphere))
|
||||
if (poleBox.Intersects(sphere) || poleBox.Intersects(offsetSphere))
|
||||
{
|
||||
atLeastOnePoleCollided = true;
|
||||
break;
|
||||
|
|
|
@ -46,7 +46,8 @@ void TestLaraWaterDepth(ItemInfo* item, CollisionInfo* coll);
|
|||
void GetTightropeFallOff(ItemInfo* item, int regularity);
|
||||
#endif
|
||||
|
||||
bool CheckLaraState(LaraState state, std::vector<LaraState> stateList);
|
||||
bool CheckLaraState(LaraState referenceState, const std::vector<LaraState>& stateList);
|
||||
bool CheckLaraWeaponType(LaraWeaponType referenceWeaponType, const std::vector<LaraWeaponType>& weaponTypeList);
|
||||
bool IsStandingWeapon(ItemInfo* item, LaraWeaponType weaponType);
|
||||
bool IsVaultState(LaraState state);
|
||||
bool IsJumpState(LaraState state);
|
||||
|
@ -123,6 +124,6 @@ bool TestLaraCrawlspaceDive(ItemInfo* item, CollisionInfo* coll);
|
|||
|
||||
bool TestLaraTightropeDismount(ItemInfo* item, CollisionInfo* coll);
|
||||
|
||||
bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool up, float offset = 0.0f);
|
||||
bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, float offset = 0.0f);
|
||||
bool TestLaraPoleUp(ItemInfo* item, CollisionInfo* coll);
|
||||
bool TestLaraPoleDown(ItemInfo* item, CollisionInfo* coll);
|
||||
|
|
|
@ -3,22 +3,23 @@
|
|||
|
||||
#include "Game/animation.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/collision/sphere.h"
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/sphere.h"
|
||||
#include "Game/effects/debris.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/effects/simple_particle.h"
|
||||
#include "Game/effects/tomb4fx.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Lara/lara_helpers.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/effects/debris.h"
|
||||
#include "Game/effects/tomb4fx.h"
|
||||
#include "Game/effects/simple_particle.h"
|
||||
#include "Game/pickup/pickup.h"
|
||||
#include "Game/room.h"
|
||||
#include "Renderer/Renderer11.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/trmath.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "ScriptInterfaceGame.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/setup.h"
|
||||
#include "Specific/trmath.h"
|
||||
|
||||
using namespace TEN::Math::Random;
|
||||
using namespace TEN::Renderer;
|
||||
|
@ -27,6 +28,8 @@ BOUNDING_BOX GlobalCollisionBounds;
|
|||
ItemInfo* CollidedItems[MAX_COLLIDED_OBJECTS];
|
||||
MESH_INFO* CollidedMeshes[MAX_COLLIDED_OBJECTS];
|
||||
|
||||
constexpr auto ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD = 6;
|
||||
|
||||
void GenericSphereBoxCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||
{
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
|
@ -38,11 +41,11 @@ void GenericSphereBoxCollision(short itemNumber, ItemInfo* laraItem, CollisionIn
|
|||
int collidedBits = TestCollision(item, laraItem);
|
||||
if (collidedBits)
|
||||
{
|
||||
short oldYOrient = item->Pose.Orientation.y;
|
||||
short prevYOrient = item->Pose.Orientation.y;
|
||||
|
||||
item->Pose.Orientation.y = 0;
|
||||
GetSpheres(item, CreatureSpheres, SPHERES_SPACE_WORLD, Matrix::Identity);
|
||||
item->Pose.Orientation.y = oldYOrient;
|
||||
item->Pose.Orientation.y = prevYOrient;
|
||||
|
||||
int deadlyBits = *((int*)&item->ItemFlags[0]);
|
||||
auto* sphere = &CreatureSpheres[0];
|
||||
|
@ -117,21 +120,22 @@ bool GetCollidedObjects(ItemInfo* collidingItem, int radius, bool onlyVisible, I
|
|||
if (!(mesh->flags & StaticMeshFlags::SM_VISIBLE))
|
||||
continue;
|
||||
|
||||
if (collidingItem->Pose.Position.y + radius + CLICK(0.5f) < mesh->pos.Position.y + bbox->Y1)
|
||||
if ((collidingItem->Pose.Position.y + radius + CLICK(0.5f)) < (mesh->pos.Position.y + bbox->Y1))
|
||||
continue;
|
||||
|
||||
if (collidingItem->Pose.Position.y > mesh->pos.Position.y + bbox->Y2)
|
||||
if (collidingItem->Pose.Position.y > (mesh->pos.Position.y + bbox->Y2))
|
||||
continue;
|
||||
|
||||
float s = phd_sin(mesh->pos.Orientation.y);
|
||||
float c = phd_cos(mesh->pos.Orientation.y);
|
||||
float rx = (collidingItem->Pose.Position.x - mesh->pos.Position.x) * c - s * (collidingItem->Pose.Position.z - mesh->pos.Position.z);
|
||||
float rz = (collidingItem->Pose.Position.z - mesh->pos.Position.z) * c + s * (collidingItem->Pose.Position.x - mesh->pos.Position.x);
|
||||
float sinY = phd_sin(mesh->pos.Orientation.y);
|
||||
float cosY = phd_cos(mesh->pos.Orientation.y);
|
||||
|
||||
if (radius + rx + CLICK(0.5f) < bbox->X1 || rx - radius - CLICK(0.5f) > bbox->X2)
|
||||
float rx = ((collidingItem->Pose.Position.x - mesh->pos.Position.x) * cosY) - ((collidingItem->Pose.Position.z - mesh->pos.Position.z) * sinY);
|
||||
float rz = ((collidingItem->Pose.Position.z - mesh->pos.Position.z) * cosY) + ((collidingItem->Pose.Position.x - mesh->pos.Position.x) * sinY);
|
||||
|
||||
if ((radius + rx + CLICK(0.5f) < bbox->X1) || (rx - radius - CLICK(0.5f) > bbox->X2))
|
||||
continue;
|
||||
|
||||
if (radius + rz + CLICK(0.5f) < bbox->Z1 || rz - radius - CLICK(0.5f) > bbox->Z2)
|
||||
if ((radius + rz + CLICK(0.5f) < bbox->Z1) || (rz - radius - CLICK(0.5f) > bbox->Z2))
|
||||
continue;
|
||||
|
||||
collidedMeshes[numMeshes++] = mesh;
|
||||
|
@ -159,8 +163,8 @@ bool GetCollidedObjects(ItemInfo* collidingItem, int radius, bool onlyVisible, I
|
|||
item->ObjectNumber == ID_LARA && ignoreLara ||
|
||||
item->Flags & 0x8000 ||
|
||||
item->MeshBits == NO_JOINT_BITS ||
|
||||
(Objects[item->ObjectNumber].drawRoutine == NULL && item->ObjectNumber != ID_LARA) ||
|
||||
(Objects[item->ObjectNumber].collision == NULL && item->ObjectNumber != ID_LARA) ||
|
||||
(Objects[item->ObjectNumber].drawRoutine == nullptr && item->ObjectNumber != ID_LARA) ||
|
||||
(Objects[item->ObjectNumber].collision == nullptr && item->ObjectNumber != ID_LARA) ||
|
||||
onlyVisible && item->Status == ITEM_INVISIBLE ||
|
||||
item->ObjectNumber == ID_BURNING_FLOOR)
|
||||
{
|
||||
|
@ -190,14 +194,14 @@ bool GetCollidedObjects(ItemInfo* collidingItem, int radius, bool onlyVisible, I
|
|||
if (dx >= -SECTOR(2) && dx <= SECTOR(2) &&
|
||||
dy >= -SECTOR(2) && dy <= SECTOR(2) &&
|
||||
dz >= -SECTOR(2) && dz <= SECTOR(2) &&
|
||||
collidingItem->Pose.Position.y + radius + CLICK(0.5f) >= item->Pose.Position.y + framePtr->boundingBox.Y1 &&
|
||||
collidingItem->Pose.Position.y - radius - CLICK(0.5f) <= item->Pose.Position.y + framePtr->boundingBox.Y2)
|
||||
(collidingItem->Pose.Position.y + radius + CLICK(0.5f)) >= (item->Pose.Position.y + framePtr->boundingBox.Y1) &&
|
||||
(collidingItem->Pose.Position.y - radius - CLICK(0.5f)) <= (item->Pose.Position.y + framePtr->boundingBox.Y2))
|
||||
{
|
||||
float s = phd_sin(item->Pose.Orientation.y);
|
||||
float c = phd_cos(item->Pose.Orientation.y);
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
float cosY = phd_cos(item->Pose.Orientation.y);
|
||||
|
||||
int rx = dx * c - s * dz;
|
||||
int rz = dz * c + s * dx;
|
||||
int rx = (dx * cosY) - (dz * sinY);
|
||||
int rz = (dz * cosY) + (dx * sinY);
|
||||
|
||||
if (item->ObjectNumber == ID_TURN_SWITCH)
|
||||
{
|
||||
|
@ -207,36 +211,39 @@ bool GetCollidedObjects(ItemInfo* collidingItem, int radius, bool onlyVisible, I
|
|||
framePtr->boundingBox.Z1 = CLICK(1);
|
||||
}
|
||||
|
||||
if (radius + rx + CLICK(0.5f) >= framePtr->boundingBox.X1 && rx - radius - CLICK(0.5f) <= framePtr->boundingBox.X2)
|
||||
if ((radius + rx + CLICK(0.5f)) >= framePtr->boundingBox.X1 &&
|
||||
(rx - radius - CLICK(0.5f)) <= framePtr->boundingBox.X2)
|
||||
{
|
||||
if (radius + rz + CLICK(0.5f) >= framePtr->boundingBox.Z1 && rz - radius - CLICK(0.5f) <= framePtr->boundingBox.Z2)
|
||||
if ((radius + rz + CLICK(0.5f)) >= framePtr->boundingBox.Z1 &&
|
||||
(rz - radius - CLICK(0.5f)) <= framePtr->boundingBox.Z2)
|
||||
{
|
||||
collidedItems[numItems++] = item;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (collidingItem->Pose.Position.y + radius + 128 >= item->Pose.Position.y + framePtr->boundingBox.Y1 &&
|
||||
collidingItem->Pose.Position.y - radius - 128 <= item->Pose.Position.y + framePtr->boundingBox.Y2)
|
||||
if ((collidingItem->Pose.Position.y + radius + CLICK(0.5f)) >= (item->Pose.Position.y + framePtr->boundingBox.Y1) &&
|
||||
(collidingItem->Pose.Position.y - radius - CLICK(0.5f)) <= (item->Pose.Position.y + framePtr->boundingBox.Y2))
|
||||
{
|
||||
float s = phd_sin(item->Pose.Orientation.y);
|
||||
float c = phd_cos(item->Pose.Orientation.y);
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
float cosY = phd_cos(item->Pose.Orientation.y);
|
||||
|
||||
int rx = dx * c - s * dz;
|
||||
int rz = dz * c + s * dx;
|
||||
int rx = (dx * cosY) - (dz * sinY);
|
||||
int rz = (dz * cosY) + (dx * sinY);
|
||||
|
||||
if (item->ObjectNumber == ID_TURN_SWITCH)
|
||||
{
|
||||
framePtr->boundingBox.X1 = -256;
|
||||
framePtr->boundingBox.X2 = 256;
|
||||
framePtr->boundingBox.Z1 = -256;
|
||||
framePtr->boundingBox.Z1 = 256;
|
||||
framePtr->boundingBox.X1 = -CLICK(1);
|
||||
framePtr->boundingBox.X2 = CLICK(1);
|
||||
framePtr->boundingBox.Z1 = -CLICK(1);
|
||||
framePtr->boundingBox.Z1 = CLICK(1);
|
||||
}
|
||||
|
||||
if (radius + rx + 128 >= framePtr->boundingBox.X1 && rx - radius - 128 <= framePtr->boundingBox.X2)
|
||||
if ((radius + rx + CLICK(0.5f)) >= framePtr->boundingBox.X1 &&
|
||||
(rx - radius - CLICK(0.5f)) <= framePtr->boundingBox.X2)
|
||||
{
|
||||
if (radius + rz + 128 >= framePtr->boundingBox.Z1 && rz - radius - 128 <= framePtr->boundingBox.Z2)
|
||||
if ((radius + rz + CLICK(0.5f)) >= framePtr->boundingBox.Z1 &&
|
||||
(rz - radius - CLICK(0.5f)) <= framePtr->boundingBox.Z2)
|
||||
{
|
||||
collidedItems[numItems++] = item;
|
||||
|
||||
|
@ -249,10 +256,11 @@ bool GetCollidedObjects(ItemInfo* collidingItem, int radius, bool onlyVisible, I
|
|||
}
|
||||
|
||||
itemNumber = item->NextItem;
|
||||
} while (itemNumber != NO_ITEM);
|
||||
}
|
||||
while (itemNumber != NO_ITEM);
|
||||
}
|
||||
|
||||
collidedItems[numItems] = NULL;
|
||||
collidedItems[numItems] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,20 +277,22 @@ bool TestWithGlobalCollisionBounds(ItemInfo* item, ItemInfo* laraItem, Collision
|
|||
if (item->Pose.Position.y + GlobalCollisionBounds.Y1 >= framePtr->boundingBox.Y2)
|
||||
return false;
|
||||
|
||||
float s = phd_sin(item->Pose.Orientation.y);
|
||||
float c = phd_cos(item->Pose.Orientation.y);
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
float cosY = phd_cos(item->Pose.Orientation.y);
|
||||
|
||||
int dx = laraItem->Pose.Position.x - item->Pose.Position.x;
|
||||
int dz = laraItem->Pose.Position.z - item->Pose.Position.z;
|
||||
|
||||
int x = c * dx - s * dz;
|
||||
int z = c * dz + s * dx;
|
||||
int x = (dx * cosY) - (dz * sinY);
|
||||
int z = (dz * cosY) + (dx * sinY);
|
||||
|
||||
if (x < GlobalCollisionBounds.X1 - coll->Setup.Radius ||
|
||||
x > GlobalCollisionBounds.X2 + coll->Setup.Radius ||
|
||||
z < GlobalCollisionBounds.Z1 - coll->Setup.Radius ||
|
||||
z > GlobalCollisionBounds.Z2 + coll->Setup.Radius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -294,15 +304,15 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto s = (i != 1) ? phd_sin(coll->Setup.ForwardAngle + ANGLE((i * 90) - 90)) : 0;
|
||||
auto c = (i != 1) ? phd_cos(coll->Setup.ForwardAngle + ANGLE((i * 90) - 90)) : 0;
|
||||
auto sinForwardAngle = (i != 1) ? (phd_sin(coll->Setup.ForwardAngle + ANGLE((i * 90.0f) - 90.0f))) : 0;
|
||||
auto cosForwardAngle = (i != 1) ? (phd_cos(coll->Setup.ForwardAngle + ANGLE((i * 90.0f) - 90.0f))) : 0;
|
||||
|
||||
auto x = item->Pose.Position.x + (s * (coll->Setup.Radius));
|
||||
auto y = item->Pose.Position.y - height - STEP_SIZE;
|
||||
auto z = item->Pose.Position.z + (c * (coll->Setup.Radius));
|
||||
auto x = item->Pose.Position.x + (sinForwardAngle * (coll->Setup.Radius));
|
||||
auto y = item->Pose.Position.y - height - CLICK(1);
|
||||
auto z = item->Pose.Position.z + (cosForwardAngle * (coll->Setup.Radius));
|
||||
|
||||
auto origin = Vector3(x, y, z);
|
||||
auto mxR = Matrix::CreateFromYawPitchRoll(TO_RAD(coll->Setup.ForwardAngle), 0, 0);
|
||||
auto mxR = Matrix::CreateFromYawPitchRoll(TO_RAD(coll->Setup.ForwardAngle), 0.0f, 0.0f);
|
||||
auto direction = (Matrix::CreateTranslation(Vector3::UnitZ) * mxR).Translation();
|
||||
|
||||
// g_Renderer.AddDebugSphere(origin, 16, Vector4::One, RENDERER_DEBUG_PAGE::DIMENSION_STATS);
|
||||
|
@ -312,10 +322,10 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
short itemNumber = g_Level.Rooms[i].itemNumber;
|
||||
while (itemNumber != NO_ITEM)
|
||||
{
|
||||
auto item2 = &g_Level.Items[itemNumber];
|
||||
auto obj = &Objects[item2->ObjectNumber];
|
||||
auto* item2 = &g_Level.Items[itemNumber];
|
||||
auto* object = &Objects[item2->ObjectNumber];
|
||||
|
||||
if (obj->isPickup || obj->collision == nullptr || !item2->Collidable || item2->Status == ITEM_INVISIBLE)
|
||||
if (object->isPickup || object->collision == nullptr || !item2->Collidable || item2->Status == ITEM_INVISIBLE)
|
||||
{
|
||||
itemNumber = item2->NextItem;
|
||||
continue;
|
||||
|
@ -338,7 +348,7 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
for (int j = 0; j < g_Level.Rooms[i].mesh.size(); j++)
|
||||
{
|
||||
auto mesh = &g_Level.Rooms[i].mesh[j];
|
||||
auto* mesh = &g_Level.Rooms[i].mesh[j];
|
||||
|
||||
if (!(mesh->flags & StaticMeshFlags::SM_VISIBLE))
|
||||
continue;
|
||||
|
@ -346,9 +356,9 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
if (phd_Distance(&item->Pose, &mesh->pos) < COLLISION_CHECK_DISTANCE)
|
||||
{
|
||||
auto box = TO_DX_BBOX(mesh->pos, GetBoundsAccurate(mesh, false));
|
||||
float dist;
|
||||
float distance;
|
||||
|
||||
if (box.Intersects(origin, direction, dist) && dist < coll->Setup.Radius * 2)
|
||||
if (box.Intersects(origin, direction, distance) && distance < coll->Setup.Radius * 2)
|
||||
{
|
||||
coll->HitStatic = true;
|
||||
return;
|
||||
|
@ -361,29 +371,29 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
bool TestLaraPosition(OBJECT_COLLISION_BOUNDS* bounds, ItemInfo* item, ItemInfo* laraItem)
|
||||
{
|
||||
auto rotRel = laraItem->Pose.Orientation - item->Pose.Orientation;
|
||||
auto deltaOrient = laraItem->Pose.Orientation - item->Pose.Orientation;
|
||||
|
||||
if (rotRel.x < bounds->rotX1)
|
||||
if (deltaOrient.x < bounds->rotX1)
|
||||
return false;
|
||||
|
||||
if (rotRel.x > bounds->rotX2)
|
||||
if (deltaOrient.x > bounds->rotX2)
|
||||
return false;
|
||||
|
||||
if (rotRel.y < bounds->rotY1)
|
||||
if (deltaOrient.y < bounds->rotY1)
|
||||
return false;
|
||||
|
||||
if (rotRel.y > bounds->rotY2)
|
||||
if (deltaOrient.y > bounds->rotY2)
|
||||
return false;
|
||||
|
||||
if (rotRel.z < bounds->rotZ1)
|
||||
if (deltaOrient.z < bounds->rotZ1)
|
||||
return false;
|
||||
|
||||
if (rotRel.z > bounds->rotZ2)
|
||||
if (deltaOrient.z > bounds->rotZ2)
|
||||
return false;
|
||||
|
||||
auto pos = (laraItem->Pose.Position - item->Pose.Position).ToVector3();
|
||||
|
||||
Matrix matrix = Matrix::CreateFromYawPitchRoll(
|
||||
auto matrix = Matrix::CreateFromYawPitchRoll(
|
||||
TO_RAD(item->Pose.Orientation.y),
|
||||
TO_RAD(item->Pose.Orientation.x),
|
||||
TO_RAD(item->Pose.Orientation.z)
|
||||
|
@ -401,34 +411,35 @@ bool TestLaraPosition(OBJECT_COLLISION_BOUNDS* bounds, ItemInfo* item, ItemInfo*
|
|||
if (pos.x < bounds->boundingBox.X1 || pos.x > bounds->boundingBox.X2 ||
|
||||
pos.y < bounds->boundingBox.Y1 || pos.y > bounds->boundingBox.Y2 ||
|
||||
pos.z < bounds->boundingBox.Z1 || pos.z > bounds->boundingBox.Z2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AlignLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
|
||||
{
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
laraItem->Pose.Orientation = item->Pose.Orientation;
|
||||
|
||||
Matrix matrix = Matrix::CreateFromYawPitchRoll(
|
||||
auto matrix = Matrix::CreateFromYawPitchRoll(
|
||||
TO_RAD(item->Pose.Orientation.y),
|
||||
TO_RAD(item->Pose.Orientation.x),
|
||||
TO_RAD(item->Pose.Orientation.z)
|
||||
);
|
||||
|
||||
Vector3 pos = Vector3::Transform(Vector3(vec->x, vec->y, vec->z), matrix);
|
||||
Vector3 newPos = item->Pose.Position.ToVector3() + pos;
|
||||
auto pos = Vector3::Transform(vec->ToVector3(), matrix);
|
||||
auto newPos = item->Pose.Position.ToVector3() + pos;
|
||||
|
||||
int height = GetCollision(newPos.x, newPos.y, newPos.z, laraItem->RoomNumber).Position.Floor;
|
||||
if ((laraItem->Pose.Position.y - height) <= CLICK(2))
|
||||
{
|
||||
laraItem->Pose.Position.x = newPos.x;
|
||||
laraItem->Pose.Position.y = newPos.y;
|
||||
laraItem->Pose.Position.z = newPos.z;
|
||||
laraItem->Pose.Position = Vector3Int(newPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
if (lara->Control.IsMoving)
|
||||
{
|
||||
lara->Control.IsMoving = false;
|
||||
|
@ -442,9 +453,8 @@ bool MoveLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
|
|||
{
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
auto dest = PHD_3DPOS(item->Pose.Orientation);
|
||||
|
||||
Vector3 pos = Vector3(vec->x, vec->y, vec->z);
|
||||
auto target = PHD_3DPOS(item->Pose.Orientation);
|
||||
auto pos = vec->ToVector3();
|
||||
|
||||
Matrix matrix = Matrix::CreateFromYawPitchRoll(
|
||||
TO_RAD(item->Pose.Orientation.y),
|
||||
|
@ -453,24 +463,23 @@ bool MoveLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
|
|||
);
|
||||
|
||||
pos = Vector3::Transform(pos, matrix);
|
||||
target.Position = item->Pose.Position + Vector3Int(pos);
|
||||
|
||||
dest.Position.x = item->Pose.Position.x + pos.x;
|
||||
dest.Position.y = item->Pose.Position.y + pos.y;
|
||||
dest.Position.z = item->Pose.Position.z + pos.z;
|
||||
if (!Objects[item->ObjectNumber].isPickup)
|
||||
return Move3DPosTo3DPos(&laraItem->Pose, &target, LARA_ALIGN_VELOCITY, ANGLE(2.0f));
|
||||
|
||||
if (item->ObjectNumber != ID_FLARE_ITEM && item->ObjectNumber != ID_BURNING_TORCH_ITEM)
|
||||
return Move3DPosTo3DPos(&laraItem->Pose, &dest, LARA_VELOCITY, ANGLE(2.0f));
|
||||
// Prevent picking up items which can result in so called "flare pickup bug"
|
||||
|
||||
int height = GetCollision(dest.Position.x, dest.Position.y, dest.Position.z, laraItem->RoomNumber).Position.Floor;
|
||||
int height = GetCollision(target.Position.x, target.Position.y, target.Position.z, laraItem->RoomNumber).Position.Floor;
|
||||
if (abs(height - laraItem->Pose.Position.y) <= CLICK(2))
|
||||
{
|
||||
auto direction = dest.Position - laraItem->Pose.Position;
|
||||
auto direction = target.Position - laraItem->Pose.Position;
|
||||
|
||||
float distance = sqrt(pow(direction.x, 2) + pow(direction.y, 2) + pow(direction.z, 2));
|
||||
float distance = sqrt(SQUARE(direction.x) + SQUARE(direction.y) + SQUARE(direction.z));
|
||||
if (distance < CLICK(0.5f))
|
||||
return true;
|
||||
|
||||
return Move3DPosTo3DPos(&laraItem->Pose, &dest, LARA_VELOCITY, ANGLE(2.0f));
|
||||
return Move3DPosTo3DPos(&laraItem->Pose, &target, LARA_ALIGN_VELOCITY, ANGLE(2.0f));
|
||||
}
|
||||
|
||||
if (lara->Control.IsMoving)
|
||||
|
@ -484,20 +493,21 @@ bool MoveLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
|
|||
|
||||
static bool ItemCollide(int value, int radius)
|
||||
{
|
||||
return value >= -radius && value <= radius;
|
||||
return (value >= -radius && value <= radius);
|
||||
}
|
||||
|
||||
static bool ItemInRange(int x, int z, int radius)
|
||||
{
|
||||
return (pow(x, 2) + pow(z, 2)) <= pow(radius, 2);
|
||||
return ((SQUARE(x) + SQUARE(z)) <= SQUARE(radius));
|
||||
}
|
||||
|
||||
bool ItemNearLara(PHD_3DPOS* pos, int radius)
|
||||
{
|
||||
GameVector target;
|
||||
target.x = pos->Position.x - LaraItem->Pose.Position.x;
|
||||
target.y = pos->Position.y - LaraItem->Pose.Position.y;
|
||||
target.z = pos->Position.z - LaraItem->Pose.Position.z;
|
||||
auto target = GameVector(
|
||||
pos->Position.x - LaraItem->Pose.Position.x,
|
||||
pos->Position.y - LaraItem->Pose.Position.y,
|
||||
pos->Position.z - LaraItem->Pose.Position.z
|
||||
);
|
||||
|
||||
if (!ItemCollide(target.y, ITEM_RADIUS_YMAX))
|
||||
return false;
|
||||
|
@ -535,22 +545,24 @@ bool ItemNearTarget(PHD_3DPOS* src, ItemInfo* target, int radius)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Move3DPosTo3DPos(PHD_3DPOS* src, PHD_3DPOS* dest, int velocity, short angleAdd)
|
||||
bool Move3DPosTo3DPos(PHD_3DPOS* origin, PHD_3DPOS* target, int velocity, short angleAdd)
|
||||
{
|
||||
auto direction = dest->Position - src->Position;
|
||||
int distance = sqrt(pow(direction.x, 2) + pow(direction.y, 2) + pow(direction.z, 2));
|
||||
auto direction = target->Position - origin->Position;
|
||||
int distance = sqrt(SQUARE(direction.x) + SQUARE(direction.y) + SQUARE(direction.z));
|
||||
|
||||
if (velocity < distance)
|
||||
src->Position += direction * velocity / distance;
|
||||
origin->Position += direction * velocity / distance;
|
||||
else
|
||||
src->Position = dest->Position;
|
||||
origin->Position = target->Position;
|
||||
|
||||
if (!Lara.Control.IsMoving)
|
||||
{
|
||||
if (Lara.Control.WaterStatus != WaterStatus::Underwater)
|
||||
bool shouldAnimate = (distance - velocity) > (velocity * ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD);
|
||||
|
||||
if (shouldAnimate && Lara.Control.WaterStatus != WaterStatus::Underwater)
|
||||
{
|
||||
int angle = mGetAngle(dest->Position.x, dest->Position.z, src->Position.x, src->Position.z);
|
||||
int direction = (GetQuadrant(angle) - GetQuadrant(dest->Orientation.y)) & 3;
|
||||
int angle = mGetAngle(target->Position.x, target->Position.z, origin->Position.x, origin->Position.z);
|
||||
int direction = (GetQuadrant(angle) - GetQuadrant(target->Orientation.y)) & 3;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
|
@ -581,42 +593,42 @@ bool Move3DPosTo3DPos(PHD_3DPOS* src, PHD_3DPOS* dest, int velocity, short angle
|
|||
Lara.Control.Count.PositionAdjust = 0;
|
||||
}
|
||||
|
||||
short deltaAngle = dest->Orientation.x - src->Orientation.x;
|
||||
short deltaAngle = target->Orientation.x - origin->Orientation.x;
|
||||
if (deltaAngle > angleAdd)
|
||||
src->Orientation.x += angleAdd;
|
||||
origin->Orientation.x += angleAdd;
|
||||
else if (deltaAngle < -angleAdd)
|
||||
src->Orientation.x -= angleAdd;
|
||||
origin->Orientation.x -= angleAdd;
|
||||
else
|
||||
src->Orientation.x = dest->Orientation.x;
|
||||
origin->Orientation.x = target->Orientation.x;
|
||||
|
||||
deltaAngle = dest->Orientation.y - src->Orientation.y;
|
||||
deltaAngle = target->Orientation.y - origin->Orientation.y;
|
||||
if (deltaAngle > angleAdd)
|
||||
src->Orientation.y += angleAdd;
|
||||
origin->Orientation.y += angleAdd;
|
||||
else if (deltaAngle < -angleAdd)
|
||||
src->Orientation.y -= angleAdd;
|
||||
origin->Orientation.y -= angleAdd;
|
||||
else
|
||||
src->Orientation.y = dest->Orientation.y;
|
||||
origin->Orientation.y = target->Orientation.y;
|
||||
|
||||
deltaAngle = dest->Orientation.z - src->Orientation.z;
|
||||
deltaAngle = target->Orientation.z - origin->Orientation.z;
|
||||
if (deltaAngle > angleAdd)
|
||||
src->Orientation.z += angleAdd;
|
||||
origin->Orientation.z += angleAdd;
|
||||
else if (deltaAngle < -angleAdd)
|
||||
src->Orientation.z -= angleAdd;
|
||||
origin->Orientation.z -= angleAdd;
|
||||
else
|
||||
src->Orientation.z = dest->Orientation.z;
|
||||
origin->Orientation.z = target->Orientation.z;
|
||||
|
||||
return (src->Position == dest->Position && src->Orientation == dest->Orientation);
|
||||
return (origin->Position == target->Position && origin->Orientation == target->Orientation);
|
||||
}
|
||||
|
||||
bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius)
|
||||
{
|
||||
auto bounds = (BOUNDING_BOX*)GetBestFrame(item);
|
||||
auto laraBounds = (BOUNDING_BOX*)GetBestFrame(laraItem);
|
||||
auto* bounds = (BOUNDING_BOX*)GetBestFrame(item);
|
||||
auto* laraBounds = (BOUNDING_BOX*)GetBestFrame(laraItem);
|
||||
|
||||
if (item->Pose.Position.y + bounds->Y2 <= laraItem->Pose.Position.y + laraBounds->Y1)
|
||||
if ((item->Pose.Position.y + bounds->Y2) <= (laraItem->Pose.Position.y + laraBounds->Y1))
|
||||
return false;
|
||||
|
||||
if (item->Pose.Position.y + bounds->Y1 >= laraItem->Pose.Position.y + laraBounds->Y2)
|
||||
if ((item->Pose.Position.y + bounds->Y1) >= (laraItem->Pose.Position.y + laraBounds->Y2))
|
||||
return false;
|
||||
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
|
@ -671,19 +683,20 @@ bool TestBoundsCollideStatic(ItemInfo* item, MESH_INFO* mesh, int radius)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spasmEnabled, char bigPush) // previously ItemPushLara
|
||||
// NOTE: Previously ItemPushLara().
|
||||
bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spasmEnabled, char bigPush)
|
||||
{
|
||||
// Get item's rotation
|
||||
// Get item's rotation.
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
float cosY = phd_cos(item->Pose.Orientation.y);
|
||||
|
||||
// Get vector from item to Lara
|
||||
// Get vector from item to Lara.
|
||||
int dx = item2->Pose.Position.x - item->Pose.Position.x;
|
||||
int dz = item2->Pose.Position.z - item->Pose.Position.z;
|
||||
|
||||
// Rotate Lara vector into item frame
|
||||
int rx = cosY * dx - sinY * dz;
|
||||
int rz = cosY * dz + sinY * dx;
|
||||
// Rotate Lara vector into item frame.
|
||||
int rx = (dx * cosY) - (dz * sinY);
|
||||
int rz = (dz * cosY) + (dx * sinY);
|
||||
|
||||
BOUNDING_BOX* bounds;
|
||||
if (bigPush & 2)
|
||||
|
@ -731,13 +744,13 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa
|
|||
|
||||
auto* lara = item2->IsLara() ? GetLaraInfo(item2) : nullptr;
|
||||
|
||||
if (lara != nullptr && spasmEnabled && bounds->Y2 - bounds->Y1 > CLICK(1))
|
||||
if (lara != nullptr && spasmEnabled && (bounds->Y2 - bounds->Y1) > CLICK(1))
|
||||
{
|
||||
rx = (bounds->X1 + bounds->X2) / 2;
|
||||
rz = (bounds->Z1 + bounds->Z2) / 2;
|
||||
|
||||
dx -= cosY * rx + sinY * rz;
|
||||
dz -= cosY * rz - sinY * rx;
|
||||
dx -= (rx * cosY) + (rz * sinY);
|
||||
dz -= (rz * cosY) - (rx * sinY);
|
||||
|
||||
lara->HitDirection = (item2->Pose.Orientation.y - phd_atan(dz, dz) - ANGLE(135.0f)) / ANGLE(90.0f);
|
||||
DoDamage(item2, 0); // Dummy hurt call. Only for ooh sound!
|
||||
|
@ -862,7 +875,7 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
for (int j = 0; j < g_Level.Rooms[i].mesh.size(); j++)
|
||||
{
|
||||
auto mesh = &g_Level.Rooms[i].mesh[j];
|
||||
auto* mesh = &g_Level.Rooms[i].mesh[j];
|
||||
|
||||
// Only process meshes which are visible and solid
|
||||
if ((mesh->flags & StaticMeshFlags::SM_VISIBLE) && (mesh->flags & StaticMeshFlags::SM_SOLID))
|
||||
|
@ -911,7 +924,7 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
|
||||
// Calculate vertical item coll bounds according to either height (land mode) or precise bounds (water mode).
|
||||
// Water mode needs special processing because height calc in original engines is inconsistent in such cases.
|
||||
if (g_Level.Rooms[item->RoomNumber].flags & ENV_FLAG_WATER)
|
||||
if (TestEnvironment(ENV_FLAG_WATER, item))
|
||||
{
|
||||
collBox.Y1 = itemBBox->Y1;
|
||||
collBox.Y2 = itemBBox->Y2;
|
||||
|
@ -1022,13 +1035,13 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
|
||||
// Determine identity rotation/distance
|
||||
auto distance = Vector3(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z);
|
||||
auto c = phd_cos(pos.Orientation.y);
|
||||
auto s = phd_sin(pos.Orientation.y);
|
||||
auto sinY = phd_sin(pos.Orientation.y);
|
||||
auto cosY = phd_cos(pos.Orientation.y);
|
||||
|
||||
// Rotate item to collision bounds identity
|
||||
auto x = round(distance.x * c - distance.z * s) + pos.Position.x;
|
||||
auto x = round(distance.x * cosY - distance.z * sinY) + pos.Position.x;
|
||||
auto y = item->Pose.Position.y;
|
||||
auto z = round(distance.x * s + distance.z * c) + pos.Position.z;
|
||||
auto z = round(distance.x * sinY + distance.z * cosY) + pos.Position.z;
|
||||
|
||||
// Determine identity static collision bounds
|
||||
auto XMin = pos.Position.x + box->X1;
|
||||
|
@ -1074,8 +1087,8 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
|
||||
// Rotate previous collision position to identity
|
||||
distance = Vector3(coll->Setup.OldPosition.x, coll->Setup.OldPosition.y, coll->Setup.OldPosition.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z);
|
||||
auto ox = round(distance.x * c - distance.z * s) + pos.Position.x;
|
||||
auto oz = round(distance.x * s + distance.z * c) + pos.Position.z;
|
||||
auto ox = round(distance.x * cosY - distance.z * sinY) + pos.Position.x;
|
||||
auto oz = round(distance.x * sinY + distance.z * cosY) + pos.Position.z;
|
||||
|
||||
// Calculate collisison type based on identity rotation
|
||||
switch (GetQuadrant(coll->Setup.ForwardAngle - pos.Orientation.y))
|
||||
|
@ -1171,12 +1184,12 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
|
||||
// Determine final shifts rotation/distance
|
||||
distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z);
|
||||
c = phd_cos(-pos.Orientation.y);
|
||||
s = phd_sin(-pos.Orientation.y);
|
||||
sinY = phd_sin(-pos.Orientation.y);
|
||||
cosY = phd_cos(-pos.Orientation.y);
|
||||
|
||||
// Calculate final shifts rotation/distance
|
||||
coll->Shift.x = (round(distance.x * c - distance.z * s) + pos.Position.x) - item->Pose.Position.x;
|
||||
coll->Shift.z = (round(distance.x * s + distance.z * c) + pos.Position.z) - item->Pose.Position.z;
|
||||
coll->Shift.x = (round(distance.x * cosY - distance.z * sinY) + pos.Position.x) - item->Pose.Position.x;
|
||||
coll->Shift.z = (round(distance.x * sinY + distance.z * cosY) + pos.Position.z) - item->Pose.Position.z;
|
||||
|
||||
if (coll->Shift.x == 0 && coll->Shift.z == 0)
|
||||
coll->CollisionType = CT_NONE; // Paranoid
|
||||
|
@ -1188,13 +1201,12 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
return true;
|
||||
}
|
||||
|
||||
void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, int zv) // previously DoProperDetection
|
||||
// NOTE: Previously DoProperDetection().
|
||||
void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, int zv)
|
||||
{
|
||||
int bs, yAngle;
|
||||
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
|
||||
auto oldCollResult = GetCollision(x, y, z, item->RoomNumber);
|
||||
auto prevCollResult = GetCollision(x, y, z, item->RoomNumber);
|
||||
auto collResult = GetCollision(item);
|
||||
|
||||
auto* bounds = GetBoundsAccurate(item);
|
||||
|
@ -1204,11 +1216,12 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
|
||||
if (item->Pose.Position.y >= collResult.Position.Floor)
|
||||
{
|
||||
bs = 0;
|
||||
int bs = 0;
|
||||
|
||||
if (collResult.Position.FloorSlope && oldCollResult.Position.Floor < collResult.Position.Floor)
|
||||
if (collResult.Position.FloorSlope && prevCollResult.Position.Floor < collResult.Position.Floor)
|
||||
{
|
||||
yAngle = (long)((unsigned short)item->Pose.Orientation.y);
|
||||
int yAngle = (long)((unsigned short)item->Pose.Orientation.y);
|
||||
|
||||
if (collResult.FloorTilt.x < 0)
|
||||
{
|
||||
if (yAngle >= ANGLE(180.0f))
|
||||
|
@ -1601,7 +1614,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (yv >= 0)
|
||||
{
|
||||
oldCollResult = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber);
|
||||
prevCollResult = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber);
|
||||
collResult = GetCollision(item);
|
||||
|
||||
// Bounce off floor.
|
||||
|
@ -1610,7 +1623,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
// was always set to 0 by GetHeight() function which was called before the check.
|
||||
// Possibly a mistake or unfinished feature by Core? -- Lwmte, 27.08.21
|
||||
|
||||
if (item->Pose.Position.y >= oldCollResult.Position.Floor)
|
||||
if (item->Pose.Position.y >= prevCollResult.Position.Floor)
|
||||
{
|
||||
// Hit the floor; bounce and slow down.
|
||||
if (item->Animation.Velocity.y > 0)
|
||||
|
@ -1644,7 +1657,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
item->Pose.Position.y = oldCollResult.Position.Floor;
|
||||
item->Pose.Position.y = prevCollResult.Position.Floor;
|
||||
}
|
||||
}
|
||||
// else
|
||||
|
@ -1709,10 +1722,10 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
laraItem->HitStatus = false;
|
||||
coll->HitStatic = false;
|
||||
|
||||
bool playerCollision = laraItem->IsLara();
|
||||
bool harmless = !playerCollision && (laraItem->Data.is<KayakInfo>() || laraItem->Data.is<UPVInfo>());
|
||||
bool doPlayerCollision = laraItem->IsLara();
|
||||
bool harmless = !doPlayerCollision && (laraItem->Data.is<KayakInfo>() || laraItem->Data.is<UPVInfo>());
|
||||
|
||||
if (playerCollision)
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
GetLaraInfo(laraItem)->HitDirection = -1;
|
||||
|
||||
|
@ -1751,7 +1764,7 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
if (phd_Distance(&item->Pose, &laraItem->Pose) >= COLLISION_CHECK_DISTANCE)
|
||||
continue;
|
||||
|
||||
if (playerCollision)
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
// Objects' own collision routines were almost universally written only for
|
||||
// managing collisions with Lara and nothing else. Until all of these routines
|
||||
|
@ -1810,7 +1823,7 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
|
||||
// For Lara, solid static mesh collisions are directly managed by GetCollisionInfo,
|
||||
// so we bypass them here to avoid interference.
|
||||
if (playerCollision && (mesh->flags & StaticMeshFlags::SM_SOLID))
|
||||
if (doPlayerCollision && (mesh->flags & StaticMeshFlags::SM_SOLID))
|
||||
continue;
|
||||
|
||||
if (phd_Distance(&mesh->pos, &laraItem->Pose) >= COLLISION_CHECK_DISTANCE)
|
||||
|
@ -1822,7 +1835,7 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
coll->HitStatic = true;
|
||||
|
||||
// HACK: Shatter statics only by non-harmless vehicles.
|
||||
if (!playerCollision &&
|
||||
if (!doPlayerCollision &&
|
||||
!harmless && abs(laraItem->Animation.Velocity.z) > VEHICLE_COLLISION_TERMINAL_VELOCITY &&
|
||||
StaticObjects[mesh->staticNumber].shatterType != SHT_NONE)
|
||||
{
|
||||
|
@ -1840,7 +1853,7 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
}
|
||||
}
|
||||
|
||||
if (playerCollision)
|
||||
if (doPlayerCollision)
|
||||
{
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
if (lara->HitDirection == -1)
|
||||
|
@ -1880,14 +1893,12 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll
|
|||
if (!TestCollision(item, laraItem))
|
||||
return;
|
||||
|
||||
bool playerCollision = laraItem->IsLara();
|
||||
bool waterPlayerCollision = playerCollision && GetLaraInfo(laraItem)->Control.WaterStatus >= WaterStatus::TreadWater;
|
||||
bool doPlayerCollision = laraItem->IsLara();
|
||||
bool waterPlayerCollision = doPlayerCollision && GetLaraInfo(laraItem)->Control.WaterStatus >= WaterStatus::TreadWater;
|
||||
|
||||
if (waterPlayerCollision || coll->Setup.EnableObjectPush)
|
||||
{
|
||||
ItemPushItem(item, laraItem, coll, coll->Setup.EnableSpasm, 0);
|
||||
}
|
||||
else if (playerCollision && coll->Setup.EnableSpasm)
|
||||
else if (doPlayerCollision && coll->Setup.EnableSpasm)
|
||||
{
|
||||
int x = laraItem->Pose.Position.x - item->Pose.Position.x;
|
||||
int z = laraItem->Pose.Position.z - item->Pose.Position.z;
|
||||
|
@ -1901,10 +1912,10 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll
|
|||
|
||||
if (frame->boundingBox.Height() > STEP_SIZE)
|
||||
{
|
||||
int angle = (laraItem->Pose.Orientation.y - phd_atan(z - cosY * rx - sinY * rz, x - cosY * rx + sinY * rz) - ANGLE(135.0f)) / ANGLE(90.0f);
|
||||
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
int angle = (laraItem->Pose.Orientation.y - phd_atan(z - cosY * rx - sinY * rz, x - cosY * rx + sinY * rz) - ANGLE(135.0f)) / ANGLE(90.0f);
|
||||
|
||||
lara->HitDirection = (short)angle;
|
||||
|
||||
// TODO: check if a second Lara.hitFrame++; is required there !
|
||||
|
|
|
@ -333,7 +333,7 @@ int ObjectOnLOS2(GameVector* start, GameVector* end, Vector3Int* vec, MESH_INFO*
|
|||
if ((priorityObject != GAME_OBJECT_ID::ID_NO_OBJECT) && (item->ObjectNumber != priorityObject))
|
||||
continue;
|
||||
|
||||
if ((item->ObjectNumber != ID_LARA) && (Objects[item->ObjectNumber].collision == NULL))
|
||||
if ((item->ObjectNumber != ID_LARA) && (Objects[item->ObjectNumber].collision == nullptr))
|
||||
continue;
|
||||
|
||||
if ((item->ObjectNumber == ID_LARA) && (priorityObject != ID_LARA))
|
||||
|
|
|
@ -1,122 +1,157 @@
|
|||
#include "framework.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Objects/Generic/Object/polerope.h"
|
||||
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/sphere.h"
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/control/lot.h"
|
||||
#include "Specific/input.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Lara/lara_helpers.h"
|
||||
#include "Game/Lara/lara_struct.h"
|
||||
#include "Game/Lara/lara_tests.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Specific/input.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/trmath.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/collision/sphere.h"
|
||||
|
||||
using namespace TEN::Input;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::Generic
|
||||
{
|
||||
Vector3Int PolePos = { 0, 0, -208 };
|
||||
Vector3Int PolePosR = { 0, 0, 0 };
|
||||
|
||||
OBJECT_COLLISION_BOUNDS PoleBounds =
|
||||
const vector<LaraState> VPoleMountedStates =
|
||||
{
|
||||
-256, 256,
|
||||
LS_POLE_IDLE,
|
||||
LS_POLE_UP,
|
||||
LS_POLE_DOWN,
|
||||
LS_POLE_TURN_CLOCKWISE,
|
||||
LS_POLE_TURN_COUNTER_CLOCKWISE
|
||||
};
|
||||
const vector<LaraState> VPoleGroundedMountStates =
|
||||
{
|
||||
LS_IDLE,
|
||||
LS_TURN_LEFT_SLOW,
|
||||
LS_TURN_RIGHT_SLOW,
|
||||
LS_TURN_LEFT_FAST,
|
||||
LS_TURN_RIGHT_FAST,
|
||||
LS_WALK_FORWARD,
|
||||
LS_RUN_FORWARD
|
||||
};
|
||||
const vector<LaraState> VPoleAirborneMountStates =
|
||||
{
|
||||
LS_REACH,
|
||||
LS_JUMP_UP
|
||||
};
|
||||
|
||||
// TODO: These might be interfering with the SetPosition command. -- Sezz 2022.08.29
|
||||
auto VPolePos = Vector3Int(0, 0, -208);
|
||||
auto VPolePosR = Vector3Int::Zero;
|
||||
|
||||
OBJECT_COLLISION_BOUNDS VPoleBounds =
|
||||
{
|
||||
-CLICK(1), CLICK(1),
|
||||
0, 0,
|
||||
-512, 512,
|
||||
-ANGLE(10.0f), ANGLE(10.0f),
|
||||
-ANGLE(30.0f), ANGLE(30.0f),
|
||||
-ANGLE(10.0f), ANGLE(10.0f)
|
||||
-CLICK(2), CLICK(2),
|
||||
ANGLE(-10.0f), ANGLE(10.0f),
|
||||
ANGLE(-30.0f), ANGLE(30.0f),
|
||||
ANGLE(-10.0f), ANGLE(10.0f)
|
||||
};
|
||||
|
||||
void PoleCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||
{
|
||||
auto* laraInfo = GetLaraInfo(laraItem);
|
||||
auto* poleItem = &g_Level.Items[itemNumber];
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
bool isLara = !poleItem->IsLara();
|
||||
bool isFacingPole = IsPointInFront(laraItem->Pose, poleItem->Pose.Position.ToVector3());
|
||||
|
||||
if (TrInput & IN_ACTION && isLara &&
|
||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||
laraItem->Animation.ActiveState == LS_IDLE &&
|
||||
laraItem->Animation.AnimNumber == LA_STAND_IDLE || laraInfo->Control.IsMoving &&
|
||||
laraInfo->InteractedItem == itemNumber)
|
||||
// Mount while grounded.
|
||||
if (TrInput & IN_ACTION && isFacingPole &&
|
||||
CheckLaraState((LaraState)laraItem->Animation.ActiveState, VPoleGroundedMountStates) &&
|
||||
lara->Control.HandStatus == HandStatus::Free ||
|
||||
(lara->Control.IsMoving && lara->InteractedItem == itemNumber))
|
||||
{
|
||||
short rot = poleItem->Pose.Orientation.y;
|
||||
// Temporarily reorient pole.
|
||||
short yOrient = poleItem->Pose.Orientation.y;
|
||||
poleItem->Pose.Orientation.y = laraItem->Pose.Orientation.y;
|
||||
|
||||
if (TestLaraPosition(&PoleBounds, poleItem, laraItem))
|
||||
if (TestLaraPosition(&VPoleBounds, poleItem, laraItem))
|
||||
{
|
||||
if (MoveLaraPosition(&PolePos, poleItem, laraItem))
|
||||
if (MoveLaraPosition(&VPolePos, poleItem, laraItem))
|
||||
{
|
||||
laraItem->Animation.AnimNumber = LA_STAND_TO_POLE;
|
||||
laraItem->Animation.ActiveState = LS_POLE_IDLE;
|
||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||
laraInfo->Control.IsMoving = false;
|
||||
laraInfo->Control.HandStatus = HandStatus::Busy;
|
||||
SetAnimation(laraItem, LA_STAND_TO_POLE);
|
||||
lara->Control.IsMoving = false;
|
||||
lara->Control.HandStatus = HandStatus::Busy;
|
||||
}
|
||||
else
|
||||
laraInfo->InteractedItem = itemNumber;
|
||||
lara->InteractedItem = itemNumber;
|
||||
|
||||
poleItem->Pose.Orientation.y = rot;
|
||||
poleItem->Pose.Orientation.y = yOrient;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
||||
if (lara->Control.IsMoving && lara->InteractedItem == itemNumber)
|
||||
{
|
||||
laraInfo->Control.IsMoving = false;
|
||||
laraInfo->Control.HandStatus = HandStatus::Free;
|
||||
lara->Control.IsMoving = false;
|
||||
lara->Control.HandStatus = HandStatus::Free;
|
||||
}
|
||||
|
||||
poleItem->Pose.Orientation.y = rot;
|
||||
poleItem->Pose.Orientation.y = yOrient;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (TrInput & IN_ACTION && isLara &&
|
||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||
laraItem->Animation.IsAirborne &&
|
||||
laraItem->Animation.Velocity.y > (int)laraInfo->Control.HandStatus && // ?????
|
||||
laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP)
|
||||
|
||||
// Mount while airborne.
|
||||
if (TrInput & IN_ACTION && isFacingPole &&
|
||||
CheckLaraState((LaraState)laraItem->Animation.ActiveState, VPoleAirborneMountStates) &&
|
||||
laraItem->Animation.IsAirborne &&
|
||||
laraItem->Animation.Velocity.y > 0.0f &&
|
||||
lara->Control.HandStatus == HandStatus::Free)
|
||||
{
|
||||
if (TestBoundsCollide(poleItem, laraItem, 100) &&
|
||||
TestLaraPoleCollision(laraItem, coll, true, -CLICK(1)) &&
|
||||
TestLaraPoleCollision(laraItem, coll, false))
|
||||
// Test sphere collision.
|
||||
if (!TestLaraPoleCollision(laraItem, coll, true, -CLICK(1)) || !TestLaraPoleCollision(laraItem, coll, false))
|
||||
return;
|
||||
|
||||
// Test bounds collision.
|
||||
if (TestBoundsCollide(poleItem, laraItem, LARA_RADIUS + (int)round(abs(laraItem->Animation.Velocity.z))))
|
||||
{
|
||||
if (TestCollision(poleItem, laraItem))
|
||||
{
|
||||
short rot = poleItem->Pose.Orientation.y;
|
||||
// Temporarily reorient pole.
|
||||
short yOrient = poleItem->Pose.Orientation.y;
|
||||
poleItem->Pose.Orientation.y = laraItem->Pose.Orientation.y;
|
||||
|
||||
// Reaching.
|
||||
if (laraItem->Animation.ActiveState == LS_REACH)
|
||||
{
|
||||
PolePosR.y = laraItem->Pose.Position.y - poleItem->Pose.Position.y + 10;
|
||||
AlignLaraPosition(&PolePosR, poleItem, laraItem);
|
||||
laraItem->Animation.AnimNumber = LA_REACH_TO_POLE;
|
||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||
VPolePosR.y = laraItem->Pose.Position.y - poleItem->Pose.Position.y + 10;
|
||||
AlignLaraPosition(&VPolePosR, poleItem, laraItem);
|
||||
SetAnimation(laraItem, LA_REACH_TO_POLE);
|
||||
}
|
||||
// Jumping up.
|
||||
else
|
||||
{
|
||||
PolePosR.y = laraItem->Pose.Position.y - poleItem->Pose.Position.y + 66;
|
||||
AlignLaraPosition(&PolePosR, poleItem, laraItem);
|
||||
laraItem->Animation.AnimNumber = LA_JUMP_UP_TO_POLE;
|
||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||
VPolePosR.y = laraItem->Pose.Position.y - poleItem->Pose.Position.y + 66;
|
||||
AlignLaraPosition(&VPolePosR, poleItem, laraItem);
|
||||
SetAnimation(laraItem, LA_JUMP_UP_TO_POLE);
|
||||
}
|
||||
|
||||
laraItem->Animation.ActiveState = LS_POLE_IDLE;
|
||||
laraItem->Animation.Velocity.y = 0;
|
||||
laraItem->Animation.IsAirborne = false;
|
||||
laraInfo->Control.HandStatus = HandStatus::Busy;
|
||||
poleItem->Pose.Orientation.y = rot;
|
||||
laraItem->Animation.Velocity.y = 0.0f;
|
||||
lara->Control.HandStatus = HandStatus::Busy;
|
||||
poleItem->Pose.Orientation.y = yOrient;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// Player is not interacting with vertical pole; do regular object collision.
|
||||
if (!CheckLaraState((LaraState)laraItem->Animation.ActiveState, VPoleMountedStates) &&
|
||||
laraItem->Animation.ActiveState != LS_JUMP_BACK)
|
||||
{
|
||||
if (!isLara || ((laraItem->Animation.ActiveState < LS_POLE_IDLE ||
|
||||
laraItem->Animation.ActiveState > LS_POLE_TURN_COUNTER_CLOCKWISE) &&
|
||||
laraItem->Animation.ActiveState != LS_JUMP_BACK))
|
||||
{
|
||||
ObjectCollision(itemNumber, laraItem, coll);
|
||||
}
|
||||
ObjectCollision(itemNumber, laraItem, coll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
struct ItemInfo;
|
||||
struct CollisionInfo;
|
||||
struct ItemInfo;
|
||||
|
||||
namespace TEN::Entities::Generic
|
||||
{
|
||||
|
|
|
@ -461,6 +461,7 @@ void StartTraps()
|
|||
object->saveFlags = true;
|
||||
object->savePosition = true;
|
||||
object->usingDrawAnimatingItem = true;
|
||||
object->isPickup = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ struct Vector3Int
|
|||
this->z = int(v.z);
|
||||
}
|
||||
|
||||
Vector3 ToVector3()
|
||||
Vector3 ToVector3() const
|
||||
{
|
||||
return Vector3(x, y, z);
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ struct Vector3Shrt
|
|||
this->z = z;
|
||||
}
|
||||
|
||||
Vector3 ToVector3()
|
||||
Vector3 ToVector3() const
|
||||
{
|
||||
return Vector3(x, y, z);
|
||||
}
|
||||
|
|
|
@ -399,3 +399,24 @@ Vector3Int TranslateVector(Vector3Int& vector, Vector3& direction, float distanc
|
|||
(int)round(newVector.z)
|
||||
);
|
||||
}
|
||||
|
||||
bool IsPointInFront(const PHD_3DPOS& pose, const Vector3& target)
|
||||
{
|
||||
return IsPointInFront(pose.Position.ToVector3(), target, pose.Orientation);
|
||||
}
|
||||
|
||||
bool IsPointInFront(const Vector3& origin, const Vector3& target, const Vector3Shrt& orient)
|
||||
{
|
||||
float sinY = phd_sin(orient.y);
|
||||
float cosY = phd_cos(orient.y);
|
||||
|
||||
// The heading angle (Y only) direction vector: X = +sinY, Y = 0, Z = +cosY
|
||||
auto headingDirection = Vector3(sinY, 0.0f, cosY);
|
||||
auto targetDirection = target - origin;
|
||||
|
||||
float dot = headingDirection.Dot(targetDirection);
|
||||
if (dot > 0.0f)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -82,3 +82,5 @@ Vector3 TranslateVector(Vector3& vector, Vector3Shrt& orient, float distance);
|
|||
Vector3Int TranslateVector(Vector3Int& vector, Vector3Shrt& orient, float distance);
|
||||
Vector3 TranslateVector(Vector3& vector, Vector3& direction, float distance);
|
||||
Vector3Int TranslateVector(Vector3Int& vector, Vector3& direction, float distance);
|
||||
bool IsPointInFront(const PHD_3DPOS& pose, const Vector3& target);
|
||||
bool IsPointInFront(const Vector3& origin, const Vector3& target, const Vector3Shrt& orient);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue