2018-08-19 09:46:58 +02:00
|
|
|
#include "control.h"
|
|
|
|
|
|
|
|
#include "..\Global\global.h"
|
2018-10-30 12:40:30 +01:00
|
|
|
|
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"
|
2018-09-03 21:08:40 +02:00
|
|
|
#include "savegame.h"
|
|
|
|
#include "sound.h"
|
2018-09-22 23:54:36 +02:00
|
|
|
#include "spotcam.h"
|
2019-11-20 11:24:36 +01:00
|
|
|
#include "box.h"
|
2019-11-01 08:35:01 +01:00
|
|
|
#include "objects.h"
|
2019-11-09 09:55:56 +01:00
|
|
|
#include "switch.h"
|
2019-12-01 08:13:19 +01:00
|
|
|
#include "laramisc.h"
|
2019-12-07 08:36:13 +01:00
|
|
|
#include "rope.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-27 15:12:35 +01:00
|
|
|
int KeyTriggerActive;
|
2019-12-07 08:36:13 +01:00
|
|
|
PENDULUM CurrentPendulum;
|
2019-11-15 07:40:22 +01:00
|
|
|
|
2018-09-22 23:54:36 +02:00
|
|
|
extern GameFlow* g_GameFlow;
|
2018-09-23 12:01:07 +02:00
|
|
|
extern GameScript* g_GameScript;
|
2019-11-18 07:48:35 +01:00
|
|
|
extern Inventory* g_Inventory;
|
2018-09-04 13:24:50 +02:00
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
GAME_STATUS ControlPhase(int numFrames, int demoMode)
|
2018-08-19 09:46:58 +02:00
|
|
|
{
|
2018-09-22 23:54:36 +02:00
|
|
|
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
|
2018-09-05 23:56:39 +02:00
|
|
|
|
2018-08-19 09:46:58 +02:00
|
|
|
RegeneratePickups();
|
|
|
|
|
|
|
|
if (numFrames > 10)
|
|
|
|
numFrames = 10;
|
|
|
|
|
|
|
|
if (TrackCameraInit)
|
2019-04-30 12:56:27 +02:00
|
|
|
UseSpotCam = false;
|
2018-08-19 09:46:58 +02:00
|
|
|
|
2019-04-30 12:56:27 +02:00
|
|
|
SetDebounce = true;
|
2018-08-19 09:46:58 +02:00
|
|
|
|
|
|
|
for (FramesCount += numFrames; FramesCount > 0; FramesCount -= 2)
|
|
|
|
{
|
|
|
|
GlobalCounter++;
|
|
|
|
|
2018-08-20 21:32:19 +02:00
|
|
|
UpdateSky();
|
|
|
|
|
2018-08-19 09:46:58 +02:00
|
|
|
// Poll the keyboard and update input variables
|
2019-05-31 21:45:13 +02:00
|
|
|
if (CurrentLevel != 0)
|
|
|
|
{
|
|
|
|
if (S_UpdateInput() == -1)
|
|
|
|
return GAME_STATUS_NONE;
|
|
|
|
}
|
|
|
|
|
2018-08-19 09:46:58 +02:00
|
|
|
// Has Lara control been disabled?
|
2019-05-31 21:45:13 +02:00
|
|
|
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?
|
2019-04-30 12:56:27 +02:00
|
|
|
SetDebounce = false;
|
2018-11-01 22:45:59 +01:00
|
|
|
if (CurrentLevel != 0 && !g_Renderer->IsFading())
|
2018-08-19 09:46:58 +02:00
|
|
|
{
|
2019-11-18 07:48:35 +01:00
|
|
|
if ((DbInput & IN_DESELECT || g_Inventory->GetEnterObject() != NO_ITEM) && !CutSeqTriggered && LaraItem->hitPoints > 0)
|
2018-09-08 21:30:48 +02:00
|
|
|
{
|
2018-09-07 18:34:18 +02:00
|
|
|
// Stop all sounds
|
2019-11-27 15:12:35 +01:00
|
|
|
int inventoryResult = g_Inventory->DoInventory();
|
2018-09-03 21:08:40 +02:00
|
|
|
switch (inventoryResult)
|
|
|
|
{
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_LOAD_GAME:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_LOAD_GAME;
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_EXIT_TO_TILE:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_EXIT_TO_TITLE;
|
2018-09-03 21:08:40 +02:00
|
|
|
}
|
2018-08-19 09:46:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Has level been completed?
|
2019-05-31 21:45:13 +02:00
|
|
|
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
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
int oldInput = TrInput;
|
2018-08-19 09:46:58 +02:00
|
|
|
|
2018-09-08 20:54:13 +02:00
|
|
|
// Is Lara dead?
|
2019-05-31 21:45:13 +02:00
|
|
|
if (CurrentLevel != 0 && (Lara.deathCount > 300 || Lara.deathCount > 60 && TrInput))
|
2018-08-19 09:46:58 +02:00
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
int inventoryResult = g_Inventory->DoInventory();
|
2018-09-08 21:30:48 +02:00
|
|
|
switch (inventoryResult)
|
|
|
|
{
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_NEW_GAME:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_NEW_GAME;
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_LOAD_GAME:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_LOAD_GAME;
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_EXIT_TO_TILE:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_EXIT_TO_TITLE;
|
2018-09-08 21:30:48 +02:00
|
|
|
}
|
2018-08-19 09:46:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (demoMode && TrInput == -1)
|
|
|
|
{
|
|
|
|
oldInput = 0;
|
|
|
|
TrInput = 0;
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
if (CurrentLevel == 0)
|
|
|
|
TrInput = 0;
|
|
|
|
|
2018-11-11 23:42:30 +01:00
|
|
|
// Handle lasersight and binocular
|
2019-05-31 21:45:13 +02:00
|
|
|
if (CurrentLevel != 0)
|
2018-11-11 11:16:37 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
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)))
|
2018-11-11 11:16:37 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (BinocularRange == 0)
|
2018-11-11 11:16:37 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (SniperCameraActive || UseSpotCam || TrackCameraInit)
|
|
|
|
TrInput &= ~IN_LOOK;
|
2018-11-11 11:16:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (LaserSight)
|
|
|
|
{
|
|
|
|
BinocularRange = 0;
|
|
|
|
LaserSight = false;
|
|
|
|
AlterFOV(ANGLE(80));
|
|
|
|
LaraItem->meshBits = 0xFFFFFFFF;
|
|
|
|
Lara.isDucked = false;
|
|
|
|
Camera.type = BinocularOldCamera;
|
2018-11-11 11:16:37 +01:00
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
Lara.headYrot = 0;
|
|
|
|
Lara.headXrot = 0;
|
2018-11-11 11:16:37 +01:00
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
Lara.torsoYrot = 0;
|
|
|
|
Lara.torsoXrot = 0;
|
|
|
|
|
|
|
|
Camera.bounce = 0;
|
|
|
|
BinocularOn = -8;
|
|
|
|
|
|
|
|
TrInput &= ~IN_LOOK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TrInput |= IN_LOOK;
|
|
|
|
}
|
|
|
|
}
|
2018-11-11 11:16:37 +01:00
|
|
|
|
|
|
|
Infrared = false;
|
2019-05-31 21:45:13 +02:00
|
|
|
}
|
|
|
|
else if (BinocularRange == 0)
|
2018-11-11 11:16:37 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
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;*/
|
2019-05-31 21:45:13 +02:00
|
|
|
Infrared = true;
|
|
|
|
}
|
2018-11-11 11:16:37 +01:00
|
|
|
else
|
2019-05-31 21:45:13 +02:00
|
|
|
Infrared = false;
|
2018-11-11 11:16:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (LaserSight)
|
|
|
|
{
|
|
|
|
/*if (!(gfLevelFlags & GF_LVOP_TRAIN))
|
|
|
|
InfraRed = TRUE;
|
|
|
|
else
|
2019-11-21 07:43:34 +01:00
|
|
|
InfraRed = false;*/
|
2019-05-31 21:45:13 +02:00
|
|
|
Infrared = true;
|
|
|
|
}
|
2018-11-11 11:16:37 +01:00
|
|
|
else
|
2019-05-31 21:45:13 +02:00
|
|
|
{
|
|
|
|
/*if ((gfLevelFlags & GF_LVOP_TRAIN) && (inputBusy & IN_ACTION))
|
|
|
|
InfraRed = TRUE;
|
|
|
|
else
|
2019-11-21 07:43:34 +01:00
|
|
|
InfraRed = false;*/
|
2019-05-31 21:45:13 +02:00
|
|
|
Infrared = false;
|
|
|
|
}
|
2018-11-11 11:16:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear dynamic lights
|
2018-08-19 09:46:58 +02:00
|
|
|
ClearDynamics();
|
|
|
|
ClearFires();
|
|
|
|
g_Renderer->ClearDynamicLights();
|
|
|
|
|
|
|
|
GotLaraSpheres = false;
|
2018-08-24 23:36:49 +02:00
|
|
|
|
2018-09-08 20:54:13 +02:00
|
|
|
// Update all items
|
2018-08-24 23:36:49 +02:00
|
|
|
InItemControlLoop = true;
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short itemNum = NextItemActive;
|
2018-08-19 09:46:58 +02:00
|
|
|
while (itemNum != NO_ITEM)
|
|
|
|
{
|
2018-08-24 23:36:49 +02:00
|
|
|
ITEM_INFO* item = &Items[itemNum];
|
2019-11-27 15:12:35 +01:00
|
|
|
short nextItem = item->nextActive;
|
2018-08-24 23:36:49 +02:00
|
|
|
|
2018-11-18 22:53:38 +01:00
|
|
|
if (item->afterDeath <= 128)
|
2018-09-04 20:54:15 +02:00
|
|
|
{
|
|
|
|
if (Objects[item->objectNumber].control)
|
|
|
|
Objects[item->objectNumber].control(itemNum);
|
|
|
|
}
|
2018-08-24 23:36:49 +02:00
|
|
|
else
|
|
|
|
{
|
2018-09-04 20:54:15 +02:00
|
|
|
KillItem(itemNum);
|
2018-08-24 23:36:49 +02:00
|
|
|
}
|
|
|
|
|
2018-08-19 09:46:58 +02:00
|
|
|
itemNum = nextItem;
|
|
|
|
}
|
2018-08-24 23:36:49 +02:00
|
|
|
|
|
|
|
InItemControlLoop = false;
|
|
|
|
KillMoveItems();
|
|
|
|
|
2018-09-08 20:54:13 +02:00
|
|
|
// Update all effects
|
2018-08-24 23:36:49 +02:00
|
|
|
InItemControlLoop = true;
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short fxNum = NextFxActive;
|
2018-08-24 23:36:49 +02:00
|
|
|
while (fxNum != NO_ITEM)
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
short nextFx = Effects[fxNum].nextActive;
|
2018-08-24 23:36:49 +02:00
|
|
|
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
|
2018-08-24 23:36:49 +02:00
|
|
|
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
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
if (CurrentLevel != 0)
|
2018-11-08 23:05:25 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (Lara.hasFired)
|
2018-11-08 23:05:25 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
AlertNearbyGuards(LaraItem);
|
|
|
|
Lara.hasFired = false;
|
2018-11-08 23:05:25 +01:00
|
|
|
}
|
2019-05-31 21:45:13 +02:00
|
|
|
|
|
|
|
// Is Lara poisoned?
|
|
|
|
if (Lara.poisoned)
|
2018-11-08 23:05:25 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
if (Lara.poisoned <= 4096)
|
2018-11-08 23:05:25 +01:00
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
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;
|
2018-11-08 23:05:25 +01:00
|
|
|
}
|
|
|
|
}
|
2018-09-09 15:39:18 +02:00
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
// Control Lara
|
|
|
|
InItemControlLoop = true;
|
|
|
|
Lara.skelebob = NULL;
|
2019-12-01 08:13:19 +01:00
|
|
|
LaraControl(Lara.itemNumber);
|
2019-05-31 21:45:13 +02:00
|
|
|
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
|
2019-05-31 21:45:13 +02:00
|
|
|
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);
|
2019-05-31 21:45:13 +02:00
|
|
|
TrackCameraInit = false;
|
2018-08-19 09:46:58 +02:00
|
|
|
CalculateCamera();
|
2018-09-07 18:34:18 +02:00
|
|
|
}
|
2018-08-28 20:39:00 +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
|
2018-11-08 23:05:25 +01:00
|
|
|
TriggerLaraDrips();
|
|
|
|
|
|
|
|
if (SmashedMeshCount)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
SmashedMeshCount--;
|
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(
|
|
|
|
SmashedMesh[SmashedMeshCount]->x,
|
|
|
|
SmashedMesh[SmashedMeshCount]->y,
|
|
|
|
SmashedMesh[SmashedMeshCount]->z,
|
|
|
|
&SmashedMeshRoom[SmashedMeshCount]);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
int height = GetFloorHeight(
|
2018-11-08 23:05:25 +01:00
|
|
|
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();
|
2018-08-19 21:49:42 +02:00
|
|
|
UpdateSmoke();
|
|
|
|
UpdateBlood();
|
2018-08-20 19:01:35 +02:00
|
|
|
UpdateBubbles();
|
|
|
|
UpdateDebris();
|
|
|
|
UpdateGunShells();
|
|
|
|
UpdateSplashes();
|
2018-08-24 23:36:49 +02:00
|
|
|
UpdateDrips();
|
|
|
|
UpdateRats();
|
|
|
|
UpdateBats();
|
|
|
|
UpdateSpiders();
|
|
|
|
UpdateShockwaves();
|
|
|
|
UpdateLightning();
|
2018-11-08 23:05:25 +01:00
|
|
|
UpdatePulseColor();
|
2019-02-09 09:35:20 +01:00
|
|
|
AnimateWaterfalls();
|
2018-11-08 23:05:25 +01:00
|
|
|
|
|
|
|
if (level->Rumble)
|
|
|
|
RumbleScreen();
|
|
|
|
|
|
|
|
SoundEffects();
|
2018-08-24 23:36:49 +02:00
|
|
|
|
|
|
|
HealtBarTimer--;
|
2019-05-06 23:48:35 +02:00
|
|
|
|
|
|
|
GameTimer++;
|
2018-08-19 09:46:58 +02:00
|
|
|
}
|
2018-09-03 21:08:40 +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();
|
2018-09-04 13:24:50 +02:00
|
|
|
|
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
|
2018-09-22 23:54:36 +02:00
|
|
|
g_GameFlow->DoGameflow();
|
2018-09-04 13:24:50 +02:00
|
|
|
|
2019-06-10 21:42:42 +02:00
|
|
|
DoTheGame = false;
|
2018-09-04 13:24:50 +02:00
|
|
|
|
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);
|
2019-06-10 21:42:42 +02:00
|
|
|
|
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
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
GAME_STATUS DoTitle(int index)
|
2018-08-19 09:46:58 +02:00
|
|
|
{
|
|
|
|
DB_Log(2, "DoTitle - DLL");
|
|
|
|
printf("DoTitle\n");
|
2018-09-03 21:08:40 +02:00
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
CreditsDone = false;
|
|
|
|
CanLoad = false;
|
|
|
|
|
|
|
|
// Load the level
|
|
|
|
S_LoadLevelFile(index);
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
int inventoryResult;
|
2019-05-31 21:45:13 +02:00
|
|
|
|
|
|
|
if (g_GameFlow->TitleType == TITLE_FLYBY)
|
|
|
|
{
|
|
|
|
// Initialise items, effects, lots, camera
|
|
|
|
InitialiseFXArray(true);
|
2019-11-15 07:40:22 +01:00
|
|
|
InitialisePickupDisplay();
|
2019-05-31 21:45:13 +02:00
|
|
|
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;
|
2019-05-10 20:38:48 +02:00
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
// 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;
|
2019-05-10 20:38:48 +02:00
|
|
|
S_CDStop();
|
|
|
|
|
2018-09-03 21:08:40 +02:00
|
|
|
switch (inventoryResult)
|
|
|
|
{
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_NEW_GAME:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_NEW_GAME;
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_LOAD_GAME:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_LOAD_GAME;
|
2019-04-26 15:10:32 +02:00
|
|
|
case INV_RESULT_EXIT_GAME:
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_EXIT_GAME;
|
2018-09-03 21:08:40 +02:00
|
|
|
}
|
|
|
|
|
2019-04-29 13:10:58 +02:00
|
|
|
return GAME_STATUS_NEW_GAME;
|
2018-08-19 09:46:58 +02:00
|
|
|
}
|
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
GAME_STATUS DoLevel(int index, int 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
|
2018-09-03 21:08:40 +02:00
|
|
|
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);
|
|
|
|
|
2018-10-28 11:34:29 +01:00
|
|
|
// Initialise items, effects, lots, camera
|
|
|
|
InitialiseFXArray(true);
|
2019-11-15 07:40:22 +01:00
|
|
|
InitialisePickupDisplay();
|
2018-10-28 11:34:29 +01:00
|
|
|
InitialiseCamera();
|
|
|
|
SOUND_Stop();
|
|
|
|
|
2018-10-24 23:32:22 +02:00
|
|
|
// Restore the game?
|
2018-09-03 21:08:40 +02:00
|
|
|
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);
|
|
|
|
|
2019-05-06 23:48:35 +02:00
|
|
|
RequiredStartPos = false;
|
|
|
|
InitialiseGame = false;
|
2018-10-24 23:32:22 +02:00
|
|
|
g_GameFlow->SelectedSaveGame = 0;
|
2018-09-03 21:08:40 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-06 23:48:35 +02:00
|
|
|
RequiredStartPos = false;
|
|
|
|
if (InitialiseGame)
|
2018-09-03 21:08:40 +02:00
|
|
|
{
|
|
|
|
GameTimer = 0;
|
2019-05-06 23:48:35 +02:00
|
|
|
RequiredStartPos = false;
|
|
|
|
InitialiseGame = false;
|
2018-09-03 21:08:40 +02:00
|
|
|
}
|
2018-08-19 09:46:58 +02:00
|
|
|
|
2018-09-03 21:08:40 +02:00
|
|
|
Savegame.Level.Timer = 0;
|
|
|
|
if (CurrentLevel == 1)
|
|
|
|
Savegame.TLCount = 0;
|
|
|
|
}
|
2018-08-19 09:46:58 +02:00
|
|
|
|
2019-05-06 23:48:35 +02:00
|
|
|
LastInventoryItem = -1;
|
2018-08-19 09:46:58 +02:00
|
|
|
DelCutSeqPlayer = 0;
|
|
|
|
TitleControlsLockedOut = false;
|
2019-11-18 07:48:35 +01:00
|
|
|
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();
|
2019-05-31 21:45:13 +02:00
|
|
|
|
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();
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
int nframes = 2;
|
2018-09-03 21:08:40 +02:00
|
|
|
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!
|
2018-09-03 21:08:40 +02:00
|
|
|
while (true)
|
2018-08-19 09:46:58 +02:00
|
|
|
{
|
|
|
|
nframes = DrawPhaseGame();
|
2019-09-22 21:14:43 +02:00
|
|
|
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();
|
|
|
|
|
2018-09-03 21:08:40 +02:00
|
|
|
return result;
|
2018-09-08 20:54:13 +02:00
|
|
|
}
|
2018-09-03 21:08:40 +02:00
|
|
|
|
2018-08-21 21:32:56 +03:00
|
|
|
Sound_UpdateScene();
|
2018-08-19 09:46:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
void TestTriggers(short* data, int heavy, int HeavyFlags)
|
2018-09-22 23:54:36 +02:00
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
int flip = -1;
|
|
|
|
int flipAvailable = 0;
|
|
|
|
int newEffect = -1;
|
|
|
|
int switchOff = 0;
|
|
|
|
int switchFlag = 0;
|
|
|
|
short objectNumber = 0;
|
|
|
|
int keyResult = 0;
|
|
|
|
short cameraFlags = 0;
|
|
|
|
short cameraTimer = 0;
|
|
|
|
int spotCamIndex = 0;
|
2018-09-22 23:54:36 +02:00
|
|
|
|
|
|
|
HeavyTriggered = false;
|
|
|
|
|
|
|
|
if (!heavy)
|
|
|
|
{
|
|
|
|
Lara.canMonkeySwing = false;
|
2018-10-28 13:55:02 +01:00
|
|
|
Lara.climbStatus = false;
|
2018-09-22 23:54:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2018-09-22 23:54:36 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lara can climb
|
|
|
|
if ((*data & 0x1F) == CLIMB_TYPE)
|
|
|
|
{
|
|
|
|
if (!heavy)
|
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
short quad = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90);
|
2018-09-22 23:54:36 +02:00
|
|
|
if ((1 << (quad + 8)) & *data)
|
|
|
|
Lara.climbStatus = true;
|
|
|
|
}
|
|
|
|
|
2018-09-23 09:38:24 +02:00
|
|
|
if (*data & 0x8000)
|
2018-09-22 23:54:36 +02:00
|
|
|
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)
|
2018-09-22 23:54:36 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trigger triggerer
|
|
|
|
if ((*data & 0x1F) == TRIGTRIGGER_TYPE)
|
|
|
|
{
|
|
|
|
if (!(*data & 0x20) || *data & 0x8000)
|
|
|
|
return;
|
|
|
|
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short triggerType = (*(data++) >> 8) & 0x3F;
|
|
|
|
short flags = *(data++);
|
|
|
|
short timer = flags & 0xFF;
|
2018-09-22 23:54:36 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short value = 0;
|
2018-09-22 23:54:36 +02:00
|
|
|
|
|
|
|
switch (triggerType)
|
|
|
|
{
|
|
|
|
case TRIGGER_TYPES::SWITCH:
|
|
|
|
value = *(data++) & 0x3FF;
|
|
|
|
|
2018-09-23 09:38:24 +02:00
|
|
|
if (flags & 0x100)
|
2018-09-22 23:54:36 +02:00
|
|
|
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;
|
2018-09-22 23:54:36 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-27 15:12:35 +01:00
|
|
|
short targetType = 0;
|
|
|
|
short trigger = 0;
|
2018-09-22 23:54:36 +02:00
|
|
|
|
|
|
|
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);
|
2018-09-22 23:54:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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))
|
2018-09-22 23:54:36 +02:00
|
|
|
{
|
|
|
|
item->status = ITEM_ACTIVE;
|
2018-09-23 09:38:24 +02:00
|
|
|
AddActiveItem(value);
|
2018-09-22 23:54:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item->status == ITEM_INVISIBLE;
|
2018-09-23 09:38:24 +02:00
|
|
|
AddActiveItem(value);
|
2018-09-22 23:54:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item->touchBits = 0;
|
|
|
|
item->status = ITEM_ACTIVE;
|
2018-09-23 09:38:24 +02:00
|
|
|
AddActiveItem(value);
|
|
|
|
EnableBaddieAI(value, 1);
|
2018-09-22 23:54:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item->touchBits = 0;
|
2018-09-23 09:38:24 +02:00
|
|
|
AddActiveItem(value);
|
2018-09-22 23:54:36 +02:00
|
|
|
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;
|
2019-05-31 21:45:13 +02:00
|
|
|
if (SpotCamRemap[value] != 0)
|
2018-09-22 23:54:36 +02:00
|
|
|
{
|
2019-11-27 15:12:35 +01:00
|
|
|
for (int i = 0; i < SpotCamRemap[value]; i++)
|
2018-09-22 23:54:36 +02:00
|
|
|
{
|
|
|
|
spotCamIndex += CameraCnt[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
if (!(SpotCam[spotCamIndex].flags & SCF_CAMERA_ONE_SHOT))
|
2018-09-22 23:54:36 +02:00
|
|
|
{
|
|
|
|
if (trigger & 0x100)
|
2019-05-31 21:45:13 +02:00
|
|
|
SpotCam[spotCamIndex].flags |= SCF_CAMERA_ONE_SHOT;
|
2018-09-22 23:54:36 +02:00
|
|
|
|
2019-05-31 21:45:13 +02:00
|
|
|
if (!UseSpotCam || CurrentLevel == 0)
|
2018-09-22 23:54:36 +02:00
|
|
|
{
|
|
|
|
UseSpotCam = true;
|
|
|
|
if (LastSpotCam != value)
|
|
|
|
TrackCameraInit = false;
|
2019-05-31 21:45:13 +02:00
|
|
|
InitialiseSpotCam(value);
|
2018-09-22 23:54:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
2018-09-22 23:54:36 +02:00
|
|
|
if ((FlipMap[value] & 0x3E00) == 0x3E00 && !FlipStatus)
|
|
|
|
flip = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TO_FLIPOFF:
|
2018-09-23 09:38:24 +02:00
|
|
|
flipAvailable = true;
|
2018-09-22 23:54:36 +02:00
|
|
|
if ((FlipMap[value] & 0x3E00) == 0x3E00 && FlipStatus)
|
|
|
|
flip = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TO_FLIPEFFECT:
|
|
|
|
TriggerTimer = timer;
|
|
|
|
newEffect = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TO_FINISH:
|
2019-05-06 23:48:35 +02:00
|
|
|
RequiredStartPos = false;
|
2018-09-22 23:54:36 +02:00
|
|
|
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
|
|
|
|
2018-09-22 23:54:36 +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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
void UpdateSky()
|
2018-12-28 12:12:58 +01:00
|
|
|
{
|
|
|
|
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-12-02 14:49:19 +01:00
|
|
|
void ActivateKey()
|
2019-11-15 07:40:22 +01:00
|
|
|
{
|
|
|
|
KeyTriggerActive = 1;
|
|
|
|
}
|
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
void ActivateCamera()
|
2019-11-15 07:40:22 +01:00
|
|
|
{
|
|
|
|
KeyTriggerActive = 2;
|
|
|
|
}
|
|
|
|
|
2019-12-02 14:49:19 +01:00
|
|
|
short GetDoor(FLOOR_INFO* floor)
|
2019-12-01 08:13:19 +01:00
|
|
|
{
|
|
|
|
if (!floor->index)
|
|
|
|
return NO_ROOM;
|
|
|
|
|
2019-12-02 09:11:21 +01:00
|
|
|
short* data = &FloorData[floor->index];
|
|
|
|
short type = *(data++);
|
2019-12-01 08:13:19 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-04 18:51:23 +01:00
|
|
|
void TranslateItem(ITEM_INFO* item, int x, int y, int z)
|
|
|
|
{
|
|
|
|
int c = COS(item->pos.yRot);
|
|
|
|
int s = SIN(item->pos.yRot);
|
|
|
|
|
|
|
|
item->pos.xPos += (c * x + s * z) >> W2V_SHIFT;
|
|
|
|
item->pos.yPos += y;
|
|
|
|
item->pos.zPos += (-s * x + c * z) >> W2V_SHIFT;
|
|
|
|
}
|
|
|
|
|
2019-12-07 08:36:13 +01:00
|
|
|
int CheckNoColFloorTriangle(FLOOR_INFO* floor, short x, short z)
|
|
|
|
{
|
|
|
|
if (!floor->index)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
short func = FloorData[floor->index] & 0x1F;
|
|
|
|
if (func != NOCOLF1T && func != NOCOLF1B && func != NOCOLF2T && func != NOCOLF2B)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int dx = x & 0x3FF;
|
|
|
|
int dz = z & 0x3FF;
|
|
|
|
|
|
|
|
switch (func)
|
|
|
|
{
|
|
|
|
case NOCOLF1T:
|
|
|
|
if (dx <= 1024 - dz)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NOCOLF1B:
|
|
|
|
if (dx > 1024 - dz)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NOCOLF2T:
|
|
|
|
if (dx <= dz)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NOCOLF2B:
|
|
|
|
if (dx > dz)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-12-05 17:35:57 +01:00
|
|
|
int GetWaterSurface(int x, int y, int z, short roomNumber)
|
|
|
|
{
|
|
|
|
ROOM_INFO* room = &Rooms[roomNumber];
|
|
|
|
FLOOR_INFO* floor = &room->floor[((z - room->z) >> WALL_SHIFT) + ((x - room->x) >> WALL_SHIFT)* room->xSize];
|
|
|
|
|
|
|
|
if (room->flags & ENV_FLAG_WATER)
|
|
|
|
{
|
|
|
|
while (floor->skyRoom != NO_ROOM)
|
|
|
|
{
|
|
|
|
room = &Rooms[floor->skyRoom];
|
|
|
|
if (!(room->flags & ENV_FLAG_WATER))
|
|
|
|
return (floor->ceiling << 8);
|
|
|
|
floor = &room->floor[((z - room->z) >> WALL_SHIFT) + ((x - room->x) >> WALL_SHIFT)* room->xSize];
|
|
|
|
}
|
|
|
|
return NO_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (floor->pitRoom != NO_ROOM)
|
|
|
|
{
|
|
|
|
room = &Rooms[floor->pitRoom];
|
|
|
|
if (room->flags & ENV_FLAG_WATER)
|
|
|
|
return (floor->floor << 8);
|
|
|
|
floor = &room->floor[((z - room->z) >> WALL_SHIFT) + ((x - room->x) >> WALL_SHIFT)* room->xSize];
|
|
|
|
}
|
|
|
|
}
|
2019-12-07 08:55:56 +01:00
|
|
|
|
2019-12-05 17:35:57 +01:00
|
|
|
return NO_HEIGHT;
|
|
|
|
}
|
|
|
|
|
2018-08-19 09:46:58 +02:00
|
|
|
void Inject_Control()
|
|
|
|
{
|
2019-05-31 21:45:13 +02:00
|
|
|
INJECT(0x00416760, TestTriggers);
|
|
|
|
INJECT(0x004167B0, TestTriggers);
|
2019-12-04 18:51:23 +01:00
|
|
|
INJECT(0x00415960, TranslateItem);
|
2018-08-19 09:46:58 +02:00
|
|
|
}
|