2020-12-21 13:16:29 -03:00
|
|
|
#include "framework.h"
|
2021-09-15 17:40:00 +03:00
|
|
|
#include <process.h>
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "collide.h"
|
|
|
|
#include "control.h"
|
2021-09-11 10:13:04 +03:00
|
|
|
#include "pickup.h"
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "camera.h"
|
|
|
|
#include "Lara.h"
|
2021-09-15 17:40:00 +03:00
|
|
|
#include "effects/hair.h"
|
2021-09-15 21:09:09 +03:00
|
|
|
#include "effects/flmtorch.h"
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "items.h"
|
2021-08-26 16:24:43 +03:00
|
|
|
#include "flipeffect.h"
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "draw.h"
|
2021-05-26 01:58:30 -05:00
|
|
|
#ifdef NEW_INV
|
|
|
|
#include "newinv2.h"
|
|
|
|
#else
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "inventory.h"
|
2021-05-26 01:58:30 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "lot.h"
|
|
|
|
#include "health.h"
|
|
|
|
#include "savegame.h"
|
2021-09-15 17:40:00 +03:00
|
|
|
#include "Sound/sound.h"
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "spotcam.h"
|
|
|
|
#include "box.h"
|
|
|
|
#include "sphere.h"
|
|
|
|
#include "level.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "winmain.h"
|
|
|
|
#include "setup.h"
|
2021-09-15 17:40:00 +03:00
|
|
|
#include "effects/effects.h"
|
|
|
|
#include "effects/tomb4fx.h"
|
|
|
|
#include "effects/debris.h"
|
|
|
|
#include "effects/footprint.h"
|
|
|
|
#include "effects/smoke.h"
|
|
|
|
#include "effects/spark.h"
|
|
|
|
#include "effects/explosion.h"
|
|
|
|
#include "effects/drip.h"
|
|
|
|
#include "effects/weather.h"
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "tr5_rats_emitter.h"
|
|
|
|
#include "tr5_bats_emitter.h"
|
|
|
|
#include "tr5_spider_emitter.h"
|
|
|
|
#include "tr4_locusts.h"
|
2021-09-08 18:07:48 +03:00
|
|
|
#include "tr4_littlebeetle.h"
|
2020-12-21 13:16:29 -03:00
|
|
|
#include "particle/SimpleParticle.h"
|
2021-09-15 17:40:00 +03:00
|
|
|
#include "Specific/prng.h"
|
2021-09-16 01:12:19 +03:00
|
|
|
#include "Specific/time.h"
|
2021-09-15 17:40:00 +03:00
|
|
|
#include "control/flipmap.h"
|
|
|
|
#include "Lara/lara_one_gun.h"
|
2021-08-28 06:37:22 +02:00
|
|
|
#include "generic_switch.h"
|
2021-09-16 01:12:19 +03:00
|
|
|
#include "Scripting/GameFlowScript.h"
|
2021-09-14 12:05:36 +03:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
using std::vector;
|
2021-06-26 07:36:54 +02:00
|
|
|
using std::unordered_map;
|
|
|
|
using std::string;
|
2021-09-14 01:22:08 +03:00
|
|
|
|
|
|
|
using namespace TEN::Effects::Footprints;
|
2021-08-30 18:03:21 +03:00
|
|
|
using namespace TEN::Effects::Explosion;
|
|
|
|
using namespace TEN::Effects::Spark;
|
|
|
|
using namespace TEN::Effects::Smoke;
|
2021-09-15 11:13:47 +03:00
|
|
|
using namespace TEN::Effects::Environment;
|
2021-08-30 18:03:21 +03:00
|
|
|
using namespace TEN::Effects;
|
2021-09-14 01:22:08 +03:00
|
|
|
using namespace TEN::Entities::Switches;
|
|
|
|
using namespace TEN::Renderer;
|
2021-08-30 18:03:21 +03:00
|
|
|
using namespace TEN::Math::Random;
|
|
|
|
using namespace TEN::Floordata;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-09-15 21:09:09 +03:00
|
|
|
int GameTimer = 0;
|
|
|
|
int RumbleTimer = 0;
|
|
|
|
int InGameCounter = 0;
|
|
|
|
short GlobalCounter = 0;
|
|
|
|
int Wibble = 0;
|
|
|
|
|
|
|
|
bool InitialiseGame;
|
|
|
|
bool DoTheGame;
|
|
|
|
bool JustLoaded;
|
|
|
|
bool ThreadEnded;
|
|
|
|
|
|
|
|
int RequiredStartPos;
|
|
|
|
int CurrentLevel;
|
|
|
|
int LevelComplete;
|
|
|
|
|
|
|
|
bool InItemControlLoop;
|
2020-12-21 13:16:29 -03:00
|
|
|
short ItemNewRoomNo;
|
|
|
|
short ItemNewRooms[512];
|
|
|
|
short NextItemActive;
|
|
|
|
short NextItemFree;
|
2021-09-15 21:09:09 +03:00
|
|
|
short NextFxActive;
|
|
|
|
short NextFxFree;
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
int WeatherType;
|
|
|
|
int LaraDrawType;
|
2021-09-15 21:09:09 +03:00
|
|
|
|
2021-09-15 22:43:19 +03:00
|
|
|
int WeaponDelay;
|
|
|
|
int WeaponEnemyTimer;
|
|
|
|
|
2021-05-26 01:58:30 -05:00
|
|
|
#ifndef NEW_INV
|
2020-12-21 13:16:29 -03:00
|
|
|
int LastInventoryItem;
|
2021-09-15 21:09:09 +03:00
|
|
|
extern Inventory g_Inventory;
|
2021-05-26 01:58:30 -05:00
|
|
|
#endif
|
2021-09-15 21:09:09 +03:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
short IsRoomOutsideNo;
|
2021-09-15 21:09:09 +03:00
|
|
|
std::vector<short> OutsideRoomTable[OUTSIDE_SIZE][OUTSIDE_SIZE];
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
GAME_STATUS ControlPhase(int numFrames, int demoMode)
|
|
|
|
{
|
|
|
|
short oldLaraFrame;
|
|
|
|
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
|
|
|
|
|
|
|
|
RegeneratePickups();
|
|
|
|
|
|
|
|
if (numFrames > 10)
|
|
|
|
numFrames = 10;
|
|
|
|
|
|
|
|
if (TrackCameraInit)
|
|
|
|
UseSpotCam = false;
|
|
|
|
|
|
|
|
SetDebounce = true;
|
|
|
|
|
2021-09-16 01:12:19 +03:00
|
|
|
g_GameScript->ProcessDisplayStrings(DELTA_TIME);
|
2021-08-30 18:44:21 +01:00
|
|
|
|
2021-08-20 14:13:06 +03:00
|
|
|
static int FramesCount = 0;
|
2021-08-16 18:19:40 -03:00
|
|
|
for (FramesCount += numFrames; FramesCount > 0; FramesCount -= 2)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
GlobalCounter++;
|
|
|
|
|
2021-08-12 18:20:14 +01:00
|
|
|
// This might not be the exact amount of time that has passed, but giving it a
|
|
|
|
// value of 1/30 keeps it in lock-step with the rest of the game logic,
|
|
|
|
// which assumes 30 iterations per second.
|
2021-09-16 01:12:19 +03:00
|
|
|
g_GameScript->OnControlPhase(DELTA_TIME);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
// Poll the keyboard and update input variables
|
|
|
|
if (CurrentLevel != 0)
|
|
|
|
{
|
|
|
|
if (S_UpdateInput() == -1)
|
|
|
|
return GAME_STATUS_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Has Lara control been disabled?
|
|
|
|
if (DisableLaraControl || CurrentLevel == 0)
|
|
|
|
{
|
|
|
|
if (CurrentLevel != 0)
|
|
|
|
DbInput = 0;
|
2021-08-02 12:35:17 +03:00
|
|
|
TrInput &= IN_LOOK;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Does the player want to enter inventory?
|
|
|
|
SetDebounce = false;
|
2021-08-02 12:35:17 +03:00
|
|
|
|
2021-05-18 19:16:58 -05:00
|
|
|
#ifdef NEW_INV
|
|
|
|
if (CurrentLevel != 0 && !g_Renderer.isFading())
|
|
|
|
{
|
2021-08-29 23:53:58 +03:00
|
|
|
if (TrInput & IN_PAUSE && GLOBAL_invMode != IM_PAUSE && LaraItem->hitPoints > 0)
|
2021-05-18 19:16:58 -05:00
|
|
|
{
|
|
|
|
SOUND_Stop();
|
|
|
|
g_Renderer.DumpGameScene();
|
2021-05-28 00:57:53 -05:00
|
|
|
GLOBAL_invMode = IM_PAUSE;
|
2021-05-18 19:16:58 -05:00
|
|
|
pause_menu_to_display = pause_main_menu;
|
|
|
|
pause_selected_option = 1;
|
|
|
|
}
|
2021-08-29 23:53:58 +03:00
|
|
|
else if ((DbInput & IN_DESELECT || GLOBAL_enterinventory != NO_ITEM) && LaraItem->hitPoints > 0)
|
2021-05-18 19:16:58 -05:00
|
|
|
{
|
|
|
|
// Stop all sounds
|
|
|
|
SOUND_Stop();
|
|
|
|
|
|
|
|
if (S_CallInventory2())
|
|
|
|
return GAME_STATUS_LOAD_GAME;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-28 00:57:53 -05:00
|
|
|
while (GLOBAL_invMode == IM_PAUSE)
|
2021-05-18 19:16:58 -05:00
|
|
|
{
|
|
|
|
DrawInv();
|
|
|
|
g_Renderer.SyncRenderer();
|
|
|
|
|
|
|
|
int z = DoPauseMenu();
|
|
|
|
|
|
|
|
if (z == INV_RESULT_EXIT_TO_TILE)
|
|
|
|
return GAME_STATUS_EXIT_TO_TITLE;
|
|
|
|
}
|
|
|
|
#else
|
2020-12-21 13:16:29 -03:00
|
|
|
if (CurrentLevel != 0 && !g_Renderer.isFading())
|
|
|
|
{
|
2021-08-29 23:53:58 +03:00
|
|
|
if ((DbInput & IN_DESELECT || g_Inventory.GetEnterObject() != NO_ITEM) && LaraItem->hitPoints > 0)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
// Stop all sounds
|
|
|
|
SOUND_Stop();
|
|
|
|
int inventoryResult = g_Inventory.DoInventory();
|
|
|
|
switch (inventoryResult)
|
|
|
|
{
|
|
|
|
case INV_RESULT_LOAD_GAME:
|
|
|
|
return GAME_STATUS_LOAD_GAME;
|
|
|
|
case INV_RESULT_EXIT_TO_TILE:
|
|
|
|
return GAME_STATUS_EXIT_TO_TITLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-18 19:16:58 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
// Has level been completed?
|
|
|
|
if (CurrentLevel != 0 && LevelComplete)
|
|
|
|
return GAME_STATUS_LEVEL_COMPLETED;
|
|
|
|
|
|
|
|
int oldInput = TrInput;
|
|
|
|
|
|
|
|
// Is Lara dead?
|
|
|
|
if (CurrentLevel != 0 && (Lara.deathCount > 300 || Lara.deathCount > 60 && TrInput))
|
|
|
|
{
|
2021-05-26 01:58:30 -05:00
|
|
|
#ifdef NEW_INV
|
|
|
|
return GAME_STATUS_EXIT_TO_TITLE;//maybe do game over menu like some PSX versions have??
|
|
|
|
#else
|
2020-12-21 13:16:29 -03:00
|
|
|
int inventoryResult = g_Inventory.DoInventory();
|
|
|
|
switch (inventoryResult)
|
|
|
|
{
|
|
|
|
case INV_RESULT_NEW_GAME:
|
|
|
|
return GAME_STATUS_NEW_GAME;
|
|
|
|
case INV_RESULT_LOAD_GAME:
|
|
|
|
return GAME_STATUS_LOAD_GAME;
|
|
|
|
case INV_RESULT_EXIT_TO_TILE:
|
|
|
|
return GAME_STATUS_EXIT_TO_TITLE;
|
|
|
|
}
|
2021-05-26 01:58:30 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (demoMode && TrInput == -1)
|
|
|
|
{
|
|
|
|
oldInput = 0;
|
|
|
|
TrInput = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CurrentLevel == 0)
|
|
|
|
TrInput = 0;
|
|
|
|
|
|
|
|
// Handle lasersight and binocular
|
|
|
|
if (CurrentLevel != 0)
|
|
|
|
{
|
|
|
|
if (!(TrInput & IN_LOOK) || SniperCameraActive || UseSpotCam || TrackCameraInit ||
|
|
|
|
((LaraItem->currentAnimState != LS_STOP || LaraItem->animNumber != LA_STAND_IDLE) && (!Lara.isDucked || TrInput & IN_DUCK || LaraItem->animNumber != LA_CROUCH_IDLE || LaraItem->goalAnimState != LS_CROUCH_IDLE)))
|
|
|
|
{
|
|
|
|
if (BinocularRange == 0)
|
|
|
|
{
|
|
|
|
if (SniperCameraActive || UseSpotCam || TrackCameraInit)
|
|
|
|
TrInput &= ~IN_LOOK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-02 12:35:17 +03:00
|
|
|
// If any input but optic controls (directions + action), immediately exit binoculars mode.
|
|
|
|
if (TrInput != IN_NONE && ((TrInput & ~IN_OPTIC_CONTROLS) != IN_NONE))
|
|
|
|
BinocularRange = 0;
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
if (LaserSight)
|
|
|
|
{
|
|
|
|
BinocularRange = 0;
|
|
|
|
LaserSight = false;
|
|
|
|
AlterFOV(ANGLE(80));
|
|
|
|
LaraItem->meshBits = 0xFFFFFFFF;
|
|
|
|
Lara.busy = 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;
|
2021-08-02 12:35:17 +03:00
|
|
|
DbInput = 0;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (BinocularRange == 0)
|
|
|
|
{
|
2021-08-11 15:18:22 +03:00
|
|
|
if (Lara.gunStatus == LG_READY && ((Lara.gunType == WEAPON_REVOLVER && Lara.Weapons[WEAPON_REVOLVER].HasLasersight) ||
|
|
|
|
(Lara.gunType == WEAPON_HK) ||
|
|
|
|
(Lara.gunType == WEAPON_CROSSBOW && Lara.Weapons[WEAPON_CROSSBOW].HasLasersight)))
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
BinocularRange = 128;
|
|
|
|
BinocularOldCamera = Camera.oldType;
|
|
|
|
|
|
|
|
Lara.busy = true;
|
|
|
|
LaserSight = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GotLaraSpheres = false;
|
|
|
|
|
|
|
|
// Update all items
|
|
|
|
InItemControlLoop = true;
|
|
|
|
|
|
|
|
short itemNum = NextItemActive;
|
|
|
|
while (itemNum != NO_ITEM)
|
|
|
|
{
|
|
|
|
ITEM_INFO *item = &g_Level.Items[itemNum];
|
|
|
|
short nextItem = item->nextActive;
|
|
|
|
|
|
|
|
if (item->afterDeath <= 128)
|
|
|
|
{
|
|
|
|
if (Objects[item->objectNumber].control)
|
|
|
|
Objects[item->objectNumber].control(itemNum);
|
|
|
|
|
|
|
|
if (item->afterDeath < 128 && item->afterDeath > 0 && !(Wibble & 3))
|
|
|
|
item->afterDeath++;
|
|
|
|
if (item->afterDeath == 128)
|
|
|
|
KillItem(itemNum);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KillItem(itemNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
itemNum = nextItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
InItemControlLoop = false;
|
|
|
|
KillMoveItems();
|
|
|
|
|
|
|
|
// Update all effects
|
|
|
|
InItemControlLoop = true;
|
|
|
|
|
|
|
|
short fxNum = NextFxActive;
|
|
|
|
while (fxNum != NO_ITEM)
|
|
|
|
{
|
|
|
|
short nextFx = EffectList[fxNum].nextActive;
|
|
|
|
FX_INFO *fx = &EffectList[fxNum];
|
|
|
|
if (Objects[fx->objectNumber].control)
|
|
|
|
Objects[fx->objectNumber].control(fxNum);
|
|
|
|
fxNum = nextFx;
|
|
|
|
}
|
|
|
|
|
|
|
|
InItemControlLoop = false;
|
|
|
|
KillMoveEffects();
|
|
|
|
|
|
|
|
// Update some effect timers
|
|
|
|
if (SmokeCountL)
|
|
|
|
SmokeCountL--;
|
|
|
|
if (SmokeCountR)
|
|
|
|
SmokeCountR--;
|
|
|
|
if (SplashCount)
|
|
|
|
SplashCount--;
|
|
|
|
if (WeaponDelay)
|
|
|
|
WeaponDelay--;
|
|
|
|
if (WeaponEnemyTimer)
|
|
|
|
WeaponEnemyTimer--;
|
|
|
|
|
|
|
|
if (CurrentLevel != 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
// Control Lara
|
|
|
|
InItemControlLoop = true;
|
2021-07-08 14:15:14 -05:00
|
|
|
// Lara.skelebob = NULL;
|
2020-12-21 13:16:29 -03:00
|
|
|
LaraControl(Lara.itemNumber);
|
|
|
|
InItemControlLoop = false;
|
|
|
|
KillMoveItems();
|
|
|
|
|
|
|
|
g_Renderer.updateLaraAnimations(true);
|
|
|
|
|
2021-06-10 14:40:28 -05:00
|
|
|
#ifdef NEW_INV
|
2021-05-31 11:57:42 -05:00
|
|
|
if (GLOBAL_inventoryitemchosen != -1)
|
|
|
|
{
|
|
|
|
SayNo();
|
|
|
|
GLOBAL_inventoryitemchosen = -1;
|
|
|
|
}
|
2021-06-10 14:40:28 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
// Update Lara's ponytails
|
|
|
|
HairControl(0, 0, 0);
|
2021-08-07 19:24:39 +01:00
|
|
|
if (level->LaraType == LARA_TYPE::YOUNG)
|
2020-12-21 13:16:29 -03:00
|
|
|
HairControl(0, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UseSpotCam)
|
|
|
|
{
|
|
|
|
// Draw flyby cameras
|
|
|
|
//if (CurrentLevel != 0)
|
|
|
|
// g_Renderer->EnableCinematicBars(true);
|
|
|
|
CalculateSpotCameras();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Do the standard camera
|
|
|
|
//g_Renderer->EnableCinematicBars(false);
|
|
|
|
TrackCameraInit = false;
|
|
|
|
CalculateCamera();
|
|
|
|
}
|
|
|
|
|
2021-09-16 01:12:19 +03:00
|
|
|
// Update oscillator seed
|
2020-12-21 13:16:29 -03:00
|
|
|
Wibble = (Wibble + 4) & 0xFC;
|
|
|
|
|
2021-09-16 01:12:19 +03:00
|
|
|
// Smash shatters and clear stopper flags under them
|
|
|
|
UpdateShatters();
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-09-15 11:13:47 +03:00
|
|
|
// Update weather
|
|
|
|
Weather.Update();
|
|
|
|
|
2021-07-10 06:55:37 +02:00
|
|
|
// Update special FX
|
2021-09-16 01:12:19 +03:00
|
|
|
TriggerLaraDrips();
|
2020-12-21 13:16:29 -03:00
|
|
|
UpdateSparks();
|
|
|
|
UpdateFireSparks();
|
|
|
|
UpdateSmoke();
|
|
|
|
UpdateBlood();
|
|
|
|
UpdateBubbles();
|
|
|
|
UpdateDebris();
|
|
|
|
UpdateGunShells();
|
2021-09-14 01:22:08 +03:00
|
|
|
UpdateFootprints();
|
2020-12-21 13:16:29 -03:00
|
|
|
UpdateSplashes();
|
|
|
|
UpdateEnergyArcs();
|
2021-04-16 06:46:54 +02:00
|
|
|
UpdateLightning();
|
2020-12-21 13:16:29 -03:00
|
|
|
UpdateDrips();
|
|
|
|
UpdateRats();
|
|
|
|
UpdateBats();
|
|
|
|
UpdateSpiders();
|
|
|
|
UpdateSparkParticles();
|
|
|
|
UpdateSmokeParticles();
|
|
|
|
updateSimpleParticles();
|
2021-08-30 18:03:21 +03:00
|
|
|
TEN::Effects::Drip::UpdateDrips();
|
2020-12-21 13:16:29 -03:00
|
|
|
UpdateExplosionParticles();
|
|
|
|
UpdateShockwaves();
|
2021-08-28 06:37:22 +02:00
|
|
|
TEN::Entities::TR4::UpdateScarabs();
|
|
|
|
TEN::Entities::TR4::UpdateLocusts();
|
2020-12-21 13:16:29 -03:00
|
|
|
//Legacy_UpdateLightning();
|
|
|
|
AnimateWaterfalls();
|
|
|
|
|
2021-07-10 06:55:37 +02:00
|
|
|
// Rumble screen (like in submarine level of TRC)
|
2020-12-21 13:16:29 -03:00
|
|
|
if (level->Rumble)
|
|
|
|
RumbleScreen();
|
|
|
|
|
2021-09-15 17:49:01 +03:00
|
|
|
PlaySoundSources();
|
|
|
|
DoFlipEffect(FlipEffect);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-08-29 23:53:58 +03:00
|
|
|
// Clear savegame loaded flag
|
|
|
|
JustLoaded = false;
|
|
|
|
|
2021-07-10 06:55:37 +02:00
|
|
|
// Update timers
|
2020-12-21 13:16:29 -03:00
|
|
|
HealthBarTimer--;
|
|
|
|
GameTimer++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GAME_STATUS_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned CALLBACK GameMain(void *)
|
|
|
|
{
|
2021-09-16 01:12:19 +03:00
|
|
|
try
|
|
|
|
{
|
2021-08-03 15:14:24 +01:00
|
|
|
printf("GameMain\n");
|
2021-09-16 01:12:19 +03:00
|
|
|
|
|
|
|
TimeInit();
|
|
|
|
|
2021-08-04 16:51:28 +01:00
|
|
|
if (g_GameFlow->IntroImagePath.empty())
|
2021-08-03 15:14:24 +01:00
|
|
|
{
|
|
|
|
throw TENScriptException("Intro image path is not set.");
|
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-08-03 15:14:24 +01:00
|
|
|
// Do a fixed time title image
|
|
|
|
g_Renderer.renderTitleImage();
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-08-03 15:14:24 +01:00
|
|
|
// Execute the LUA gameflow and play the game
|
|
|
|
g_GameFlow->DoGameflow();
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-08-03 15:14:24 +01:00
|
|
|
DoTheGame = false;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-08-03 15:14:24 +01:00
|
|
|
// Finish the thread
|
|
|
|
PostMessage(WindowsHandle, WM_CLOSE, NULL, NULL);
|
|
|
|
EndThread();
|
|
|
|
}
|
2021-09-16 01:12:19 +03:00
|
|
|
catch (TENScriptException const& e)
|
|
|
|
{
|
2021-08-03 15:14:24 +01:00
|
|
|
std::string msg = std::string{ "An unrecoverable error occurred in " } + __func__ + ": " + e.what();
|
|
|
|
TENLog(msg, LogLevel::Error, LogConfig::All);
|
|
|
|
throw;
|
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
GAME_STATUS DoTitle(int index)
|
|
|
|
{
|
|
|
|
//DB_Log(2, "DoTitle - DLL");
|
|
|
|
printf("DoTitle\n");
|
|
|
|
|
2021-09-14 16:34:58 +03:00
|
|
|
// Reset all the globals for the game which needs this
|
|
|
|
ResetGlobals();
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
// Load the level
|
|
|
|
S_LoadLevelFile(index);
|
|
|
|
|
|
|
|
int inventoryResult;
|
|
|
|
|
2021-08-07 19:25:13 +01:00
|
|
|
if (g_GameFlow->TitleType == TITLE_TYPE::FLYBY)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
// Initialise items, effects, lots, camera
|
|
|
|
InitialiseFXArray(true);
|
|
|
|
InitialisePickupDisplay();
|
|
|
|
InitialiseCamera();
|
|
|
|
SOUND_Stop();
|
|
|
|
|
2021-07-10 17:51:01 +01:00
|
|
|
// Run the level script
|
|
|
|
GameScriptLevel* level = g_GameFlow->Levels[index];
|
|
|
|
std::string err;
|
|
|
|
if (!level->ScriptFileName.empty())
|
|
|
|
{
|
2021-08-03 15:14:24 +01:00
|
|
|
g_GameScript->ExecuteScript(level->ScriptFileName);
|
2021-07-10 17:51:01 +01:00
|
|
|
g_GameScript->InitCallbacks();
|
2021-08-27 19:02:10 +01:00
|
|
|
g_GameScript->SetCallbackDrawString([](std::string const key, D3DCOLOR col, int x, int y, int flags)
|
|
|
|
{
|
2021-08-29 21:08:07 +01:00
|
|
|
g_Renderer.drawString(float(x)/float(g_Configuration.Width) * ASSUMED_WIDTH_FOR_TEXT_DRAWING, float(y)/float(g_Configuration.Height) * ASSUMED_HEIGHT_FOR_TEXT_DRAWING, key.c_str(), col, flags);
|
2021-08-27 19:02:10 +01:00
|
|
|
});
|
2021-07-10 17:51:01 +01:00
|
|
|
}
|
2021-09-16 01:12:19 +03:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
RequiredStartPos = false;
|
|
|
|
if (InitialiseGame)
|
|
|
|
{
|
|
|
|
GameTimer = 0;
|
|
|
|
RequiredStartPos = false;
|
|
|
|
InitialiseGame = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Savegame.Level.Timer = 0;
|
|
|
|
if (CurrentLevel == 1)
|
|
|
|
Savegame.TLCount = 0;
|
2021-05-26 01:58:30 -05:00
|
|
|
#ifndef NEW_INV
|
2020-12-21 13:16:29 -03:00
|
|
|
LastInventoryItem = -1;
|
2021-05-26 01:58:30 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
// Initialise flyby cameras
|
|
|
|
InitSpotCamSequences();
|
2021-09-16 01:12:19 +03:00
|
|
|
InitialiseSpotCam(0);
|
2020-12-21 13:16:29 -03:00
|
|
|
UseSpotCam = true;
|
|
|
|
|
|
|
|
// Play background music
|
2021-09-16 01:12:19 +03:00
|
|
|
S_CDPlay("083_horus", SOUND_TRACK_BGM);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
// Initialise ponytails
|
|
|
|
InitialiseHair();
|
|
|
|
|
2021-08-27 19:03:23 +01:00
|
|
|
g_GameScript->OnStart();
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
ControlPhase(2, 0);
|
2021-05-18 19:16:58 -05:00
|
|
|
#ifdef NEW_INV
|
|
|
|
int status = 0, frames;
|
|
|
|
while (!status)
|
|
|
|
{
|
|
|
|
g_Renderer.renderTitle();
|
|
|
|
|
|
|
|
SetDebounce = true;
|
|
|
|
S_UpdateInput();
|
|
|
|
SetDebounce = false;
|
|
|
|
|
|
|
|
status = TitleOptions();
|
|
|
|
|
|
|
|
if (status)
|
|
|
|
break;
|
|
|
|
|
|
|
|
Camera.numberFrames = g_Renderer.SyncRenderer();
|
|
|
|
frames = Camera.numberFrames;
|
|
|
|
ControlPhase(frames, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
inventoryResult = status;
|
|
|
|
#else
|
2020-12-21 13:16:29 -03:00
|
|
|
inventoryResult = g_Inventory.DoTitleInventory();
|
2021-05-18 19:16:58 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-05-18 19:16:58 -05:00
|
|
|
#ifdef NEW_INV
|
|
|
|
inventoryResult = TitleOptions();
|
|
|
|
#else
|
2020-12-21 13:16:29 -03:00
|
|
|
inventoryResult = g_Inventory.DoTitleInventory();
|
2021-05-18 19:16:58 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
2021-09-16 01:12:19 +03:00
|
|
|
StopSoundTracks();
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-08-27 19:03:23 +01:00
|
|
|
g_GameScript->OnEnd();
|
|
|
|
g_GameScript->FreeLevelScripts();
|
2021-09-16 01:12:19 +03:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
switch (inventoryResult)
|
|
|
|
{
|
|
|
|
case INV_RESULT_NEW_GAME:
|
|
|
|
return GAME_STATUS_NEW_GAME;
|
|
|
|
case INV_RESULT_LOAD_GAME:
|
|
|
|
return GAME_STATUS_LOAD_GAME;
|
|
|
|
case INV_RESULT_EXIT_GAME:
|
|
|
|
return GAME_STATUS_EXIT_GAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GAME_STATUS_NEW_GAME;
|
|
|
|
}
|
|
|
|
|
2021-06-26 07:36:54 +02:00
|
|
|
GAME_STATUS DoLevel(int index, std::string ambient, bool loadFromSavegame)
|
2020-12-21 13:16:29 -03: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;
|
|
|
|
}
|
|
|
|
|
2021-08-05 14:26:23 +03:00
|
|
|
// Reset all the globals for the game which needs this
|
|
|
|
ResetGlobals();
|
|
|
|
|
2021-09-14 16:34:58 +03:00
|
|
|
// Load the level
|
|
|
|
S_LoadLevelFile(index);
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
// Initialise items, effects, lots, camera
|
|
|
|
InitialiseFXArray(true);
|
|
|
|
InitialisePickupDisplay();
|
|
|
|
InitialiseCamera();
|
|
|
|
SOUND_Stop();
|
|
|
|
|
2021-06-28 18:34:59 +01:00
|
|
|
// Run the level script
|
|
|
|
GameScriptLevel* level = g_GameFlow->Levels[index];
|
2021-08-03 15:14:24 +01:00
|
|
|
|
2021-07-06 11:54:34 +02:00
|
|
|
if (!level->ScriptFileName.empty())
|
|
|
|
{
|
2021-08-03 15:14:24 +01:00
|
|
|
g_GameScript->ExecuteScript(level->ScriptFileName);
|
2021-07-06 11:54:34 +02:00
|
|
|
g_GameScript->InitCallbacks();
|
2021-08-27 19:02:10 +01:00
|
|
|
g_GameScript->SetCallbackDrawString([](std::string const key, D3DCOLOR col, int x, int y, int flags)
|
|
|
|
{
|
2021-08-29 21:08:07 +01:00
|
|
|
g_Renderer.drawString(float(x)/float(g_Configuration.Width) * ASSUMED_WIDTH_FOR_TEXT_DRAWING, float(y)/float(g_Configuration.Height) * ASSUMED_HEIGHT_FOR_TEXT_DRAWING, key.c_str(), col, flags);
|
2021-08-27 19:02:10 +01:00
|
|
|
});
|
2021-07-06 11:54:34 +02:00
|
|
|
}
|
2021-06-28 18:34:59 +01:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
// Restore the game?
|
|
|
|
if (loadFromSavegame)
|
|
|
|
{
|
|
|
|
char fileName[255];
|
|
|
|
ZeroMemory(fileName, 255);
|
|
|
|
sprintf(fileName, "savegame.%d", g_GameFlow->SelectedSaveGame);
|
|
|
|
SaveGame::Load(fileName);
|
|
|
|
|
|
|
|
Camera.pos.x = LaraItem->pos.xPos + 256;
|
|
|
|
Camera.pos.y = LaraItem->pos.yPos + 256;
|
|
|
|
Camera.pos.z = LaraItem->pos.zPos + 256;
|
|
|
|
|
|
|
|
Camera.target.x = LaraItem->pos.xPos;
|
|
|
|
Camera.target.y = LaraItem->pos.yPos;
|
|
|
|
Camera.target.z = LaraItem->pos.zPos;
|
|
|
|
|
|
|
|
int x = Lara.weaponItem;
|
|
|
|
|
|
|
|
RequiredStartPos = false;
|
|
|
|
InitialiseGame = false;
|
|
|
|
g_GameFlow->SelectedSaveGame = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RequiredStartPos = false;
|
|
|
|
if (InitialiseGame)
|
|
|
|
{
|
|
|
|
GameTimer = 0;
|
|
|
|
RequiredStartPos = false;
|
|
|
|
InitialiseGame = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Savegame.Level.Timer = 0;
|
|
|
|
if (CurrentLevel == 1)
|
|
|
|
Savegame.TLCount = 0;
|
|
|
|
}
|
2021-05-26 01:58:30 -05:00
|
|
|
#ifndef NEW_INV
|
2020-12-21 13:16:29 -03:00
|
|
|
LastInventoryItem = -1;
|
2021-05-26 01:58:30 -05:00
|
|
|
#endif
|
2021-05-20 14:19:11 -05:00
|
|
|
|
|
|
|
#ifdef NEW_INV
|
|
|
|
GLOBAL_inventoryitemchosen = NO_ITEM;
|
|
|
|
GLOBAL_enterinventory = NO_ITEM;
|
|
|
|
#else
|
2020-12-21 13:16:29 -03:00
|
|
|
g_Inventory.SetEnterObject(NO_ITEM);
|
|
|
|
g_Inventory.SetSelectedObject(NO_ITEM);
|
2021-05-20 14:19:11 -05:00
|
|
|
#endif
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
// Initialise flyby cameras
|
|
|
|
InitSpotCamSequences();
|
|
|
|
|
|
|
|
// Play background music
|
2021-09-16 01:12:19 +03:00
|
|
|
S_CDPlay(ambient, SOUND_TRACK_BGM);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
// Initialise ponytails
|
|
|
|
InitialiseHair();
|
|
|
|
|
2021-07-03 22:56:12 +01:00
|
|
|
g_GameScript->OnStart();
|
|
|
|
if (loadFromSavegame)
|
|
|
|
{
|
|
|
|
g_GameScript->OnLoad();
|
|
|
|
}
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
int nframes = 2;
|
|
|
|
|
|
|
|
// First control phase
|
|
|
|
g_Renderer.resetAnimations();
|
|
|
|
GAME_STATUS result = ControlPhase(nframes, 0);
|
|
|
|
|
|
|
|
// Fade in screen
|
|
|
|
g_Renderer.fadeIn();
|
|
|
|
|
|
|
|
// The game loop, finally!
|
|
|
|
while (true)
|
|
|
|
{
|
2021-08-06 11:06:43 +03:00
|
|
|
result = ControlPhase(nframes, 0);
|
2020-12-21 13:16:29 -03:00
|
|
|
nframes = DrawPhaseGame();
|
2021-08-06 11:06:43 +03:00
|
|
|
Sound_UpdateScene();
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
if (result == GAME_STATUS_EXIT_TO_TITLE ||
|
|
|
|
result == GAME_STATUS_LOAD_GAME ||
|
|
|
|
result == GAME_STATUS_LEVEL_COMPLETED)
|
|
|
|
{
|
2021-07-01 19:32:10 +01:00
|
|
|
g_GameScript->OnEnd();
|
2021-08-23 02:02:47 +01:00
|
|
|
g_GameScript->FreeLevelScripts();
|
2020-12-21 13:16:29 -03:00
|
|
|
// Here is the only way for exiting from the loop
|
|
|
|
SOUND_Stop();
|
2021-09-16 01:12:19 +03:00
|
|
|
StopSoundTracks();
|
2021-06-06 18:14:13 -04:00
|
|
|
DisableBubbles();
|
2021-06-23 14:14:58 -04:00
|
|
|
DisableDebris();
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TranslateItem(ITEM_INFO *item, int x, int y, int z)
|
|
|
|
{
|
|
|
|
float c = phd_cos(item->pos.yRot);
|
|
|
|
float s = phd_sin(item->pos.yRot);
|
|
|
|
|
|
|
|
item->pos.xPos += c * x + s * z;
|
|
|
|
item->pos.yPos += y;
|
|
|
|
item->pos.zPos += -s * x + c * z;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetWaterSurface(int x, int y, int z, short roomNumber)
|
|
|
|
{
|
|
|
|
ROOM_INFO *room = &g_Level.Rooms[roomNumber];
|
2021-09-03 09:37:42 +02:00
|
|
|
FLOOR_INFO *floor = XZ_GET_SECTOR(room, x - room->x, z - room->z);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
if (room->flags & ENV_FLAG_WATER)
|
|
|
|
{
|
2021-09-11 23:50:54 +03:00
|
|
|
while (floor->RoomAbove() != NO_ROOM)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-09-11 23:50:54 +03:00
|
|
|
room = &g_Level.Rooms[floor->RoomAbove()];
|
2020-12-21 13:16:29 -03:00
|
|
|
if (!(room->flags & ENV_FLAG_WATER))
|
2021-09-14 14:38:59 +03:00
|
|
|
return (floor->CeilingHeight(x, z));
|
2021-09-03 09:37:42 +02:00
|
|
|
floor = XZ_GET_SECTOR(room, x - room->x, z - room->z);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
return NO_HEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-11 23:50:54 +03:00
|
|
|
while (floor->RoomBelow() != NO_ROOM)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-09-11 23:50:54 +03:00
|
|
|
room = &g_Level.Rooms[floor->RoomBelow()];
|
2020-12-21 13:16:29 -03:00
|
|
|
if (room->flags & ENV_FLAG_WATER)
|
2021-09-14 14:38:59 +03:00
|
|
|
return (floor->FloorHeight(x, z));
|
2021-09-03 09:37:42 +02:00
|
|
|
floor = XZ_GET_SECTOR(room, x - room->x, z - room->z);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NO_HEIGHT;
|
|
|
|
}
|
|
|
|
|
2021-09-16 01:12:19 +03:00
|
|
|
void UpdateShatters()
|
|
|
|
{
|
|
|
|
if (!SmashedMeshCount)
|
|
|
|
return;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
SmashedMeshCount--;
|
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(
|
|
|
|
SmashedMesh[SmashedMeshCount]->pos.xPos,
|
|
|
|
SmashedMesh[SmashedMeshCount]->pos.yPos,
|
|
|
|
SmashedMesh[SmashedMeshCount]->pos.zPos,
|
|
|
|
&SmashedMeshRoom[SmashedMeshCount]);
|
|
|
|
|
|
|
|
TestTriggers(SmashedMesh[SmashedMeshCount]->pos.xPos,
|
|
|
|
SmashedMesh[SmashedMeshCount]->pos.yPos,
|
|
|
|
SmashedMesh[SmashedMeshCount]->pos.zPos,
|
|
|
|
SmashedMeshRoom[SmashedMeshCount], true);
|
|
|
|
|
|
|
|
floor->Stopper = false;
|
|
|
|
SmashedMesh[SmashedMeshCount] = 0;
|
|
|
|
} while (SmashedMeshCount != 0);
|
|
|
|
}
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
void KillMoveItems()
|
|
|
|
{
|
|
|
|
if (ItemNewRoomNo > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ItemNewRoomNo; i++)
|
|
|
|
{
|
|
|
|
short itemNumber = ItemNewRooms[2 * i];
|
|
|
|
if (itemNumber >= 0)
|
|
|
|
ItemNewRoom(itemNumber, ItemNewRooms[2 * i + 1]);
|
|
|
|
else
|
|
|
|
KillItem(itemNumber & 0x7FFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ItemNewRoomNo = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KillMoveEffects()
|
|
|
|
{
|
|
|
|
if (ItemNewRoomNo > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ItemNewRoomNo; i++)
|
|
|
|
{
|
|
|
|
short itemNumber = ItemNewRooms[2 * i];
|
|
|
|
if (itemNumber >= 0)
|
|
|
|
EffectNewRoom(itemNumber, ItemNewRooms[2 * i + 1]);
|
|
|
|
else
|
|
|
|
KillEffect(itemNumber & 0x7FFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ItemNewRoomNo = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetChange(ITEM_INFO *item, ANIM_STRUCT *anim)
|
|
|
|
{
|
|
|
|
if (item->currentAnimState == item->goalAnimState)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (anim->numberChanges <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < anim->numberChanges; i++)
|
|
|
|
{
|
|
|
|
CHANGE_STRUCT *change = &g_Level.Changes[anim->changeIndex + i];
|
|
|
|
if (change->goalAnimState == item->goalAnimState)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < change->numberRanges; j++)
|
|
|
|
{
|
|
|
|
RANGE_STRUCT *range = &g_Level.Ranges[change->rangeIndex + j];
|
|
|
|
if (item->frameNumber >= range->startFrame && item->frameNumber <= range->endFrame)
|
|
|
|
{
|
|
|
|
item->animNumber = range->linkAnimNum;
|
|
|
|
item->frameNumber = range->linkFrameNum;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlterFloorHeight(ITEM_INFO *item, int height)
|
|
|
|
{
|
|
|
|
FLOOR_INFO *floor;
|
|
|
|
FLOOR_INFO *ceiling;
|
|
|
|
BOX_INFO *box;
|
|
|
|
short roomNumber;
|
|
|
|
int flag = 0;
|
|
|
|
|
|
|
|
if (abs(height))
|
|
|
|
{
|
|
|
|
flag = 1;
|
|
|
|
if (height >= 0)
|
|
|
|
height++;
|
|
|
|
else
|
|
|
|
height--;
|
|
|
|
}
|
|
|
|
|
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
ceiling = GetFloor(item->pos.xPos, height + item->pos.yPos - WALL_SIZE, item->pos.zPos, &roomNumber);
|
|
|
|
|
2021-09-13 02:51:52 +03:00
|
|
|
/*if (floor->AverageFloor == NO_HEIGHT / STEP_SIZE)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-09-13 02:51:52 +03:00
|
|
|
floor->AverageFloor = ceiling->ceiling + height / STEP_SIZE;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-13 02:51:52 +03:00
|
|
|
floor->AverageFloor += height / STEP_SIZE;
|
|
|
|
if (floor->AverageFloor == ceiling->ceiling && !flag)
|
|
|
|
floor->AverageFloor = NO_HEIGHT / STEP_SIZE;
|
2020-12-21 13:16:29 -03:00
|
|
|
}*/
|
|
|
|
|
|
|
|
floor->FloorCollision.Planes[0].z += height;
|
|
|
|
floor->FloorCollision.Planes[1].z += height;
|
|
|
|
|
2021-09-13 02:46:48 +03:00
|
|
|
box = &g_Level.Boxes[floor->Box];
|
2020-12-21 13:16:29 -03:00
|
|
|
if (box->flags & BLOCKABLE)
|
|
|
|
{
|
|
|
|
if (height >= 0)
|
|
|
|
box->flags &= ~BLOCKED;
|
|
|
|
else
|
|
|
|
box->flags |= BLOCKED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FLOOR_INFO *GetFloor(int x, int y, int z, short *roomNumber)
|
|
|
|
{
|
2021-01-06 17:53:13 -03:00
|
|
|
const auto location = GetRoom(ROOM_VECTOR{*roomNumber, y}, x, y, z);
|
|
|
|
*roomNumber = location.roomNumber;
|
2020-12-21 13:16:29 -03:00
|
|
|
return &GetFloor(*roomNumber, x, z);
|
|
|
|
}
|
|
|
|
|
2021-08-20 15:26:12 +03:00
|
|
|
int GetFloorHeight(FLOOR_INFO *floor, int x, int y, int z)
|
|
|
|
{
|
2021-01-06 17:53:13 -03:00
|
|
|
return GetFloorHeight(ROOM_VECTOR{floor->Room, y}, x, z).value_or(NO_HEIGHT);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
int GetRandomControl()
|
|
|
|
{
|
|
|
|
return generateInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetRandomDraw()
|
|
|
|
{
|
|
|
|
return generateInt();
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
int GetCeiling(FLOOR_INFO *floor, int x, int y, int z)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-01-06 17:53:13 -03:00
|
|
|
return GetCeilingHeight(ROOM_VECTOR{floor->Room, y}, x, z).value_or(NO_HEIGHT);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimateItem(ITEM_INFO *item)
|
|
|
|
{
|
|
|
|
item->touchBits = 0;
|
|
|
|
item->hitStatus = false;
|
|
|
|
|
|
|
|
item->frameNumber++;
|
|
|
|
|
|
|
|
ANIM_STRUCT *anim = &g_Level.Anims[item->animNumber];
|
|
|
|
if (anim->numberChanges > 0 && GetChange(item, anim))
|
|
|
|
{
|
|
|
|
anim = &g_Level.Anims[item->animNumber];
|
|
|
|
|
|
|
|
item->currentAnimState = anim->currentAnimState;
|
|
|
|
|
|
|
|
if (item->requiredAnimState == item->currentAnimState)
|
|
|
|
item->requiredAnimState = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item->frameNumber > anim->frameEnd)
|
|
|
|
{
|
|
|
|
if (anim->numberCommands > 0)
|
|
|
|
{
|
|
|
|
short *cmd = &g_Level.Commands[anim->commandIndex];
|
|
|
|
for (int i = anim->numberCommands; i > 0; i--)
|
|
|
|
{
|
|
|
|
switch (*(cmd++))
|
|
|
|
{
|
|
|
|
case COMMAND_MOVE_ORIGIN:
|
|
|
|
TranslateItem(item, cmd[0], cmd[1], cmd[2]);
|
|
|
|
cmd += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMMAND_JUMP_VELOCITY:
|
|
|
|
item->fallspeed = *(cmd++);
|
|
|
|
item->speed = *(cmd++);
|
|
|
|
item->gravityStatus = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMMAND_DEACTIVATE:
|
|
|
|
if (Objects[item->objectNumber].intelligent && !item->afterDeath)
|
|
|
|
item->afterDeath = 1;
|
|
|
|
item->status = ITEM_DEACTIVATED;
|
|
|
|
break;
|
|
|
|
case COMMAND_SOUND_FX:
|
|
|
|
case COMMAND_EFFECT:
|
|
|
|
cmd += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
item->animNumber = anim->jumpAnimNum;
|
|
|
|
item->frameNumber = anim->jumpFrameNum;
|
|
|
|
|
|
|
|
anim = &g_Level.Anims[item->animNumber];
|
|
|
|
|
|
|
|
if (item->currentAnimState != anim->currentAnimState)
|
|
|
|
{
|
|
|
|
item->currentAnimState = anim->currentAnimState;
|
|
|
|
item->goalAnimState = anim->currentAnimState;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item->requiredAnimState == item->currentAnimState)
|
|
|
|
item->requiredAnimState = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (anim->numberCommands > 0)
|
|
|
|
{
|
|
|
|
short *cmd = &g_Level.Commands[anim->commandIndex];
|
|
|
|
int flags;
|
|
|
|
int effectID = 0;
|
|
|
|
|
|
|
|
for (int i = anim->numberCommands; i > 0; i--)
|
|
|
|
{
|
|
|
|
switch (*(cmd++))
|
|
|
|
{
|
|
|
|
case COMMAND_MOVE_ORIGIN:
|
|
|
|
cmd += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMMAND_JUMP_VELOCITY:
|
|
|
|
cmd += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMMAND_SOUND_FX:
|
|
|
|
if (item->frameNumber != *cmd)
|
|
|
|
{
|
|
|
|
cmd += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = cmd[1] & 0xC000;
|
|
|
|
|
|
|
|
if (!Objects[item->objectNumber].waterCreature)
|
|
|
|
{
|
|
|
|
if (item->roomNumber == NO_ROOM)
|
|
|
|
{
|
|
|
|
item->pos.xPos = LaraItem->pos.xPos;
|
|
|
|
item->pos.yPos = LaraItem->pos.yPos - 762;
|
|
|
|
item->pos.zPos = LaraItem->pos.zPos;
|
|
|
|
|
|
|
|
SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2);
|
|
|
|
}
|
|
|
|
else if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_WATER)
|
|
|
|
{
|
|
|
|
if (!flags || flags == SFX_WATERONLY && (g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER || Objects[item->objectNumber].intelligent))
|
|
|
|
{
|
|
|
|
SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!flags || flags == SFX_LANDONLY && !(g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER))
|
|
|
|
{
|
|
|
|
SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (g_Level.Rooms[Camera.pos.roomNumber].flags & ENV_FLAG_WATER)
|
|
|
|
SoundEffect(cmd[1] & 0x3FFF, &item->pos, 1);
|
|
|
|
else
|
|
|
|
SoundEffect(cmd[1] & 0x3FFF, &item->pos, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMMAND_EFFECT:
|
|
|
|
if (item->frameNumber != *cmd)
|
|
|
|
{
|
|
|
|
cmd += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
FXType = cmd[1] & 0xC000;
|
|
|
|
effectID = cmd[1] & 0x3FFF;
|
2021-09-15 17:49:01 +03:00
|
|
|
DoFlipEffect(effectID, item);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
cmd += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int lateral = 0;
|
|
|
|
|
|
|
|
if (item->gravityStatus)
|
|
|
|
{
|
|
|
|
item->fallspeed += (item->fallspeed >= 128 ? 1 : 6);
|
|
|
|
item->pos.yPos += item->fallspeed;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int velocity = anim->velocity;
|
|
|
|
if (anim->acceleration)
|
|
|
|
velocity += anim->acceleration * (item->frameNumber - anim->frameBase);
|
2021-08-30 15:13:18 -05:00
|
|
|
item->speed = velocity >> 16;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
lateral = anim->Xvelocity;
|
|
|
|
if (anim->Xacceleration)
|
|
|
|
lateral += anim->Xacceleration * (item->frameNumber - anim->frameBase);
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
lateral >>= 16;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
item->pos.xPos += item->speed * phd_sin(item->pos.yRot);
|
|
|
|
item->pos.zPos += item->speed * phd_cos(item->pos.yRot);
|
|
|
|
|
|
|
|
item->pos.xPos += lateral * phd_sin(item->pos.yRot + ANGLE(90));
|
|
|
|
item->pos.zPos += lateral * phd_cos(item->pos.yRot + ANGLE(90));
|
|
|
|
|
|
|
|
// Update matrices
|
|
|
|
short itemNumber = item - g_Level.Items.data();
|
|
|
|
g_Renderer.updateItemAnimations(itemNumber, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RumbleScreen()
|
|
|
|
{
|
|
|
|
if (!(GlobalCounter & 0x1FF))
|
2021-05-26 06:04:32 +02:00
|
|
|
SoundEffect(SFX_TR5_KLAXON, 0, 4104);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
if (RumbleTimer >= 0)
|
|
|
|
RumbleTimer++;
|
|
|
|
|
|
|
|
if (RumbleTimer > 450)
|
|
|
|
{
|
|
|
|
if (!(GetRandomControl() & 0x1FF))
|
|
|
|
{
|
2021-09-15 21:09:09 +03:00
|
|
|
InGameCounter = 0;
|
2020-12-21 13:16:29 -03:00
|
|
|
RumbleTimer = -32 - (GetRandomControl() & 0x1F);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RumbleTimer < 0)
|
|
|
|
{
|
2021-09-15 21:09:09 +03:00
|
|
|
if (InGameCounter >= abs(RumbleTimer))
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
Camera.bounce = -(GetRandomControl() % abs(RumbleTimer));
|
|
|
|
RumbleTimer++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-15 21:09:09 +03:00
|
|
|
InGameCounter++;
|
|
|
|
Camera.bounce = -(GetRandomControl() % InGameCounter);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RefreshCamera(short type, short *data)
|
|
|
|
{
|
|
|
|
short trigger, value, targetOk;
|
|
|
|
|
|
|
|
targetOk = 2;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
trigger = *(data++);
|
|
|
|
value = trigger & VALUE_BITS;
|
|
|
|
|
|
|
|
switch (TRIG_BITS(trigger))
|
|
|
|
{
|
|
|
|
case TO_CAMERA:
|
|
|
|
data++;
|
|
|
|
|
|
|
|
if (value == Camera.last)
|
|
|
|
{
|
|
|
|
Camera.number = value;
|
|
|
|
|
|
|
|
if ((Camera.timer < 0) || (Camera.type == LOOK_CAMERA) || (Camera.type == COMBAT_CAMERA))
|
|
|
|
{
|
|
|
|
Camera.timer = -1;
|
|
|
|
targetOk = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Camera.type = FIXED_CAMERA;
|
|
|
|
targetOk = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
targetOk = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TO_TARGET:
|
|
|
|
if (Camera.type == LOOK_CAMERA || Camera.type == COMBAT_CAMERA)
|
|
|
|
break;
|
|
|
|
|
|
|
|
Camera.item = &g_Level.Items[value];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (!(trigger & END_BIT));
|
|
|
|
|
|
|
|
if (Camera.item)
|
|
|
|
if (!targetOk || (targetOk == 2 && Camera.item->lookedAt && Camera.item != Camera.lastItem))
|
|
|
|
Camera.item = NULL;
|
|
|
|
|
|
|
|
if (Camera.number == -1 && Camera.timer > 0)
|
|
|
|
Camera.timer = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ExplodeItemNode(ITEM_INFO *item, int Node, int NoXZVel, int bits)
|
|
|
|
{
|
|
|
|
if (1 << Node & item->meshBits)
|
|
|
|
{
|
2021-09-10 18:13:40 +03:00
|
|
|
auto num = bits;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (item->objectNumber == ID_SHOOT_SWITCH1 && (CurrentLevel == 4 || CurrentLevel == 7)) // TODO: remove hardcoded think !
|
|
|
|
{
|
2021-05-26 06:04:32 +02:00
|
|
|
SoundEffect(SFX_TR5_SMASH_METAL, &item->pos, 0);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
2021-09-10 18:13:40 +03:00
|
|
|
else if (num == 256)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-09-10 18:13:40 +03:00
|
|
|
num = -64;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
GetSpheres(item, CreatureSpheres, SPHERES_SPACE_WORLD | SPHERES_SPACE_BONE_ORIGIN, Matrix::Identity);
|
|
|
|
ShatterItem.yRot = item->pos.yRot;
|
|
|
|
ShatterItem.bit = 1 << Node;
|
|
|
|
ShatterItem.meshp = &g_Level.Meshes[Objects[item->objectNumber].meshIndex + Node];
|
|
|
|
ShatterItem.sphere.x = CreatureSpheres[Node].x;
|
|
|
|
ShatterItem.sphere.y = CreatureSpheres[Node].y;
|
|
|
|
ShatterItem.sphere.z = CreatureSpheres[Node].z;
|
|
|
|
ShatterItem.flags = item->objectNumber == ID_CROSSBOW_BOLT ? 0x400 : 0;
|
|
|
|
ShatterImpactData.impactDirection = Vector3(0, -1, 0);
|
|
|
|
ShatterImpactData.impactLocation = {(float)ShatterItem.sphere.x, (float)ShatterItem.sphere.y, (float)ShatterItem.sphere.z};
|
2021-09-10 18:13:40 +03:00
|
|
|
ShatterObject(&ShatterItem, NULL, num, item->roomNumber, NoXZVel);
|
2020-12-21 13:16:29 -03:00
|
|
|
item->meshBits &= ~ShatterItem.bit;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetWaterHeight(int x, int y, int z, short roomNumber)
|
|
|
|
{
|
|
|
|
ROOM_INFO *r = &g_Level.Rooms[roomNumber];
|
|
|
|
FLOOR_INFO *floor;
|
|
|
|
short adjoiningRoom = NO_ROOM;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2021-09-08 03:01:32 -05:00
|
|
|
int xBlock = (x - r->x) / SECTOR(1);
|
|
|
|
int zBlock = (z - r->z) / SECTOR(1);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
if (zBlock <= 0)
|
|
|
|
{
|
|
|
|
zBlock = 0;
|
|
|
|
if (xBlock < 1)
|
|
|
|
xBlock = 1;
|
|
|
|
else if (xBlock > r->ySize - 2)
|
|
|
|
xBlock = r->ySize - 2;
|
|
|
|
}
|
|
|
|
else if (zBlock >= r->xSize - 1)
|
|
|
|
{
|
|
|
|
zBlock = r->xSize - 1;
|
|
|
|
if (xBlock < 1)
|
|
|
|
xBlock = 1;
|
|
|
|
else if (xBlock > r->ySize - 2)
|
|
|
|
xBlock = r->ySize - 2;
|
|
|
|
}
|
|
|
|
else if (xBlock < 0)
|
|
|
|
xBlock = 0;
|
|
|
|
else if (xBlock >= r->ySize)
|
|
|
|
xBlock = r->ySize - 1;
|
|
|
|
|
|
|
|
floor = &r->floor[zBlock + xBlock * r->xSize];
|
2021-09-11 22:41:25 +03:00
|
|
|
adjoiningRoom = floor->WallPortal;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
if (adjoiningRoom != NO_ROOM)
|
|
|
|
{
|
|
|
|
roomNumber = adjoiningRoom;
|
|
|
|
r = &g_Level.Rooms[adjoiningRoom];
|
|
|
|
}
|
|
|
|
} while (adjoiningRoom != NO_ROOM);
|
|
|
|
|
|
|
|
if (r->flags & (ENV_FLAG_WATER | ENV_FLAG_SWAMP))
|
|
|
|
{
|
2021-09-11 23:50:54 +03:00
|
|
|
while (floor->RoomAbove() != NO_ROOM)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-09-13 03:20:53 +03:00
|
|
|
if (CheckNoColCeilingTriangle(floor, x, z) == SPLIT_SOLID)
|
2020-12-21 13:16:29 -03:00
|
|
|
break;
|
2021-09-11 23:50:54 +03:00
|
|
|
r = &g_Level.Rooms[floor->RoomAbove()];
|
2020-12-21 13:16:29 -03:00
|
|
|
if (!(r->flags & (ENV_FLAG_WATER | ENV_FLAG_SWAMP)))
|
|
|
|
return r->minfloor;
|
2021-09-03 09:37:42 +02:00
|
|
|
floor = XZ_GET_SECTOR(r, x - r->x, z - r->z);
|
2021-09-11 23:50:54 +03:00
|
|
|
if (floor->RoomAbove() == NO_ROOM)
|
2020-12-21 13:16:29 -03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r->maxceiling;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-11 23:50:54 +03:00
|
|
|
while (floor->RoomBelow() != NO_ROOM)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-09-13 03:20:53 +03:00
|
|
|
if (CheckNoColFloorTriangle(floor, x, z) == SPLIT_SOLID)
|
2020-12-21 13:16:29 -03:00
|
|
|
break;
|
2021-09-11 23:50:54 +03:00
|
|
|
r = &g_Level.Rooms[floor->RoomBelow()];
|
2020-12-21 13:16:29 -03:00
|
|
|
if (r->flags & (ENV_FLAG_WATER | ENV_FLAG_SWAMP))
|
|
|
|
return r->maxceiling;
|
2021-09-03 09:37:42 +02:00
|
|
|
floor = XZ_GET_SECTOR(r, x - r->x, z - r->z);
|
2021-09-11 23:50:54 +03:00
|
|
|
if (floor->RoomBelow() == NO_ROOM)
|
2020-12-21 13:16:29 -03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NO_HEIGHT;
|
|
|
|
}
|
|
|
|
|
2021-09-15 17:40:00 +03:00
|
|
|
int IsObjectInRoom(short roomNumber, short objectNumber)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
short itemNumber = g_Level.Rooms[roomNumber].itemNumber;
|
|
|
|
|
|
|
|
if (itemNumber == NO_ITEM)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
ITEM_INFO *item = &g_Level.Items[itemNumber];
|
|
|
|
|
|
|
|
if (item->objectNumber == objectNumber)
|
|
|
|
break;
|
|
|
|
|
|
|
|
itemNumber = item->nextItem;
|
|
|
|
|
|
|
|
if (itemNumber == NO_ITEM)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IsRoomOutside(int x, int y, int z)
|
|
|
|
{
|
|
|
|
if (x < 0 || z < 0)
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
int xTable = x / 1024;
|
|
|
|
int zTable = z / 1024;
|
|
|
|
|
|
|
|
if (OutsideRoomTable[xTable][zTable].size() == 0)
|
|
|
|
return -2;
|
|
|
|
|
2021-08-12 22:10:05 +01:00
|
|
|
for (size_t i = 0; i < OutsideRoomTable[xTable][zTable].size(); i++)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
short roomNumber = OutsideRoomTable[xTable][zTable][i];
|
|
|
|
ROOM_INFO* r = &g_Level.Rooms[roomNumber];
|
|
|
|
|
|
|
|
if ((y > r->maxceiling) && (y < r->minfloor)
|
|
|
|
&& ((z > (r->z + 1024)) && (z < (r->z + ((r->xSize - 1) * 1024))))
|
|
|
|
&& ((x > (r->x + 1024)) && (x < (r->x + ((r->ySize - 1) * 1024)))))
|
|
|
|
{
|
|
|
|
IsRoomOutsideNo = roomNumber;
|
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber);
|
|
|
|
int height = GetFloorHeight(floor, x, y, z);
|
|
|
|
if (height == NO_HEIGHT || y > height)
|
|
|
|
return -2;
|
|
|
|
height = GetCeiling(floor, x, y, z);
|
|
|
|
if (y < height)
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
return ((r->flags & (ENV_FLAG_WIND | ENV_FLAG_WATER)) != 0 ? 1 : -3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2021-08-05 14:26:23 +03:00
|
|
|
void ResetGlobals()
|
|
|
|
{
|
2021-09-15 21:09:09 +03:00
|
|
|
// Reset oscillator seed
|
|
|
|
Wibble = 0;
|
|
|
|
|
2021-09-14 15:54:49 +03:00
|
|
|
// Needs to be cleared or otherwise controls will lockup if user will exit to title
|
|
|
|
// while playing flyby with locked controls
|
2021-08-05 14:26:23 +03:00
|
|
|
DisableLaraControl = false;
|
2021-09-14 15:54:49 +03:00
|
|
|
|
2021-09-15 11:18:11 +03:00
|
|
|
// Weather.Clear resets lightning and wind parameters so user won't see prev weather in new level
|
2021-09-15 11:13:47 +03:00
|
|
|
Weather.Clear();
|
2021-09-14 16:00:06 +03:00
|
|
|
|
2021-09-14 15:54:49 +03:00
|
|
|
// Needs to be cleared because otherwise a list of active creatures from previous level
|
|
|
|
// will spill into new level
|
|
|
|
ActiveCreatures.clear();
|
2021-09-14 16:34:58 +03:00
|
|
|
|
|
|
|
// Clear spotcam array
|
|
|
|
ClearSpotCamSequences();
|
2021-09-15 17:20:42 +03:00
|
|
|
}
|