#include "framework.h" #include "camera.h" #include "animation.h" #include "lara.h" #include "effects/effects.h" #include "effects/debris.h" #include "lara_fire.h" #include "effects/weather.h" #include "level.h" #include "setup.h" #include "collide.h" #include "Sound/sound.h" #include "control/los.h" #include "savegame.h" #include "input.h" #include "items.h" #include "Objects/Generic/Object/burning_torch.h" using TEN::Renderer::g_Renderer; using namespace TEN::Entities::Generic; using namespace TEN::Effects::Environment; struct OLD_CAMERA { short currentAnimState; short goalAnimState; int targetDistance; short actualElevation; short targetElevation; short actualAngle; PHD_3DPOS pos; PHD_3DPOS pos2; PHD_VECTOR target; }; float LfAspectCorrection; GAME_VECTOR LastTarget; byte SniperCamActive; extern int KeyTriggerActive; PHD_VECTOR CurrentCameraPosition; SVECTOR CurrentCameraRotation; GAME_VECTOR LastIdeal; GAME_VECTOR Ideals[5]; OLD_CAMERA OldCam; int CameraSnaps = 0; int TargetSnaps = 0; GAME_VECTOR LookCamPosition; GAME_VECTOR LookCamTarget; int LSHKTimer = 0; int LSHKShotsFired = 0; PHD_VECTOR CamOldPos; CAMERA_INFO Camera; GAME_VECTOR ForcedFixedCamera; int UseForcedFixedCamera; int NumberCameras; int BinocularRange; int BinocularOn; CAMERA_TYPE BinocularOldCamera; bool LaserSight; int PhdPerspective; short CurrentFOV; int RumbleTimer = 0; int RumbleCounter = 0; void LookAt(CAMERA_INFO* cam, short roll) { Vector3 position = Vector3(cam->pos.x, cam->pos.y, cam->pos.z); Vector3 target = Vector3(cam->target.x, cam->target.y, cam->target.z); Vector3 up = Vector3(0.0f, -1.0f, 0.0f); float fov = TO_RAD(CurrentFOV / 1.333333f); float r = 0; TO_RAD(roll); g_Renderer.UpdateCameraMatrices(cam, r, fov); } void AlterFOV(int value) { CurrentFOV = value; PhdPerspective = g_Renderer.ScreenWidth / 2 * phd_cos(CurrentFOV / 2) / phd_sin(CurrentFOV / 2); } int mgLOS(GAME_VECTOR* start, GAME_VECTOR* target, int push) { int floorHeight, ceilingHeight; FLOOR_INFO* floor; auto x = start->x; auto y = start->y; auto z = start->z; auto roomNum = start->roomNumber; auto roomNum2 = roomNum; auto dx = target->x - x >> 3; auto dy = target->y - y >> 3; auto dz = target->z - z >> 3; auto flag = false; auto result = false; int i; for (i = 0; i < 8; ++i) { roomNum2 = roomNum; floor = GetFloor(x, y, z, &roomNum); if (g_Level.Rooms[roomNum2].flags & ENV_FLAG_SWAMP) { flag = true; break; } floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); if (floorHeight != NO_HEIGHT && ceilingHeight != NO_HEIGHT && ceilingHeight < floorHeight) { if (y > floorHeight) { if (y - floorHeight >= push) { flag = true; break; } y = floorHeight; } if (y < ceilingHeight) { if (ceilingHeight - y >= push) { flag = true; break; } y = ceilingHeight; } result = true; } else if (result) { flag = true; break; } x += dx; y += dy; z += dz; } if (i) { x -= dx; y -= dy; z -= dz; } GetFloor(x, y, z, &roomNum2); target->x = x; target->y = y; target->z = z; target->roomNumber = roomNum2; return !flag; } void InitialiseCamera() { Camera.shift = LaraItem->pos.yPos - WALL_SIZE; LastTarget.x = LaraItem->pos.xPos; LastTarget.y = Camera.shift; LastTarget.z = LaraItem->pos.zPos; LastTarget.roomNumber = LaraItem->roomNumber; Camera.target.x = LastTarget.x; Camera.target.y = Camera.shift; Camera.target.z = LastTarget.z; Camera.target.roomNumber = LaraItem->roomNumber; Camera.pos.x = LastTarget.x; Camera.pos.y = Camera.shift; Camera.pos.z = LastTarget.z - 100; Camera.pos.roomNumber = LaraItem->roomNumber; Camera.targetDistance = WALL_SIZE + STEP_SIZE * 2; Camera.item = NULL; Camera.numberFrames = 1; Camera.type = CAMERA_TYPE::CHASE_CAMERA; Camera.speed = 1; Camera.flags = CF_FOLLOW_CENTER; Camera.bounce = 0; Camera.number = -1; Camera.fixedCamera = false; AlterFOV(14560); UseForcedFixedCamera = 0; CalculateCamera(); } void MoveCamera(GAME_VECTOR* ideal, int speed) { GAME_VECTOR from, to; if (BinocularOn < 0) { speed = 1; BinocularOn++; } if (OldCam.pos.xRot != LaraItem->pos.xRot || OldCam.pos.yRot != LaraItem->pos.yRot || OldCam.pos.zRot != LaraItem->pos.zRot || OldCam.pos2.xRot != Lara.headXrot || OldCam.pos2.yRot != Lara.headYrot || OldCam.pos2.xPos != Lara.torsoXrot || OldCam.pos2.yPos != Lara.torsoYrot || OldCam.pos.xPos != LaraItem->pos.xPos || OldCam.pos.yPos != LaraItem->pos.yPos || OldCam.pos.zPos != LaraItem->pos.zPos || OldCam.currentAnimState != LaraItem->currentAnimState || OldCam.goalAnimState != LaraItem->goalAnimState || OldCam.targetDistance != Camera.targetDistance || OldCam.targetElevation != Camera.targetElevation || OldCam.actualElevation != Camera.actualElevation || OldCam.actualAngle != Camera.actualAngle || OldCam.target.x != Camera.target.x || OldCam.target.y != Camera.target.y || OldCam.target.z != Camera.target.z || Camera.oldType != Camera.type || BinocularOn < 0) { OldCam.pos.xRot = LaraItem->pos.xRot; OldCam.pos.yRot = LaraItem->pos.yRot; OldCam.pos.zRot = LaraItem->pos.zRot; OldCam.pos2.xRot = Lara.headXrot; OldCam.pos2.yRot = Lara.headYrot; OldCam.pos2.xPos = Lara.torsoXrot; OldCam.pos2.yPos = Lara.torsoYrot; OldCam.pos.xPos = LaraItem->pos.xPos; OldCam.pos.yPos = LaraItem->pos.yPos; OldCam.pos.zPos = LaraItem->pos.zPos; OldCam.currentAnimState = LaraItem->currentAnimState; OldCam.goalAnimState = LaraItem->goalAnimState; OldCam.targetDistance = Camera.targetDistance; OldCam.targetElevation = Camera.targetElevation; OldCam.actualElevation = Camera.actualElevation; OldCam.actualAngle = Camera.actualAngle; OldCam.target.x = Camera.target.x; OldCam.target.y = Camera.target.y; OldCam.target.z = Camera.target.z; LastIdeal.x = ideal->x; LastIdeal.y = ideal->y; LastIdeal.z = ideal->z; LastIdeal.roomNumber = ideal->roomNumber; } else { ideal->x = LastIdeal.x; ideal->y = LastIdeal.y; ideal->z = LastIdeal.z; ideal->roomNumber = LastIdeal.roomNumber; } Camera.pos.x += (ideal->x - Camera.pos.x) / speed; Camera.pos.y += (ideal->y - Camera.pos.y) / speed; Camera.pos.z += (ideal->z - Camera.pos.z) / speed; Camera.pos.roomNumber = ideal->roomNumber; if (Camera.bounce) { if (Camera.bounce <= 0) { int bounce = -Camera.bounce; int bounce2 = -Camera.bounce >> 2; Camera.target.x += GetRandomControl() % bounce - bounce2; Camera.target.y += GetRandomControl() % bounce - bounce2; Camera.target.z += GetRandomControl() % bounce - bounce2; Camera.bounce += 5; } else { Camera.pos.y += Camera.bounce; Camera.target.y += Camera.bounce; Camera.bounce = 0; } } auto roomNum = Camera.pos.roomNumber; auto yPos = Camera.pos.y; if (g_Level.Rooms[roomNum].flags & ENV_FLAG_SWAMP) yPos = g_Level.Rooms[roomNum].y - STEP_SIZE; FLOOR_INFO* floor = GetFloor(Camera.pos.x, yPos, Camera.pos.z, &roomNum); auto floorHeight = GetFloorHeight(floor, Camera.pos.x, yPos, Camera.pos.z); if (yPos < GetCeiling(floor, Camera.pos.x, yPos, Camera.pos.z) || yPos > floorHeight) { mgLOS(&Camera.target, &Camera.pos, 0); if (abs(Camera.pos.x - ideal->x) < (WALL_SIZE - STEP_SIZE) && abs(Camera.pos.y - ideal->y) < (WALL_SIZE - STEP_SIZE) && abs(Camera.pos.z - ideal->z) < (WALL_SIZE - STEP_SIZE)) { to.x = Camera.pos.x; to.y = Camera.pos.y; to.z = Camera.pos.z; to.roomNumber = Camera.pos.roomNumber; from.x = ideal->x; from.y = ideal->y; from.z = ideal->z; from.roomNumber = ideal->roomNumber; if (!mgLOS(&from, &to, 0) && ++CameraSnaps >= 8) { Camera.pos.x = ideal->x; Camera.pos.y = ideal->y; Camera.pos.z = ideal->z; Camera.pos.roomNumber = ideal->roomNumber; CameraSnaps = 0; } } } roomNum = Camera.pos.roomNumber; floor = GetFloor(Camera.pos.x, Camera.pos.y, Camera.pos.z, &roomNum); floorHeight = GetFloorHeight(floor, Camera.pos.x, Camera.pos.y, Camera.pos.z); auto ceilingHeight = GetCeiling(floor, Camera.pos.x, Camera.pos.y, Camera.pos.z); auto buffer = STEP_SIZE - 1; if ((Camera.pos.y - buffer) < ceilingHeight && (Camera.pos.y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { Camera.pos.y = (floorHeight + ceilingHeight) >> 1; } else if ((Camera.pos.y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { Camera.pos.y = floorHeight - buffer; } else if ((Camera.pos.y - buffer) < ceilingHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { Camera.pos.y = ceilingHeight + buffer; } else if (ceilingHeight >= floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT) { Camera.pos.x = ideal->x; Camera.pos.y = ideal->y; Camera.pos.z = ideal->z; Camera.pos.roomNumber = ideal->roomNumber; } GetFloor(Camera.pos.x, Camera.pos.y, Camera.pos.z, &Camera.pos.roomNumber); LookAt(&Camera, 0); if (Camera.mikeAtLara) { Camera.mikePos.x = LaraItem->pos.xPos; Camera.mikePos.y = LaraItem->pos.yPos; Camera.mikePos.z = LaraItem->pos.zPos; Camera.oldType = Camera.type; } else { short angle = phd_atan(Camera.target.z - Camera.pos.z, Camera.target.x - Camera.pos.x); Camera.mikePos.x = Camera.pos.x + PhdPerspective * phd_sin(angle); Camera.mikePos.y = Camera.pos.y; Camera.mikePos.z = Camera.pos.z + PhdPerspective * phd_cos(angle); Camera.oldType = Camera.type; } } void ChaseCamera(ITEM_INFO* item) { if (!Camera.targetElevation) Camera.targetElevation = -ANGLE(10.0f); Camera.targetElevation += item->pos.xRot; UpdateCameraElevation(); if (Camera.actualElevation > ANGLE(85.0f)) Camera.actualElevation = ANGLE(85.0f); else if (Camera.actualElevation < -ANGLE(85.0f)) Camera.actualElevation = -ANGLE(85.0f); int distance = Camera.targetDistance * phd_cos(Camera.actualElevation); short roomNum = Camera.target.roomNumber; GetFloor(Camera.target.x, Camera.target.y + STEP_SIZE, Camera.target.z, &roomNum); if (g_Level.Rooms[roomNum].flags & ENV_FLAG_SWAMP) Camera.target.y = g_Level.Rooms[roomNum].y - STEP_SIZE; auto x = Camera.target.x; auto y = Camera.target.y; auto z = Camera.target.z; roomNum = Camera.target.roomNumber; auto floor = GetFloor(x, y, z, &roomNum); auto floorHeight = GetFloorHeight(floor, x, y, z); auto ceilingHeight = GetCeiling(floor, x, y, z); if (((y < ceilingHeight || floorHeight < y) || floorHeight <= ceilingHeight) || (floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT)) { TargetSnaps++; Camera.target.x = LastTarget.x; Camera.target.y = LastTarget.y; Camera.target.z = LastTarget.z; Camera.target.roomNumber = LastTarget.roomNumber; } else TargetSnaps = 0; for (int i = 0; i < 5; i++) Ideals[i].y = Camera.target.y + Camera.targetDistance * phd_sin(Camera.actualElevation); int farthest = 0x7FFFFFFF; int farthestnum = 0; GAME_VECTOR temp[2]; for (int i = 0; i < 5; i++) { short angle; if (i == 0) angle = Camera.actualAngle; else angle = (i - 1) * ANGLE(90.0f); Ideals[i].x = Camera.target.x - distance * phd_sin(angle); Ideals[i].z = Camera.target.z - distance * phd_cos(angle); Ideals[i].roomNumber = Camera.target.roomNumber; if (mgLOS(&Camera.target, &Ideals[i], 200)) { temp[0].x = Ideals[i].x; temp[0].y = Ideals[i].y; temp[0].z = Ideals[i].z; temp[0].roomNumber = Ideals[i].roomNumber; temp[1].x = Camera.pos.x; temp[1].y = Camera.pos.y; temp[1].z = Camera.pos.z; temp[1].roomNumber = Camera.pos.roomNumber; if (i == 0 || mgLOS(&temp[0], &temp[1], 0)) { if (i == 0) { farthestnum = 0; break; } int dx = (Camera.pos.x - Ideals[i].x) * (Camera.pos.x - Ideals[i].x); dx += (Camera.pos.z - Ideals[i].z) * (Camera.pos.z - Ideals[i].z); if (dx < farthest) { farthest = dx; farthestnum = i; } } } else if (i == 0) { temp[0].x = Ideals[i].x; temp[0].y = Ideals[i].y; temp[0].z = Ideals[i].z; temp[0].roomNumber = Ideals[i].roomNumber; temp[1].x = Camera.pos.x; temp[1].y = Camera.pos.y; temp[1].z = Camera.pos.z; temp[1].roomNumber = Camera.pos.roomNumber; if (i == 0 || mgLOS(&temp[0], &temp[1], 0)) { int dx = (Camera.target.x - Ideals[i].x) * (Camera.target.x - Ideals[i].x); int dz = (Camera.target.z - Ideals[i].z) * (Camera.target.z - Ideals[i].z); if ((dx + dz) > 0x90000) { farthestnum = 0; break; } } } } GAME_VECTOR ideal = { Ideals[farthestnum].x , Ideals[farthestnum].y, Ideals[farthestnum].z }; ideal.roomNumber = Ideals[farthestnum].roomNumber; CameraCollisionBounds(&ideal, (STEP_SIZE + STEP_SIZE / 2), 1); MoveCamera(&ideal, Camera.speed); } void UpdateCameraElevation() { if (Camera.laraNode != -1) { PHD_VECTOR pos = { 0, 0, 0 }; GetLaraJointPosition(&pos, Camera.laraNode); PHD_VECTOR pos1 = { 0, -STEP_SIZE, WALL_SIZE * 2 }; GetLaraJointPosition(&pos1, Camera.laraNode); pos.z = pos1.z - pos.z; pos.x = pos1.x - pos.x; Camera.actualAngle = Camera.targetAngle + phd_atan(pos.z, pos.x); } else Camera.actualAngle = LaraItem->pos.yRot + Camera.targetAngle; Camera.actualElevation += (Camera.targetElevation - Camera.actualElevation) >> 3; } void CombatCamera(ITEM_INFO* item) { Camera.target.x = item->pos.xPos; Camera.target.z = item->pos.zPos; if (Lara.target) { Camera.targetAngle = Lara.targetAngles[0]; Camera.targetElevation = Lara.targetAngles[1] + item->pos.xRot; } else { Camera.targetAngle = Lara.headYrot + Lara.torsoYrot; Camera.targetElevation = Lara.headXrot + Lara.torsoXrot + item->pos.xRot - ANGLE(15.0f); } auto roomNum = Camera.target.roomNumber; GetFloor(Camera.target.x, Camera.target.y + STEP_SIZE, Camera.target.z, &roomNum); if (g_Level.Rooms[roomNum].flags & ENV_FLAG_SWAMP) Camera.target.y = g_Level.Rooms[roomNum].y - STEP_SIZE; auto floor = GetFloor(Camera.target.x, Camera.target.y, Camera.target.z, &Camera.target.roomNumber); auto floorHeight = GetFloorHeight(floor, Camera.target.x, Camera.target.y, Camera.target.z); auto ceilingHeight = GetCeiling(floor, Camera.target.x, Camera.target.y, Camera.target.z); auto buffer = STEP_SIZE / 4; if ((ceilingHeight + buffer) > (floorHeight - buffer) && floorHeight != NO_HEIGHT && ceilingHeight != NO_HEIGHT) { Camera.target.y = (ceilingHeight + floorHeight) >> 1; Camera.targetElevation = 0; } else if (Camera.target.y > (floorHeight - buffer) && floorHeight != NO_HEIGHT) { Camera.target.y = floorHeight - buffer; Camera.targetElevation = 0; } else if (Camera.target.y < (ceilingHeight + buffer) && ceilingHeight != NO_HEIGHT) { Camera.target.y = ceilingHeight + buffer; Camera.targetElevation = 0; } GetFloor(Camera.target.x, Camera.target.y, Camera.target.z, &Camera.target.roomNumber); int x = Camera.target.x; int y = Camera.target.y; int z = Camera.target.z; roomNum = Camera.target.roomNumber; floor = GetFloor(Camera.target.x, Camera.target.y, Camera.target.z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); if (y < ceilingHeight || y > floorHeight || ceilingHeight >= floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT) { TargetSnaps++; Camera.target.x = LastTarget.x; Camera.target.y = LastTarget.y; Camera.target.z = LastTarget.z; Camera.target.roomNumber = LastTarget.roomNumber; } else TargetSnaps = 0; UpdateCameraElevation(); Camera.targetDistance = WALL_SIZE + STEP_SIZE * 2; int distance = Camera.targetDistance * phd_cos(Camera.actualElevation); for (int i = 0; i < 5; i++) Ideals[i].y = Camera.target.y + Camera.targetDistance * phd_sin(Camera.actualElevation); int farthest = INT_MAX; int farthestnum = 0; GAME_VECTOR temp[2]; for (int i = 0; i < 5; i++) { short angle; if (i == 0) angle = Camera.actualAngle; else angle = (i - 1) * ANGLE(90.0f); Ideals[i].x = Camera.target.x - distance * phd_sin(angle); Ideals[i].z = Camera.target.z - distance * phd_cos(angle); Ideals[i].roomNumber = Camera.target.roomNumber; if (mgLOS(&Camera.target, &Ideals[i], 200)) { temp[0].x = Ideals[i].x; temp[0].y = Ideals[i].y; temp[0].z = Ideals[i].z; temp[0].roomNumber = Ideals[i].roomNumber; temp[1].x = Camera.pos.x; temp[1].y = Camera.pos.y; temp[1].z = Camera.pos.z; temp[1].roomNumber = Camera.pos.roomNumber; if (i == 0 || mgLOS(&temp[0], &temp[1], 0)) { if (i == 0) { farthestnum = 0; break; } int dx = (Camera.pos.x - Ideals[i].x) * (Camera.pos.x - Ideals[i].x); dx += (Camera.pos.z - Ideals[i].z) * (Camera.pos.z - Ideals[i].z); if (dx < farthest) { farthest = dx; farthestnum = i; } } } else if (i == 0) { temp[0].x = Ideals[i].x; temp[0].y = Ideals[i].y; temp[0].z = Ideals[i].z; temp[0].roomNumber = Ideals[i].roomNumber; temp[1].x = Camera.pos.x; temp[1].y = Camera.pos.y; temp[1].z = Camera.pos.z; temp[1].roomNumber = Camera.pos.roomNumber; if (i == 0 || mgLOS(&temp[0], &temp[1], 0)) { int dx = (Camera.target.x - Ideals[i].x) * (Camera.target.x - Ideals[i].x); int dz = (Camera.target.z - Ideals[i].z) * (Camera.target.z - Ideals[i].z); if ((dx + dz) > 0x90000) { farthestnum = 0; break; } } } } GAME_VECTOR ideal = { Ideals[farthestnum].x, Ideals[farthestnum].y, Ideals[farthestnum].z }; ideal.roomNumber = Ideals[farthestnum].roomNumber; CameraCollisionBounds(&ideal, (STEP_SIZE + STEP_SIZE / 2), 1); if (Camera.oldType == CAMERA_TYPE::FIXED_CAMERA) Camera.speed = 1; MoveCamera(&ideal, Camera.speed); } bool CameraCollisionBounds(GAME_VECTOR* ideal, int push, int yFirst) { auto x = ideal->x; auto y = ideal->y; auto z = ideal->z; FLOOR_INFO* floor; short roomNum; int floorHeight, ceilingHeight; if (yFirst) { roomNum = ideal->roomNumber; floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); auto buffer = STEP_SIZE - 1; if ((y - buffer) < ceilingHeight && (y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { y = (floorHeight + ceilingHeight) >> 1; } else if ((y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { y = floorHeight - buffer; } else if ((y - buffer) < ceilingHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { y = ceilingHeight + buffer; } } roomNum = ideal->roomNumber; floor = GetFloor(x - push, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x - push, y, z); ceilingHeight = GetCeiling(floor, x - push, y, z); if (y > floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || y < ceilingHeight) { x = (x & (~1023)) + push; } roomNum = ideal->roomNumber; floor = GetFloor(x, y, z - push, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z - push); ceilingHeight = GetCeiling(floor, x, y, z - push); if (y > floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || y < ceilingHeight) { z = (z & (~1023)) + push; } roomNum = ideal->roomNumber; floor = GetFloor(x + push, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x + push, y, z); ceilingHeight = GetCeiling(floor, x + push, y, z); if (y > floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || y < ceilingHeight) { x = (x | 1023) - push; } roomNum = ideal->roomNumber; floor = GetFloor(x, y, z + push, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z + push); ceilingHeight = GetCeiling(floor, x, y, z + push); if (y > floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || y < ceilingHeight) { z = (z | 1023) - push; } if (!yFirst) { roomNum = ideal->roomNumber; floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); auto buffer = STEP_SIZE - 1; if ((y - buffer) < ceilingHeight && (y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { y = (floorHeight + ceilingHeight) >> 1; } else if ((y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { y = floorHeight - buffer; } else if ((y - buffer) < ceilingHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { y = ceilingHeight + buffer; } } roomNum = ideal->roomNumber; floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); if (y > floorHeight || y < ceilingHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight) { return true; } floor = GetFloor(x, y, z, &ideal->roomNumber); ideal->x = x; ideal->y = y; ideal->z = z; return false; } void FixedCamera(ITEM_INFO* item) { GAME_VECTOR from, to; // Fixed cameras before TR3 had optional "movement" effect. // Later for some reason it was forced to always be 1, and actual speed value // from camera trigger was ignored. In TEN, we move speed value out of legacy // floordata trigger to camera itself and make use of it again. Still, by default, // value is 1 for UseForcedFixedCamera hack. int moveSpeed = 1; if (UseForcedFixedCamera) { from.x = ForcedFixedCamera.x; from.y = ForcedFixedCamera.y; from.z = ForcedFixedCamera.z; from.roomNumber = ForcedFixedCamera.roomNumber; } else { LEVEL_CAMERA_INFO* camera = &g_Level.Cameras[Camera.number]; from.x = camera->x; from.y = camera->y; from.z = camera->z; from.roomNumber = camera->roomNumber; // Multiply original speed by 8 to comply with original bitshifted speed from TR1-2 moveSpeed = camera->speed * 8 + 1; } Camera.fixedCamera = true; MoveCamera(&from, moveSpeed); if (Camera.timer) { if (!--Camera.timer) Camera.timer = -1; } } void LookCamera(ITEM_INFO* item) { auto headXrot = Lara.headXrot; auto headYrot = Lara.headYrot; auto torsoXrot = Lara.torsoXrot; auto torsoYrot = Lara.torsoYrot; Lara.torsoXrot = 0; Lara.torsoYrot = 0; Lara.headXrot <<= 1; Lara.headYrot <<= 1; if (Lara.headXrot > ANGLE(55.0f)) Lara.headXrot = ANGLE(55.0f); else if (Lara.headXrot < -ANGLE(75.0f)) Lara.headXrot = -ANGLE(75.0f); if (Lara.headYrot < -ANGLE(80.0f)) Lara.headYrot = -ANGLE(80.0f); else if (Lara.headYrot > ANGLE(80.0f)) Lara.headYrot = ANGLE(80.0f); if (abs(Lara.headXrot - OldCam.pos.xRot) >= 16) OldCam.pos.xRot = (Lara.headXrot + OldCam.pos.xRot) >> 1; else OldCam.pos.xRot = Lara.headXrot; if (abs(Lara.headYrot - OldCam.pos.yRot) >= 16) OldCam.pos.yRot = (Lara.headYrot + OldCam.pos.yRot) >> 1; else OldCam.pos.yRot = Lara.headYrot; PHD_VECTOR pos = { 0, STEP_SIZE / 16, STEP_SIZE / 4 }; GetLaraJointPosition(&pos, LM_HEAD); short roomNum = LaraItem->roomNumber; FLOOR_INFO* floor = GetFloor(pos.x, pos.y, pos.z, &roomNum); auto floorHeight = GetFloorHeight(floor, pos.x, pos.y, pos.z); auto ceilingHeight = GetCeiling(floor, pos.x, pos.y, pos.z); if (floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || pos.y > floorHeight || pos.y < ceilingHeight) { pos = { 0, STEP_SIZE / 16 , 0 }; GetLaraJointPosition(&pos, LM_HEAD); roomNum = LaraItem->roomNumber; floor = GetFloor(pos.x, pos.y + STEP_SIZE, pos.z, &roomNum); if (g_Level.Rooms[roomNum].flags & ENV_FLAG_SWAMP) { pos.y = g_Level.Rooms[roomNum].y - STEP_SIZE; floor = GetFloor(pos.x, pos.y, pos.z, &roomNum); } else floor = GetFloor(pos.x, pos.y, pos.z, &roomNum); floorHeight = GetFloorHeight(floor, pos.x, pos.y, pos.z); ceilingHeight = GetCeiling(floor, pos.x, pos.y, pos.z); if (floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || pos.y > floorHeight || pos.y < ceilingHeight) { pos.x = 0; pos.y = STEP_SIZE / 16; pos.z = -(STEP_SIZE / 4); GetLaraJointPosition(&pos, LM_HEAD); } } PHD_VECTOR pos2 = { 0, 0, -WALL_SIZE }; GetLaraJointPosition(&pos2, LM_HEAD); PHD_VECTOR pos3 = { 0, 0, WALL_SIZE * 2 }; GetLaraJointPosition(&pos3, LM_HEAD); int dx = (pos2.x - pos.x) >> 3; int dy = (pos2.y - pos.y) >> 3; int dz = (pos2.z - pos.z) >> 3; int x = pos.x; int y = pos.y; int z = pos.z; short roomNumber2 = LaraItem->roomNumber; int i = 0; for (i = 0; i < 8; i++) { roomNum = roomNumber2; floor = GetFloor(x, y + STEP_SIZE, z, &roomNumber2); if (g_Level.Rooms[roomNumber2].flags & ENV_FLAG_SWAMP) { y = g_Level.Rooms[roomNumber2].y - STEP_SIZE; break; } else floor = GetFloor(x, y, z, &roomNumber2); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); if (floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || ceilingHeight >= floorHeight || y > floorHeight || y < ceilingHeight) { break; } x += dx; y += dy; z += dz; } if (i) { x -= dx; y -= dy; z -= dz; } GAME_VECTOR ideal = { x, y, z }; ideal.roomNumber = roomNum; if (OldCam.pos.xRot == Lara.headXrot && OldCam.pos.yRot == Lara.headYrot && OldCam.pos.xPos == LaraItem->pos.xPos && OldCam.pos.yPos == LaraItem->pos.yPos && OldCam.pos.zPos == LaraItem->pos.zPos && OldCam.currentAnimState == LaraItem->currentAnimState && OldCam.goalAnimState == LaraItem->goalAnimState && Camera.oldType == CAMERA_TYPE::LOOK_CAMERA) { ideal.x = LookCamPosition.x; ideal.y = LookCamPosition.y; ideal.z = LookCamPosition.z; ideal.roomNumber = LookCamPosition.roomNumber; pos3.x = LookCamTarget.x; pos3.y = LookCamTarget.y; pos3.z = LookCamTarget.z; } else { OldCam.pos.xRot = Lara.headXrot; OldCam.pos.yRot = Lara.headYrot; OldCam.pos.xPos = LaraItem->pos.xPos; OldCam.pos.yPos = LaraItem->pos.yPos; OldCam.pos.zPos = LaraItem->pos.zPos; OldCam.currentAnimState = LaraItem->currentAnimState; OldCam.goalAnimState = LaraItem->goalAnimState; LookCamPosition.x = ideal.x; LookCamPosition.y = ideal.y; LookCamPosition.z = ideal.z; LookCamPosition.roomNumber = ideal.roomNumber; LookCamTarget.x = pos3.x; LookCamTarget.y = pos3.y; LookCamTarget.z = pos3.z; } CameraCollisionBounds(&ideal, (STEP_SIZE - STEP_SIZE / 8), 1); if (Camera.oldType == CAMERA_TYPE::FIXED_CAMERA) { Camera.pos.x = ideal.x; Camera.pos.y = ideal.y; Camera.pos.z = ideal.z; Camera.target.x = pos3.x; Camera.target.y = pos3.y; Camera.target.z = pos3.z; Camera.target.roomNumber = LaraItem->roomNumber; } else { Camera.pos.x += (ideal.x - Camera.pos.x) >> 2; Camera.pos.y += (ideal.y - Camera.pos.y) >> 2; Camera.pos.z += (ideal.z - Camera.pos.z) >> 2; Camera.target.x += (pos3.x - Camera.target.x) >> 2; Camera.target.y += (pos3.y - Camera.target.y) >> 2; Camera.target.z += (pos3.z - Camera.target.z) >> 2; Camera.target.roomNumber = LaraItem->roomNumber; } if (Camera.bounce && Camera.type == Camera.oldType) { if (Camera.bounce <= 0) { Camera.target.x += GetRandomControl() % (-Camera.bounce) - (-Camera.bounce >> 1); Camera.target.y += GetRandomControl() % (-Camera.bounce) - (-Camera.bounce >> 1); Camera.target.z += GetRandomControl() % (-Camera.bounce) - (-Camera.bounce >> 1); Camera.bounce += 5; } else { Camera.pos.y += Camera.bounce; Camera.target.y += Camera.bounce; Camera.bounce = 0; } } x = Camera.pos.x; y = Camera.pos.y; z = Camera.pos.z; roomNum = Camera.pos.roomNumber; floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); auto buffer = STEP_SIZE - 1; if ((y - buffer) < ceilingHeight && (y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { Camera.pos.y = (floorHeight + ceilingHeight) >> 1; } else if ((y + buffer) > floorHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { Camera.pos.y = floorHeight - buffer; } else if ((y - buffer) < ceilingHeight && ceilingHeight < floorHeight && ceilingHeight != NO_HEIGHT && floorHeight != NO_HEIGHT) { Camera.pos.y = ceilingHeight + buffer; } x = Camera.pos.x; y = Camera.pos.y; z = Camera.pos.z; roomNum = Camera.pos.roomNumber; floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); if ((g_Level.Rooms[roomNum].flags & ENV_FLAG_SWAMP)) Camera.pos.y = g_Level.Rooms[roomNum].y - STEP_SIZE; else if (y < ceilingHeight || y > floorHeight || ceilingHeight >= floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT) { mgLOS(&Camera.target, &Camera.pos, 0); } x = Camera.pos.x; y = Camera.pos.y; z = Camera.pos.z; roomNum = Camera.pos.roomNumber; floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); ceilingHeight = GetCeiling(floor, x, y, z); if (y < ceilingHeight || y > floorHeight || ceilingHeight >= floorHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT || g_Level.Rooms[roomNum].flags & ENV_FLAG_SWAMP) { Camera.pos.x = pos.x; Camera.pos.y = pos.y; Camera.pos.z = pos.z; Camera.pos.roomNumber = LaraItem->roomNumber; } GetFloor(Camera.pos.x, Camera.pos.y, Camera.pos.z, &Camera.pos.roomNumber); LookAt(&Camera, 0); if (Camera.mikeAtLara) { Camera.actualAngle = LaraItem->pos.yRot + Lara.headYrot + Lara.torsoYrot; Camera.mikePos.x = LaraItem->pos.xPos; Camera.mikePos.y = LaraItem->pos.yPos; Camera.mikePos.z = LaraItem->pos.zPos; } else { Camera.actualAngle = phd_atan(Camera.target.z - Camera.pos.z, Camera.target.x - Camera.pos.x); Camera.mikePos.x = Camera.pos.x + PhdPerspective * phd_sin(Camera.actualAngle); Camera.mikePos.z = Camera.pos.z + PhdPerspective * phd_cos(Camera.actualAngle); Camera.mikePos.y = Camera.pos.y; } Camera.oldType = Camera.type; Lara.headXrot = headXrot; Lara.headYrot = headYrot; Lara.torsoXrot = torsoXrot; Lara.torsoYrot = torsoYrot; } void BounceCamera(ITEM_INFO* item, short bounce, short maxDistance) { int distance = sqrt( SQUARE(item->pos.xPos - Camera.pos.x) + SQUARE(item->pos.yPos - Camera.pos.y) + SQUARE(item->pos.zPos - Camera.pos.z)); if (distance < maxDistance) { if (maxDistance == -1) Camera.bounce = bounce; else Camera.bounce = -(bounce * (maxDistance - distance) / maxDistance); } else if (maxDistance == -1) Camera.bounce = bounce; } void BinocularCamera(ITEM_INFO* item) { static int exittingBinos = 0; if (LSHKTimer) --LSHKTimer; if (!LaserSight) { if (InputBusy & IN_DRAW) exittingBinos = 1; else if (exittingBinos) { exittingBinos = 0; BinocularRange = 0; AlterFOV(14560); LaraItem->meshBits = -1; Lara.busy = false; Lara.headYrot = 0; Lara.headXrot = 0; Lara.torsoYrot = 0; Lara.torsoXrot = 0; Camera.type = BinocularOldCamera; return; } } LaraItem->meshBits = 0; AlterFOV(7 * (2080 - BinocularRange)); short headXrot = Lara.headXrot * 2; short headYrot = Lara.headYrot; if (headXrot > ANGLE(75.0f)) headXrot = ANGLE(75.0f); else if (headXrot < -ANGLE(75.0f)) headXrot = -ANGLE(75.0f); if (headYrot > ANGLE(80.0f)) headYrot = ANGLE(80.0f); else if (headYrot < -ANGLE(80.0f)) headYrot = -ANGLE(80.0f); auto x = LaraItem->pos.xPos; auto y = LaraItem->pos.yPos - (WALL_SIZE / 2); auto z = LaraItem->pos.zPos; short roomNum = LaraItem->roomNumber; FLOOR_INFO* floor = GetFloor(x, y, z, &roomNum); auto ceilingHeight = GetCeiling(floor, x, y, z); if (ceilingHeight <= (y - STEP_SIZE)) y -= STEP_SIZE; else y = ceilingHeight + (STEP_SIZE / 4); Camera.pos.x = x; Camera.pos.y = y; Camera.pos.z = z; Camera.pos.roomNumber = roomNum; int l = (WALL_SIZE * 20 + STEP_SIZE) * phd_cos(headXrot); int tx = x + l * phd_sin(LaraItem->pos.yRot + headYrot); int ty = y - (WALL_SIZE * 20 + STEP_SIZE) * phd_sin(headXrot); int tz = z + l * phd_cos(LaraItem->pos.yRot + headYrot); if (Camera.oldType == CAMERA_TYPE::FIXED_CAMERA) { Camera.target.x = tx; Camera.target.y = ty; Camera.target.z = tz; Camera.target.roomNumber = LaraItem->roomNumber; } else { Camera.target.x += (tx - Camera.target.x) >> 2; Camera.target.y += (ty - Camera.target.y) >> 2; Camera.target.z += (tz - Camera.target.z) >> 2; Camera.target.roomNumber = LaraItem->roomNumber; } if (Camera.bounce && Camera.type == Camera.oldType) { if (Camera.bounce <= 0) { Camera.target.x += (STEP_SIZE / 16) * (GetRandomControl() % (-Camera.bounce) - (-Camera.bounce >> 1)); Camera.target.y += (STEP_SIZE / 16) * (GetRandomControl() % (-Camera.bounce) - (-Camera.bounce >> 1)); Camera.target.z += (STEP_SIZE / 16) * (GetRandomControl() % (-Camera.bounce) - (-Camera.bounce >> 1)); Camera.bounce += 5; } else { Camera.bounce = 0; Camera.target.y += Camera.bounce; } } GetFloor(Camera.pos.x, Camera.pos.y, Camera.pos.z, &Camera.pos.roomNumber); LookAt(&Camera, 0); if (Camera.mikeAtLara) { Camera.actualAngle = LaraItem->pos.yRot + Lara.headYrot + Lara.torsoYrot; Camera.mikePos.x = LaraItem->pos.xPos; Camera.mikePos.y = LaraItem->pos.yPos; Camera.mikePos.z = LaraItem->pos.zPos; } else { Camera.actualAngle = phd_atan(Camera.target.z - Camera.pos.z, Camera.target.x - Camera.pos.x); Camera.mikePos.x = Camera.pos.x + PhdPerspective * phd_sin(Camera.actualAngle); Camera.mikePos.z = Camera.pos.z + PhdPerspective * phd_cos(Camera.actualAngle); Camera.mikePos.y = Camera.pos.y; } Camera.oldType = Camera.type; int range = 0; int flags = 0; if (!(InputBusy & IN_WALK)) { range = 64; flags = 0x10000; } else { range = 32; flags = 0x8000; } if (InputBusy & IN_SPRINT) { BinocularRange -= range; if (BinocularRange < 128) BinocularRange = 128; else SoundEffect(SFX_TR5_ZOOM_VIEW_WHIRR, 0, (flags << 8) | 6); } else if (InputBusy & IN_DUCK) { BinocularRange += range; if (BinocularRange > 1536) BinocularRange = 1536; else SoundEffect(SFX_TR5_ZOOM_VIEW_WHIRR, 0, (flags << 8) | 6); } PHD_VECTOR src = { Camera.pos.x, Camera.pos.y, Camera.pos.z }; PHD_VECTOR target = { Camera.target.x, Camera.target.y, Camera.target.z }; if (LaserSight) { int firing = 0; Ammo& ammo = GetAmmo(Lara.gunType); if (!(InputBusy & IN_ACTION) || WeaponDelay || !ammo) { if (!(InputBusy & IN_ACTION)) { if (Lara.gunType != WEAPON_CROSSBOW) WeaponDelay = 0; LSHKShotsFired = 0; Camera.bounce = 0; } } else { if (Lara.gunType == WEAPON_REVOLVER) { firing = 1; WeaponDelay = 16; Statistics.Game.AmmoUsed++; if (!ammo.hasInfinite()) (ammo)--; Camera.bounce = -16 - (GetRandomControl() & 0x1F); } else if (Lara.gunType == WEAPON_CROSSBOW) { firing = 1; WeaponDelay = 32; } else { if (Lara.Weapons[WEAPON_HK].SelectedAmmo == WEAPON_AMMO1) { WeaponDelay = 12; firing = 1; if (Lara.Weapons[WEAPON_HK].HasSilencer) SoundEffect(SFX_TR5_HK_SILENCED, 0, 0); else { SoundEffect(SFX_TR4_EXPLOSION1, 0, 83888140); SoundEffect(SFX_TR5_HK_FIRE, 0, 0); } } else if (Lara.Weapons[WEAPON_HK].SelectedAmmo == WEAPON_AMMO2) { if (!LSHKTimer) { if (++LSHKShotsFired == 5) { LSHKShotsFired = 0; WeaponDelay = 12; } LSHKTimer = 4; firing = 1; if (Lara.Weapons[WEAPON_HK].HasSilencer) SoundEffect(SFX_TR5_HK_SILENCED, 0, 0); else { SoundEffect(SFX_TR4_EXPLOSION1, 0, 83888140); SoundEffect(SFX_TR5_HK_FIRE, 0, 0); } } else { Camera.bounce = -16 - (GetRandomControl() & 0x1F); if (Lara.Weapons[WEAPON_HK].HasSilencer) SoundEffect(SFX_TR5_HK_SILENCED, 0, 0); else { SoundEffect(SFX_TR4_EXPLOSION1, 0, 83888140); SoundEffect(SFX_TR5_HK_FIRE, 0, 0); } } } else { if (LSHKTimer) { if (Lara.Weapons[WEAPON_HK].HasSilencer) SoundEffect(SFX_TR5_HK_SILENCED, 0, 0); else { SoundEffect(SFX_TR4_EXPLOSION1, 0, 83888140); SoundEffect(SFX_TR5_HK_FIRE, 0, 0); } } else { LSHKTimer = 4; firing = 1; if (Lara.Weapons[WEAPON_HK].HasSilencer) SoundEffect(SFX_TR5_HK_SILENCED, 0, 0); else { SoundEffect(SFX_TR4_EXPLOSION1, 0, 83888140); SoundEffect(SFX_TR5_HK_FIRE, 0, 0); } } Camera.bounce = -16 - (GetRandomControl() & 0x1F); } if (!ammo.hasInfinite()) (ammo)--; } } GetTargetOnLOS(&Camera.pos, &Camera.target, 1, firing); } else { GetTargetOnLOS(&Camera.pos, &Camera.target, 0, 0); if (!(InputBusy & IN_ACTION)) { // Reimplement this mode? } else LaraTorch(&src, &target, Lara.headYrot, 192); } } void ConfirmCameraTargetPos() { PHD_VECTOR pos = { 0, 0, 0 }; GetLaraJointPosition(&pos, LM_TORSO); if (Camera.laraNode != -1) { Camera.target.x = pos.x; Camera.target.y = pos.y; Camera.target.z = pos.z; } else { Camera.target.x = LaraItem->pos.xPos; Camera.target.y = (Camera.target.y + pos.y) >> 1; Camera.target.z = LaraItem->pos.zPos; } auto x = Camera.target.x; auto y = Camera.target.y; auto z = Camera.target.z; short roomNumber = Camera.target.roomNumber; FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber); auto floorHeight = GetFloorHeight(floor, x, y, z); auto ceilingHeight = GetCeiling(floor, x, y, z); if (y < ceilingHeight || floorHeight < y || floorHeight <= ceilingHeight || floorHeight == NO_HEIGHT || ceilingHeight == NO_HEIGHT) { Camera.target.x = pos.x; Camera.target.y = pos.y; Camera.target.z = pos.z; } } void CalculateCamera() { CamOldPos.x = Camera.pos.x; CamOldPos.y = Camera.pos.y; CamOldPos.z = Camera.pos.z; if (BinocularRange != 0) { BinocularOn = 1; BinocularCamera(LaraItem); if (BinocularRange != 0) return; } if (BinocularOn == 1) BinocularOn = -8; if (UseForcedFixedCamera != 0) { Camera.type = CAMERA_TYPE::FIXED_CAMERA; if (Camera.oldType != CAMERA_TYPE::FIXED_CAMERA) Camera.speed = 1; } // Camera is in a water room, play water sound effect. if (g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER) { SoundEffect(SFX_TR4_UNDERWATER, NULL, SFX_ALWAYS); if (Camera.underwater == false) Camera.underwater = true; } else { if (Camera.underwater == true) Camera.underwater = false; } ITEM_INFO* item; bool fixedCamera = false; if (Camera.item != NULL && (Camera.type == CAMERA_TYPE::FIXED_CAMERA || Camera.type == CAMERA_TYPE::HEAVY_CAMERA)) { item = Camera.item; fixedCamera = true; } else { item = LaraItem; fixedCamera = false; } BOUNDING_BOX* bounds = GetBoundsAccurate(item); int x; int y = ((bounds->Y1 + bounds->Y2) / 2) + item->pos.yPos - STEP_SIZE; int z; if (Camera.item) { if (!fixedCamera) { auto dx = Camera.item->pos.xPos - item->pos.xPos; auto dz = Camera.item->pos.zPos - item->pos.zPos; int shift = sqrt(SQUARE(dx) + SQUARE(dz)); short angle = phd_atan(dz, dx) - item->pos.yRot; short tilt = phd_atan(shift, y - (bounds->Y1 + bounds->Y2) / 2 - Camera.item->pos.yPos); bounds = GetBoundsAccurate(Camera.item); angle >>= 1; tilt >>= 1; if (angle > -ANGLE(50.0f) && angle < ANGLE(50.0f) && tilt > -ANGLE(85.0f) && tilt < ANGLE(85.0f)) { short change = angle - Lara.headYrot; if (change > ANGLE(4.0f)) Lara.headYrot += ANGLE(4.0f); else if (change < -ANGLE(4.0f)) Lara.headYrot -= ANGLE(4.0f); else Lara.headYrot += change; Lara.torsoYrot = Lara.headYrot; change = tilt - Lara.headXrot; if (change > ANGLE(4.0f)) Lara.headXrot += ANGLE(4.0f); else if (change < -ANGLE(4.0f)) Lara.headXrot -= ANGLE(4.0f); else Lara.headXrot += change; Lara.torsoXrot = Lara.headXrot; Camera.type = CAMERA_TYPE::LOOK_CAMERA; Camera.item->lookedAt = 1; } } } if (Camera.type == CAMERA_TYPE::LOOK_CAMERA || Camera.type == CAMERA_TYPE::COMBAT_CAMERA) { if (Camera.type == CAMERA_TYPE::COMBAT_CAMERA) { LastTarget.x = Camera.target.x; LastTarget.y = Camera.target.y; LastTarget.z = Camera.target.z; LastTarget.roomNumber = Camera.target.roomNumber; } Camera.target.roomNumber = item->roomNumber; if (Camera.fixedCamera || BinocularOn < 0) { Camera.target.y = y; Camera.speed = 1; } else { Camera.target.y += (y - Camera.target.y) >> 2; Camera.speed = Camera.type != CAMERA_TYPE::LOOK_CAMERA ? 8 : 4; } Camera.fixedCamera = false; if (Camera.type == CAMERA_TYPE::LOOK_CAMERA) LookCamera(item); else CombatCamera(item); } else { LastTarget.x = Camera.target.x; LastTarget.y = Camera.target.y; LastTarget.z = Camera.target.z; LastTarget.roomNumber = Camera.target.roomNumber; Camera.target.roomNumber = item->roomNumber; Camera.target.y = y; if (Camera.type != CAMERA_TYPE::CHASE_CAMERA && Camera.flags != CF_CHASE_OBJECT && (Camera.number != -1 &&(SniperCamActive = g_Level.Cameras[Camera.number].flags & 3, g_Level.Cameras[Camera.number].flags & 2))) { PHD_VECTOR pos = { 0, 0, 0 }; GetLaraJointPosition(&pos, LM_TORSO); x = pos.x; y = pos.y; z = pos.z; Camera.target.x = pos.x; Camera.target.y = pos.y; Camera.target.z = pos.z; } else { auto shift = (bounds->X1 + bounds->X2 + bounds->Z1 + bounds->Z2) / 4; x = item->pos.xPos + shift * phd_sin(item->pos.yRot); z = item->pos.zPos + shift * phd_cos(item->pos.yRot); Camera.target.x = x; Camera.target.z = z; if (item->objectNumber == ID_LARA) { ConfirmCameraTargetPos(); x = Camera.target.x; y = Camera.target.y; z = Camera.target.z; } } if (fixedCamera == Camera.fixedCamera) { Camera.fixedCamera = false; if (Camera.speed != 1 && Camera.oldType != CAMERA_TYPE::LOOK_CAMERA && BinocularOn >= 0) { if (TargetSnaps <= 8) { x = LastTarget.x + ((x - LastTarget.x) >> 2); Camera.target.x = x; y = LastTarget.y + ((y - LastTarget.y) >> 2); Camera.target.y = y; z = LastTarget.z + ((z - LastTarget.z) >> 2); Camera.target.z = z; } else TargetSnaps = 0; } } else { Camera.fixedCamera = true; Camera.speed = 1; } GetFloor(x, y, z, &Camera.target.roomNumber); if (abs(LastTarget.x - Camera.target.x) < 4 && abs(LastTarget.y - Camera.target.y) < 4 && abs(LastTarget.z - Camera.target.z) < 4) { Camera.target.x = LastTarget.x; Camera.target.y = LastTarget.y; Camera.target.z = LastTarget.z; } if (Camera.type != CAMERA_TYPE::CHASE_CAMERA && Camera.flags != CF_CHASE_OBJECT) FixedCamera(item); else ChaseCamera(item); } Camera.fixedCamera = fixedCamera; Camera.last = Camera.number; if (Camera.type != CAMERA_TYPE::HEAVY_CAMERA || Camera.timer == -1) { Camera.type = CAMERA_TYPE::CHASE_CAMERA; Camera.speed = 10; Camera.number = -1; Camera.lastItem = Camera.item; Camera.item = NULL; Camera.targetElevation = 0; Camera.targetAngle = 0; Camera.targetDistance = 1536; Camera.flags = 0; Camera.laraNode = -1; } } void LookLeftRight() { Camera.type = CAMERA_TYPE::LOOK_CAMERA; if (TrInput & IN_LEFT) { TrInput &= ~IN_LEFT; if (Lara.headYrot > -ANGLE(44.0f)) { if (BinocularRange) Lara.headYrot += ANGLE(2.0f) * (BinocularRange - 1792) / 1536; else Lara.headYrot -= ANGLE(2.0f); } } else if (TrInput & IN_RIGHT) { TrInput &= ~IN_RIGHT; if (Lara.headYrot < ANGLE(44.0f)) { if (BinocularRange) Lara.headYrot += ANGLE(2.0f) * (1792 - BinocularRange) / 1536; else Lara.headYrot += ANGLE(2.0f); } } if (Lara.gunStatus != LG_HANDS_BUSY && Lara.Vehicle == NO_ITEM && !Lara.leftArm.lock && !Lara.rightArm.lock) { Lara.torsoYrot = Lara.headYrot; } } void LookUpDown() { Camera.type = CAMERA_TYPE::LOOK_CAMERA; if (TrInput & IN_FORWARD) { TrInput &= ~IN_FORWARD; if (Lara.headXrot > -ANGLE(35.0f)) { if (BinocularRange) Lara.headXrot += ANGLE(2.0f) * (BinocularRange - 1792) / 3072; else Lara.headXrot -= ANGLE(2.0f); } } else if (TrInput & IN_BACK) { TrInput &= ~IN_BACK; if (Lara.headXrot < ANGLE(30.0f)) { if (BinocularRange) Lara.headXrot += ANGLE(2.0f) * (1792 - BinocularRange) / 3072; else Lara.headXrot += ANGLE(2.0f); } } if (Lara.gunStatus != LG_HANDS_BUSY && Lara.Vehicle == NO_ITEM && !Lara.leftArm.lock && !Lara.rightArm.lock) { Lara.torsoXrot = Lara.headXrot; } } void ResetLook() { if (Camera.type != CAMERA_TYPE::LOOK_CAMERA) { if (Lara.headXrot <= -ANGLE(2.0f) || Lara.headXrot >= ANGLE(2.0f)) Lara.headXrot = Lara.headXrot / -8 + Lara.headXrot; else Lara.headXrot = 0; if (Lara.headYrot <= -ANGLE(2.0f) || Lara.headYrot >= ANGLE(2.0f)) Lara.headYrot = Lara.headYrot / -8 + Lara.headYrot; else Lara.headYrot = 0; if (Lara.gunStatus != LG_HANDS_BUSY && !Lara.leftArm.lock && !Lara.rightArm.lock && Lara.Vehicle == NO_ITEM) { Lara.torsoYrot = Lara.headYrot; Lara.torsoXrot = Lara.headXrot; } else { if (!Lara.headXrot) Lara.torsoXrot = 0; if (!Lara.headYrot) Lara.torsoYrot = 0; } } } void RumbleScreen() { if (!(GlobalCounter & 0x1FF)) SoundEffect(SFX_TR5_KLAXON, 0, 4104); if (RumbleTimer >= 0) RumbleTimer++; if (RumbleTimer > 450) { if (!(GetRandomControl() & 0x1FF)) { RumbleCounter = 0; RumbleTimer = -32 - (GetRandomControl() & 0x1F); return; } } if (RumbleTimer < 0) { if (RumbleCounter >= abs(RumbleTimer)) { Camera.bounce = -(GetRandomControl() % abs(RumbleTimer)); RumbleTimer++; } else { RumbleCounter++; Camera.bounce = -(GetRandomControl() % RumbleCounter); } } }