Merge branch 'master' into very_experimental_input_stuff

This commit is contained in:
Sezz 2022-10-01 12:27:36 +10:00
commit 0fe92bfa82
30 changed files with 424 additions and 453 deletions

View file

@ -1,8 +1,15 @@
Version 1.0.3
=============
* Fix dodgy weapon lock angle constraints.
* Fix wrong shotgun ammo pickup amount.
Version 1.0.2
=============
* Removing Pistols with TakeItem and SetItemCount now works correctly.
* Vec3s can now be saved and loaded in LevelVars and GameVars.
* Fix removing Pistols with TakeItem and SetItemCount.
* Allow saving and loading of Vec3s in LevelVars and GameVars.
* Support volume triggers made with node editor.
* Adjust max turn rate of idle state.
* Align Lara on slopes when crouching, crawling, and dying.
@ -27,28 +34,30 @@ Version 1.0.2
* Fix incorrect pole mounting.
* Fix zeroed forward velocity upon landing.
* Fix incorrect behaviour when falling on statics from the top after monkeyswing.
* Fix missing animcommand calls on first animation frame.
* Fix 1-frame turn rate delays.
* Fix occasional leave event calls when moving closer to volumes.
* Fix incorrect viewport size in windowed mode.
* Fix late landing animation dispatch in rare cases.
* Fix Lara's subway train death so that she no longer slides slowly after the animation has finished.
* Fix incorrect velocity calculations for death animations.
* Fix horseman's axe attack using his left foot as the damaging joint.
* Fix stargate blades needlessly pushing the player around while hardly doing any damage.
* Fix weapon hotkeys and add missing crossbow hotkey.
Lua API changes:
* Util.ShortenTENCalls no longer needs to be called; it is now automatic.
* Util.ShortenTENCalls no longer needs to be called; it is now automatic for both level scripts and Gameflow.lua.
* Flow.InvID has been removed; any function taking a pickup (e.g. GiveItem) now takes an Objects.ObjID instead.
* Added Enable, Disable, GetActive, Get/SetSolid functions for static meshes.
* Added FadeOutComplete, StopAudioTrack and StopAudioTracks functions.
* Add Enable, Disable, GetActive, Get/SetSolid functions for static meshes.
* Add FadeOutComplete, StopAudioTrack and StopAudioTracks functions.
* Account for objects in HasLineOfSight tests.
* Timer.lua, EventSequence.lua and Util.lua have been moved to a subfolder, Engine.
* Move Timer.lua, EventSequence.lua and Util.lua to a subfolder named "Engine".
* LevelFuncs can now contain tables as well as functions. These tables can contain functions and other tables, and so forth.
* Moveable functions SetOnHit, SetOnKilled, SetOnCollidedWithObject and SetOnCollidedWithRoom no longer take strings, and instead take function objects themselves.
* EventSequence and Timer no longer require you to call Timer.UpdateAll in OnControlPhase.
* TEN.Logic.AddCallback and TEN.Logic.RemoveCallback have been added.
* GiveItem, TakeItem, and SetItemCount have been reworked (e.g. SetItemCount with a value of -1 can give infinite ammo/consumables).
* Don't require EventSequence and Timer to call Timer.UpdateAll in OnControlPhase.
* Add TEN.Logic.AddCallback and TEN.Logic.RemoveCallback.
* Rework GiveItem, TakeItem, and SetItemCount (e.g. SetItemCount with a value of -1 can give infinite ammo/consumables).
Version 1.0.1
=============

View file

@ -15,6 +15,8 @@ TombEngine (TEN) is a new, open-source engine which aims to abolish all limits,
TEN is based on the Tomb Raider: Chronicles engine of the classic era and continues to build upon and replace its systems to modernize ...
If you would like to participate in TEN discussion with other TEN devs whether it is contributing or bugs, then join this discord server: https://discord.gg/apjBW2NsVj and head to #tombengine channel.
# Compiling TombEngine
To compile TEN, ensure you have installed:
- Microsoft Visual Studio
@ -75,9 +77,11 @@ We do not and have never worked for Core Design, Eidos Interactive, or Square En
## Assets and Miscellaneous
### Animations
- SrDanielPonces (Diagonal shimmy transitions)
- SrDanielPonces (Diagonal shimmy transitions, backwards monkey swinging)
- Krystian (Flexibility crawlspace, slope climbing animations)
- Sezz (Additional Animations for player state refactoring)
- Naotheia (Underwater puzzle placement, crouch 180° turn, crawl 180° turn, water surface 180° turn)
- JoeyQuint (Standing 180° turn, monkey swing 180° turn)
### TombEngine Wiki tutorials
- Kubsy (Lua Basics tutorial)

View file

@ -1,17 +1,6 @@
-- Place in this LUA script all the levels of your game
-- Place in this Lua script all the levels of your game
-- Title is mandatory and must be the first level.
-- Shorten some of the internal data types.
local Flow = TEN.Flow
local Level = Flow.Level
local Color = TEN.Color
local Rotation = TEN.Rotation
local InventoryItem = Flow.InventoryItem
local ObjID = TEN.Objects.ObjID
local RotationAxis = Flow.RotationAxis
local ItemAction = Flow.ItemAction
-- Intro image is a splash screen which appears before actual loading screen.
-- If you don't want it to appear, just remove this line.

View file

@ -95,3 +95,4 @@ void LaraWaterSurface(ItemInfo* item, CollisionInfo* coll);
void LaraUnderwater(ItemInfo* item, CollisionInfo* coll);
void LaraCheat(ItemInfo* item, CollisionInfo* coll);
void AnimateLara(ItemInfo* item);
void PerformAnimCommands(ItemInfo* item, bool frameBased);

View file

@ -51,6 +51,23 @@ bool LaraDeflectEdge(ItemInfo* item, CollisionInfo* coll)
return false;
}
bool LaraDeflectTopSide(ItemInfo* item, CollisionInfo* coll)
{
// HACK: If we are falling down, collision is CT_CLAMP and
// HitStatic flag is set, it means we've collided static from the top.
if (coll->CollisionType == CT_CLAMP &&
coll->HitStatic && item->Animation.Velocity.y > 0.0f)
{
SetAnimation(item, LA_JUMP_WALL_SMASH_START, 1);
Rumble(0.5f, 0.15f);
return true;
}
return false;
}
bool LaraDeflectEdgeJump(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
@ -60,16 +77,21 @@ bool LaraDeflectEdgeJump(ItemInfo* item, CollisionInfo* coll)
if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT)
{
if (!lara->Control.CanClimbLadder || item->Animation.Velocity.z != 2)
if (!lara->Control.CanClimbLadder || item->Animation.Velocity.z != 2.0f)
{
if (coll->Middle.Floor <= CLICK(1))
{
SetAnimation(item, LA_LAND);
LaraSnapToHeight(item, coll);
if (TestLaraSlide(item, coll))
SetLaraSlideAnimation(item, coll);
else
{
SetAnimation(item, LA_LAND);
LaraSnapToHeight(item, coll);
}
}
else if (abs(item->Animation.Velocity.z) > 47)
// TODO: Demagic. This is Lara's running velocity. Jumps have a minimum of 50.
else if (abs(item->Animation.Velocity.z) > 47.0f)
{
// TODO: Demagic. This is Lara's running velocity. Jumps have a minimum of 50.
SetAnimation(item, LA_JUMP_WALL_SMASH_START, 1);
Rumble(0.5f, 0.15f);
}
@ -77,8 +99,8 @@ bool LaraDeflectEdgeJump(ItemInfo* item, CollisionInfo* coll)
item->Animation.Velocity.z /= 4;
lara->Control.MoveAngle += ANGLE(180.0f);
if (item->Animation.Velocity.y <= 0)
item->Animation.Velocity.y = 1;
if (item->Animation.Velocity.y <= 0.0f)
item->Animation.Velocity.y = 1.0f;
}
return true;
@ -96,19 +118,19 @@ bool LaraDeflectEdgeJump(ItemInfo* item, CollisionInfo* coll)
case CT_TOP:
case CT_TOP_FRONT:
if (item->Animation.Velocity.y <= 0)
item->Animation.Velocity.y = 1;
if (item->Animation.Velocity.y <= 0.0f)
item->Animation.Velocity.y = 1.0f;
break;
case CT_CLAMP:
item->Pose.Position.z += CLICK(1.5f) * phd_cos(item->Pose.Orientation.y + ANGLE(180.0f));
item->Pose.Position.x += CLICK(1.5f) * phd_sin(item->Pose.Orientation.y + ANGLE(180.0f));
item->Animation.Velocity.z = 0;
coll->Middle.Floor = 0;
item->Animation.Velocity.z = 0.0f;
coll->Middle.Floor = 0.0f;
if (item->Animation.Velocity.y <= 0)
item->Animation.Velocity.y = 16;
if (item->Animation.Velocity.y <= 0.0f)
item->Animation.Velocity.y = 16.0f;
break;
}

View file

@ -15,6 +15,7 @@ constexpr auto DEFLECT_DIAGONAL_ANGLE_CRAWL = 5.0f;
bool LaraDeflectEdge(ItemInfo* item, CollisionInfo* coll);
bool LaraDeflectEdgeJump(ItemInfo* item, CollisionInfo* coll);
bool LaraDeflectTopSide(ItemInfo* item, CollisionInfo* coll);
void LaraSlideEdgeJump(ItemInfo* item, CollisionInfo* coll);
bool LaraDeflectEdgeCrawl(ItemInfo* item, CollisionInfo* coll);
bool LaraDeflectEdgeMonkey(ItemInfo* item, CollisionInfo* coll);

View file

@ -58,7 +58,7 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Pistols
{
{ Vector3Shrt(ANGLE(-60.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(60.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-170.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(170.0f), 0) },
ANGLE(10.0f),
@ -75,7 +75,7 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Revolver
{
{ Vector3Shrt(ANGLE(-60.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(60.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-10.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(10.0f), 0) },
{ Vector3Shrt::Zero, Vector3Shrt::Zero },
ANGLE(10.0f),
@ -92,7 +92,7 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Uzis
{
{ Vector3Shrt(ANGLE(-60.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(60.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-170.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-80.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(80.0f), ANGLE(170.0f), 0) },
ANGLE(10.0f),
@ -109,9 +109,9 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Shotgun
{
{ Vector3Shrt(ANGLE(-55.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(55.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
ANGLE(10.0f),
0,
500,
@ -126,9 +126,9 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// HK
{
{ Vector3Shrt(ANGLE(-55.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(55.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
ANGLE(10.0f),
ANGLE(4.0f),
500,
@ -143,9 +143,9 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Crossbow
{
{ Vector3Shrt(ANGLE(-55.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(55.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
ANGLE(10.0f),
ANGLE(8.0f),
500,
@ -194,9 +194,9 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Grenade launcher
{
{ Vector3Shrt(ANGLE(-55.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(55.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
ANGLE(10.0f),
ANGLE(8.0f),
500,
@ -211,7 +211,7 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Harpoon gun
{
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-75.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(75.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-75.0f), ANGLE(-20.0f), 0), Vector3Shrt(ANGLE(75.0f), ANGLE(20.0f), 0) },
{ Vector3Shrt(ANGLE(-75.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(75.0f), ANGLE(80.0f), 0) },
ANGLE(10.0f),
@ -228,9 +228,9 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
// Rocket launcher
{
{ Vector3Shrt(ANGLE(-55.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(55.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-65.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-60.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(60.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
{ Vector3Shrt(ANGLE(-70.0f), ANGLE(-80.0f), 0), Vector3Shrt(ANGLE(65.0f), ANGLE(80.0f), 0) },
ANGLE(10.0f),
ANGLE(8.0f),
500,
@ -981,10 +981,10 @@ void LaraTargetInfo(ItemInfo* laraItem, WeaponInfo* weaponInfo)
if (LOS(&origin, &target))
{
if (angles.x >= weaponInfo->LockAngles[0].x &&
angles.y >= weaponInfo->LockAngles[0].y &&
angles.x <= weaponInfo->LockAngles[1].x &&
angles.y <= weaponInfo->LockAngles[1].y)
if (angles.x >= weaponInfo->LockOrientConstraint.first.x &&
angles.y >= weaponInfo->LockOrientConstraint.first.y &&
angles.x <= weaponInfo->LockOrientConstraint.second.x &&
angles.y <= weaponInfo->LockOrientConstraint.second.y)
{
lara->RightArm.Locked = true;
lara->LeftArm.Locked = true;
@ -993,10 +993,10 @@ void LaraTargetInfo(ItemInfo* laraItem, WeaponInfo* weaponInfo)
{
if (lara->LeftArm.Locked)
{
if (angles.x < weaponInfo->LeftAngles[0].x ||
angles.y < weaponInfo->LeftAngles[0].y ||
angles.x > weaponInfo->LeftAngles[1].x ||
angles.y > weaponInfo->LeftAngles[1].y)
if (angles.x < weaponInfo->LeftOrientConstraint.first.x ||
angles.y < weaponInfo->LeftOrientConstraint.first.y ||
angles.x > weaponInfo->LeftOrientConstraint.second.x ||
angles.y > weaponInfo->LeftOrientConstraint.second.y)
{
lara->LeftArm.Locked = false;
}
@ -1004,10 +1004,10 @@ void LaraTargetInfo(ItemInfo* laraItem, WeaponInfo* weaponInfo)
if (lara->RightArm.Locked)
{
if (angles.x < weaponInfo->RightAngles[0].x ||
angles.y < weaponInfo->RightAngles[0].y ||
angles.x > weaponInfo->RightAngles[1].x ||
angles.y > weaponInfo->RightAngles[1].y)
if (angles.x < weaponInfo->RightOrientConstraint.first.x ||
angles.y < weaponInfo->RightOrientConstraint.first.y ||
angles.x > weaponInfo->RightOrientConstraint.second.x ||
angles.y > weaponInfo->RightOrientConstraint.second.y)
{
lara->RightArm.Locked = false;
}
@ -1076,10 +1076,10 @@ void LaraGetNewTarget(ItemInfo* laraItem, WeaponInfo* weaponInfo)
angles.x -= laraItem->Pose.Orientation.x + lara->ExtraTorsoRot.x;
angles.y -= laraItem->Pose.Orientation.y + lara->ExtraTorsoRot.y;
if (angles.x >= weaponInfo->LockAngles[0].x &&
angles.y >= weaponInfo->LockAngles[0].y &&
angles.x <= weaponInfo->LockAngles[1].x &&
angles.y <= weaponInfo->LockAngles[1].y)
if (angles.x >= weaponInfo->LockOrientConstraint.first.x &&
angles.y >= weaponInfo->LockOrientConstraint.first.y &&
angles.x <= weaponInfo->LockOrientConstraint.second.x &&
angles.y <= weaponInfo->LockOrientConstraint.second.y)
{
TargetList[targets] = item;
++targets;

View file

@ -1,6 +1,8 @@
#pragma once
#include "Game/Lara/lara.h"
using std::pair;
struct CollisionInfo;
struct ItemInfo;
struct Vector3Shrt;
@ -16,9 +18,9 @@ enum class FireWeaponType
struct WeaponInfo
{
Vector3Shrt LockAngles[2];
Vector3Shrt LeftAngles[2];
Vector3Shrt RightAngles[2];
pair<Vector3Shrt, Vector3Shrt> LockOrientConstraint = {};
pair<Vector3Shrt, Vector3Shrt> LeftOrientConstraint = {};
pair<Vector3Shrt, Vector3Shrt> RightOrientConstraint = {};
int AimSpeed;
short ShotAccuracy;

View file

@ -639,6 +639,8 @@ void lara_col_jump_up(ItemInfo* item, CollisionInfo* coll)
if (TestLaraHangJumpUp(item, coll))
return;
LaraDeflectTopSide(item, coll);
if (coll->Middle.Ceiling >= 0 ||
coll->CollisionType == CT_TOP ||
coll->CollisionType == CT_TOP_FRONT ||

View file

@ -44,7 +44,7 @@ void AnimateShotgun(ItemInfo* laraItem, LaraWeaponType weaponType)
if (lara->LeftArm.GunSmoke > 0)
{
Vector3Int pos;
auto pos = Vector3Int::Zero;
if (weaponType == LaraWeaponType::HK)
pos = Vector3Int(0, 228, 96);
else if (weaponType == LaraWeaponType::Shotgun)
@ -263,8 +263,8 @@ void ReadyShotgun(ItemInfo* laraItem, LaraWeaponType weaponType)
auto* lara = GetLaraInfo(laraItem);
lara->Control.HandStatus = HandStatus::WeaponReady;
lara->LeftArm.Orientation = Vector3Shrt();
lara->RightArm.Orientation = Vector3Shrt();
lara->LeftArm.Orientation = Vector3Shrt::Zero;
lara->RightArm.Orientation = Vector3Shrt::Zero;
lara->LeftArm.FrameNumber = 0;
lara->RightArm.FrameNumber = 0;
lara->LeftArm.Locked = false;
@ -340,7 +340,7 @@ void DrawShotgun(ItemInfo* laraItem, LaraWeaponType weaponType)
{
auto* lara = GetLaraInfo(laraItem);
ItemInfo* item;
ItemInfo* item = nullptr;
if (lara->Control.Weapon.WeaponItem == NO_ITEM)
{
@ -446,8 +446,8 @@ void FireHarpoon(ItemInfo* laraItem)
{
auto* lara = GetLaraInfo(laraItem);
auto& ammos = GetAmmo(laraItem, LaraWeaponType::HarpoonGun);
if (!ammos)
auto& ammo = GetAmmo(laraItem, LaraWeaponType::HarpoonGun);
if (!ammo)
return;
lara->Control.Weapon.HasFired = true;
@ -456,8 +456,8 @@ void FireHarpoon(ItemInfo* laraItem)
short itemNumber = CreateItem();
if (itemNumber != NO_ITEM)
{
if (!ammos.HasInfinite())
(ammos)--;
if (!ammo.HasInfinite())
ammo--;
auto* item = &g_Level.Items[itemNumber];
@ -651,7 +651,7 @@ void FireGrenade(ItemInfo* laraItem)
int y = 0;
int z = 0;
Ammo& ammo = GetAmmo(laraItem, LaraWeaponType::GrenadeLauncher);
auto& ammo = GetAmmo(laraItem, LaraWeaponType::GrenadeLauncher);
if (!ammo)
return;
@ -718,7 +718,7 @@ void FireGrenade(ItemInfo* laraItem)
AddActiveItem(itemNumber);
if (!ammo.HasInfinite())
(ammo)--;
ammo--;
item->ItemFlags[0] = (int)lara->Weapons[(int)LaraWeaponType::GrenadeLauncher].SelectedAmmo;
@ -817,16 +817,16 @@ void GrenadeControl(short itemNumber)
{
aboveWater = false;
someFlag = false;
item->Animation.Velocity.y += (5.0f - item->Animation.Velocity.y) / 2.0f;
item->Animation.Velocity.z -= item->Animation.Velocity.z / 4.0f;
item->Animation.Velocity.y += (5.0f - item->Animation.Velocity.y) / 2;
item->Animation.Velocity.z -= item->Animation.Velocity.z / 4;
if (item->Animation.Velocity.z)
{
item->Pose.Orientation.z += (short((item->Animation.Velocity.z / 16.0f) + 3.0f) * ANGLE(1.0f));
item->Pose.Orientation.z += (short((item->Animation.Velocity.z / 16) + 3.0f) * ANGLE(1.0f));
if (item->Animation.RequiredState)
item->Pose.Orientation.y += (short((item->Animation.Velocity.z / 4.0f) + 3.0f) * ANGLE(1.0f));
item->Pose.Orientation.y += (short((item->Animation.Velocity.z / 4) + 3.0f) * ANGLE(1.0f));
else
item->Pose.Orientation.x += (short((item->Animation.Velocity.z / 4.0f) + 3.0f) * ANGLE(1.0f));
item->Pose.Orientation.x += (short((item->Animation.Velocity.z / 4) + 3.0f) * ANGLE(1.0f));
}
}
else
@ -837,11 +837,11 @@ void GrenadeControl(short itemNumber)
if (item->Animation.Velocity.z)
{
item->Pose.Orientation.z += (short((item->Animation.Velocity.z / 4.0f) + 7.0f) * ANGLE(1.0f));
item->Pose.Orientation.z += (short((item->Animation.Velocity.z / 4) + 7.0f) * ANGLE(1.0f));
if (item->Animation.RequiredState)
item->Pose.Orientation.y += (short((item->Animation.Velocity.z / 2.0f) + 7.0f) * ANGLE(1.0f));
item->Pose.Orientation.y += (short((item->Animation.Velocity.z / 2) + 7.0f) * ANGLE(1.0f));
else
item->Pose.Orientation.x += (short((item->Animation.Velocity.z / 2.0f) + 7.0f) * ANGLE(1.0f));
item->Pose.Orientation.x += (short((item->Animation.Velocity.z / 2) + 7.0f) * ANGLE(1.0f));
}
}
@ -1057,7 +1057,7 @@ void GrenadeControl(short itemNumber)
SoundEffect(SFX_TR4_EXPLOSION1, &item->Pose, SoundEnvironment::Land, 0.7f, 0.5f);
SoundEffect(SFX_TR4_EXPLOSION2, &item->Pose);
// Setup the counter for spawned grenades in the case of flash and super grenades ammos
// Setup the counter for spawned grenades in the case of flash and super grenades ammo
if (item->ItemFlags[0] != (int)GrenadeType::Normal && item->ItemFlags[0] != (int)GrenadeType::Ultra)
{
item->MeshBits = 0;
@ -1074,8 +1074,8 @@ void FireRocket(ItemInfo* laraItem)
{
auto* lara = GetLaraInfo(laraItem);
auto& ammos = GetAmmo(laraItem, LaraWeaponType::RocketLauncher);
if (!ammos)
auto& ammo = GetAmmo(laraItem, LaraWeaponType::RocketLauncher);
if (!ammo)
return;
lara->Control.Weapon.HasFired = true;
@ -1087,8 +1087,8 @@ void FireRocket(ItemInfo* laraItem)
item->ObjectNumber = ID_ROCKET;
item->RoomNumber = laraItem->RoomNumber;
if (!ammos.HasInfinite())
(ammos)--;
if (!ammo.HasInfinite())
ammo--;
auto jointPos = Vector3Int(0, 180, 72);
GetLaraJointPosition(&jointPos, LM_RHAND);
@ -1175,7 +1175,7 @@ void RocketControl(short itemNumber)
item->Color = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
// Calculate offset in rocket direction for fire and smoke sparks
Matrix world = Matrix::CreateFromYawPitchRoll(
auto world = Matrix::CreateFromYawPitchRoll(
TO_RAD(item->Pose.Orientation.y - ANGLE(180.0f)),
TO_RAD(item->Pose.Orientation.x),
TO_RAD(item->Pose.Orientation.z)
@ -1354,8 +1354,8 @@ void FireCrossbow(ItemInfo* laraItem, PHD_3DPOS* pos)
{
auto* lara = GetLaraInfo(laraItem);
auto& ammos = GetAmmo(laraItem, LaraWeaponType::Crossbow);
if (!ammos)
auto& ammo = GetAmmo(laraItem, LaraWeaponType::Crossbow);
if (!ammo)
return;
lara->Control.Weapon.HasFired = true;
@ -1367,8 +1367,8 @@ void FireCrossbow(ItemInfo* laraItem, PHD_3DPOS* pos)
item->ObjectNumber = ID_CROSSBOW_BOLT;
item->Color = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
if (!ammos.HasInfinite())
(ammos)--;
if (!ammo.HasInfinite())
ammo--;
if (pos)
{
@ -1422,7 +1422,7 @@ void FireCrossbow(ItemInfo* laraItem, PHD_3DPOS* pos)
}
}
void FireCrossBowFromLaserSight(ItemInfo* laraItem, GameVector* src, GameVector* target)
void FireCrossBowFromLaserSight(ItemInfo* laraItem, GameVector* origin, GameVector* target)
{
/* this part makes arrows fire at bad angles
target->x &= ~1023;
@ -1430,8 +1430,8 @@ void FireCrossBowFromLaserSight(ItemInfo* laraItem, GameVector* src, GameVector*
target->x |= 512;
target->z |= 512;*/
auto angles = GetVectorAngles(target->x - src->x, target->y - src->y, target->z - src->z);
auto boltPose = PHD_3DPOS(src->x, src->y, src->z, angles);
auto angles = GetVectorAngles(target->x - origin->x, target->y - origin->y, target->z - origin->z);
auto boltPose = PHD_3DPOS(origin->x, origin->y, origin->z, angles);
FireCrossbow(laraItem, &boltPose);
}
@ -1440,13 +1440,13 @@ void CrossbowBoltControl(short itemNumber)
auto* lara = GetLaraInfo(LaraItem);
auto* item = &g_Level.Items[itemNumber];
// Store old position for later
auto oldPos = item->Pose.Position;
// Store previous position for later.
auto prevPos = item->Pose.Position;
bool aboveWater = false;
bool explode = false;
// Update speed and check if above water
// Update speed and check if above water.
if (TestEnvironment(ENV_FLAG_WATER, item))
{
auto bubblePos = item->Pose.Position;
@ -1471,9 +1471,9 @@ void CrossbowBoltControl(short itemNumber)
probe.Position.Ceiling > item->Pose.Position.y)
{
// I have hit a solid wall, this is the end for the bolt
item->Pose.Position = oldPos;
item->Pose.Position = prevPos;
// If ammos are normal, then just shatter the bolt and quit
// If ammo is normal, simply shatter the bolt and exit.
if (item->ItemFlags[0] != (int)CrossbowBoltType::Explosive)
{
ExplodeItemNode(item, 0, 0, BODY_EXPLODE);
@ -1510,7 +1510,7 @@ void CrossbowBoltControl(short itemNumber)
foundCollidedObjects = true;
// If explosive ammos selected and item hit, then blast everything
// If explosive ammo selected and item hit, then blast everything
if (item->ItemFlags[0] == (int)CrossbowBoltType::Explosive)
explode = true;
@ -1541,7 +1541,7 @@ void CrossbowBoltControl(short itemNumber)
// Normal hit
HitTarget(LaraItem, currentItem, (GameVector*)& item->Pose, Weapons[(int)LaraWeaponType::Crossbow].Damage << item->ItemFlags[0], 0);
// Poisoned ammos
// Poisone ammo
if (item->ItemFlags[0] == (int)CrossbowBoltType::Poison)
{
if (currentItem->Data.is<CreatureInfo>())
@ -1624,10 +1624,10 @@ void CrossbowBoltControl(short itemNumber)
{
TriggerShockwave(&item->Pose, 48, 304, 96, 0, 96, 128, 24, 0, 0);
item->Pose.Position.y += 128;
TriggerExplosionSparks(oldPos.x, oldPos.y, oldPos.z, 3, -2, 0, item->RoomNumber);
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 0, item->RoomNumber);
for (int j = 0; j < 2; j++)
TriggerExplosionSparks(oldPos.x, oldPos.y, oldPos.z, 3, -1, 0, item->RoomNumber);
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -1, 0, item->RoomNumber);
}
AlertNearbyGuards(item);
@ -1702,7 +1702,7 @@ void RifleHandler(ItemInfo* laraItem, LaraWeaponType weaponType)
lara->ExtraTorsoRot.y = lara->LeftArm.Orientation.y;
if (Camera.oldType != CameraType::Look && !BinocularRange)
lara->ExtraHeadRot = { 0, 0, 0 };
lara->ExtraHeadRot = Vector3Shrt::Zero;
}
if (weaponType == LaraWeaponType::Revolver)
@ -1718,9 +1718,7 @@ void RifleHandler(ItemInfo* laraItem, LaraWeaponType weaponType)
pos.y = -64;
GetLaraJointPosition(&pos, LM_RHAND);
TriggerDynamicLight(
pos.x,
pos.y,
pos.z,
pos.x, pos.y, pos.z,
12,
(GetRandomControl() & 0x3F) + 192,
(GetRandomControl() & 0x1F) + 128,

View file

@ -57,7 +57,7 @@ void FireRocket(ItemInfo* laraItem);
void RocketControl(short itemNumber);
void FireCrossbow(ItemInfo* laraItem, PHD_3DPOS* pos);
void CrossbowBoltControl(short itemNumber);
void FireCrossBowFromLaserSight(ItemInfo* laraItem, GameVector* src, GameVector* target);
void FireCrossBowFromLaserSight(ItemInfo* laraItem, GameVector* origin, GameVector* target);
void FireHK(ItemInfo* laraItem, int mode);
void RifleHandler(ItemInfo* laraItem, LaraWeaponType weaponType);

View file

@ -22,6 +22,8 @@ void AnimateLara(ItemInfo* item)
{
auto* lara = GetLaraInfo(item);
PerformAnimCommands(item, true);
item->Animation.FrameNumber++;
auto* anim = &g_Level.Anims[item->Animation.AnimNumber];
@ -33,47 +35,7 @@ void AnimateLara(ItemInfo* item)
if (item->Animation.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, item->Pose.Orientation.y, cmd[2], cmd[1], cmd[0]);
UpdateItemRoom(item, -LARA_HEIGHT / 2, -cmd[0], -cmd[2]);
cmd += 3;
break;
case COMMAND_JUMP_VELOCITY:
item->Animation.Velocity.y = *(cmd++);
item->Animation.Velocity.z = *(cmd++);
item->Animation.IsAirborne = true;
if (lara->Control.CalculatedJumpVelocity)
{
item->Animation.Velocity.y = lara->Control.CalculatedJumpVelocity;
lara->Control.CalculatedJumpVelocity = 0;
}
break;
case COMMAND_ATTACK_READY:
if (lara->Control.HandStatus != HandStatus::Special)
lara->Control.HandStatus = HandStatus::Free;
break;
case COMMAND_SOUND_FX:
case COMMAND_EFFECT:
cmd += 2;
break;
default:
break;
}
}
}
PerformAnimCommands(item, false);
item->Animation.AnimNumber = anim->jumpAnimNum;
item->Animation.FrameNumber = anim->jumpFrameNum;
@ -82,70 +44,8 @@ void AnimateLara(ItemInfo* item)
item->Animation.ActiveState = anim->ActiveState;
}
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:
cmd += 3;
break;
case COMMAND_JUMP_VELOCITY:
cmd += 2;
break;
case COMMAND_SOUND_FX:
if (item->Animation.FrameNumber != *cmd)
{
cmd += 2;
break;
}
else
{
bool inWater = (cmd[1] & 0x8000) != 0;
bool inDry = (cmd[1] & 0x4000) != 0;
bool always = (inWater && inDry) || (!inWater && !inDry);
SoundEnvironment condition = SoundEnvironment::Always;
if (inWater) condition = SoundEnvironment::Water;
if (inDry) condition = SoundEnvironment::Land;
if (always) condition = SoundEnvironment::Always;
if (condition == SoundEnvironment::Always ||
(condition == SoundEnvironment::Land && (lara->WaterSurfaceDist >= -SHALLOW_WATER_START_LEVEL || lara->WaterSurfaceDist == NO_HEIGHT)) ||
(condition == SoundEnvironment::Water && lara->WaterSurfaceDist < -SHALLOW_WATER_START_LEVEL && lara->WaterSurfaceDist != NO_HEIGHT && !TestEnvironment(ENV_FLAG_SWAMP, item)))
{
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
}
cmd += 2;
break;
case COMMAND_EFFECT:
if (item->Animation.FrameNumber != *cmd)
{
cmd += 2;
break;
}
DoFlipEffect((cmd[1] & 0x3FFF), item);
cmd += 2;
break;
default:
break;
}
}
}
int frameCount = (anim->frameEnd - anim->frameBase) + 1;
int frameCount = anim->frameEnd - anim->frameBase;
frameCount = (frameCount > 0) ? frameCount : 1;
int currentFrame = item->Animation.FrameNumber - anim->frameBase;
if (item->Animation.IsAirborne)
@ -194,14 +94,142 @@ void AnimateLara(ItemInfo* item)
g_Renderer.UpdateLaraAnimations(true);
}
void PerformAnimCommands(ItemInfo* item, bool frameBased)
{
auto* anim = &g_Level.Anims[item->Animation.AnimNumber];
if (anim->numberCommands == 0)
return;
short* cmd = &g_Level.Commands[anim->commandIndex];
for (int i = anim->numberCommands; i > 0; i--)
{
auto animCommand = (AnimCommandType)cmd[0];
cmd++;
switch (animCommand)
{
case AnimCommandType::MoveOrigin:
if (!frameBased)
{
TranslateItem(item, item->Pose.Orientation.y, cmd[2], cmd[1], cmd[0]);
auto* bounds = GetBoundsAccurate(item);
UpdateItemRoom(item, -bounds->Height() / 2, -cmd[0], -cmd[2]);
}
cmd += 3;
break;
case AnimCommandType::JumpVelocity:
if (!frameBased)
{
item->Animation.Velocity.y = cmd[0];
item->Animation.Velocity.z = cmd[1];
item->Animation.IsAirborne = true;
if (item->IsLara())
{
auto* lara = GetLaraInfo(item);
if (lara->Control.CalculatedJumpVelocity)
{
item->Animation.Velocity.y = lara->Control.CalculatedJumpVelocity;
lara->Control.CalculatedJumpVelocity = 0;
}
}
}
cmd += 2;
break;
case AnimCommandType::Deactivate:
if (!frameBased)
{
if (Objects[item->ObjectNumber].intelligent && !item->AfterDeath)
item->AfterDeath = 1;
item->Status = ITEM_DEACTIVATED;
}
break;
case AnimCommandType::AttackReady:
if (!frameBased && item->IsLara())
{
auto* lara = GetLaraInfo(item);
if (lara->Control.HandStatus != HandStatus::Special)
lara->Control.HandStatus = HandStatus::Free;
}
break;
case AnimCommandType::SoundEffect:
if (frameBased && item->Animation.FrameNumber == cmd[0])
{
if (!Objects[item->ObjectNumber].waterCreature)
{
bool inWater = (cmd[1] & 0x8000) != 0;
bool inDry = (cmd[1] & 0x4000) != 0;
bool always = (inWater && inDry) || (!inWater && !inDry);
if (item->IsLara())
{
auto* lara = GetLaraInfo(item);
if (always ||
(inDry && (lara->WaterSurfaceDist >= -SHALLOW_WATER_START_LEVEL || lara->WaterSurfaceDist == NO_HEIGHT)) ||
(inWater && lara->WaterSurfaceDist < -SHALLOW_WATER_START_LEVEL && lara->WaterSurfaceDist != NO_HEIGHT && !TestEnvironment(ENV_FLAG_SWAMP, item)))
{
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
}
else
{
if (item->RoomNumber == NO_ROOM)
{
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
else if (TestEnvironment(ENV_FLAG_WATER, item))
{
if (always || (inWater && TestEnvironment(ENV_FLAG_WATER, Camera.pos.roomNumber)))
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
else if (always || (inDry && !TestEnvironment(ENV_FLAG_WATER, Camera.pos.roomNumber) && !TestEnvironment(ENV_FLAG_SWAMP, Camera.pos.roomNumber)))
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
}
else
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, TestEnvironment(ENV_FLAG_WATER, item) ? SoundEnvironment::Water : SoundEnvironment::Land);
}
cmd += 2;
break;
case AnimCommandType::Flipeffect:
if (frameBased && item->Animation.FrameNumber == cmd[0])
DoFlipEffect((cmd[1] & 0x3FFF), item);
cmd += 2;
break;
default:
break;
}
}
}
void AnimateItem(ItemInfo* item)
{
item->TouchBits = NO_JOINT_BITS;
item->HitStatus = false;
PerformAnimCommands(item, true);
item->Animation.FrameNumber++;
auto* anim = &g_Level.Anims[item->Animation.AnimNumber];
if (anim->numberChanges > 0 && GetChange(item, anim))
{
anim = &g_Level.Anims[item->Animation.AnimNumber];
@ -213,41 +241,7 @@ void AnimateItem(ItemInfo* item)
if (item->Animation.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, item->Pose.Orientation.y, cmd[2], cmd[1], cmd[0]);
cmd += 3;
break;
case COMMAND_JUMP_VELOCITY:
item->Animation.Velocity.y = *(cmd++);
item->Animation.Velocity.z = *(cmd++);
item->Animation.IsAirborne = 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;
}
}
}
PerformAnimCommands(item, false);
item->Animation.AnimNumber = anim->jumpAnimNum;
item->Animation.FrameNumber = anim->jumpFrameNum;
@ -263,77 +257,8 @@ void AnimateItem(ItemInfo* item)
item->Animation.RequiredState = 0;
}
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:
cmd += 3;
break;
case COMMAND_JUMP_VELOCITY:
cmd += 2;
break;
case COMMAND_SOUND_FX:
if (item->Animation.FrameNumber != *cmd)
{
cmd += 2;
break;
}
if (!Objects[item->ObjectNumber].waterCreature)
{
bool inWater = (cmd[1] & 0x8000) != 0;
bool inDry = (cmd[1] & 0x4000) != 0;
bool always = (inWater && inDry) || (!inWater && !inDry);
if (item->RoomNumber == NO_ROOM)
{
item->Pose.Position.x = LaraItem->Pose.Position.x;
item->Pose.Position.y = LaraItem->Pose.Position.y - 762;
item->Pose.Position.z = LaraItem->Pose.Position.z;
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
else if (TestEnvironment(ENV_FLAG_WATER, item))
{
if (always || (inWater && TestEnvironment(ENV_FLAG_WATER, Camera.pos.roomNumber)))
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
else if (always || (inDry && !TestEnvironment(ENV_FLAG_WATER, Camera.pos.roomNumber) && !TestEnvironment(ENV_FLAG_SWAMP, Camera.pos.roomNumber)))
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, SoundEnvironment::Always);
}
else
{
SoundEffect(cmd[1] & 0x3FFF, &item->Pose, TestEnvironment(ENV_FLAG_WATER, item) ? SoundEnvironment::Water : SoundEnvironment::Land);
}
break;
case COMMAND_EFFECT:
if (item->Animation.FrameNumber != *cmd)
{
cmd += 2;
break;
}
DoFlipEffect((cmd[1] & 0x3FFF), item);
cmd += 2;
break;
default:
break;
}
}
}
int frameCount = (anim->frameEnd - anim->frameBase) + 1;
int frameCount = anim->frameEnd - anim->frameBase;
frameCount = (frameCount > 0) ? frameCount : 1;
int currentFrame = item->Animation.FrameNumber - anim->frameBase;
if (item->Animation.IsAirborne)

View file

@ -50,15 +50,15 @@ struct ANIM_STRUCT
int commandIndex;
};
enum ANIMCOMMAND_TYPES
enum class AnimCommandType
{
COMMAND_NULL = 0,
COMMAND_MOVE_ORIGIN,
COMMAND_JUMP_VELOCITY,
COMMAND_ATTACK_READY,
COMMAND_DEACTIVATE,
COMMAND_SOUND_FX,
COMMAND_EFFECT
None = 0,
MoveOrigin,
JumpVelocity,
AttackReady,
Deactivate,
SoundEffect,
Flipeffect
};
struct BoneMutator

View file

@ -20,10 +20,13 @@ HAIR_STRUCT Hairs[HAIR_MAX][HAIR_SEGMENTS + 1];
void InitialiseHair()
{
bool youngLara = g_GameFlow->GetLevel(CurrentLevel)->GetLaraType() == LaraType::Young;
for (int h = 0; h < HAIR_MAX; h++)
{
int* bone = &g_Level.Bones[Objects[ID_HAIR].boneIndex];
Hairs[h][0].enabled = (h == 0 || youngLara);
Hairs[h][0].initialised = true;
Hairs[h][0].pos.Orientation.y = 0;
Hairs[h][0].pos.Orientation.x = -0x4000;

View file

@ -15,6 +15,7 @@ struct HAIR_STRUCT
Vector3Int unknown;
bool initialised = false;
bool enabled = false;
};
extern HAIR_STRUCT Hairs[HAIR_MAX][HAIR_SEGMENTS + 1];

View file

@ -1481,7 +1481,9 @@ namespace TEN::Gui
Ammo.AmountShotGunAmmo2 = -1;
else
Ammo.AmountShotGunAmmo2 = lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[1].GetCount() / 6;
Ammo.AmountShotGunAmmo1 = Lara.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : Lara.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
Ammo.AmountShotGunAmmo2 = Lara.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].HasInfinite() ? -1 : Lara.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
Ammo.AmountHKAmmo1 = lara->Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : lara->Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
Ammo.AmountCrossBowAmmo1 = lara->Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : lara->Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
Ammo.AmountCrossBowAmmo2 = lara->Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo2].HasInfinite() ? -1 : lara->Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
@ -2572,13 +2574,11 @@ namespace TEN::Gui
switch (InventoryObjectTable[Rings[ringIndex]->CurrentObjectList[n].InventoryItem].ObjectNumber)
{
case ID_SHOTGUN_AMMO1_ITEM:
count = lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
numMeUp = count == -1 ? count : count / 6;
numMeUp = lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
break;
case ID_SHOTGUN_AMMO2_ITEM:
count = lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
numMeUp = count == -1 ? count : count / 6;
nummeup = Lara.Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2].GetCount();
break;
case ID_HK_AMMO_ITEM:

View file

@ -636,15 +636,12 @@ int GlobalItemReplace(short search, GAME_OBJECT_ID replace)
// Offset values may be used to account for the quirk of room traversal only being able to occur at portals.
void UpdateItemRoom(ItemInfo* item, int height, int xOffset, int zOffset)
{
float sinY = phd_sin(item->Pose.Orientation.y);
float cosY = phd_cos(item->Pose.Orientation.y);
auto point = TranslateVector(item->Pose.Position, item->Pose.Orientation.y, zOffset, height, xOffset);
int x = (int)round(item->Pose.Position.x + ((cosY * xOffset) + (sinY * zOffset)));
int y = height + item->Pose.Position.y;
int z = (int)round(item->Pose.Position.z + ((-sinY * xOffset) + (cosY * zOffset)));
item->Location = GetRoom(item->Location, x, y, z);
item->Floor = GetFloorHeight(item->Location, x, z).value_or(NO_HEIGHT);
// Hacky L-shaped Location traversal.
item->Location = GetRoom(item->Location, point.x, point.y, point.z);
item->Location = GetRoom(item->Location, item->Pose.Position.x, point.y, item->Pose.Position.z);
item->Floor = GetFloorHeight(item->Location, item->Pose.Position.x, item->Pose.Position.z).value_or(NO_HEIGHT);
if (item->RoomNumber != item->Location.roomNumber)
ItemNewRoom(item->Index, item->Location.roomNumber);
@ -673,7 +670,7 @@ ItemInfo* FindItem(int objectNumber)
return item;
}
return 0;
return nullptr;
}
int FindItem(ItemInfo* item)

View file

@ -716,12 +716,12 @@ void RegeneratePickups()
for (int i = 0; i < NumRPickups; i++)
{
auto* item = &g_Level.Items[RPickups[i]];
auto& item = g_Level.Items[RPickups[i]];
if (item->Status == ITEM_INVISIBLE)
if (item.Status == ITEM_INVISIBLE)
{
short ammo = 0;
switch (item->ObjectNumber)
switch (item.ObjectNumber)
{
case ID_CROSSBOW_AMMO1_ITEM:
ammo = lara->Weapons[(int)LaraWeaponType::Crossbow].Ammo[(int)WeaponAmmoType::Ammo1];
@ -777,7 +777,7 @@ void RegeneratePickups()
}
if (ammo == 0)
item->Status = ITEM_NOT_ACTIVE;
item.Status = ITEM_NOT_ACTIVE;
}
}
}
@ -792,7 +792,7 @@ void PickupControl(short itemNumber)
switch (triggerFlags)
{
case 5:
item->Animation.Velocity.y += 6;
item->Animation.Velocity.y += 6.0f;
item->Pose.Position.y += item->Animation.Velocity.y;
roomNumber = item->RoomNumber;
@ -801,7 +801,7 @@ void PickupControl(short itemNumber)
if (item->Pose.Position.y > item->ItemFlags[0])
{
item->Pose.Position.y = item->ItemFlags[0];
if (item->Animation.Velocity.y <= 64)
if (item->Animation.Velocity.y <= 64.0f)
item->TriggerFlags &= 0xC0;
else
item->Animation.Velocity.y = -item->Animation.Velocity.y / 4;
@ -846,7 +846,9 @@ BOUNDING_BOX* FindPlinth(ItemInfo* item)
if (frame->X1 <= bbox->X2 && frame->X2 >= bbox->X1 &&
frame->Z1 <= bbox->Z2 && frame->Z2 >= bbox->Z1 &&
(bbox->X1 || bbox->X2))
{
return bbox;
}
}
if (room->itemNumber == NO_ITEM)

View file

@ -41,10 +41,10 @@ bool TryModifyingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int
if (-1 == arrayPos)
return false;
AmmoPickupInfo info = kAmmo[arrayPos];
auto ammoPickup = kAmmo[arrayPos];
auto& currentWeapon = lara.Weapons[(int)info.LaraWeaponType];
auto& currentAmmo = currentWeapon.Ammo[(int)info.AmmoType];
auto& currentWeapon = lara.Weapons[(int)ammoPickup.LaraWeaponType];
auto& currentAmmo = currentWeapon.Ammo[(int)ammoPickup.AmmoType];
switch(modType)
{
@ -56,10 +56,11 @@ bool TryModifyingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int
default:
if (!currentAmmo.HasInfinite())
{
int defaultModify = modType == ModificationType::Add ? info.Amount : -info.Amount;
int newVal = int{ currentAmmo.GetCount() } + (amount.has_value() ? amount.value() : defaultModify);
int defaultModify = modType == ModificationType::Add ? ammoPickup.Amount : -ammoPickup.Amount;
int newVal = (int)currentAmmo.GetCount() + (amount.has_value() ? amount.value() : defaultModify);
currentAmmo = std::max(0, newVal);
}
break;
};

View file

@ -55,42 +55,41 @@ bool TryModifyWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int>
if (-1 == arrayPos)
return false;
WeaponPickupInfo info = kWeapons[arrayPos];
auto weaponPickup = kWeapons[arrayPos];
// Set the SelectedAmmo type to WeaponAmmoType::Ammo1 (0) if adding the weapon for the first time.
// Note that this refers to the index of the weapon's ammo array, and not the weapon's actual ammunition count.
auto& currWeapon = lara.Weapons[(int)info.LaraWeaponType];
auto& currentWeapon = lara.Weapons[(int)weaponPickup.LaraWeaponType];
if (!currWeapon.Present)
currWeapon.SelectedAmmo = WeaponAmmoType::Ammo1;
if (!currentWeapon.Present)
currentWeapon.SelectedAmmo = WeaponAmmoType::Ammo1;
bool add = ModificationType::Add == type || ((ModificationType::Set == type) && count != 0);
currWeapon.Present = add;
currentWeapon.Present = add;
if(!add)
{
if (info.LaraWeaponType == lara.Control.Weapon.GunType || info.LaraWeaponType == lara.Control.Weapon.LastGunType)
if (weaponPickup.LaraWeaponType == lara.Control.Weapon.GunType ||
weaponPickup.LaraWeaponType == lara.Control.Weapon.LastGunType)
{
lara.Control.Weapon.RequestGunType = LaraWeaponType::None;
// If Lara has pistols and it's not the pistols we're removing, set them
// as the "next weapon" so that Lara equips them next.
if (LaraWeaponType::Pistol == info.LaraWeaponType || !lara.Weapons[(int)LaraWeaponType::Pistol].Present)
{
if (LaraWeaponType::Pistol == weaponPickup.LaraWeaponType || !lara.Weapons[(int)LaraWeaponType::Pistol].Present)
lara.Control.Weapon.LastGunType = LaraWeaponType::None;
}
else
{
lara.Control.Weapon.LastGunType = LaraWeaponType::Pistol;
}
}
if (HolsterType::Hips == info.Holster && lara.Control.Weapon.HolsterInfo.LeftHolster == HolsterSlotForWeapon(info.LaraWeaponType))
if (HolsterType::Hips == weaponPickup.Holster &&
lara.Control.Weapon.HolsterInfo.LeftHolster == HolsterSlotForWeapon(weaponPickup.LaraWeaponType))
{
lara.Control.Weapon.HolsterInfo.LeftHolster = HolsterSlot::Empty;
lara.Control.Weapon.HolsterInfo.RightHolster = HolsterSlot::Empty;
}
else if (HolsterType::Back == info.Holster && lara.Control.Weapon.HolsterInfo.BackHolster == HolsterSlotForWeapon(info.LaraWeaponType))
else if (HolsterType::Back == weaponPickup.Holster &&
lara.Control.Weapon.HolsterInfo.BackHolster == HolsterSlotForWeapon(weaponPickup.LaraWeaponType))
{
lara.Control.Weapon.HolsterInfo.BackHolster = HolsterSlot::Empty;
}
@ -99,7 +98,7 @@ bool TryModifyWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int>
return true;
}
// Adding a weapon will not give the player any ammo even if they already have the weapon
// Adding a weapon will not give the player any ammo even if they already have the weapon.
bool TryAddingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID)
{
return TryModifyWeapon(lara, objectID, 1, ModificationType::Add);
@ -117,6 +116,6 @@ std::optional<bool> HasWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID)
if (-1 == arrPos)
return std::nullopt;
WeaponPickupInfo info = kWeapons[arrPos];
return lara.Weapons[(int)info.LaraWeaponType].Present;
auto weaponPickup = kWeapons[arrPos];
return lara.Weapons[(int)weaponPickup.LaraWeaponType].Present;
}

View file

@ -138,15 +138,15 @@ namespace TEN::Entities::Switches
break;
}
if (switchItem->Animation.ActiveState == SWITCH_ON) /* Switch down */
if (switchItem->Animation.ActiveState == SWITCH_OFF) /* Switch down */
{
SetAnimation(laraItem, offAnim);
switchItem->Animation.TargetState = SWITCH_OFF;
switchItem->Animation.TargetState = SWITCH_ON;
}
else /* Switch up */
{
SetAnimation(laraItem, onAnim);
switchItem->Animation.TargetState = SWITCH_ON;
switchItem->Animation.TargetState = SWITCH_OFF;
}
ResetLaraFlex(laraItem);

View file

@ -42,21 +42,22 @@ namespace TEN::Entities::Creatures::TR3
// TODO
enum CivvyState
{
CIVVY_STATE_IDLE,
CIVVY_STATE_WALK_FORWARD,
CIVVY_PUNCH2,
CIVVY_AIM2,
CIVVY_WAIT,
CIVVY_AIM1,
CIVVY_AIM0,
CIVVY_PUNCH1,
CIVVY_PUNCH0,
CIVVY_STATE_RUN_FORWARD,
CIVVY_DEATH,
CIVVY_CLIMB3,
CIVVY_CLIMB1,
CIVVY_CLIMB2,
CIVVY_FALL3
// No state 0.
CIVVY_STATE_IDLE = 1,
CIVVY_STATE_WALK_FORWARD = 2,
CIVVY_PUNCH2 = 3,
CIVVY_AIM2 = 4,
CIVVY_WAIT = 5,
CIVVY_AIM1 = 6,
CIVVY_AIM0 = 7,
CIVVY_PUNCH1 = 8,
CIVVY_PUNCH0 = 9,
CIVVY_STATE_RUN_FORWARD = 10,
CIVVY_DEATH = 11,
CIVVY_CLIMB3 = 12,
CIVVY_CLIMB1 = 13,
CIVVY_CLIMB2 = 14,
CIVVY_FALL3 = 15
};
// TODO

View file

@ -26,22 +26,23 @@ namespace TEN::Entities::Creatures::TR3
enum MPStickState
{
MPSTICK_STATE_STOP,
MPSTICK_STATE_WALK,
MPSTICK_STATE_PUNCH2,
MPSTICK_STATE_AIM2,
MPSTICK_STATE_WAIT,
MPSTICK_STATE_AIM1,
MPSTICK_STATE_AIM0,
MPSTICK_STATE_PUNCH1,
MPSTICK_STATE_PUNCH0,
MPSTICK_STATE_RUN,
MPSTICK_STATE_DEATH,
MPSTICK_STATE_KICK,
MPSTICK_STATE_CLIMB3,
MPSTICK_STATE_CLIMB1,
MPSTICK_STATE_CLIMB2,
MPSTICK_STATE_FALL3
// No state 0.
MPSTICK_STATE_STOP = 1,
MPSTICK_STATE_WALK = 2,
MPSTICK_STATE_PUNCH2 = 3,
MPSTICK_STATE_AIM2 = 4,
MPSTICK_STATE_WAIT = 5,
MPSTICK_STATE_AIM1 = 6,
MPSTICK_STATE_AIM0 = 7,
MPSTICK_STATE_PUNCH1 = 8,
MPSTICK_STATE_PUNCH0 = 9,
MPSTICK_STATE_RUN = 10,
MPSTICK_STATE_DEATH = 11,
MPSTICK_STATE_KICK = 12,
MPSTICK_STATE_CLIMB3 = 13,
MPSTICK_STATE_CLIMB1 = 14,
MPSTICK_STATE_CLIMB2 = 15,
MPSTICK_STATE_FALL3 = 16,
};
// TODO

View file

@ -25,19 +25,19 @@ namespace TEN::Entities::Creatures::TR3
enum SophiaState
{
LONDONBOSS_EMPTY,
LONDONBOSS_STAND,
LONDONBOSS_WALK,
LONDONBOSS_RUN,
LONDONBOSS_SUMMON,
LONDONBOSS_BIGZAP,
LONDONBOSS_DEATH,
LONDONBOSS_LAUGH,
LONDONBOSS_LILZAP,
LONDONBOSS_VAULT2,
LONDONBOSS_VAULT3,
LONDONBOSS_VAULT4,
LONDONBOSS_GODOWN
LONDONBOSS_EMPTY = 0,
LONDONBOSS_STAND = 1,
LONDONBOSS_WALK = 2,
LONDONBOSS_RUN = 3,
LONDONBOSS_SUMMON = 4,
LONDONBOSS_BIGZAP = 5,
LONDONBOSS_DEATH = 6,
LONDONBOSS_LAUGH = 7,
LONDONBOSS_LILZAP = 8,
LONDONBOSS_VAULT2 = 9,
LONDONBOSS_VAULT3 = 10,
LONDONBOSS_VAULT4 = 11,
LONDONBOSS_GODOWN = 12,
};
// TODO

View file

@ -319,28 +319,34 @@ void TEN::Renderer::Renderer11::DrawLara(RenderView& view, bool transparent)
{
RendererObject& hairsObj = *m_moveableObjects[ID_HAIR];
// First matrix is Lara's head matrix, then all 6 hairs matrices. Bones are adjusted at load time for accounting this.
m_stItem.World = Matrix::Identity;
m_stItem.BonesMatrices[0] = laraObj.AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
for (int i = 0; i < hairsObj.BindPoseTransforms.size(); i++)
for (int h = 0; h < HAIR_MAX; h++)
{
auto* hairs = &Hairs[0][i];
Matrix world = Matrix::CreateFromYawPitchRoll(TO_RAD(hairs->pos.Orientation.y), TO_RAD(hairs->pos.Orientation.x), 0) *
Matrix::CreateTranslation(hairs->pos.Position.x, hairs->pos.Position.y, hairs->pos.Position.z);
m_stItem.BonesMatrices[i + 1] = world;
m_stItem.BoneLightModes[i] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
if (!Hairs[h][0].enabled)
continue;
// First matrix is Lara's head matrix, then all 6 hairs matrices. Bones are adjusted at load time for accounting this.
m_stItem.World = Matrix::Identity;
m_stItem.BonesMatrices[0] = laraObj.AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
for (int i = 0; i < hairsObj.BindPoseTransforms.size(); i++)
{
auto* hairs = &Hairs[h][i];
Matrix world = Matrix::CreateFromYawPitchRoll(TO_RAD(hairs->pos.Orientation.y), TO_RAD(hairs->pos.Orientation.x), 0) *
Matrix::CreateTranslation(hairs->pos.Position.x, hairs->pos.Position.y, hairs->pos.Position.z);
m_stItem.BonesMatrices[i + 1] = world;
m_stItem.BoneLightModes[i] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
}
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
for (int k = 0; k < hairsObj.ObjectMeshes.size(); k++)
{
RendererMesh* mesh = hairsObj.ObjectMeshes[k];
DrawMoveableMesh(item, mesh, room, k, transparent);
}
}
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
for (int k = 0; k < hairsObj.ObjectMeshes.size(); k++)
{
RendererMesh* mesh = hairsObj.ObjectMeshes[k];
DrawMoveableMesh(item, mesh, room, k, transparent);
}
}
}

View file

@ -37,6 +37,7 @@ public:
virtual void OnControlPhase(float dt) = 0;
virtual void OnSave() = 0;
virtual void OnEnd() = 0;
virtual void ShortenTENCalls() = 0;
virtual void FreeLevelScripts() = 0;
virtual void ResetScripts(bool clearGameVars) = 0;

View file

@ -257,6 +257,7 @@ int FlowHandler::GetLevelNumber(std::string const& fileName)
return i;
}
TENLog("Specified level filename was not found in script. Level won't be loaded. Please edit level filename in gameflow.lua.");
return -1;
}
@ -310,7 +311,7 @@ bool FlowHandler::DoFlow()
{
// We start with the title level, if no other index is specified
if (CurrentLevel == -1)
CurrentLevel = 0;
CurrentLevel = SystemNameHash = 0;
SelectedLevelForNewGame = 0;
SelectedSaveGame = 0;

View file

@ -602,15 +602,14 @@ void LogicHandler::ShortenTENCalls()
ShortenInner(TEN))";
ExecuteString(str);
m_shortenedCalls = true;
}
void LogicHandler::ExecuteScriptFile(const std::string & luaFilename)
{
if (!m_shortenedCalls)
{
ShortenTENCalls();
m_shortenedCalls = true;
}
m_handler.ExecuteScript(luaFilename);
}

View file

@ -78,7 +78,7 @@ public:
void RemoveCallback(CallbackPoint point, LevelFunc const & lf);
void ResetScripts(bool clearGameVars) override;
void ShortenTENCalls();
void ShortenTENCalls() override;
sol::object GetLevelFuncsMember(sol::table tab, std::string const& luaName);

View file

@ -283,7 +283,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
{
g_GameFlow = ScriptInterfaceState::CreateFlow();
g_GameScriptEntities = ScriptInterfaceState::CreateObjectsHandler();
g_GameFlow->LoadFlowScript();
g_GameStringsHandler = ScriptInterfaceState::CreateStringsHandler();
// This must be loaded last as it adds metafunctions to the global
@ -293,6 +292,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// are added to a hierarchy in the REAL global table, not the fake
// hidden one.
g_GameScript = ScriptInterfaceState::CreateGame();
//todo Major hack. This should not be needed to leak outside of
//LogicHandler internals. In a future version stuff from FlowHandler
//should be moved to LogicHandler or vice versa to make this stuff
//less fragile (squidshire, 16/09/22)
g_GameScript->ShortenTENCalls();
g_GameFlow->LoadFlowScript();
}
catch (TENScriptException const& e)
{