TombEngine/TR5Main/Game/control.cpp

1187 lines
24 KiB
C++
Raw Normal View History

2018-08-19 09:46:58 +02:00
#include "control.h"
#include "..\Global\global.h"
2018-08-19 09:46:58 +02:00
#include "pickup.h"
#include "spotcam.h"
2019-11-21 07:43:34 +01:00
#include "Camera.h"
#include "Lara.h"
2018-08-19 09:46:58 +02:00
#include "hair.h"
#include "items.h"
#include "effect2.h"
#include "draw.h"
#include "inventory.h"
#include "gameflow.h"
#include "lot.h"
#include "pickup.h"
#include "draw.h"
#include "healt.h"
#include "savegame.h"
#include "sound.h"
#include "spotcam.h"
#include "Box.h"
#include "objects.h"
#include "switch.h"
2019-12-01 08:13:19 +01:00
#include "laramisc.h"
2018-08-19 09:46:58 +02:00
#include "..\Specific\roomload.h"
#include "..\Specific\input.h"
#include "..\Specific\init.h"
#include "..\Specific\winmain.h"
#include <process.h>
#include <stdio.h>
2019-11-15 07:40:22 +01:00
__int32 KeyTriggerActive;
extern GameFlow* g_GameFlow;
2018-09-23 12:01:07 +02:00
extern GameScript* g_GameScript;
extern Inventory* g_Inventory;
GAME_STATUS __cdecl ControlPhase(__int32 numFrames, __int32 demoMode)
2018-08-19 09:46:58 +02:00
{
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
2018-08-19 09:46:58 +02:00
RegeneratePickups();
if (numFrames > 10)
numFrames = 10;
if (TrackCameraInit)
UseSpotCam = false;
2018-08-19 09:46:58 +02:00
SetDebounce = true;
2018-08-19 09:46:58 +02:00
for (FramesCount += numFrames; FramesCount > 0; FramesCount -= 2)
{
GlobalCounter++;
UpdateSky();
2018-08-19 09:46:58 +02:00
// Poll the keyboard and update input variables
if (CurrentLevel != 0)
{
if (S_UpdateInput() == -1)
return GAME_STATUS_NONE;
}
2018-08-19 09:46:58 +02:00
// Has Lara control been disabled?
if (DisableLaraControl || CurrentLevel == 0)
2018-08-19 09:46:58 +02:00
{
if (CurrentLevel != 0)
DbInput = 0;
TrInput &= 0x200;
}
// If cutscene has been triggered then clear input
if (CutSeqTriggered)
TrInput = 0;
// Does the player want to enter inventory?
SetDebounce = false;
if (CurrentLevel != 0 && !g_Renderer->IsFading())
2018-08-19 09:46:58 +02:00
{
if ((DbInput & IN_DESELECT || g_Inventory->GetEnterObject() != NO_ITEM) && !CutSeqTriggered && LaraItem->hitPoints > 0)
{
2018-09-07 18:34:18 +02:00
// Stop all sounds
__int32 inventoryResult = g_Inventory->DoInventory();
switch (inventoryResult)
{
case INV_RESULT_LOAD_GAME:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_LOAD_GAME;
case INV_RESULT_EXIT_TO_TILE:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_EXIT_TO_TITLE;
}
2018-08-19 09:46:58 +02:00
}
}
// Has level been completed?
if (CurrentLevel != 0 && LevelComplete)
2019-04-29 13:10:58 +02:00
return GAME_STATUS_LEVEL_COMPLETED;
2018-08-19 09:46:58 +02:00
__int32 oldInput = TrInput;
2018-09-08 20:54:13 +02:00
// Is Lara dead?
if (CurrentLevel != 0 && (Lara.deathCount > 300 || Lara.deathCount > 60 && TrInput))
2018-08-19 09:46:58 +02:00
{
__int32 inventoryResult = g_Inventory->DoInventory();
switch (inventoryResult)
{
case INV_RESULT_NEW_GAME:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_NEW_GAME;
case INV_RESULT_LOAD_GAME:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_LOAD_GAME;
case INV_RESULT_EXIT_TO_TILE:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_EXIT_TO_TITLE;
}
2018-08-19 09:46:58 +02:00
}
if (demoMode && TrInput == -1)
{
oldInput = 0;
TrInput = 0;
}
if (CurrentLevel == 0)
TrInput = 0;
2018-11-11 23:42:30 +01:00
// Handle lasersight and binocular
if (CurrentLevel != 0)
{
if (!(TrInput & IN_LOOK) || SniperCameraActive || UseSpotCam || TrackCameraInit ||
((LaraItem->currentAnimState != STATE_LARA_STOP || LaraItem->animNumber != ANIMATION_LARA_STAY_IDLE)
&& (!Lara.isDucked
|| TrInput & IN_DUCK
|| LaraItem->animNumber != ANIMATION_LARA_CROUCH_IDLE
|| LaraItem->goalAnimState != STATE_LARA_CROUCH_IDLE)))
{
if (BinocularRange == 0)
{
if (SniperCameraActive || UseSpotCam || TrackCameraInit)
TrInput &= ~IN_LOOK;
}
else
{
if (LaserSight)
{
BinocularRange = 0;
LaserSight = false;
AlterFOV(ANGLE(80));
LaraItem->meshBits = 0xFFFFFFFF;
Lara.isDucked = false;
Camera.type = BinocularOldCamera;
Lara.headYrot = 0;
Lara.headXrot = 0;
Lara.torsoYrot = 0;
Lara.torsoXrot = 0;
Camera.bounce = 0;
BinocularOn = -8;
TrInput &= ~IN_LOOK;
}
else
{
TrInput |= IN_LOOK;
}
}
Infrared = false;
}
else if (BinocularRange == 0)
{
if (Lara.gunStatus == LG_READY
&& ((Lara.gunType == WEAPON_REVOLVER && g_LaraExtra.Weapons[WEAPON_REVOLVER].HasLasersight)
|| (Lara.gunType == WEAPON_HK)
|| (Lara.gunType == WEAPON_CROSSBOW && g_LaraExtra.Weapons[WEAPON_CROSSBOW].HasLasersight)))
{
BinocularRange = 128;
BinocularOldCamera = Camera.oldType;
Lara.busy = true;
LaserSight = true;
/*if (!(gfLevelFlags & GF_LVOP_TRAIN))
InfraRed = TRUE;
else*
2019-11-21 07:43:34 +01:00
InfraRed = false;*/
Infrared = true;
}
else
Infrared = false;
}
else
{
if (LaserSight)
{
/*if (!(gfLevelFlags & GF_LVOP_TRAIN))
InfraRed = TRUE;
else
2019-11-21 07:43:34 +01:00
InfraRed = false;*/
Infrared = true;
}
else
{
/*if ((gfLevelFlags & GF_LVOP_TRAIN) && (inputBusy & IN_ACTION))
InfraRed = TRUE;
else
2019-11-21 07:43:34 +01:00
InfraRed = false;*/
Infrared = false;
}
}
}
// Clear dynamic lights
2018-08-19 09:46:58 +02:00
ClearDynamics();
ClearFires();
g_Renderer->ClearDynamicLights();
GotLaraSpheres = false;
2018-09-08 20:54:13 +02:00
// Update all items
InItemControlLoop = true;
2018-08-19 09:46:58 +02:00
__int16 itemNum = NextItemActive;
while (itemNum != NO_ITEM)
{
ITEM_INFO* item = &Items[itemNum];
__int16 nextItem = item->nextActive;
if (item->afterDeath <= 128)
{
if (Objects[item->objectNumber].control)
Objects[item->objectNumber].control(itemNum);
}
else
{
KillItem(itemNum);
}
2018-08-19 09:46:58 +02:00
itemNum = nextItem;
}
InItemControlLoop = false;
KillMoveItems();
2018-09-08 20:54:13 +02:00
// Update all effects
InItemControlLoop = true;
__int16 fxNum = NextFxActive;
while (fxNum != NO_ITEM)
{
__int16 nextFx = Effects[fxNum].nextActive;
if (Objects[Effects[fxNum].objectNumber].control)
(*Objects[Effects[fxNum].objectNumber].control)(fxNum);
fxNum = nextFx;
}
InItemControlLoop = false;
KillMoveEffects();
2018-09-08 20:54:13 +02:00
// Update some effect timers
if (SmokeCountL)
SmokeCountL--;
if (SmokeCountR)
SmokeCountR--;
if (SplashCount)
SplashCount--;
if (WeaponDelay)
WeaponDelay--;
2018-09-12 20:37:37 +02:00
if (WeaponEnemyTimer)
WeaponEnemyTimer--;
2018-08-19 09:46:58 +02:00
if (CurrentLevel != 0)
{
if (Lara.hasFired)
{
AlertNearbyGuards(LaraItem);
Lara.hasFired = false;
}
// Is Lara poisoned?
if (Lara.poisoned)
{
if (Lara.poisoned <= 4096)
{
if (Lara.dpoisoned)
++Lara.dpoisoned;
}
else
{
Lara.poisoned = 4096;
}
if ((gfLevelFlags & 0x80u) != 0 && !Lara.gassed)
{
if (Lara.dpoisoned)
{
Lara.dpoisoned -= 8;
if (Lara.dpoisoned < 0)
Lara.dpoisoned = 0;
}
}
if (Lara.dpoisoned >= 256 && !(Wibble & 0xFF))
{
LaraItem->hitPoints -= Lara.poisoned >> (8 - Lara.gassed);
PoisonFlags = 16;
}
}
// Control Lara
InItemControlLoop = true;
Lara.skelebob = NULL;
2019-12-01 08:13:19 +01:00
LaraControl(Lara.itemNumber);
InItemControlLoop = false;
KillMoveItems();
// Update Lara's ponytails
HairControl(0, 0, 0);
if (level->LaraType == LARA_YOUNG)
HairControl(0, 1, 0);
}
2018-08-19 09:46:58 +02:00
if (UseSpotCam)
2018-09-07 18:34:18 +02:00
{
2018-09-08 20:54:13 +02:00
// Draw flyby cameras
if (CurrentLevel != 0)
g_Renderer->EnableCinematicBars(true);
2018-08-19 09:46:58 +02:00
CalculateSpotCameras();
2018-09-07 18:34:18 +02:00
}
2018-08-19 09:46:58 +02:00
else
2018-09-07 18:34:18 +02:00
{
2018-09-08 20:54:13 +02:00
// Do the standard camera
2018-09-07 18:34:18 +02:00
g_Renderer->EnableCinematicBars(false);
TrackCameraInit = false;
2018-08-19 09:46:58 +02:00
CalculateCamera();
2018-09-07 18:34:18 +02:00
}
2018-09-08 20:54:13 +02:00
//WTF: what is this? It's used everywhere so it has to stay
2018-08-19 09:46:58 +02:00
Wibble = (Wibble + 4) & 0xFC;
2018-09-08 20:54:13 +02:00
// Update special effects
TriggerLaraDrips();
if (SmashedMeshCount)
{
do
{
SmashedMeshCount--;
FLOOR_INFO* floor = GetFloor(
SmashedMesh[SmashedMeshCount]->x,
SmashedMesh[SmashedMeshCount]->y,
SmashedMesh[SmashedMeshCount]->z,
&SmashedMeshRoom[SmashedMeshCount]);
__int32 height = GetFloorHeight(
floor,
SmashedMesh[SmashedMeshCount]->x,
SmashedMesh[SmashedMeshCount]->y,
SmashedMesh[SmashedMeshCount]->z);
TestTriggers(TriggerIndex, 1, 0);
floor->stopper = false;
SmashedMesh[SmashedMeshCount] = 0;
} while (SmashedMeshCount != 0);
}
2018-08-19 09:46:58 +02:00
UpdateSparks();
UpdateFireSparks();
UpdateSmoke();
UpdateBlood();
UpdateBubbles();
UpdateDebris();
UpdateGunShells();
UpdateSplashes();
UpdateDrips();
UpdateRats();
UpdateBats();
UpdateSpiders();
UpdateShockwaves();
UpdateLightning();
UpdatePulseColor();
AnimateWaterfalls();
if (level->Rumble)
RumbleScreen();
SoundEffects();
HealtBarTimer--;
GameTimer++;
2018-08-19 09:46:58 +02:00
}
2019-04-29 13:10:58 +02:00
return GAME_STATUS_NONE;
2018-08-19 09:46:58 +02:00
}
unsigned __stdcall GameMain(void*)
{
DB_Log(2, "GameMain - DLL");
printf("GameMain\n");
2018-09-08 20:54:13 +02:00
// We still need legacy matrices because control routines use them
2018-08-19 09:46:58 +02:00
MatrixPtr = MatrixStack;
DxMatrixPtr = (byte*)malloc(48 * 40);
2018-09-08 20:54:13 +02:00
// Initialise legacy memory buffer and game timer
2018-08-19 09:46:58 +02:00
InitGameMalloc();
TIME_Init();
2019-05-09 13:50:55 +02:00
// Do a fixed time title image
g_Renderer->DoTitleImage();
2018-09-08 20:54:13 +02:00
// Execute the LUA gameflow and play the game
g_GameFlow->DoGameflow();
DoTheGame = false;
2018-09-08 20:54:13 +02:00
// Finish the thread
2018-08-19 09:46:58 +02:00
PostMessageA((HWND)WindowsHandle, 0x10u, 0, 0);
_endthreadex(1);
2018-08-19 09:46:58 +02:00
return 1;
2018-09-01 15:46:37 +02:00
}
2018-08-19 09:46:58 +02:00
GAME_STATUS __cdecl DoTitle(__int32 index)
2018-08-19 09:46:58 +02:00
{
DB_Log(2, "DoTitle - DLL");
printf("DoTitle\n");
CreditsDone = false;
CanLoad = false;
// Load the level
S_LoadLevelFile(index);
__int32 inventoryResult;
if (g_GameFlow->TitleType == TITLE_FLYBY)
{
// Initialise items, effects, lots, camera
InitialiseFXArray(true);
2019-11-15 07:40:22 +01:00
InitialisePickupDisplay();
InitialiseCamera();
SOUND_Stop();
RequiredStartPos = false;
if (InitialiseGame)
{
GameTimer = 0;
RequiredStartPos = false;
InitialiseGame = false;
}
Savegame.Level.Timer = 0;
if (CurrentLevel == 1)
Savegame.TLCount = 0;
LastInventoryItem = -1;
DelCutSeqPlayer = 0;
TitleControlsLockedOut = false;
GameMode = 1;
// Initialise flyby cameras
InitSpotCamSequences();
InitialiseSpotCam(2);
CurrentAtmosphere = 83;
UseSpotCam = true;
// Play background music
//CurrentAtmosphere = ambient;
S_CDPlay(CurrentAtmosphere, 1);
IsAtmospherePlaying = true;
// Initialise ponytails
InitialiseHair();
ControlPhase(2, 0);
inventoryResult = g_Inventory->DoTitleInventory();
}
else
{
inventoryResult = g_Inventory->DoTitleInventory();
}
UseSpotCam = false;
S_CDStop();
switch (inventoryResult)
{
case INV_RESULT_NEW_GAME:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_NEW_GAME;
case INV_RESULT_LOAD_GAME:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_LOAD_GAME;
case INV_RESULT_EXIT_GAME:
2019-04-29 13:10:58 +02:00
return GAME_STATUS_EXIT_GAME;
}
2019-04-29 13:10:58 +02:00
return GAME_STATUS_NEW_GAME;
2018-08-19 09:46:58 +02:00
}
GAME_STATUS __cdecl DoLevel(__int32 index, __int32 ambient, bool loadFromSavegame)
2018-08-19 09:46:58 +02:00
{
CreditsDone = false;
CanLoad = false;
2018-09-08 20:54:13 +02:00
// If not loading a savegame, then clear all the infos
if (!loadFromSavegame)
{
Savegame.Level.Timer = 0;
Savegame.Level.Distance = 0;
Savegame.Level.AmmoUsed = 0;
Savegame.Level.AmmoHits = 0;
Savegame.Level.Kills = 0;
}
2018-10-24 23:32:22 +02:00
// Load the level
S_LoadLevelFile(index);
// Initialise items, effects, lots, camera
InitialiseFXArray(true);
2019-11-15 07:40:22 +01:00
InitialisePickupDisplay();
InitialiseCamera();
SOUND_Stop();
2018-10-24 23:32:22 +02:00
// Restore the game?
if (loadFromSavegame)
{
2018-10-24 23:32:22 +02:00
char fileName[255];
ZeroMemory(fileName, 255);
sprintf(fileName, "savegame.%d", g_GameFlow->SelectedSaveGame);
SaveGame::Load(fileName);
RequiredStartPos = false;
InitialiseGame = false;
2018-10-24 23:32:22 +02:00
g_GameFlow->SelectedSaveGame = 0;
}
else
{
RequiredStartPos = false;
if (InitialiseGame)
{
GameTimer = 0;
RequiredStartPos = false;
InitialiseGame = false;
}
2018-08-19 09:46:58 +02:00
Savegame.Level.Timer = 0;
if (CurrentLevel == 1)
Savegame.TLCount = 0;
}
2018-08-19 09:46:58 +02:00
LastInventoryItem = -1;
2018-08-19 09:46:58 +02:00
DelCutSeqPlayer = 0;
TitleControlsLockedOut = false;
g_Inventory->SetEnterObject(NO_ITEM);
g_Inventory->SetSelectedObject(NO_ITEM);
2018-08-22 08:53:34 +02:00
2018-09-08 20:54:13 +02:00
// Initialise flyby cameras
InitSpotCamSequences();
2018-09-08 20:54:13 +02:00
// Play background music
2018-08-22 08:53:34 +02:00
CurrentAtmosphere = ambient;
S_CDPlay(CurrentAtmosphere, 1);
IsAtmospherePlaying = true;
2018-08-19 09:46:58 +02:00
2018-09-08 20:54:13 +02:00
// Initialise ponytails
2018-08-19 09:46:58 +02:00
InitialiseHair();
__int32 nframes = 2;
GAME_STATUS result = ControlPhase(nframes, 0);
2018-09-07 18:34:18 +02:00
g_Renderer->FadeIn();
2018-09-08 20:54:13 +02:00
// The game loop, finally!
while (true)
2018-08-19 09:46:58 +02:00
{
nframes = DrawPhaseGame();
result = ControlPhase(nframes, 0); //printf("LastSpotCam: %d\n", LastSpotCam);
2018-09-08 20:54:13 +02:00
2019-04-29 13:10:58 +02:00
if (result == GAME_STATUS_EXIT_TO_TITLE ||
result == GAME_STATUS_LOAD_GAME ||
result == GAME_STATUS_LEVEL_COMPLETED)
2018-09-08 20:54:13 +02:00
{
// Here is the only way for exiting from the loop
SOUND_Stop();
S_CDStop();
return result;
2018-09-08 20:54:13 +02:00
}
2018-08-21 21:32:56 +03:00
Sound_UpdateScene();
2018-08-19 09:46:58 +02:00
}
}
void __cdecl TestTriggers(__int16* data, __int32 heavy, __int32 HeavyFlags)
{
__int32 flip = -1;
__int32 flipAvailable = 0;
__int32 newEffect = -1;
__int32 switchOff = 0;
__int32 switchFlag = 0;
__int16 objectNumber = 0;
__int32 keyResult = 0;
__int16 cameraFlags = 0;
__int16 cameraTimer = 0;
__int32 spotCamIndex = 0;
HeavyTriggered = false;
if (!heavy)
{
Lara.canMonkeySwing = false;
Lara.climbStatus = false;
}
if (!data)
return;
// Burn Lara
if ((*data & 0x1F) == LAVA_TYPE)
{
if (!heavy && (LaraItem->pos.yPos == LaraItem->floor || Lara.waterStatus))
LavaBurn(LaraItem);
2018-09-23 09:38:24 +02:00
if (*data & 0x8000)
return;
data++;
}
// Lara can climb
if ((*data & 0x1F) == CLIMB_TYPE)
{
if (!heavy)
{
__int16 quad = (unsigned __int16)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90);
if ((1 << (quad + 8)) & *data)
Lara.climbStatus = true;
}
2018-09-23 09:38:24 +02:00
if (*data & 0x8000)
return;
data++;
}
// Lara can monkey
if ((*data & 0x1F) == MONKEY_TYPE)
{
if (!heavy)
Lara.canMonkeySwing = true;
2018-09-23 09:38:24 +02:00
if (*data & 0x8000)
return;
data++;
}
// Trigger triggerer
if ((*data & 0x1F) == TRIGTRIGGER_TYPE)
{
if (!(*data & 0x20) || *data & 0x8000)
return;
data++;
}
__int16 triggerType = (*(data++) >> 8) & 0x3F;
__int16 flags = *(data++);
__int16 timer = flags & 0xFF;
if (Camera.type != HEAVY_CAMERA)
RefreshCamera(triggerType, data);
if (heavy)
{
switch (triggerType)
{
case HEAVY:
case HEAVYANTITRIGGER:
break;
case HEAVYSWITCH:
if (!HeavyFlags)
return;
if (HeavyFlags >= 0)
{
flags &= 0x3E00u;
if (flags != HeavyFlags)
return;
}
else
{
flags |= 0x3E00u;
flags += HeavyFlags;
}
break;
default:
// Enemies can only activate heavy triggers
return;
}
}
__int16 value = 0;
switch (triggerType)
{
case TRIGGER_TYPES::SWITCH:
value = *(data++) & 0x3FF;
2018-09-23 09:38:24 +02:00
if (flags & 0x100)
Items[value].itemFlags[0] = 1;
if (!SwitchTrigger(value, timer))
return;
objectNumber = Items[value].objectNumber;
if (objectNumber >= ID_SWITCH_TYPE1 && objectNumber <= ID_SWITCH_TYPE6 && Items[value].triggerFlags == 5)
switchFlag = 1;
switchOff = (Items[value].currentAnimState == 1);
break;
case TRIGGER_TYPES::MONKEY:
if (LaraItem->currentAnimState >= 75 &&
(LaraItem->currentAnimState <= 79 ||
LaraItem->currentAnimState == 82 ||
LaraItem->currentAnimState == 83))
break;
return;
case TRIGGER_TYPES::TIGHTROPE_T:
if (LaraItem->currentAnimState >= 119 &&
LaraItem->currentAnimState <= 127 &&
LaraItem->currentAnimState != 126)
break;
return;
case TRIGGER_TYPES::CRAWLDUCK_T:
if (LaraItem->currentAnimState == 80 ||
LaraItem->currentAnimState == 81 ||
LaraItem->currentAnimState == 84 ||
LaraItem->currentAnimState == 85 ||
LaraItem->currentAnimState == 86 ||
LaraItem->currentAnimState == 71 ||
LaraItem->currentAnimState == 72 ||
LaraItem->currentAnimState == 105 ||
LaraItem->currentAnimState == 106)
break;
return;
case TRIGGER_TYPES::CLIMB_T:
if (LaraItem->currentAnimState == 10 ||
LaraItem->currentAnimState == 56 ||
LaraItem->currentAnimState == 57 ||
LaraItem->currentAnimState == 58 ||
LaraItem->currentAnimState == 59 ||
LaraItem->currentAnimState == 60 ||
LaraItem->currentAnimState == 61 ||
LaraItem->currentAnimState == 75)
break;
return;
case TRIGGER_TYPES::PAD:
case TRIGGER_TYPES::ANTIPAD:
if (LaraItem->pos.yPos == LaraItem->floor)
break;
return;
case TRIGGER_TYPES::KEY:
value = *(data++) & 0x3FF;
keyResult = KeyTrigger(value);
if (keyResult != -1)
2018-09-23 09:38:24 +02:00
break;
return;
case TRIGGER_TYPES::PICKUP:
value = *(data++) & 0x3FF;
if (!PickupTrigger(value))
return;
break;
case TRIGGER_TYPES::COMBAT:
if (Lara.gunStatus == LG_READY)
break;
return;
case TRIGGER_TYPES::SKELETON_T:
Lara.skelebob = 2;
break;
case TRIGGER_TYPES::HEAVY:
case TRIGGER_TYPES::DUMMY:
case TRIGGER_TYPES::HEAVYSWITCH:
case TRIGGER_TYPES::HEAVYANTITRIGGER:
return;
default:
break;
}
__int16 targetType = 0;
__int16 trigger = 0;
ITEM_INFO* item = NULL;
ITEM_INFO* cameraItem = NULL;
do
{
trigger = *(data++);
value = trigger & 0x3FF;
targetType = (trigger >> 10) & 0xF;
switch (targetType)
{
case TO_OBJECT:
item = &Items[value];
if (keyResult >= 2 ||
(triggerType == TRIGGER_TYPES::ANTIPAD ||
triggerType == TRIGGER_TYPES::ANTITRIGGER ||
triggerType == TRIGGER_TYPES::HEAVYANTITRIGGER) &&
item->flags & 0x80)
break;
if (triggerType == TRIGGER_TYPES::SWITCH)
{
if (item->flags & 0x40)
break;
if (item->objectNumber == ID_DART_EMITTER && item->active)
break;
}
item->timer = timer;
if (timer != 1)
item->timer = 30 * timer;
if (triggerType == TRIGGER_TYPES::SWITCH ||
triggerType == TRIGGER_TYPES::HEAVYSWITCH)
{
if (HeavyFlags >= 0)
{
if (switchFlag)
item->flags |= (flags & 0x3E00);
else
item->flags ^= (flags & 0x3E00);
if (flags & 0x100)
item->flags |= 0x40;
}
else
{
if (((flags ^ item->flags) & 0x3E00) == 0x3E00)
{
item->flags ^= (flags & 0x3E00);
if (flags & 0x100)
item->flags |= 0x40;
}
}
}
else if (triggerType == TRIGGER_TYPES::ANTIPAD ||
triggerType == TRIGGER_TYPES::ANTITRIGGER ||
triggerType == TRIGGER_TYPES::HEAVYANTITRIGGER)
{
if (item->objectNumber == ID_EARTHQUAKE)
{
item->itemFlags[0] = 0;
item->itemFlags[1] = 100;
}
item->flags &= ~(0x3E00 | 0x4000);
if (flags & 0x100)
item->flags |= 0x80;
if (item->active && Objects[item->objectNumber].intelligent)
{
item->hitPoints = -16384;
2018-09-23 09:38:24 +02:00
DisableBaddieAI(value);
KillItem(value);
}
}
else if (flags & 0x3E00)
{
item->flags |= flags & 0x3E00;
}
if ((item->flags & 0x3E00) & 0x3E00)
{
item->flags |= 0x20;
if (flags & 0x100)
item->flags |= 1;
if (!(item->active))
{
if (Objects[item->objectNumber].intelligent)
{
if (item->status != ITEM_DEACTIVATED)
{
if (item->status == ITEM_INVISIBLE)
{
item->touchBits = 0;
2018-09-23 09:38:24 +02:00
if (EnableBaddieAI(value, 0))
{
item->status = ITEM_ACTIVE;
2018-09-23 09:38:24 +02:00
AddActiveItem(value);
}
else
{
item->status == ITEM_INVISIBLE;
2018-09-23 09:38:24 +02:00
AddActiveItem(value);
}
}
}
else
{
item->touchBits = 0;
item->status = ITEM_ACTIVE;
2018-09-23 09:38:24 +02:00
AddActiveItem(value);
EnableBaddieAI(value, 1);
}
}
else
{
item->touchBits = 0;
2018-09-23 09:38:24 +02:00
AddActiveItem(value);
item->status = ITEM_ACTIVE;
HeavyTriggered = heavy;
}
}
}
break;
case TO_CAMERA:
trigger = *(data++);
if (keyResult == 1)
break;
if (Camera.fixed[value].flags & 0x100)
break;
Camera.number = value;
if (Camera.type == LOOK_CAMERA || Camera.type == COMBAT_CAMERA && !(Camera.fixed[value].flags & 3))
break;
if (triggerType == TRIGGER_TYPES::COMBAT)
break;
if (triggerType == TRIGGER_TYPES::SWITCH && timer && switchOff)
break;
if (Camera.number != Camera.last || triggerType == TRIGGER_TYPES::SWITCH)
{
Camera.timer = (trigger & 0xFF) * 30;
if (trigger & 0x100)
Camera.fixed[Camera.number].flags |= 0x100;
Camera.speed = ((trigger & 0x3E00) >> 6) + 1;
Camera.type = heavy ? HEAVY_CAMERA : FIXED_CAMERA;
}
break;
case TO_FLYBY:
trigger = *(data++);
if (keyResult == 1)
break;
if (triggerType == TRIGGER_TYPES::ANTIPAD ||
triggerType == TRIGGER_TYPES::ANTITRIGGER ||
triggerType == TRIGGER_TYPES::HEAVYANTITRIGGER)
UseSpotCam = false;
else
{
spotCamIndex = 0;
if (SpotCamRemap[value] != 0)
{
for (__int32 i = 0; i < SpotCamRemap[value]; i++)
{
spotCamIndex += CameraCnt[i];
}
}
if (!(SpotCam[spotCamIndex].flags & SCF_CAMERA_ONE_SHOT))
{
if (trigger & 0x100)
SpotCam[spotCamIndex].flags |= SCF_CAMERA_ONE_SHOT;
if (!UseSpotCam || CurrentLevel == 0)
{
UseSpotCam = true;
if (LastSpotCam != value)
TrackCameraInit = false;
InitialiseSpotCam(value);
}
}
}
break;
case TO_TARGET:
cameraItem = &Items[value];
break;
case TO_SINK:
Lara.currentActive = value + 1;
break;
case TO_FLIPMAP:
flipAvailable = true;
if (FlipMap[value] & 0x100)
break;
if (triggerType == TRIGGER_TYPES::SWITCH)
FlipMap[value] ^= (flags & 0x3E00);
else if (flags & 0x3E00)
FlipMap[value] |= (flags & 0x3E00);
if ((FlipMap[value] & 0x3E00) == 0x3E00)
{
if (flags & 0x100)
FlipMap[value] |= 0x100;
if (!FlipStatus)
flip = value;
}
else if (FlipStatus)
flip = value;
break;
case TO_FLIPON:
2018-09-23 09:38:24 +02:00
flipAvailable = true;
if ((FlipMap[value] & 0x3E00) == 0x3E00 && !FlipStatus)
flip = value;
break;
case TO_FLIPOFF:
2018-09-23 09:38:24 +02:00
flipAvailable = true;
if ((FlipMap[value] & 0x3E00) == 0x3E00 && FlipStatus)
flip = value;
break;
case TO_FLIPEFFECT:
TriggerTimer = timer;
newEffect = value;
break;
case TO_FINISH:
RequiredStartPos = false;
LevelComplete = CurrentLevel + 1;
break;
case TO_CD:
PlaySoundTrack(value, flags);
break;
case TO_CUTSCENE:
// TODO: not used for now
break;
case TO_LUA_SCRIPT:
2018-09-23 09:38:24 +02:00
trigger = *(data++);
2018-09-23 12:01:07 +02:00
g_GameScript->ExecuteTrigger(trigger & 0x7FFF);
2018-09-23 09:38:24 +02:00
break;
default:
break;
}
} while (!(trigger & 0x8000));
if (cameraItem && (Camera.type == FIXED_CAMERA || Camera.type == HEAVY_CAMERA))
Camera.item = cameraItem;
if (flip != -1)
DoFlipMap(flip);
if (newEffect != -1 && (flip || !flipAvailable))
{
FlipEffect = newEffect;
FlipTimer = 0;
}
}
void __cdecl UpdateSky()
{
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
if (level->Layer1.Enabled)
{
SkyPos1 += level->Layer1.CloudSpeed;
if (SkyPos1 <= 9728)
{
if (SkyPos1 < 0)
SkyPos1 += 9728;
}
else
{
SkyPos1 -= 9728;
}
}
if (level->Layer1.Enabled)
{
SkyPos2 += level->Layer2.CloudSpeed;
if (SkyPos2 <= 9728)
{
if (SkyPos2 < 0)
SkyPos2 += 9728;
}
else
{
SkyPos2 -= 9728;
}
}
}
2019-11-15 07:40:22 +01:00
void __cdecl ActivateKey()
{
KeyTriggerActive = 1;
}
void __cdecl ActivateCamera()
{
KeyTriggerActive = 2;
}
2019-12-01 08:13:19 +01:00
__int16 __cdecl GetDoor(FLOOR_INFO* floor)
{
if (!floor->index)
return NO_ROOM;
__int16* data = &FloorData[floor->index];
__int16 type = *(data++);
if (((type & DATA_TYPE) == TILT_TYPE)
|| ((type & DATA_TYPE) == SPLIT1)
|| ((type & DATA_TYPE) == SPLIT2)
|| ((type & DATA_TYPE) == NOCOLF1B)
|| ((type & DATA_TYPE) == NOCOLF1T)
|| ((type & DATA_TYPE) == NOCOLF2B)
|| ((type & DATA_TYPE) == NOCOLF2T))
{
if (type & END_BIT)
return NO_ROOM;
data++;
type = *(data++);
}
if (((type & DATA_TYPE) == ROOF_TYPE)
|| ((type & DATA_TYPE) == SPLIT3)
|| ((type & DATA_TYPE) == SPLIT4)
|| ((type & DATA_TYPE) == NOCOLC1B)
|| ((type & DATA_TYPE) == NOCOLC1T)
|| ((type & DATA_TYPE) == NOCOLC2B)
|| ((type & DATA_TYPE) == NOCOLC2T))
{
if (type & END_BIT)
return NO_ROOM;
data++;
type = *(data++);
}
if ((type & DATA_TYPE) == DOOR_TYPE)
return (*data);
return NO_ROOM;
}
2018-08-19 09:46:58 +02:00
void Inject_Control()
{
INJECT(0x00416760, TestTriggers);
INJECT(0x004167B0, TestTriggers);
2018-08-19 09:46:58 +02:00
}