mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-02 17:57:59 +03:00
336 lines
8.6 KiB
C++
336 lines
8.6 KiB
C++
#include "framework.h"
|
|
#include "Objects/Generic/puzzles_keys.h"
|
|
|
|
#include "Game/animation.h"
|
|
#include "Game/camera.h"
|
|
#include "Game/collision/collide_item.h"
|
|
#include "Game/control/control.h"
|
|
#include "Game/gui.h"
|
|
#include "Game/items.h"
|
|
#include "Game/Lara/lara.h"
|
|
#include "Game/Lara/lara_helpers.h"
|
|
#include "Game/pickup/pickup.h"
|
|
#include "Objects/Generic/Switches/generic_switch.h"
|
|
#include "Specific/input.h"
|
|
#include "Specific/level.h"
|
|
#include "Specific/setup.h"
|
|
|
|
using namespace TEN::Entities::Switches;
|
|
|
|
short puzzleItem;
|
|
|
|
enum PuzzleType
|
|
{
|
|
PUZZLETYPE_NORMAL,
|
|
PUZZLETYPE_SPECIFIC,
|
|
PUZZLETYPE_CUTSCENE,
|
|
PUZZLETYPE_ANIM_AFTER
|
|
};
|
|
|
|
OBJECT_COLLISION_BOUNDS PuzzleBounds =
|
|
{
|
|
0, 0,
|
|
-256, 256,
|
|
0, 0,
|
|
ANGLE(-10.0f), ANGLE(10.0f),
|
|
ANGLE(-30.0f), ANGLE(30.0f),
|
|
ANGLE(-10.0f), ANGLE(10.0f)
|
|
};
|
|
|
|
static PHD_VECTOR KeyHolePosition(0, 0, 312);
|
|
OBJECT_COLLISION_BOUNDS KeyHoleBounds =
|
|
{
|
|
-256, 256,
|
|
0, 0,
|
|
0, 412,
|
|
ANGLE(-10.0f), ANGLE(10.0f),
|
|
ANGLE(-30.0f), ANGLE(30.0f),
|
|
ANGLE(-10.0f), ANGLE(10.0f)
|
|
};
|
|
|
|
// Puzzles
|
|
void PuzzleHoleCollision(short itemNumber, ITEM_INFO* laraItem, COLL_INFO* coll)
|
|
{
|
|
auto* laraInfo = GetLaraInfo(laraItem);
|
|
auto* receptableItem = &g_Level.Items[itemNumber];
|
|
|
|
int flag = PUZZLETYPE_NORMAL;
|
|
|
|
if (receptableItem->TriggerFlags >= 0)
|
|
{
|
|
if (receptableItem->TriggerFlags <= 1024)
|
|
{
|
|
if (receptableItem->TriggerFlags &&
|
|
receptableItem->TriggerFlags != 999 &&
|
|
receptableItem->TriggerFlags != 998)
|
|
{
|
|
flag = PUZZLETYPE_ANIM_AFTER;
|
|
}
|
|
}
|
|
else
|
|
flag = PUZZLETYPE_CUTSCENE;
|
|
}
|
|
else
|
|
flag = PUZZLETYPE_SPECIFIC;
|
|
|
|
if (((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() != NO_ITEM) &&
|
|
!BinocularRange &&
|
|
laraItem->ActiveState == LS_IDLE &&
|
|
laraItem->AnimNumber == LA_STAND_IDLE &&
|
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
|
GetKeyTrigger(&g_Level.Items[itemNumber])) ||
|
|
(laraInfo->Control.IsMoving &&
|
|
laraInfo->interactedItem == itemNumber))
|
|
{
|
|
short oldYrot = receptableItem->Position.yRot;
|
|
|
|
auto* bounds = GetBoundsAccurate(receptableItem);
|
|
PuzzleBounds.boundingBox.X1 = bounds->X1 - 256;
|
|
PuzzleBounds.boundingBox.X2 = bounds->X2 + 256;
|
|
PuzzleBounds.boundingBox.Z1 = bounds->Z1 - 256;
|
|
PuzzleBounds.boundingBox.Z2 = bounds->Z2 + 256;
|
|
|
|
if (TestLaraPosition(&PuzzleBounds, receptableItem, laraItem))
|
|
{
|
|
if (!laraInfo->Control.IsMoving)
|
|
{
|
|
if (g_Gui.GetInventoryItemChosen() == NO_ITEM)
|
|
{
|
|
if (g_Gui.IsObjectInInventory(receptableItem->ObjectNumber - (ID_PUZZLE_HOLE1 - ID_PUZZLE_ITEM1)))
|
|
g_Gui.SetEnterInventory(receptableItem->ObjectNumber - (ID_PUZZLE_HOLE1 - ID_PUZZLE_ITEM1));
|
|
|
|
receptableItem->Position.yRot = oldYrot;
|
|
return;
|
|
}
|
|
|
|
if (g_Gui.GetInventoryItemChosen() != receptableItem->ObjectNumber - (ID_PUZZLE_HOLE1 - ID_PUZZLE_ITEM1))
|
|
{
|
|
receptableItem->Position.yRot = oldYrot;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (flag != PUZZLETYPE_CUTSCENE)
|
|
{
|
|
PHD_VECTOR pos = { 0, 0, bounds->Z1 - 100 };
|
|
if (!MoveLaraPosition(&pos, receptableItem, laraItem))
|
|
{
|
|
laraInfo->interactedItem = itemNumber;
|
|
g_Gui.SetInventoryItemChosen(NO_ITEM);
|
|
receptableItem->Position.yRot = oldYrot;
|
|
return;
|
|
}
|
|
}
|
|
|
|
RemoveObjectFromInventory(static_cast<GAME_OBJECT_ID>(receptableItem->ObjectNumber - (ID_PUZZLE_HOLE1 - ID_PUZZLE_ITEM1)), 1);
|
|
|
|
if (flag == PUZZLETYPE_SPECIFIC)
|
|
{
|
|
laraItem->ActiveState = LS_MISC_CONTROL;
|
|
laraItem->AnimNumber = -receptableItem->TriggerFlags;
|
|
|
|
if (laraItem->AnimNumber != LA_TRIDENT_SET)
|
|
PuzzleDone(receptableItem, itemNumber);
|
|
}
|
|
else
|
|
{
|
|
laraItem->AnimNumber = LA_USE_PUZZLE;
|
|
laraItem->ActiveState = LS_INSERT_PUZZLE;
|
|
receptableItem->ItemFlags[0] = 1;
|
|
}
|
|
|
|
laraItem->FrameNumber = g_Level.Anims[laraItem->AnimNumber].frameBase;
|
|
laraInfo->Control.IsMoving = false;
|
|
ResetLaraFlex(laraItem);
|
|
laraInfo->Control.HandStatus = HandStatus::Busy;
|
|
receptableItem->Flags |= 0x20;
|
|
laraInfo->interactedItem = itemNumber;
|
|
g_Gui.SetInventoryItemChosen(NO_ITEM);
|
|
receptableItem->Position.yRot = oldYrot;
|
|
return;
|
|
}
|
|
|
|
if (laraInfo->Control.IsMoving)
|
|
{
|
|
if (laraInfo->interactedItem == itemNumber)
|
|
{
|
|
laraInfo->Control.IsMoving = false;
|
|
laraInfo->Control.HandStatus = HandStatus::Free;
|
|
}
|
|
}
|
|
|
|
receptableItem->Position.yRot = oldYrot;
|
|
}
|
|
else
|
|
{
|
|
if (!laraInfo->Control.IsMoving && laraInfo->interactedItem == itemNumber || laraInfo->interactedItem != itemNumber)
|
|
{
|
|
if (laraInfo->interactedItem == itemNumber)
|
|
{
|
|
if (laraItem->ActiveState != LS_MISC_CONTROL)
|
|
{
|
|
if (flag != PUZZLETYPE_CUTSCENE)
|
|
ObjectCollision(itemNumber, laraItem, coll);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (laraItem->ActiveState == LS_MISC_CONTROL)
|
|
return;
|
|
|
|
if (flag != PUZZLETYPE_CUTSCENE)
|
|
ObjectCollision(itemNumber, laraItem, coll);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PuzzleDoneCollision(short itemNumber, ITEM_INFO* laraItem, COLL_INFO* coll)
|
|
{
|
|
if (g_Level.Items[itemNumber].TriggerFlags - 998 > 1)
|
|
ObjectCollision(itemNumber, laraItem, coll);
|
|
}
|
|
|
|
void PuzzleDone(ITEM_INFO* item, short itemNumber)
|
|
{
|
|
item->ObjectNumber += GAME_OBJECT_ID{ ID_PUZZLE_DONE1 - ID_PUZZLE_HOLE1 };
|
|
item->AnimNumber = Objects[item->ObjectNumber].animIndex;
|
|
item->FrameNumber = g_Level.Anims[item->AnimNumber].frameBase;
|
|
item->RequiredState = 0;
|
|
item->TargetState = g_Level.Anims[item->AnimNumber].ActiveState;
|
|
item->ActiveState = g_Level.Anims[item->AnimNumber].ActiveState;
|
|
|
|
AddActiveItem(itemNumber);
|
|
|
|
item->Flags |= IFLAG_ACTIVATION_MASK;
|
|
item->Status = ITEM_ACTIVE;
|
|
}
|
|
|
|
void DoPuzzle()
|
|
{
|
|
puzzleItem = Lara.interactedItem;
|
|
auto* item = &g_Level.Items[puzzleItem];
|
|
|
|
int flag = 0;
|
|
|
|
if (item->TriggerFlags >= 0)
|
|
{
|
|
if (item->TriggerFlags <= 1024)
|
|
{
|
|
if (item->TriggerFlags && item->TriggerFlags != 999 && item->TriggerFlags != 998)
|
|
flag = 3;
|
|
}
|
|
else
|
|
flag = 2;
|
|
}
|
|
else
|
|
flag = 1;
|
|
|
|
if (LaraItem->ActiveState == LS_INSERT_PUZZLE)
|
|
{
|
|
if (item->ItemFlags[0])
|
|
{
|
|
if (flag == 3)
|
|
LaraItem->ItemFlags[0] = item->TriggerFlags;
|
|
else
|
|
{
|
|
LaraItem->ItemFlags[0] = 0;
|
|
PuzzleDone(item, puzzleItem);
|
|
item->ItemFlags[0] = 0;
|
|
}
|
|
}
|
|
if (LaraItem->AnimNumber == LA_TRIDENT_SET)
|
|
PuzzleDone(item, puzzleItem);
|
|
}
|
|
}
|
|
|
|
// Keys
|
|
void KeyHoleCollision(short itemNumber, ITEM_INFO* laraItem, COLL_INFO* coll)
|
|
{
|
|
auto* laraInfo = GetLaraInfo(laraItem);
|
|
auto* keyHoleItem = &g_Level.Items[itemNumber];
|
|
|
|
if (g_Level.Items[itemNumber].TriggerFlags == 1 &&
|
|
keyHoleItem->ObjectNumber == ID_KEY_HOLE8)
|
|
{
|
|
if (keyHoleItem->ItemFlags[3])
|
|
{
|
|
keyHoleItem->ItemFlags[3]--;
|
|
if (!keyHoleItem->ItemFlags[3])
|
|
keyHoleItem->MeshBits = 2;
|
|
}
|
|
}
|
|
|
|
if (!((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() != NO_ITEM) &&
|
|
!BinocularRange &&
|
|
laraItem->ActiveState == LS_IDLE &&
|
|
laraItem->AnimNumber == LA_STAND_IDLE) &&
|
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
|
(!laraInfo->Control.IsMoving || laraInfo->interactedItem != itemNumber))
|
|
{
|
|
if (keyHoleItem->ObjectNumber < ID_KEY_HOLE6)
|
|
ObjectCollision(itemNumber, laraItem, coll);
|
|
}
|
|
else
|
|
{
|
|
if (TestLaraPosition(&KeyHoleBounds, keyHoleItem, laraItem))
|
|
{
|
|
if (!laraInfo->Control.IsMoving) //TROYE INVENTORY FIX ME
|
|
{
|
|
if (keyHoleItem->Status != ITEM_NOT_ACTIVE)
|
|
return;
|
|
|
|
if (g_Gui.GetInventoryItemChosen() == NO_ITEM)
|
|
{
|
|
if (g_Gui.IsObjectInInventory(keyHoleItem->ObjectNumber - (ID_KEY_HOLE1 - ID_KEY_ITEM1)))
|
|
g_Gui.SetEnterInventory(keyHoleItem->ObjectNumber - (ID_KEY_HOLE1 - ID_KEY_ITEM1));
|
|
|
|
return;
|
|
}
|
|
|
|
if (g_Gui.GetInventoryItemChosen() != keyHoleItem->ObjectNumber - (ID_KEY_HOLE1 - ID_KEY_ITEM1))
|
|
return;
|
|
}
|
|
|
|
if (MoveLaraPosition(&KeyHolePosition, keyHoleItem, laraItem))
|
|
{
|
|
if (keyHoleItem->ObjectNumber == ID_KEY_HOLE8)
|
|
laraItem->AnimNumber = LA_KEYCARD_USE;
|
|
else
|
|
{
|
|
RemoveObjectFromInventory(static_cast<GAME_OBJECT_ID>(keyHoleItem->ObjectNumber - (ID_KEY_HOLE1 - ID_KEY_ITEM1)), 1);
|
|
laraItem->AnimNumber = LA_USE_KEY;
|
|
}
|
|
|
|
laraItem->ActiveState = LS_INSERT_KEY;
|
|
laraItem->FrameNumber = g_Level.Anims[laraItem->AnimNumber].frameBase;
|
|
laraInfo->Control.IsMoving = false;
|
|
ResetLaraFlex(laraItem);
|
|
laraInfo->Control.HandStatus = HandStatus::Busy;
|
|
keyHoleItem->Flags |= 0x20;
|
|
keyHoleItem->Status = ITEM_ACTIVE;
|
|
|
|
if (keyHoleItem->TriggerFlags == 1 && keyHoleItem->ObjectNumber == ID_KEY_HOLE8)
|
|
{
|
|
keyHoleItem->ItemFlags[3] = 92;
|
|
g_Gui.SetInventoryItemChosen(NO_ITEM);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
laraInfo->interactedItem = itemNumber;
|
|
|
|
g_Gui.SetInventoryItemChosen(NO_ITEM);
|
|
return;
|
|
}
|
|
|
|
if (laraInfo->Control.IsMoving && laraInfo->interactedItem == itemNumber)
|
|
{
|
|
laraInfo->Control.IsMoving = false;
|
|
laraInfo->Control.HandStatus = HandStatus::Free;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|