TombEngine/TR5Main/Game/Lara/lara_collide.cpp

483 lines
10 KiB
C++
Raw Normal View History

#include "framework.h"
#include "lara.h"
#include "input.h"
2021-09-19 18:29:25 +03:00
#include "level.h"
#include "animation.h"
2021-09-19 18:29:25 +03:00
#include "effects/effects.h"
2021-08-28 13:27:58 +02:00
#include "collide.h"
2021-09-19 23:41:26 +03:00
#include "control/control.h"
#include "lara_collide.h"
#include "lara_swim.h"
2021-11-07 04:54:48 +03:00
#include "lara_tests.h"
2021-09-25 16:00:30 +03:00
#include "items.h"
2021-11-07 04:54:48 +03:00
#include "setup.h"
2021-11-11 01:16:27 +03:00
#include "GameFlowScript.h"
#include "GameScriptLevel.h"
2021-09-25 11:27:47 +02:00
/*this file has all the generic **collision** test functions called in lara's state code*/
bool LaraDeflectEdge(ITEM_INFO* item, COLL_INFO* coll)
{
2021-09-10 00:18:47 +03:00
if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT)
{
ShiftItem(item, coll);
item->goalAnimState = LS_STOP;
item->speed = 0;
item->gravityStatus = false;
return true;
}
2021-09-10 00:18:47 +03:00
if (coll->CollisionType == CT_LEFT)
{
ShiftItem(item, coll);
item->pos.yRot += ANGLE(coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
}
2021-09-10 00:18:47 +03:00
else if (coll->CollisionType == CT_RIGHT)
{
ShiftItem(item, coll);
item->pos.yRot -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE : DEFLECT_STRAIGHT_ANGLE);
}
return false;
}
2021-02-03 01:50:59 -03:00
void LaraDeflectEdgeJump(ITEM_INFO* item, COLL_INFO* coll)
{
ShiftItem(item, coll);
2021-09-10 00:18:47 +03:00
switch (coll->CollisionType)
{
case CT_FRONT:
case CT_TOP_FRONT:
if (!Lara.climbStatus || item->speed != 2)
{
2021-09-10 00:18:47 +03:00
if (coll->Middle.Floor <= 512)
{
2021-09-10 00:18:47 +03:00
if (coll->Middle.Floor <= 128)
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_JUMP_UP_LAND);
}
else
{
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_JUMP_WALL_SMASH_START, 1);
}
item->speed /= 4;
Lara.moveAngle += ANGLE(180);
if (item->fallspeed <= 0)
item->fallspeed = 1;
}
break;
case CT_TOP:
if (item->fallspeed <= 0)
item->fallspeed = 1;
break;
case CT_LEFT:
item->pos.yRot += ANGLE(5.0f);
break;
case CT_RIGHT:
item->pos.yRot -= ANGLE(5.0f);
break;
case CT_CLAMP:
2021-09-10 00:20:59 +03:00
item->pos.xPos -= 400 * phd_sin(coll->Setup.ForwardAngle);
item->pos.zPos -= 400 * phd_cos(coll->Setup.ForwardAngle);
item->speed = 0;
2021-09-10 00:18:47 +03:00
coll->Middle.Floor = 0;
if (item->fallspeed <= 0)
item->fallspeed = 16;
break;
}
}
bool LaraDeflectEdgeCrawl(ITEM_INFO* item, COLL_INFO* coll)
{
2021-09-10 00:18:47 +03:00
if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT)
{
ShiftItem(item, coll);
item->gravityStatus = false;
item->speed = 0;
return true;
}
2021-09-10 00:18:47 +03:00
if (coll->CollisionType == CT_LEFT)
{
ShiftItem(item, coll);
item->pos.yRot += ANGLE(2.0f);
}
2021-09-10 00:18:47 +03:00
else if (coll->CollisionType == CT_RIGHT)
{
ShiftItem(item, coll);
item->pos.yRot -= ANGLE(2.0f);
}
return false;
}
bool LaraHitCeiling(ITEM_INFO* item, COLL_INFO* coll)
{
2021-09-10 00:18:47 +03:00
if (coll->CollisionType == CT_TOP || coll->CollisionType == CT_CLAMP)
{
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x;
item->pos.yPos = coll->Setup.OldPosition.y;
item->pos.zPos = coll->Setup.OldPosition.z;
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_STAND_SOLID);
item->speed = 0;
item->fallspeed = 0;
item->gravityStatus = false;
return true;
}
return false;
}
2021-02-03 01:50:59 -03:00
void LaraCollideStop(ITEM_INFO* item, COLL_INFO* coll)
{
2021-09-10 00:20:59 +03:00
switch (coll->Setup.OldAnimState)
{
case LS_STOP:
case LS_TURN_RIGHT_SLOW:
case LS_TURN_LEFT_SLOW:
case LS_TURN_FAST:
2021-09-10 00:20:59 +03:00
item->currentAnimState = coll->Setup.OldAnimState;
item->animNumber = coll->Setup.OldAnimNumber;
item->frameNumber = coll->Setup.OldFrameNumber;
if (TrInput & IN_LEFT)
{
item->goalAnimState = LS_TURN_LEFT_SLOW;
}
else if (TrInput & IN_RIGHT)
{
item->goalAnimState = LS_TURN_RIGHT_SLOW;
}
else
{
item->goalAnimState = LS_STOP;
}
AnimateLara(item);
break;
default:
item->goalAnimState = LS_STOP;
if (item->animNumber != LA_STAND_SOLID)
{
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_STAND_SOLID);
}
break;
}
}
2021-09-25 13:00:14 +03:00
void LaraSnapToEdgeOfBlock(ITEM_INFO* item, COLL_INFO* coll, short angle)
{
if (item->currentAnimState == LS_SHIMMY_RIGHT)
{
switch (angle)
{
case NORTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFF90 | 0x390;
return;
case EAST:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFC70 | 0x70;
return;
case SOUTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFC70 | 0x70;
return;
case WEST:
default:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFF90 | 0x390;
return;
}
}
if (item->currentAnimState == LS_SHIMMY_LEFT)
{
switch (angle)
{
case NORTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFC70 | 0x70;
return;
case EAST:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFF90 | 0x390;
return;
case SOUTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFF90 | 0x390;
return;
case WEST:
default:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFC70 | 0x70;
return;
}
}
if (item->currentAnimState == LS_SHIMMY_FEET_RIGHT)
{
switch (angle)
{
case NORTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFF90 | 0x720;
return;
case EAST:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFC70 | 0xE0;
return;
case SOUTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFC70 | 0xE0;
return;
case WEST:
default:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFF90 | 0x720;
return;
}
}
if (item->currentAnimState == LS_SHIMMY_FEET_LEFT)
{
switch (angle)
{
case NORTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFC70 | 0xE0;
return;
case EAST:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFF90 | 0x720;
return;
case SOUTH:
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x & 0xFFFFFF90 | 0x720;
return;
case WEST:
default:
2021-09-10 00:20:59 +03:00
item->pos.zPos = coll->Setup.OldPosition.z & 0xFFFFFC70 | 0xE0;
return;
}
}
}
2021-09-25 13:00:14 +03:00
void LaraResetGravityStatus(ITEM_INFO* item, COLL_INFO* coll)
{
// This routine cleans gravity status flag and fallspeed, making it
// impossible to perform bugs such as QWOP and flare jump. Found by Troye -- Lwmte, 25.09.2021
if (coll->Middle.Floor <= STEPUP_HEIGHT)
{
item->gravityStatus = false;
item->fallspeed = 0;
}
}
2021-11-07 04:54:48 +03:00
void LaraSnapToHeight(ITEM_INFO* item, COLL_INFO* coll)
{
if (TestLaraSwamp(item) && coll->Middle.Floor > 0)
item->pos.yPos += SWAMP_GRAVITY;
else if (coll->Middle.Floor != NO_HEIGHT)
item->pos.yPos += coll->Middle.Floor;
}
2021-02-03 01:50:59 -03:00
short GetDirOctant(int rot)
{
return abs(rot) >= ANGLE(45) && abs(rot) <= ANGLE(135.0f);
}
2021-02-03 01:50:59 -03:00
void GetLaraDeadlyBounds()
{
BOUNDING_BOX* bounds;
BOUNDING_BOX tbounds;
bounds = GetBoundsAccurate(LaraItem);
phd_RotBoundingBoxNoPersp(&LaraItem->pos, bounds, &tbounds);
DeadlyBounds[0] = LaraItem->pos.xPos + tbounds.X1;
DeadlyBounds[1] = LaraItem->pos.xPos + tbounds.X2;
DeadlyBounds[2] = LaraItem->pos.yPos + tbounds.Y1;
DeadlyBounds[3] = LaraItem->pos.yPos + tbounds.Y2;
DeadlyBounds[4] = LaraItem->pos.zPos + tbounds.Z1;
DeadlyBounds[5] = LaraItem->pos.zPos + tbounds.Z2;
}
void LaraSurfaceCollision(ITEM_INFO* item, COLL_INFO* coll)
{
coll->Setup.ForwardAngle = Lara.moveAngle;
GetCollisionInfo(coll, item, PHD_VECTOR(0, LARA_HEIGHT_SURFSWIM, 0));
ShiftItem(item, coll);
if (coll->CollisionType & (CT_FRONT | CT_TOP | CT_TOP_FRONT | CT_CLAMP) ||
coll->Middle.Floor < 0 && coll->Middle.Slope)
{
item->fallspeed = 0;
item->pos.xPos = coll->Setup.OldPosition.x;
item->pos.yPos = coll->Setup.OldPosition.y;
item->pos.zPos = coll->Setup.OldPosition.z;
}
else if (coll->CollisionType == CT_LEFT)
{
item->pos.yRot += ANGLE(5);
}
else if (coll->CollisionType == CT_RIGHT)
{
item->pos.yRot -= ANGLE(5);
}
if (GetWaterHeight(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber) - item->pos.yPos > -100)
{
TestLaraWaterStepOut(item, coll);
}
else
SwimDive(item);
}
void LaraSwimCollision(ITEM_INFO* item, COLL_INFO* coll)
{
int oldX = item->pos.xPos;
int oldY = item->pos.yPos;
int oldZ = item->pos.zPos;
short oldXrot = item->pos.xRot;
short oldYrot = item->pos.yRot;
short oldZrot = item->pos.zRot;
if (item->pos.xRot < -ANGLE(90.0f) ||
item->pos.xRot > ANGLE(90.0f))
{
Lara.moveAngle = item->pos.yRot + ANGLE(180.0f);
coll->Setup.ForwardAngle = item->pos.yRot - ANGLE(180.0f);
}
else
{
Lara.moveAngle = item->pos.yRot;
coll->Setup.ForwardAngle = item->pos.yRot;
}
int height = LARA_HEIGHT * phd_sin(item->pos.xRot);
height = abs(height);
2021-11-11 01:16:27 +03:00
auto level = g_GameFlow->GetLevel(CurrentLevel);
if (height < ((level->LaraType == LaraType::Divesuit) << 6) + 200)
height = ((level->LaraType == LaraType::Divesuit) << 6) + 200;
coll->Setup.BadHeightUp = -(STEP_SIZE / 4);
coll->Setup.Height = height;
GetCollisionInfo(coll, item, PHD_VECTOR(0, height / 2, 0));
auto c1 = *coll;
c1.Setup.ForwardAngle += ANGLE(45.0f);
GetCollisionInfo(&c1, item, PHD_VECTOR(0, height / 2, 0));
auto c2 = *coll;
c2.Setup.ForwardAngle -= ANGLE(45.0f);
GetCollisionInfo(&c2, item, PHD_VECTOR(0, height / 2, 0));
ShiftItem(item, coll);
int flag = 0;
switch (coll->CollisionType)
{
case CT_FRONT:
if (item->pos.xRot <= ANGLE(25.0f))
{
if (item->pos.xRot >= -ANGLE(25.0f))
{
if (item->pos.xRot > ANGLE(5.0f))
item->pos.xRot += ANGLE(0.5f);
else if (item->pos.xRot < -ANGLE(5.0f))
item->pos.xRot -= ANGLE(0.5f);
else if (item->pos.xRot > 0)
item->pos.xRot += 45;
else if (item->pos.xRot < 0)
item->pos.xRot -= 45;
else
{
item->fallspeed = 0;
flag = 1;
}
}
else
{
item->pos.xRot -= ANGLE(1.0f);
flag = 1;
}
}
else
{
item->pos.xRot += ANGLE(1.0f);
flag = 1;
}
if (c1.CollisionType == CT_LEFT)
item->pos.yRot += ANGLE(2.0f);
else if (c1.CollisionType == CT_RIGHT)
item->pos.yRot -= ANGLE(2.0f);
else if (c2.CollisionType == CT_LEFT)
item->pos.yRot += ANGLE(2.0f);
else if (c2.CollisionType == CT_RIGHT)
item->pos.yRot -= ANGLE(2.0f);
break;
case CT_TOP:
if (item->pos.xRot >= -8190)
{
flag = 1;
item->pos.xRot -= ANGLE(1.0f);
}
break;
case CT_TOP_FRONT:
item->fallspeed = 0;
flag = 1;
break;
case CT_LEFT:
item->pos.yRot += ANGLE(2.0f);
flag = 1;
break;
case CT_RIGHT:
item->pos.yRot -= ANGLE(2.0f);
flag = 1;
break;
case CT_CLAMP:
flag = 2;
item->pos.xPos = coll->Setup.OldPosition.x;
item->pos.yPos = coll->Setup.OldPosition.y;
item->pos.zPos = coll->Setup.OldPosition.z;
item->fallspeed = 0;
break;
}
if (coll->Middle.Floor < 0 && coll->Middle.Floor != NO_HEIGHT)
{
flag = 1;
item->pos.xRot += ANGLE(1.0f);
item->pos.yPos += coll->Middle.Floor;
}
if (oldX == item->pos.xPos &&
oldY == item->pos.yPos &&
oldZ == item->pos.zPos &&
oldXrot == item->pos.xRot &&
oldYrot == item->pos.yRot ||
flag != 1)
{
if (flag == 2)
return;
}
if (Lara.waterStatus != LW_FLYCHEAT && Lara.ExtraAnim == NO_ITEM)
TestLaraWaterDepth(item, coll);
}