TombEngine/TR5Main/Game/rope.cpp

757 lines
22 KiB
C++
Raw Normal View History

#include "framework.h"
#include "rope.h"
#include "draw.h"
2020-04-23 19:22:01 +02:00
#include "lara.h"
#include "level.h"
#include "input.h"
2020-04-24 19:15:05 +02:00
#include "control.h"
#include "sound.h"
PENDULUM CurrentPendulum;
PENDULUM AlternatePendulum;
2020-04-24 19:15:05 +02:00
ROPE_STRUCT Ropes[12];
int NumRopes, RopeSwing = 0;
2021-02-03 01:50:59 -03:00
void InitialiseRope(short itemNumber)
{
PHD_VECTOR itemPos;
ITEM_INFO* item = &g_Level.Items[itemNumber];
short roomNumber = item->roomNumber;
itemPos.x = item->pos.xPos;
itemPos.y = item->pos.yPos;
itemPos.z = item->pos.zPos;
FLOOR_INFO* floor = GetFloor(itemPos.x, itemPos.y, itemPos.z, &roomNumber);
itemPos.y = GetCeiling(floor, itemPos.x, itemPos.y, itemPos.z);
PHD_VECTOR pos;
pos.x = 0;
pos.y = 16384;
pos.z = 0;
ROPE_STRUCT* rope = &Ropes[NumRopes];
PrepareRope(rope, &itemPos, &pos, 128, item);
item->triggerFlags = NumRopes;
NumRopes++;
}
2021-02-03 01:50:59 -03:00
void PrepareRope(ROPE_STRUCT* rope, PHD_VECTOR* pos1, PHD_VECTOR* pos2, int length, ITEM_INFO* item)
{
rope->position = *pos1;
2020-10-16 12:06:33 -05:00
rope->segmentLength = length * 65536;
2020-10-16 12:06:33 -05:00
pos2->x *= 65536;
pos2->y *= 65536;
pos2->z *= 65536;
NormaliseRopeVector(pos2);
if (item->triggerFlags == -1)
rope->coiled = 30;
else
rope->coiled = 0;
int l = 0;
int sum = 0;
int il = 3145728;
for (int i = 0; i < 24; ++i)
{
2020-10-16 12:06:33 -05:00
rope->segment[i].x = ((int64_t) sum * pos2->x) / 65536;
rope->segment[i].y = ((int64_t) sum * pos2->y) / 65536;
rope->segment[i].z = ((int64_t) sum * pos2->z) / 65536;
rope->velocity[i].x = 0;
rope->velocity[i].y = 0;
rope->velocity[i].z = 0;
if (item->triggerFlags == -1)
{
rope->segment[i].x = l;
2020-10-16 12:06:33 -05:00
rope->segment[i].y /= 16;
rope->velocity[i].x = 16384;
rope->velocity[i].y = il;
rope->velocity[i].z = 16384;
}
l += 1024;
sum += rope->segmentLength;
il -= 131072;
}
rope->active = 0;
}
2021-02-03 01:50:59 -03:00
PHD_VECTOR* NormaliseRopeVector(PHD_VECTOR* vec)
{
2020-10-16 12:06:33 -05:00
int x = vec->x / 65536;
int y = vec->y / 65536;
int z = vec->z / 65536;
if (!x && !y && !z)
return vec;
int length = SQUARE(x) + SQUARE(y) + SQUARE(z);
if (length < 0)
length = -length;
2020-04-20 14:17:01 +02:00
length = 65536 / sqrt(length);
2020-10-16 12:06:33 -05:00
vec->x = ((int64_t) length * vec->x) / 65536;
vec->y = ((int64_t) length * vec->y) / 65536;
vec->z = ((int64_t) length * vec->z) / 65536;
return vec;
}
2021-02-03 01:50:59 -03:00
void _0x0046D130(ROPE_STRUCT* rope, int segmentFrame, int* x, int* y, int* z)
{
int segment;
short frame;
2020-10-16 12:06:33 -05:00
segment = segmentFrame / 128;
frame = segmentFrame & 0x7F;
2020-10-16 12:06:33 -05:00
*x = ((rope->normalisedSegment[segment].x * frame) / 65536) + ((rope->meshSegment[segment].x) / 65536) + rope->position.x;
*y = ((rope->normalisedSegment[segment].y * frame) / 65536) + ((rope->meshSegment[segment].y) / 65536) + rope->position.y;
*z = ((rope->normalisedSegment[segment].z * frame) / 65536) + ((rope->meshSegment[segment].z) / 65536) + rope->position.z;
}
2021-02-03 01:50:59 -03:00
int DotProduct(PHD_VECTOR* u, PHD_VECTOR* v)
{
return (u->x * v->x + u->y * v->y + u->z * v->z) / 16384;
}
2021-02-03 01:50:59 -03:00
void ScaleVector(PHD_VECTOR* u, int c, PHD_VECTOR* destination)
{
destination->x = c * u->x / 16384;
destination->y = c * u->y / 16384;
destination->z = c * u->z / 16384;
}
2021-02-03 01:50:59 -03:00
void CrossProduct(PHD_VECTOR* u, PHD_VECTOR* v, PHD_VECTOR* destination)
{
destination->x = (u->y * v->z - u->z * v->y) / 16384;
destination->y = (u->z * v->x - u->x * v->z) / 16384;
destination->z = (u->x * v->y - u->y * v->x) / 16384;
}
2021-02-03 01:50:59 -03:00
void _0x0046D420(int* matrix, short* angle)
{
2020-04-25 16:23:53 +02:00
angle[0] = phd_atan(sqrt(SQUARE(matrix[M22]) + SQUARE(matrix[M02])), matrix[M12]);
if (matrix[M12] >= 0 && angle[0] > 0 || matrix[M12] < 0 && angle[0] < 0)
angle[0] = -angle[0];
2020-04-25 16:23:53 +02:00
angle[1] = phd_atan(matrix[M22], matrix[M02]);
angle[2] = phd_atan(matrix[M00] * phd_cos(angle[1]) - matrix[M20] * phd_sin(angle[1]), matrix[M21] * phd_sin(angle[1]) - matrix[M01] * phd_cos(angle[1]));
}
2021-02-03 01:50:59 -03:00
void RopeControl(short itemNumber)
{
ITEM_INFO* item;
ROPE_STRUCT* rope;
item = &g_Level.Items[itemNumber];
rope = &Ropes[item->triggerFlags];
if (TriggerActive(item))
{
rope->active = 1;
RopeDynamics(rope);
}
else
{
rope->active = 0;
}
}
2021-02-03 01:50:59 -03:00
void RopeCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item;
ROPE_STRUCT* rope;
2020-07-25 18:02:35 +02:00
BOUNDING_BOX* frame;
int segment;
item = &g_Level.Items[itemNumber];
rope = &Ropes[item->triggerFlags];
if (TrInput & IN_ACTION && Lara.gunStatus == LG_NO_ARMS && (l->currentAnimState == LS_REACH || l->currentAnimState == LS_JUMP_UP) && l->gravityStatus && l->fallspeed > 0 && rope->active)
{
2020-07-25 18:02:35 +02:00
frame = GetBoundsAccurate(l);
2020-10-05 22:24:57 -03:00
segment = _0x0046D200(rope, l->pos.xPos, l->pos.yPos + frame->Y1 + 512, l->pos.zPos + frame->Z2 * phd_cos(l->pos.yRot), l->currentAnimState == LS_REACH ? 128 : 320);
if (segment >= 0)
{
if (l->currentAnimState == LS_REACH)
{
l->animNumber = LA_REACH_TO_ROPE_SWING;
l->currentAnimState = LS_ROPE_SWING;
2020-10-16 12:06:33 -05:00
Lara.ropeFrame = (g_Level.Anims[LA_ROPE_SWING].frameBase + 32) * 256;
Lara.ropeDFrame = (g_Level.Anims[LA_ROPE_SWING].frameBase + 60) * 256;
}
else
{
l->animNumber = LA_JUMP_UP_TO_ROPE_START;
l->currentAnimState = LS_ROPE_IDLE;
}
l->frameNumber = g_Level.Anims[l->animNumber].frameBase;
l->gravityStatus = false;
l->fallspeed = 0;
Lara.gunStatus = LG_HANDS_BUSY;
Lara.ropePtr = item->triggerFlags;
Lara.ropeSegment = segment;
Lara.ropeY = l->pos.yRot;
DelAlignLaraToRope(l);
CurrentPendulum.Velocity.x = 0;
CurrentPendulum.Velocity.y = 0;
CurrentPendulum.Velocity.z = 0;
ApplyVelocityToRope(segment, l->pos.yRot, 16 * LaraItem->speed);
}
}
}
2021-02-03 01:50:59 -03:00
void RopeDynamics(ROPE_STRUCT* rope)
{
int flag, i;
PENDULUM* pendulumPointer;
PHD_VECTOR vec, vec2;
flag = 0;
if (rope->coiled)
{
--rope->coiled;
if (!rope->coiled)
{
for (i = 0; i < 24; ++i)
rope->velocity[i].y = 0;
}
}
if (rope == &Ropes[Lara.ropePtr])
{
pendulumPointer = &CurrentPendulum;
if (CurrentPendulum.node != Lara.ropeSegment + 1)
{
_0x0046E1C0(rope, Lara.ropeSegment + 1);
flag = 1;
}
}
else
{
pendulumPointer = &AlternatePendulum;
if (Lara.ropePtr == -1 && CurrentPendulum.Rope)
{
for (i = 0; i < CurrentPendulum.node; ++i)
{
CurrentPendulum.Rope->velocity[i].x = CurrentPendulum.Rope->velocity[CurrentPendulum.node].x;
CurrentPendulum.Rope->velocity[i].y = CurrentPendulum.Rope->velocity[CurrentPendulum.node].y;
CurrentPendulum.Rope->velocity[i].z = CurrentPendulum.Rope->velocity[CurrentPendulum.node].z;
}
CurrentPendulum.Position.x = 0;
CurrentPendulum.Position.y = 0;
CurrentPendulum.Position.z = 0;
CurrentPendulum.Velocity.x = 0;
CurrentPendulum.Velocity.y = 0;
CurrentPendulum.Velocity.z = 0;
CurrentPendulum.node = -1;
CurrentPendulum.Rope = NULL;
}
}
if (Lara.ropePtr != -1)
{
vec.x = pendulumPointer->Position.x - rope->segment[0].x;
vec.y = pendulumPointer->Position.y - rope->segment[0].y;
vec.z = pendulumPointer->Position.z - rope->segment[0].z;
NormaliseRopeVector(&vec);
for (i = pendulumPointer->node; i >= 0; --i)
{
2020-10-16 12:06:33 -05:00
rope->segment[i].x = rope->meshSegment[i - 1].x + (((int64_t) rope->segmentLength * vec.x) / 65536);
rope->segment[i].y = rope->meshSegment[i - 1].y + (((int64_t) rope->segmentLength * vec.y) / 65536);
rope->segment[i].z = rope->meshSegment[i - 1].z + (((int64_t) rope->segmentLength * vec.z) / 65536);
rope->velocity[i].x = 0;
rope->velocity[i].y = 0;
rope->velocity[i].z = 0;
}
if (flag)
{
vec2.x = pendulumPointer->Position.x - rope->segment[pendulumPointer->node].x;
vec2.y = pendulumPointer->Position.y - rope->segment[pendulumPointer->node].y;
vec2.z = pendulumPointer->Position.z - rope->segment[pendulumPointer->node].z;
rope->segment[pendulumPointer->node].x = pendulumPointer->Position.x;
rope->segment[pendulumPointer->node].y = pendulumPointer->Position.y;
rope->segment[pendulumPointer->node].z = pendulumPointer->Position.z;
for (i = pendulumPointer->node; i < 24; ++i)
{
rope->segment[i].x -= vec2.x;
rope->segment[i].y -= vec2.y;
rope->segment[i].z -= vec2.z;
rope->velocity[i].x = 0;
rope->velocity[i].y = 0;
rope->velocity[i].z = 0;
}
}
_0x0046E080(rope, pendulumPointer, &rope->velocity[0], &pendulumPointer->Velocity, rope->segmentLength * pendulumPointer->node);
pendulumPointer->Velocity.y += 393216;
pendulumPointer->Position.x += pendulumPointer->Velocity.x;
pendulumPointer->Position.y += pendulumPointer->Velocity.y;
pendulumPointer->Position.z += pendulumPointer->Velocity.z;
2020-10-16 12:06:33 -05:00
pendulumPointer->Velocity.x -= pendulumPointer->Velocity.x / 256;
pendulumPointer->Velocity.z -= pendulumPointer->Velocity.z / 256;
}
for (i = pendulumPointer->node; i < 23; ++i)
_0x0046DF00(&rope->segment[i], &rope->segment[i + 1], &rope->velocity[i], &rope->velocity[i + 1], rope->segmentLength);
for (i = 0; i < 24; ++i)
{
rope->segment[i].x += rope->velocity[i].x;
rope->segment[i].y += rope->velocity[i].y;
rope->segment[i].z += rope->velocity[i].z;
}
for (i = pendulumPointer->node; i < 24; ++i)
{
rope->velocity[i].y += 196608;
if (pendulumPointer->Rope)
{
2020-10-16 12:06:33 -05:00
rope->velocity[i].x -= rope->velocity[i].x / 16;
rope->velocity[i].z -= rope->velocity[i].z / 16;
}
else
{
2020-10-16 12:06:33 -05:00
rope->velocity[i].x -= rope->velocity[i].x / 128;
rope->velocity[i].z -= rope->velocity[i].z / 128;
}
}
rope->segment[0].x = 0;
rope->segment[0].y = 0;
rope->segment[0].z = 0;
rope->velocity[0].x = 0;
rope->velocity[0].y = 0;
rope->velocity[0].z = 0;
for (i = 0; i < 23; ++i)
{
rope->normalisedSegment[i].x = rope->segment[i + 1].x - rope->segment[i].x;
rope->normalisedSegment[i].y = rope->segment[i + 1].y - rope->segment[i].y;
rope->normalisedSegment[i].z = rope->segment[i + 1].z - rope->segment[i].z;
NormaliseRopeVector(&rope->normalisedSegment[i]);
}
if (rope != &Ropes[Lara.ropePtr])
{
rope->meshSegment[0].x = rope->segment[0].x;
rope->meshSegment[0].y = rope->segment[0].y;
rope->meshSegment[0].z = rope->segment[0].z;
2020-10-16 12:06:33 -05:00
rope->meshSegment[1].x = rope->segment[0].x + (((int64_t) rope->segmentLength * rope->normalisedSegment[0].x) / 65536);
rope->meshSegment[1].y = rope->segment[0].y + (((int64_t) rope->segmentLength * rope->normalisedSegment[0].y) / 65536);
rope->meshSegment[1].z = rope->segment[0].z + (((int64_t) rope->segmentLength * rope->normalisedSegment[0].z) / 65536);
for (i = 2; i < 24; ++i)
{
2020-10-16 12:06:33 -05:00
rope->meshSegment[i].x = rope->meshSegment[i - 1].x + (((int64_t) rope->segmentLength * rope->normalisedSegment[i - 1].x) / 65536);
rope->meshSegment[i].y = rope->meshSegment[i - 1].y + (((int64_t) rope->segmentLength * rope->normalisedSegment[i - 1].y) / 65536);
rope->meshSegment[i].z = rope->meshSegment[i - 1].z + (((int64_t) rope->segmentLength * rope->normalisedSegment[i - 1].z) / 65536);
}
}
else
{
rope->meshSegment[pendulumPointer->node].x = rope->segment[pendulumPointer->node].x;
rope->meshSegment[pendulumPointer->node].y = rope->segment[pendulumPointer->node].y;
rope->meshSegment[pendulumPointer->node].z = rope->segment[pendulumPointer->node].z;
2020-10-16 12:06:33 -05:00
rope->meshSegment[pendulumPointer->node + 1].x = rope->segment[pendulumPointer->node].x + (((int64_t) rope->segmentLength * rope->normalisedSegment[pendulumPointer->node].x) / 65536);
rope->meshSegment[pendulumPointer->node + 1].y = rope->segment[pendulumPointer->node].y + (((int64_t) rope->segmentLength * rope->normalisedSegment[pendulumPointer->node].y) / 65536);
rope->meshSegment[pendulumPointer->node + 1].z = rope->segment[pendulumPointer->node].z + (((int64_t) rope->segmentLength * rope->normalisedSegment[pendulumPointer->node].z) / 65536);
for (i = pendulumPointer->node + 1; i < 23; ++i)
{
2020-10-16 12:06:33 -05:00
rope->meshSegment[i + 1].x = rope->meshSegment[i].x + (((int64_t) rope->segmentLength * rope->normalisedSegment[i].x) / 65536);
rope->meshSegment[i + 1].y = rope->meshSegment[i].y + (((int64_t) rope->segmentLength * rope->normalisedSegment[i].y) / 65536);
rope->meshSegment[i + 1].z = rope->meshSegment[i].z + (((int64_t) rope->segmentLength * rope->normalisedSegment[i].z) / 65536);
}
for (i = 0; i < pendulumPointer->node; ++i)
{
rope->meshSegment[i].x = rope->segment[i].x;
rope->meshSegment[i].y = rope->segment[i].y;
rope->meshSegment[i].z = rope->segment[i].z;
}
}
}
2021-02-03 01:50:59 -03:00
int _0x0046D200(ROPE_STRUCT* rope, int x, int y, int z, int radius)
{
int dx, dy, dz;
for (int i = 0; i < 22; ++i)
{
2020-10-16 12:06:33 -05:00
if (y > rope->position.y + (rope->meshSegment[i].y / 65536) && y < rope->position.y + (rope->meshSegment[i + 1].y / 65536))
{
2020-10-16 12:06:33 -05:00
dx = x - ((rope->meshSegment[i + 1].x + rope->meshSegment[i].x) / 131072) - rope->position.x;
dy = y - ((rope->meshSegment[i + 1].y + rope->meshSegment[i].y) / 131072) - rope->position.y;
dz = z - ((rope->meshSegment[i + 1].z + rope->meshSegment[i].z) / 131072) - rope->position.z;
if (SQUARE(dx) + SQUARE(dy) + SQUARE(dz) < SQUARE(radius + 64))
return i;
}
}
return -1;
}
2021-02-03 01:50:59 -03:00
void ApplyVelocityToRope(int node, short angle, short n)
{
SetPendulumVelocity(
2020-10-05 22:24:57 -03:00
(unsigned short) n * phd_sin(angle) * 4096,
0,
2020-10-05 22:24:57 -03:00
(unsigned short) n * phd_cos(angle) * 4096); /* @ORIGINAL_BUG: casting n to unsigned short results in the rope glitch */
}
2021-02-03 01:50:59 -03:00
void SetPendulumVelocity(int x, int y, int z)
{
int node;
2020-10-16 12:06:33 -05:00
node = 2 * (CurrentPendulum.node / 2);
if (node < 24)
{
int val = 4096 / (24 - node) * 256;
2020-10-16 12:06:33 -05:00
x = ((int64_t) val * x) / 65536;
y = ((int64_t) val * y) / 65536;
z = ((int64_t) val * z) / 65536;
}
CurrentPendulum.Velocity.x += x;
CurrentPendulum.Velocity.y += y;
CurrentPendulum.Velocity.z += z;
}
2021-02-03 01:50:59 -03:00
void _0x0046E1C0(ROPE_STRUCT* rope, int node)
{
CurrentPendulum.Position.x = rope->segment[node].x;
CurrentPendulum.Position.y = rope->segment[node].y;
CurrentPendulum.Position.z = rope->segment[node].z;
if (CurrentPendulum.node == -1)
{
CurrentPendulum.Velocity.x += rope->velocity[node].x;
CurrentPendulum.Velocity.y += rope->velocity[node].y;
CurrentPendulum.Velocity.z += rope->velocity[node].z;
}
CurrentPendulum.node = node;
CurrentPendulum.Rope = rope;
}
2021-02-03 01:50:59 -03:00
void _0x0046E080(ROPE_STRUCT* rope, PENDULUM* pendulumPointer, PHD_VECTOR* ropeVelocity, PHD_VECTOR* pendulumVelocity, int value)
{
PHD_VECTOR vec;
int result;
vec.x = pendulumPointer->Position.x + pendulumVelocity->x - rope->segment[0].x;
vec.y = pendulumPointer->Position.y + pendulumVelocity->y - rope->segment[0].y;
vec.z = pendulumPointer->Position.z + pendulumVelocity->z - rope->segment[0].z;
2020-10-16 12:06:33 -05:00
result = 65536 * sqrt(abs(SQUARE(vec.x / 65536) + SQUARE(vec.y / 65536) + SQUARE(vec.z / 65536))) - value;
NormaliseRopeVector(&vec);
2020-10-16 12:06:33 -05:00
pendulumVelocity->x -= ((int64_t) result * vec.x) / 65536;
pendulumVelocity->y -= ((int64_t) result * vec.y) / 65536;
pendulumVelocity->z -= ((int64_t) result * vec.z) / 65536;
}
2021-02-03 01:50:59 -03:00
void _0x0046DF00(PHD_VECTOR* segment, PHD_VECTOR* nextSegment, PHD_VECTOR* velocity, PHD_VECTOR* nextVelocity, int length)
{
PHD_VECTOR vec;
int result;
vec.x = nextSegment->x + nextVelocity->x - segment->x - velocity->x;
vec.y = nextSegment->y + nextVelocity->y - segment->y - velocity->y;
vec.z = nextSegment->z + nextVelocity->z - segment->z - velocity->z;
2020-10-16 12:06:33 -05:00
result = (65536 * sqrt(abs(SQUARE(vec.x / 65536) + SQUARE(vec.y / 65536) + SQUARE(vec.z / 65536))) - length) / 2;
NormaliseRopeVector(&vec);
2020-10-16 12:06:33 -05:00
vec.x = ((int64_t) result * vec.x) / 65536;
vec.y = ((int64_t) result * vec.y) / 65536;
vec.z = ((int64_t) result * vec.z) / 65536;
velocity->x += vec.x;
velocity->y += vec.y;
velocity->z += vec.z;
nextVelocity->x -= vec.x;
nextVelocity->y -= vec.y;
nextVelocity->z -= vec.z;
}
2021-02-03 01:50:59 -03:00
void UpdateRopeSwing(ITEM_INFO* item)
{
if (Lara.ropeMaxXForward > 9000)
{
Lara.ropeMaxXForward = 9000;
}
if (Lara.ropeMaxXBackward > 9000)
{
Lara.ropeMaxXBackward = 9000;
}
if (Lara.ropeDirection)
{
if (item->pos.xRot > 0 && item->pos.xRot - Lara.ropeLastX < -100)
{
Lara.ropeArcFront = Lara.ropeLastX;
Lara.ropeDirection = 0;
Lara.ropeMaxXBackward = 0;
2020-10-16 12:06:33 -05:00
int frame = (15 * Lara.ropeMaxXForward / 18000 + g_Level.Anims[LA_ROPE_SWING].frameBase + 47) * 256;
if (frame > Lara.ropeDFrame)
{
Lara.ropeDFrame = frame;
RopeSwing = 1;
}
else
{
RopeSwing = 0;
}
SoundEffect(SFX_LARA_ROPE_CREAK, &item->pos, 0);
}
else if (Lara.ropeLastX < 0 && Lara.ropeFrame == Lara.ropeDFrame)
{
RopeSwing = 0;
2020-10-16 12:06:33 -05:00
Lara.ropeDFrame = (15 * Lara.ropeMaxXBackward / 18000 + g_Level.Anims[LA_ROPE_SWING].frameBase + 47) * 256;
Lara.ropeFrameRate = 15 * Lara.ropeMaxXBackward / 9000 + 1;
}
else if (Lara.ropeFrameRate < 512)
{
int num = RopeSwing ? 31 : 7;
Lara.ropeFrameRate += num * Lara.ropeMaxXBackward / 9000 + 1;
}
}
else
{
if (item->pos.xRot < 0 && item->pos.xRot - Lara.ropeLastX > 100)
{
Lara.ropeArcBack = Lara.ropeLastX;
Lara.ropeDirection = 1;
Lara.ropeMaxXForward = 0;
2020-10-16 12:06:33 -05:00
int frame = (g_Level.Anims[LA_ROPE_SWING].frameBase - 15 * Lara.ropeMaxXBackward / 18000 + 17) * 256;
if (frame < Lara.ropeDFrame)
{
Lara.ropeDFrame = frame;
RopeSwing = 1;
}
else
{
RopeSwing = 0;
}
SoundEffect(SFX_LARA_ROPE_CREAK, &item->pos, 0);
}
else if (Lara.ropeLastX > 0 && Lara.ropeFrame == Lara.ropeDFrame)
{
RopeSwing = 0;
2020-10-16 12:06:33 -05:00
Lara.ropeDFrame = (g_Level.Anims[LA_ROPE_SWING].frameBase - 15 * Lara.ropeMaxXForward / 18000 + 17) * 256;
Lara.ropeFrameRate = 15 * Lara.ropeMaxXForward / 9000 + 1;
}
else if (Lara.ropeFrameRate < 512)
{
int num = RopeSwing ? 31 : 7;
Lara.ropeFrameRate += num * Lara.ropeMaxXForward / 9000 + 1;
}
}
Lara.ropeLastX = item->pos.xRot;
if (Lara.ropeDirection)
{
if (item->pos.xRot > Lara.ropeMaxXForward)
Lara.ropeMaxXForward = item->pos.xRot;
}
else
{
if (item->pos.xRot < -Lara.ropeMaxXBackward)
Lara.ropeMaxXBackward = abs(item->pos.xRot);
}
}
2021-02-03 01:50:59 -03:00
void JumpOffRope(ITEM_INFO* item)
{
if (Lara.ropePtr != -1)
{
if (item->pos.xRot >= 0)
{
item->fallspeed = -112;
item->speed = item->pos.xRot / 128;
}
else
{
item->speed = 0;
item->fallspeed = -20;
}
item->pos.xRot = 0;
item->gravityStatus = true;
Lara.gunStatus = LG_NO_ARMS;
if (item->frameNumber - g_Level.Anims[LA_ROPE_SWING].frameBase > 42)
{
item->animNumber = LA_ROPE_SWING_TO_REACH_1;
}
else if (item->frameNumber - g_Level.Anims[LA_ROPE_SWING].frameBase > 21)
{
item->animNumber = LA_ROPE_SWING_TO_REACH_2;
}
else
{
item->animNumber = LA_ROPE_SWING_TO_REACH_3;
}
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
item->currentAnimState = LS_REACH;
item->goalAnimState = LS_REACH;
Lara.ropePtr = -1;
}
}
2021-02-03 01:50:59 -03:00
void FallFromRope(ITEM_INFO* item)
{
2020-10-16 12:06:33 -05:00
item->speed = (abs(CurrentPendulum.Velocity.x / 65536) + abs(CurrentPendulum.Velocity.z / 65536)) / 2;
item->pos.xRot = 0;
item->pos.yPos += 320;
item->animNumber = LA_FALL_START;
item->frameNumber = g_Level.Anims[LA_FALL_START].frameBase;
item->currentAnimState = LS_JUMP_FORWARD;
item->goalAnimState = LS_JUMP_FORWARD;
item->fallspeed = 0;
item->gravityStatus = true;
Lara.gunStatus = LG_NO_ARMS;
Lara.ropePtr = -1;
}
2021-02-03 01:50:59 -03:00
void LaraClimbRope(ITEM_INFO* item, COLL_INFO* coll)
{
if (!(TrInput & IN_ACTION))
{
FallFromRope(item);
}
else
{
Camera.targetAngle = ANGLE(30.0f);
if (Lara.ropeCount)
{
if (!Lara.ropeFlag)
{
--Lara.ropeCount;
Lara.ropeOffset += Lara.ropeDownVel;
if (!Lara.ropeCount)
Lara.ropeFlag = 1;
return;
}
}
else
{
if (!Lara.ropeFlag)
{
ROPE_STRUCT* rope = &Ropes[Lara.ropePtr];
Lara.ropeOffset = 0;
2020-10-16 12:06:33 -05:00
Lara.ropeDownVel = ((unsigned int)(rope->meshSegment[Lara.ropeSegment + 1].y - rope->meshSegment[Lara.ropeSegment].y)) / 131072;
Lara.ropeCount = 0;
Lara.ropeOffset += Lara.ropeDownVel;
Lara.ropeFlag = 1;
return;
}
}
if (item->animNumber == LA_ROPE_DOWN && item->frameNumber == g_Level.Anims[item->animNumber].frameEnd)
{
SoundEffect(SFX_LARA_ROPEDOWN_LOOP, &LaraItem->pos, 0);
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
Lara.ropeFlag = 0;
++Lara.ropeSegment;
Lara.ropeOffset = 0;
}
if (!(TrInput & IN_BACK) || Lara.ropeSegment >= 21)
item->goalAnimState = LS_ROPE_IDLE;
}
}
2021-02-03 01:50:59 -03:00
void DelAlignLaraToRope(ITEM_INFO* item)
{
ROPE_STRUCT* rope;
short ropeY;
PHD_VECTOR vec, vec2, vec3, vec4, vec5, pos, pos2, diff, diff2;
int matrix[12];
short angle[3];
ANIM_FRAME* frame;
vec.x = 4096;
vec.y = 0;
vec.z = 0;
frame = (ANIM_FRAME*)GetBestFrame(item);
ropeY = Lara.ropeY - ANGLE(90);
rope = &Ropes[Lara.ropePtr];
2020-10-16 12:06:33 -05:00
_0x0046D130(rope, ((Lara.ropeSegment - 1) * 128) + frame->offsetY, &pos.x, &pos.y, &pos.z);
_0x0046D130(rope, ((Lara.ropeSegment - 1) * 128) + frame->offsetY - 192, &pos2.x, &pos2.y, &pos2.z);
diff.x = (pos.x - pos2.x) * 65536;
diff.y = (pos.y - pos2.y) * 65536;
diff.z = (pos.z - pos2.z) * 65536;
NormaliseRopeVector(&diff);
2020-10-16 12:06:33 -05:00
diff.x /= 4;
diff.y /= 4;
diff.z /= 4;
ScaleVector(&diff, DotProduct(&vec, &diff), &vec2);
vec2.x = vec.x - vec2.x;
vec2.y = vec.y - vec2.y;
vec2.z = vec.z - vec2.z;
vec3.x = vec2.x;
vec3.y = vec2.y;
vec3.z = vec2.z;
vec4.x = vec2.x;
vec4.y = vec2.y;
vec4.z = vec2.z;
diff2.x = diff.x;
diff2.y = diff.y;
diff2.z = diff.z;
2020-10-05 22:24:57 -03:00
ScaleVector(&vec3, 16384 * phd_cos(ropeY), &vec3);
ScaleVector(&diff2, DotProduct(&diff2, &vec2), &diff2);
2020-10-05 22:24:57 -03:00
ScaleVector(&diff2, 4096 - 16384 * phd_cos(ropeY), &diff2);
CrossProduct(&diff, &vec2, &vec4);
2020-10-05 22:24:57 -03:00
ScaleVector(&vec4, 16384 * phd_sin(ropeY), &vec4);
diff2.x += vec3.x;
diff2.y += vec3.y;
diff2.z += vec3.z;
2020-10-16 12:06:33 -05:00
vec2.x = (diff2.x + vec4.x) * 65536;
vec2.y = (diff2.y + vec4.y) * 65536;
vec2.z = (diff2.z + vec4.z) * 65536;
NormaliseRopeVector(&vec2);
2020-10-16 12:06:33 -05:00
vec2.x /= 4;
vec2.y /= 4;
vec2.z /= 4;
CrossProduct(&diff, &vec2, &vec5);
2020-10-16 12:06:33 -05:00
vec5.x *= 65536;
vec5.y *= 65536;
vec5.z *= 65536;
NormaliseRopeVector(&vec5);
2020-10-16 12:06:33 -05:00
vec5.x /= 4;
vec5.y /= 4;
vec5.z /= 4;
matrix[M00] = vec5.x;
matrix[M01] = diff.x;
matrix[M02] = vec2.x;
matrix[M10] = vec5.y;
matrix[M11] = diff.y;
matrix[M12] = vec2.y;
matrix[M20] = vec5.z;
matrix[M21] = diff.z;
matrix[M22] = vec2.z;
_0x0046D420(matrix, angle);
2020-10-16 12:06:33 -05:00
item->pos.xPos = rope->position.x + (rope->meshSegment[Lara.ropeSegment].x / 65536);
item->pos.yPos = rope->position.y + (rope->meshSegment[Lara.ropeSegment].y / 65536) + Lara.ropeOffset;
item->pos.zPos = rope->position.z + (rope->meshSegment[Lara.ropeSegment].z / 65536);
Matrix rotMatrix = Matrix::CreateFromYawPitchRoll(
TO_DEGREES(angle[1]),
TO_DEGREES(angle[0]),
TO_DEGREES(angle[2])
);
// PHD_MATH!
item->pos.xPos += -112 * rotMatrix.m[0][2]; // MatrixPtr[M02] >> W2V_SHIFT;
item->pos.yPos += -112 * rotMatrix.m[1][2]; // MatrixPtr[M12] >> W2V_SHIFT;
item->pos.zPos += -112 * rotMatrix.m[2][2]; // MatrixPtr[M22] >> W2V_SHIFT;
item->pos.xRot = angle[0];
item->pos.yRot = angle[1];
item->pos.zRot = angle[2];
}