Dynamic bridge collision (#1137)

* Initial commit

* Don't update bridge offset if not necessary

* Don't stick to bridge when in air

* Update Changes.txt

* Minor simplification

* Simplify

* Update collide_room.h

* Update collide_room.h

* Use real floor height to determine bridge collision

* Detect bridges first to avoid potential issues with item init

* Remove incorrect forward declaration

* Move pickups on dynamic bridges

* Push player away from moving bridges

* Update Changes.txt

* Use actual pickup bounds for collision detection

* Stabilize collision by using both abs Y and bb Y ref points

* Update collide_item.cpp

* Swap function parameters

* Update collide_room.cpp

* Increase movement tolerance

---------

Co-authored-by: Sezz <sezzary@outlook.com>
Co-authored-by: Jakub <80340234+Kubsy@users.noreply.github.com>
This commit is contained in:
Lwmte 2023-06-17 12:52:02 +03:00 committed by GitHub
parent ba368be4b7
commit 35304ce84a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 223 additions and 77 deletions

View file

@ -14,6 +14,8 @@ Version 1.1.0
* Add multiple doppelgangers by using the same OCB for the origin nullmesh and doppelganger.
* Pause all sounds when entering inventory or pause menu.
* Improve deflection against slopes.
* Move and rotate Lara together with dynamic bridge objects.
* Move and rotate activated pickups together with dynamic bridge objects.
* Add TR1 skateboard kid.
* Add TR1 Kold.

View file

@ -48,6 +48,10 @@ bool LaraDeflectEdge(ItemInfo* item, CollisionInfo* coll)
ShiftItem(item, coll);
item->Pose.Orientation.y -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
}
else if (coll->LastBridgeItemNumber != NO_ITEM)
{
ShiftItem(item, coll);
}
return false;
}
@ -202,8 +206,8 @@ bool LaraDeflectEdgeCrawl(ItemInfo* item, CollisionInfo* coll)
bool LaraDeflectEdgeMonkey(ItemInfo* item, CollisionInfo* coll)
{
// HACK
if (coll->Shift.y >= 0 && coll->Shift.y <= CLICK(1.25f))
coll->Shift.y = 0;
if (coll->Shift.Position.y >= 0 && coll->Shift.Position.y <= CLICK(1.25f))
coll->Shift.Position.y = 0;
if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT ||
coll->HitTallObject)

View file

@ -140,8 +140,8 @@ void lara_col_monkey_idle(ItemInfo* item, CollisionInfo* coll)
GetCollisionInfo(coll, item);
// HACK: Prevent ShiftItem() from causing an instantaneous snap, thereby interfering with DoLaraMonkeyStep(), when going down a step. @Sezz 2022.01.28
if (coll->Shift.y >= 0 && coll->Shift.y <= CLICK(1.25f))
coll->Shift.y = 0;
if (coll->Shift.Position.y >= 0 && coll->Shift.Position.y <= CLICK(1.25f))
coll->Shift.Position.y = 0;
ShiftItem(item, coll);
if (TestLaraMonkeyFall(item, coll))

View file

@ -250,9 +250,9 @@ bool TestLaraHang(ItemInfo* item, CollisionInfo* coll)
else // Death, incorrect ledge or ACTION release
{
SetAnimation(item, LA_JUMP_UP, 9);
item->Pose.Position.x += coll->Shift.x;
item->Pose.Position.x += coll->Shift.Position.x;
item->Pose.Position.y += GameBoundingBox(item).Y2 * 1.8f;
item->Pose.Position.z += coll->Shift.z;
item->Pose.Position.z += coll->Shift.Position.z;
item->Animation.IsAirborne = true;
item->Animation.Velocity.z = 2;
item->Animation.Velocity.y = 1;
@ -472,12 +472,12 @@ bool TestLaraHangOnClimbableWall(ItemInfo* item, CollisionInfo* coll)
{
case NORTH:
case SOUTH:
item->Pose.Position.z += coll2.Shift.z;
item->Pose.Position.z += coll2.Shift.Position.z;
break;
case EAST:
case WEST:
item->Pose.Position.x += coll2.Shift.x;
item->Pose.Position.x += coll2.Shift.Position.x;
break;
default:

View file

@ -753,6 +753,54 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool ena
return true;
}
// Simplified version of ItemPushItem for basic pushes.
bool ItemPushItem(ItemInfo* item, ItemInfo* item2)
{
float sinY = phd_sin(item->Pose.Orientation.y);
float cosY = phd_cos(item->Pose.Orientation.y);
// Get direction vector from item to player.
auto direction = item2->Pose.Position - item->Pose.Position;
// Rotate Lara vector into item frame.
int rx = (direction.x * cosY) - (direction.z * sinY);
int rz = (direction.z * cosY) + (direction.x * sinY);
const auto& bounds = GetBestFrame(*item).BoundingBox;
int minX = bounds.X1;
int maxX = bounds.X2;
int minZ = bounds.Z1;
int maxZ = bounds.Z2;
// Big enemies
if (abs(direction.x) > BLOCK(4.5f) || abs(direction.z) > BLOCK(4.5f) ||
rx <= minX || rx >= maxX ||
rz <= minZ || rz >= maxZ)
{
return false;
}
int left = rx - minX;
int top = maxZ - rz;
int bottom = rz - minZ;
int right = maxX - rx;
if (right <= left && right <= top && right <= bottom)
rx += right;
else if (left <= right && left <= top && left <= bottom)
rx -= left;
else if (top <= left && top <= right && top <= bottom)
rz += top;
else
rz -= bottom;
item2->Pose.Position.x = item->Pose.Position.x + (rx * cosY) + (rz * sinY);
item2->Pose.Position.z = item->Pose.Position.z + (rz * cosY) - (rx * sinY);
return true;
}
// NOTE: Previously ItemPushLaraStatic().
bool ItemPushStatic(ItemInfo* item, const MESH_INFO& mesh, CollisionInfo* coll)
{
@ -828,6 +876,62 @@ bool ItemPushStatic(ItemInfo* item, const MESH_INFO& mesh, CollisionInfo* coll)
return true;
}
void ItemPushBridge(ItemInfo& item, CollisionInfo& coll)
{
coll.Setup.ForwardAngle = item.Pose.Orientation.y;
coll.Setup.OldPosition = item.Pose.Position;
GetCollisionInfo(&coll, &item);
ShiftItem(&item, &coll);
}
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResult& collResult)
{
// Store an offset for a bridge item into shifts, if exists.
if (coll.LastBridgeItemNumber == collResult.Position.Bridge && coll.LastBridgeItemNumber != NO_ITEM)
{
auto& bridgeItem = g_Level.Items[collResult.Position.Bridge];
auto deltaPos = bridgeItem.Pose.Position - coll.LastBridgeItemPose.Position;
auto deltaOrient = bridgeItem.Pose.Orientation - coll.LastBridgeItemPose.Orientation;
auto deltaPose = Pose(deltaPos, deltaOrient);
int absDeltaHeight = item.Pose.Position.y - collResult.Position.Floor;
int relDeltaHeight = absDeltaHeight + GameBoundingBox(&item).Y2;
if (deltaPose != Pose::Zero &&
(abs(absDeltaHeight) <= CLICK(1 / 8.0f) || abs(relDeltaHeight) <= CLICK(1 / 8.0f)))
{
const auto& bridgePos = bridgeItem.Pose.Position;
// Calculate offset.
auto relOffset = (item.Pose.Position - bridgePos).ToVector3();
auto rotMatrix = deltaPose.Orientation.ToRotationMatrix();
auto offset = bridgePos.ToVector3() + Vector3::Transform(relOffset, rotMatrix);
deltaPose.Position -= item.Pose.Position - Vector3i(offset);
// Don't update shifts if difference is too big (possibly bridge was teleported or just entered bridge).
if (deltaPose.Position.ToVector3().Length() <= coll.Setup.Radius * 2)
coll.Shift = deltaPose;
}
else if (deltaPos.ToVector3().Length() <= coll.Setup.Radius && relDeltaHeight > 0 &&
(deltaPos != Vector3i::Zero || deltaOrient != EulerAngles::Zero))
{
// Push item away if not directly above bridge, and bridge position was changed.
ItemPushItem(&bridgeItem, &item);
}
coll.LastBridgeItemPose = bridgeItem.Pose;
}
else
{
coll.LastBridgeItemPose = Pose::Zero;
coll.LastBridgeItemNumber = NO_ITEM;
}
coll.LastBridgeItemNumber = collResult.Position.Bridge;
}
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
{
coll->HitTallObject = false;
@ -1057,20 +1161,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
case NORTH:
if (rawShift.x > coll->Setup.Radius || rawShift.x < -coll->Setup.Radius)
{
coll->Shift.z = rawShift.z;
coll->Shift.x = ox - x;
coll->Shift.Position.z = rawShift.z;
coll->Shift.Position.x = ox - x;
coll->CollisionType = CT_FRONT;
}
else if (rawShift.x > 0 && rawShift.x <= coll->Setup.Radius)
{
coll->Shift.x = rawShift.x;
coll->Shift.z = 0;
coll->Shift.Position.x = rawShift.x;
coll->Shift.Position.z = 0;
coll->CollisionType = CT_LEFT;
}
else if (rawShift.x < 0 && rawShift.x >= -coll->Setup.Radius)
{
coll->Shift.x = rawShift.x;
coll->Shift.z = 0;
coll->Shift.Position.x = rawShift.x;
coll->Shift.Position.z = 0;
coll->CollisionType = CT_RIGHT;
}
@ -1079,20 +1183,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
case SOUTH:
if (rawShift.x > coll->Setup.Radius || rawShift.x < -coll->Setup.Radius)
{
coll->Shift.z = rawShift.z;
coll->Shift.x = ox - x;
coll->Shift.Position.z = rawShift.z;
coll->Shift.Position.x = ox - x;
coll->CollisionType = CT_FRONT;
}
else if (rawShift.x > 0 && rawShift.x <= coll->Setup.Radius)
{
coll->Shift.x = rawShift.x;
coll->Shift.z = 0;
coll->Shift.Position.x = rawShift.x;
coll->Shift.Position.z = 0;
coll->CollisionType = CT_RIGHT;
}
else if (rawShift.x < 0 && rawShift.x >= -coll->Setup.Radius)
{
coll->Shift.x = rawShift.x;
coll->Shift.z = 0;
coll->Shift.Position.x = rawShift.x;
coll->Shift.Position.z = 0;
coll->CollisionType = CT_LEFT;
}
@ -1101,20 +1205,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
case EAST:
if (rawShift.z > coll->Setup.Radius || rawShift.z < -coll->Setup.Radius)
{
coll->Shift.x = rawShift.x;
coll->Shift.z = oz - z;
coll->Shift.Position.x = rawShift.x;
coll->Shift.Position.z = oz - z;
coll->CollisionType = CT_FRONT;
}
else if (rawShift.z > 0 && rawShift.z <= coll->Setup.Radius)
{
coll->Shift.z = rawShift.z;
coll->Shift.x = 0;
coll->Shift.Position.z = rawShift.z;
coll->Shift.Position.x = 0;
coll->CollisionType = CT_RIGHT;
}
else if (rawShift.z < 0 && rawShift.z >= -coll->Setup.Radius)
{
coll->Shift.z = rawShift.z;
coll->Shift.x = 0;
coll->Shift.Position.z = rawShift.z;
coll->Shift.Position.x = 0;
coll->CollisionType = CT_LEFT;
}
@ -1123,20 +1227,20 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
case WEST:
if (rawShift.z > coll->Setup.Radius || rawShift.z < -coll->Setup.Radius)
{
coll->Shift.x = rawShift.x;
coll->Shift.z = oz - z;
coll->Shift.Position.x = rawShift.x;
coll->Shift.Position.z = oz - z;
coll->CollisionType = CT_FRONT;
}
else if (rawShift.z > 0 && rawShift.z <= coll->Setup.Radius)
{
coll->Shift.z = rawShift.z;
coll->Shift.x = 0;
coll->Shift.Position.z = rawShift.z;
coll->Shift.Position.x = 0;
coll->CollisionType = CT_LEFT;
}
else if (rawShift.z < 0 && rawShift.z >= -coll->Setup.Radius)
{
coll->Shift.z = rawShift.z;
coll->Shift.x = 0;
coll->Shift.Position.z = rawShift.z;
coll->Shift.Position.x = 0;
coll->CollisionType = CT_RIGHT;
}
@ -1144,15 +1248,15 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
}
// Determine final shifts orientation/distance.
distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - pose.Position.ToVector3();
distance = Vector3(x + coll->Shift.Position.x, y, z + coll->Shift.Position.z) - pose.Position.ToVector3();
sinY = phd_sin(-pose.Orientation.y);
cosY = phd_cos(-pose.Orientation.y);
// Calculate final shifts orientation/distance.
coll->Shift.x = (round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x) - item->Pose.Position.x;
coll->Shift.z = (round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z) - item->Pose.Position.z;
coll->Shift.Position.x = (round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x) - item->Pose.Position.x;
coll->Shift.Position.z = (round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z) - item->Pose.Position.z;
if (coll->Shift.x == 0 && coll->Shift.z == 0)
if (coll->Shift.Position.x == 0 && coll->Shift.Position.z == 0)
coll->CollisionType = CT_NONE; // Paranoid.
// Set splat state flag if item is Lara and bounds are taller than Lara's headroom.
@ -1838,7 +1942,7 @@ void ObjectCollision(const short itemNumber, ItemInfo* laraItem, CollisionInfo*
if (TestCollision(item, laraItem))
{
if (coll->Setup.EnableObjectPush)
ItemPushItem(item, laraItem, coll, false, true);
ItemPushItem(item, laraItem, coll, false, 1);
}
}
}

View file

@ -1,10 +1,9 @@
#pragma once
#include "Math/Math.h"
using std::pair;
class FloorInfo;
struct CollisionInfo;
struct CollisionResult;
struct ItemInfo;
struct MESH_INFO;
@ -19,8 +18,8 @@ extern MESH_INFO* CollidedMeshes[MAX_COLLIDED_OBJECTS];
struct ObjectCollisionBounds
{
GameBoundingBox BoundingBox = GameBoundingBox::Zero;
pair<EulerAngles, EulerAngles> OrientConstraint = {};
GameBoundingBox BoundingBox = GameBoundingBox::Zero;
std::pair<EulerAngles, EulerAngles> OrientConstraint = {};
};
void GenericSphereBoxCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
@ -40,10 +39,13 @@ bool Move3DPosTo3DPos(ItemInfo* item, Pose& fromPose, const Pose& toPose, int ve
bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius);
bool TestBoundsCollideStatic(ItemInfo* item, const MESH_INFO& mesh, int radius);
bool ItemPushItem(ItemInfo* item, ItemInfo* laraItem, CollisionInfo* coll, bool enableSpasm, char bigPush);
bool ItemPushItem(ItemInfo* item, ItemInfo* item2);
bool ItemPushStatic(ItemInfo* laraItem, const MESH_INFO& mesh, CollisionInfo* coll);
void ItemPushBridge(ItemInfo& item, CollisionInfo& coll);
bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose& pose, CollisionInfo* coll);
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll);
void CollideBridgeItems(ItemInfo& item, CollisionInfo& coll, const CollisionResult& collResult);
void AIPickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
void ObjectCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);

View file

@ -18,7 +18,8 @@ using namespace TEN::Renderer;
void ShiftItem(ItemInfo* item, CollisionInfo* coll)
{
item->Pose.Position += coll->Shift;
item->Pose.Position += coll->Shift.Position;
item->Pose.Orientation += coll->Shift.Orientation;
coll->Shift = Vector3i::Zero;
}
@ -227,7 +228,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
// Reset collision parameters.
coll->CollisionType = CollisionType::CT_NONE;
coll->Shift = Vector3i::Zero;
coll->Shift = Pose::Zero;
// Offset base probe position by provided offset, if any.
auto entityPos = item->Pose.Position + offset;
@ -348,6 +349,9 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
coll->Middle.Floor = height;
coll->Middle.Ceiling = ceiling;
// Additionally calculate bridge shifts, if present.
CollideBridgeItems(*item, *coll, collResult);
// TEST 3: FRONTAL PROBE
probePos.x = entityPos.x + xFront;
@ -698,21 +702,21 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
if (coll->Middle.Floor == NO_HEIGHT)
{
coll->Shift = coll->Setup.OldPosition - entityPos;
coll->Shift.Position += coll->Setup.OldPosition - entityPos;
coll->CollisionType = CT_FRONT;
return;
}
if (coll->Middle.Floor - coll->Middle.Ceiling <= 0)
{
coll->Shift = coll->Setup.OldPosition - entityPos;
coll->Shift.Position += coll->Setup.OldPosition - entityPos;
coll->CollisionType = CT_CLAMP;
return;
}
if (coll->Middle.Ceiling >= 0)
{
coll->Shift.y = coll->Middle.Ceiling;
coll->Shift.Position.y += coll->Middle.Ceiling;
coll->CollisionType = CT_TOP;
}
@ -724,8 +728,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
{
if (coll->Front.HasDiagonalSplit())
{
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
}
else
{
@ -733,14 +737,14 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
{
case 0:
case 2:
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.z = FindGridShift(entityPos.z + zFront, entityPos.z);
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.Position.z += FindGridShift(entityPos.z + zFront, entityPos.z);
break;
case 1:
case 3:
coll->Shift.x = FindGridShift(entityPos.x + xFront, entityPos.x);
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
coll->Shift.Position.x += FindGridShift(entityPos.x + xFront, entityPos.x);
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
break;
}
@ -752,7 +756,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
if (coll->Front.Ceiling > coll->Setup.LowerCeilingBound ||
coll->Front.Ceiling < coll->Setup.UpperCeilingBound)
{
coll->Shift = coll->Setup.OldPosition - entityPos;
coll->Shift.Position += coll->Setup.OldPosition - entityPos;
coll->CollisionType = CT_TOP_FRONT;
return;
}
@ -768,8 +772,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
// HACK: Force slight push-out to the left side to avoid stucking
TranslateItem(item, coll->Setup.ForwardAngle + ANGLE(8.0f), item->Animation.Velocity.z);
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
}
else
{
@ -777,12 +781,12 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
{
case 0:
case 2:
coll->Shift.x = FindGridShift(entityPos.x + xLeft, entityPos.x + xFront);
coll->Shift.Position.x += FindGridShift(entityPos.x + xLeft, entityPos.x + xFront);
break;
case 1:
case 3:
coll->Shift.z = FindGridShift(entityPos.z + zLeft, entityPos.z + zFront);
coll->Shift.Position.z += FindGridShift(entityPos.z + zLeft, entityPos.z + zFront);
break;
}
}
@ -822,8 +826,8 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
// HACK: Force slight push out to the right side to avoid getting stuck.
TranslateItem(item, coll->Setup.ForwardAngle - ANGLE(8.0f), item->Animation.Velocity.z);
coll->Shift.x = coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.z = coll->Setup.OldPosition.z - entityPos.z;
coll->Shift.Position.x += coll->Setup.OldPosition.x - entityPos.x;
coll->Shift.Position.z += coll->Setup.OldPosition.z - entityPos.z;
}
else
{
@ -831,12 +835,12 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
{
case 0:
case 2:
coll->Shift.x = FindGridShift(entityPos.x + xRight, entityPos.x + xFront);
coll->Shift.Position.x += FindGridShift(entityPos.x + xRight, entityPos.x + xFront);
break;
case 1:
case 3:
coll->Shift.z = FindGridShift(entityPos.z + zRight, entityPos.z + zFront);
coll->Shift.Position.z += FindGridShift(entityPos.z + zRight, entityPos.z + zFront);
break;
}
}

View file

@ -1,9 +1,9 @@
#pragma once
#include "Math/Math.h"
#include "Objects/game_object_ids.h"
struct ItemInfo;
struct CollisionInfo;
class FloorInfo;
struct ROOM_INFO;
struct MESH_INFO;
@ -105,13 +105,16 @@ struct CollisionInfo
CollisionPosition FrontLeft;
CollisionPosition FrontRight;
Vector3i Shift;
Pose Shift = Pose::Zero;
CollisionType CollisionType;
Vector2 FloorTilt; // x = x, y = z
Vector2 CeilingTilt; // x = x, y = z
short NearestLedgeAngle;
float NearestLedgeDistance;
int LastBridgeItemNumber;
Pose LastBridgeItemPose;
bool HitStatic;
bool HitTallObject;

View file

@ -4,6 +4,7 @@
#include <stdexcept>
#include <variant>
#include "Game/collision/collide_room.h"
#include "Game/itemdata/creature_info.h"
#include "Game/itemdata/door_data.h"
#include "Game/Lara/lara_struct.h"
@ -56,6 +57,7 @@ class ItemData
PushableInfo,
ItemInfo*,
LaraInfo*,
CollisionInfo,
CreatureInfo,
WraithInfo,
GuardianInfo,

View file

@ -958,6 +958,8 @@ void DropPickups(ItemInfo* item)
void PickupControl(short itemNumber)
{
auto* item = &g_Level.Items[itemNumber];
ItemPushBridge(*item, *(CollisionInfo*)item->Data);
short roomNumber;
short triggerFlags = item->TriggerFlags & 0x3F;
@ -1056,9 +1058,13 @@ const GameBoundingBox* FindPlinth(ItemInfo* item)
void InitializePickup(short itemNumber)
{
auto* item = &g_Level.Items[itemNumber];
auto bounds = GameBoundingBox(item);
item->Data = CollisionInfo();
auto* coll = (CollisionInfo*)item->Data;
coll->Setup.Radius = std::max(bounds.GetWidth(), bounds.GetDepth());
coll->Setup.Height = bounds.GetHeight();
short triggerFlags = item->TriggerFlags & 0x3F;
if (triggerFlags == 5)
{

View file

@ -253,7 +253,7 @@ namespace TEN::Entities::Doors
if (!(doorItem->ObjectNumber >= ID_LIFT_DOORS1 &&
doorItem->ObjectNumber <= ID_LIFT_DOORS2) || doorItem->ItemFlags[0])
{
ItemPushItem(doorItem, laraItem, coll, FALSE, TRUE);
ItemPushItem(doorItem, laraItem, coll, false, 1);
}
}
}

View file

@ -112,7 +112,7 @@ namespace TEN::Entities::Traps::TR1
return;
if (coll->Setup.EnableObjectPush)
ItemPushItem(&item, laraItem, coll, false, true);
ItemPushItem(&item, laraItem, coll, false, 1);
if (item.Animation.IsAirborne)
{

View file

@ -184,7 +184,7 @@ namespace TEN::Entities::Vehicles
{
// HACK: Collision in water behaves differently? @Sezz 2022.06.28
if (TestBoundsCollide(UPVItem, laraItem, coll->Setup.Radius) && TestCollision(UPVItem, laraItem))
ItemPushItem(UPVItem, laraItem, coll, false, false);
ItemPushItem(UPVItem, laraItem, coll, false, 0);
}
else
{

View file

@ -152,7 +152,7 @@ namespace TEN::Entities::TR4
if (TestCollision(item, laraItem))
{
if (coll->Setup.EnableObjectPush)
ItemPushItem(item, laraItem, coll, 0, 0);
ItemPushItem(item, laraItem, coll, false, 0);
}
}
}

View file

@ -106,17 +106,17 @@ void ScalesCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
GlobalCollisionBounds.Z1 = -256;
GlobalCollisionBounds.Z2 = 384;
ItemPushItem(item, laraItem, coll, 0, 2);
ItemPushItem(item, laraItem, coll, false, 2);
GlobalCollisionBounds.X1 = -256;
GlobalCollisionBounds.X2 = 256;
ItemPushItem(item, laraItem, coll, 0, 2);
ItemPushItem(item, laraItem, coll, false, 2);
GlobalCollisionBounds.X1 = -1280;
GlobalCollisionBounds.X2 = -640;
ItemPushItem(item, laraItem, coll, 0, 2);
ItemPushItem(item, laraItem, coll, false, 2);
}
else
{

View file

@ -29,7 +29,7 @@ namespace TEN::Entities::TR4
int dy = 0;
int dz = 0;
if (ItemPushItem(bladeItem, laraItem, coll, 1, 1))
if (ItemPushItem(bladeItem, laraItem, coll, true, 1))
{
DoDamage(laraItem, bladeItem->ItemFlags[3]);

View file

@ -57,7 +57,7 @@ namespace TEN::Entities::TR4
DoDamage(laraItem, 10);
}
else if (coll->Setup.EnableObjectPush)
ItemPushItem(cogItem, laraItem, coll, 0, 0);
ItemPushItem(cogItem, laraItem, coll, false, 0);
}
}
}

View file

@ -57,7 +57,7 @@ namespace TEN::Entities::Traps
GlobalCollisionBounds.Z1 = bounds.z;
if (TestWithGlobalCollisionBounds(item, laraItem, coll))
ItemPushItem(item, laraItem, coll, 0, 2);
ItemPushItem(item, laraItem, coll, false, 2);
}*/
if (!TestBoundsCollide(item, laraItem, coll->Setup.Radius))

View file

@ -1,6 +1,7 @@
#include "framework.h"
#include "Game/items.h"
#include "Game/collision/floordata.h"
#include "Game/control/lot.h"
#include "Game/effects/debris.h"
#include "Game/effects/item_fx.h"
@ -21,6 +22,7 @@
#include "Scripting/Internal/TEN/Rotation/Rotation.h"
#include "Scripting/Internal/TEN/Vec3/Vec3.h"
using namespace TEN::Collision::Floordata;
using namespace TEN::Effects::Items;
/***
@ -576,6 +578,10 @@ void Moveable::SetPos(Vec3 const& pos, sol::optional<bool> updateRoom)
SetRoomNumber(potentialNewRoom);
}
}
const auto& object = Objects[m_item->ObjectNumber];
if (object.floor != nullptr || object.ceiling != nullptr)
UpdateBridgeItem((int)m_item->Index);
}
Vec3 Moveable::GetJointPos(int jointIndex) const
@ -598,11 +604,15 @@ Rotation Moveable::GetRot() const
};
}
void Moveable::SetRot(Rotation const& rot)
void Moveable::SetRot(const Rotation& rot)
{
m_item->Pose.Orientation.x = ANGLE(rot.x);
m_item->Pose.Orientation.y = ANGLE(rot.y);
m_item->Pose.Orientation.z = ANGLE(rot.z);
const auto& object = Objects[m_item->ObjectNumber];
if (object.floor != nullptr || object.ceiling != nullptr)
UpdateBridgeItem(m_item->Index);
}
/// Get current HP (hit points/health points)

View file

@ -187,8 +187,17 @@ void LoadItems()
memcpy(&item->StartPose, &item->Pose, sizeof(Pose));
}
for (int i = 0; i < g_Level.NumItems; i++)
InitializeItem(i);
// Initialize all bridges first.
// It is needed because some other items need final floor height to init properly.
for (int isFloor = 0; isFloor <= 1; isFloor++)
{
for (int i = 0; i < g_Level.NumItems; i++)
{
if ((Objects[g_Level.Items[i].ObjectNumber].floor == nullptr) == (bool)isFloor)
InitializeItem(i);
}
}
}
}