mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
Merge branch 'develop' into develop_60fps
# Conflicts: # TombEngine/Game/control/control.cpp
This commit is contained in:
commit
b03480e926
30 changed files with 575 additions and 427 deletions
|
@ -1,3 +1,13 @@
|
|||
Version 1.5
|
||||
===========
|
||||
|
||||
* Fixed original issue with classic switch off trigger wrongly activating some trigger actions.
|
||||
* Fixed incorrect diving animation when swandiving from a high place.
|
||||
* Fixed AI for skidoo driver and worker with shotgun TR2 enemies.
|
||||
|
||||
Lua API changes:
|
||||
* Added Inventory.GetUsedItem(), Inventory.SetUsedItem() and Inventory.ClearUsedItem() functions.
|
||||
|
||||
Version 1.4
|
||||
===========
|
||||
|
||||
|
@ -15,8 +25,10 @@ Version 1.4
|
|||
* Fixed occasional collision warnings in a log when teeth spikes object was activated.
|
||||
* Fixed climbable pushables collision during continuous pulling action.
|
||||
* Fixed collision for solid static meshes with zero collision box.
|
||||
* Fixed bottom collision for solid static meshes.
|
||||
* Fixed T-Rex's head rotation.
|
||||
* Auto-switch to a crawl state if player start position is in a crawlspace.
|
||||
* Allow directional flame emitter (negative OCBs) to be rotated at any angle.
|
||||
* Revise wall spikes:
|
||||
- Wall spikes now stop when they touch a pushable, another spike wall or a normal wall.
|
||||
- Wall spikes will shatter any shatter in its path.
|
||||
|
|
|
@ -126,6 +126,18 @@
|
|||
<td class="name" ><a href="#SetItemCount">SetItemCount(objectID, count)</a></td>
|
||||
<td class="summary">Set the amount of an item in the player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetUsedItem">GetUsedItem()</a></td>
|
||||
<td class="summary">Get last item used in the player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#SetUsedItem">SetUsedItem(objectID)</a></td>
|
||||
<td class="summary">Set last item used in the player's inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#ClearUsedItem">ClearUsedItem()</a></td>
|
||||
<td class="summary">Clear last item used in the player's inventory.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
@ -247,6 +259,70 @@
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "GetUsedItem"></a>
|
||||
<strong>GetUsedItem()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get last item used in the player's inventory.
|
||||
This value will be valid only for a single frame after exiting inventory, after which Lara says "No".
|
||||
Therefore, this function must be preferably used either in OnLoop or OnUseItem events.
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
|
||||
Last item used in the inventory.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "SetUsedItem"></a>
|
||||
<strong>SetUsedItem(objectID)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set last item used in the player's inventory.
|
||||
You will be able to specify only objects which already exist in the inventory.
|
||||
Will only be valid for the next frame. If not processed by the game, Lara will say "No".
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">objectID</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
|
||||
Object ID of the item to select from inventory.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "ClearUsedItem"></a>
|
||||
<strong>ClearUsedItem()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Clear last item used in the player's inventory.
|
||||
When this function is used in OnUseItem level function, it allows to override existing item functionality.
|
||||
For items without existing functionality, this function is needed to avoid Lara saying "No" after using it.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
|
|
@ -265,7 +265,8 @@ LOAD
|
|||
SAVE
|
||||
START
|
||||
END
|
||||
LOOP</pre>
|
||||
LOOP
|
||||
USEITEM</pre>
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace TEN::Entities::Player
|
|||
}
|
||||
|
||||
// 3) Check for death floor (if applicable).
|
||||
if (setup.TestDeathFloor && pointColl.Block->Flags.Death)
|
||||
if (setup.TestDeathFloor && pointColl.Block->Flags.Death && pointColl.Position.Bridge == NO_VALUE)
|
||||
return false;
|
||||
|
||||
// LOS setup at upper floor bound.
|
||||
|
|
|
@ -153,7 +153,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
else if (item->Animation.ActiveState == LS_FREEFALL_DIVE)
|
||||
{
|
||||
SetAnimation(item, LA_SWANDIVE_DIVE);
|
||||
SetAnimation(item, LA_SWANDIVE_FREEFALL_DIVE);
|
||||
item->Animation.Velocity.y /= 2;
|
||||
item->Pose.Orientation.x = ANGLE(-85.0f);
|
||||
player.Control.HandStatus = HandStatus::Free;
|
||||
|
@ -642,12 +642,6 @@ void UpdateLara(ItemInfo* item, bool isTitle)
|
|||
if (isTitle)
|
||||
ActionMap = actionMap;
|
||||
|
||||
if (g_Gui.GetInventoryItemChosen() != NO_VALUE)
|
||||
{
|
||||
g_Gui.SetInventoryItemChosen(NO_VALUE);
|
||||
SayNo();
|
||||
}
|
||||
|
||||
// Update player animations.
|
||||
g_Renderer.UpdateLaraAnimations(true);
|
||||
|
||||
|
|
|
@ -276,49 +276,6 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa
|
|||
}
|
||||
}
|
||||
|
||||
static void UsePlayerMedipack(ItemInfo& item)
|
||||
{
|
||||
auto& player = GetLaraInfo(item);
|
||||
|
||||
// Can't use medipack; return early.
|
||||
if (item.HitPoints <= 0 ||
|
||||
(item.HitPoints >= LARA_HEALTH_MAX && player.Status.Poison == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasUsedMedipack = false;
|
||||
|
||||
if (IsClicked(In::SmallMedipack) &&
|
||||
player.Inventory.TotalSmallMedipacks != 0)
|
||||
{
|
||||
hasUsedMedipack = true;
|
||||
|
||||
item.HitPoints += LARA_HEALTH_MAX / 2;
|
||||
if (item.HitPoints > LARA_HEALTH_MAX)
|
||||
item.HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
if (player.Inventory.TotalSmallMedipacks != -1)
|
||||
player.Inventory.TotalSmallMedipacks--;
|
||||
}
|
||||
else if (IsClicked(In::LargeMedipack) &&
|
||||
player.Inventory.TotalLargeMedipacks != 0)
|
||||
{
|
||||
hasUsedMedipack = true;
|
||||
item.HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
if (player.Inventory.TotalLargeMedipacks != -1)
|
||||
player.Inventory.TotalLargeMedipacks--;
|
||||
}
|
||||
|
||||
if (hasUsedMedipack)
|
||||
{
|
||||
player.Status.Poison = 0;
|
||||
SaveGame::Statistics.Game.HealthUsed++;
|
||||
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<LaraWeaponType> GetPlayerScrolledWeaponType(const ItemInfo& item, LaraWeaponType currentWeaponType, bool getPrev)
|
||||
{
|
||||
static const auto SCROLL_WEAPON_TYPES = std::vector<LaraWeaponType>
|
||||
|
@ -376,8 +333,14 @@ void HandlePlayerQuickActions(ItemInfo& item)
|
|||
auto& player = GetLaraInfo(item);
|
||||
|
||||
// Handle medipacks.
|
||||
if (IsClicked(In::SmallMedipack) || IsClicked(In::LargeMedipack))
|
||||
UsePlayerMedipack(item);
|
||||
if (IsClicked(In::SmallMedipack))
|
||||
{
|
||||
g_Gui.UseItem(item, GAME_OBJECT_ID::ID_SMALLMEDI_ITEM);
|
||||
}
|
||||
else if (IsClicked(In::LargeMedipack))
|
||||
{
|
||||
g_Gui.UseItem(item, GAME_OBJECT_ID::ID_BIGMEDI_ITEM);
|
||||
}
|
||||
|
||||
// Handle weapon scroll request.
|
||||
if (IsClicked(In::PreviousWeapon) || IsClicked(In::NextWeapon))
|
||||
|
@ -419,7 +382,7 @@ void HandlePlayerQuickActions(ItemInfo& item)
|
|||
|
||||
// TODO: 10th possible weapon, probably grapple gun.
|
||||
/*if (IsClicked(In::Weapon10) && player.Weapons[(int)LaraWeaponType::].Present)
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::;*/
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::;*/
|
||||
}
|
||||
|
||||
bool CanPlayerLookAround(const ItemInfo& item)
|
||||
|
|
|
@ -1010,10 +1010,6 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
auto collBounds = collBox.ToBoundingOrientedBox(Pose(item->Pose.Position));
|
||||
bool intersects = staticBounds.Intersects(collBounds);
|
||||
|
||||
// Check if previous item horizontal position intersects bounds.
|
||||
auto prevCollBounds = collBox.ToBoundingOrientedBox(Pose(coll->Setup.PrevPosition));
|
||||
bool prevHorIntersects = staticBounds.Intersects(prevCollBounds);
|
||||
|
||||
// Draw item coll bounds.
|
||||
g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
|
||||
|
||||
|
@ -1072,7 +1068,7 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
|
|||
auto distanceToVerticalPlane = height / 2 - yPoint;
|
||||
|
||||
// Correct position according to top/bottom bounds, if collided and plane is nearby.
|
||||
if (intersects && prevHorIntersects && minDistance < height)
|
||||
if (intersects && minDistance < height)
|
||||
{
|
||||
if (bottom)
|
||||
{
|
||||
|
|
|
@ -214,6 +214,14 @@ GameStatus ControlPhase(int numFrames)
|
|||
// Smash shatters and clear stopper flags under them.
|
||||
UpdateShatters();
|
||||
|
||||
// Clear last selected item in inventory (need to be after on loop event handling, so they can detect that).
|
||||
g_Gui.CancelInventorySelection();
|
||||
|
||||
// Control lock is processed after handling scripts, because builder may want to
|
||||
// process input externally, while still locking Lara from input.
|
||||
if (!isTitle && Lara.Control.IsLocked)
|
||||
ClearAllActions();
|
||||
|
||||
// Update weather.
|
||||
Weather.Update();
|
||||
|
||||
|
@ -252,7 +260,7 @@ GameStatus ControlPhase(int numFrames)
|
|||
g_GameFlow->GetLevel(CurrentLevel)->GetLensFlareSpriteID()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Update HUD.
|
||||
g_Hud.Update(*LaraItem);
|
||||
UpdateFadeScreenAndCinematicBars();
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace TEN::Control::Volumes
|
|||
Save,
|
||||
Start,
|
||||
End,
|
||||
UseItem,
|
||||
|
||||
Count
|
||||
};
|
||||
|
|
|
@ -114,7 +114,7 @@ int GetSwitchTrigger(ItemInfo* item, short* itemNumbersPtr, int attatchedToSwitc
|
|||
return k;
|
||||
}
|
||||
|
||||
int SwitchTrigger(short itemNumber, short timer)
|
||||
bool SwitchTrigger(short itemNumber, short timer)
|
||||
{
|
||||
auto& item = g_Level.Items[itemNumber];
|
||||
const auto& player = Lara;
|
||||
|
@ -127,7 +127,7 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
item.Status = ITEM_ACTIVE;
|
||||
item.ItemFlags[1] = false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.ObjectNumber >= ID_PUZZLE_HOLE1 && item.ObjectNumber <= ID_PUZZLE_HOLE16 &&
|
||||
|
@ -137,13 +137,13 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
item.Status = ITEM_DEACTIVATED;
|
||||
item.ItemFlags[1] = false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((item.ObjectNumber >= ID_PUZZLE_DONE1 && item.ObjectNumber <= ID_PUZZLE_DONE16) ||
|
||||
(item.ObjectNumber >= ID_PUZZLE_HOLE1 && item.ObjectNumber <= ID_PUZZLE_HOLE16))
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle reusable receptacles.
|
||||
|
@ -156,7 +156,7 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
item.Status = ITEM_ACTIVE;
|
||||
item.ItemFlags[5] = (int)ReusableReceptacleState::Done;
|
||||
item.ItemFlags[1] = false;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.ObjectNumber >= ID_KEY_HOLE1 && item.ObjectNumber <= ID_KEY_HOLE16 &&
|
||||
|
@ -167,11 +167,11 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
item.Status = ITEM_DEACTIVATED;
|
||||
item.ItemFlags[5] = (int)ReusableReceptacleState::Empty;
|
||||
item.ItemFlags[1] = false;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.ObjectNumber >= ID_KEY_HOLE1 && item.ObjectNumber <= ID_KEY_HOLE16)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
// Handle switches.
|
||||
if (item.Status == ITEM_DEACTIVATED)
|
||||
|
@ -186,7 +186,7 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
if (timer != 1)
|
||||
item.Timer = FPS * timer;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.TriggerFlags >= 0 || item.Animation.ActiveState != SWITCH_OFF)
|
||||
|
@ -197,12 +197,12 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
if (!item.ItemFlags[0] == 0)
|
||||
item.Flags |= ONESHOT;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Status = ITEM_ACTIVE;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (item.Status != ITEM_NOT_ACTIVE)
|
||||
|
@ -211,13 +211,14 @@ int SwitchTrigger(short itemNumber, short timer)
|
|||
item.Animation.AnimNumber == GetAnimIndex(item, 2) &&
|
||||
item.Animation.FrameNumber == GetFrameIndex(&item, 0))
|
||||
{
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return ((item.Flags & ONESHOT) >> 8);
|
||||
if (item.Flags & ONESHOT)
|
||||
return true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int KeyTrigger(short itemNumber)
|
||||
|
@ -398,15 +399,11 @@ void Trigger(short const value, short const flags)
|
|||
|
||||
void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bool heavy, int heavyFlags)
|
||||
{
|
||||
int flip = -1;
|
||||
int flipAvailable = 0;
|
||||
int newEffect = -1;
|
||||
int switchOff = 0;
|
||||
//int switchFlag = 0;
|
||||
short objectNumber = 0;
|
||||
bool switchOff = false;
|
||||
bool flipAvailable = false;
|
||||
int flip = NO_VALUE;
|
||||
int newEffect = NO_VALUE;
|
||||
int keyResult = 0;
|
||||
short cameraFlags = 0;
|
||||
short cameraTimer = 0;
|
||||
int spotCamIndex = 0;
|
||||
|
||||
auto data = GetTriggerIndex(floor, x, y, z);
|
||||
|
@ -466,13 +463,7 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
if (!SwitchTrigger(value, timer))
|
||||
return;
|
||||
|
||||
objectNumber = g_Level.Items[value].ObjectNumber;
|
||||
//This disables the antitrigger of the Valve switch (ocb 5). I don't know the purpose of this in TR4.
|
||||
//if (objectNumber >= ID_SWITCH_TYPE1 && objectNumber <= ID_SWITCH_TYPE6 && g_Level.Items[value].TriggerFlags == 5)
|
||||
//switchFlag = 1;
|
||||
|
||||
switchOff = (g_Level.Items[value].Animation.ActiveState == 1);
|
||||
|
||||
switchOff = (triggerType == TRIGGER_TYPES::SWITCH && timer && g_Level.Items[value].Animation.ActiveState == 1);
|
||||
break;
|
||||
|
||||
case TRIGGER_TYPES::MONKEY:
|
||||
|
@ -571,8 +562,8 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
|
||||
if (keyResult >= 2 ||
|
||||
(triggerType == TRIGGER_TYPES::ANTIPAD ||
|
||||
triggerType == TRIGGER_TYPES::ANTITRIGGER ||
|
||||
triggerType == TRIGGER_TYPES::HEAVYANTITRIGGER) &&
|
||||
triggerType == TRIGGER_TYPES::ANTITRIGGER ||
|
||||
triggerType == TRIGGER_TYPES::HEAVYANTITRIGGER) &&
|
||||
item->Flags & ATONESHOT)
|
||||
break;
|
||||
|
||||
|
@ -656,7 +647,7 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
if (triggerType == TRIGGER_TYPES::COMBAT)
|
||||
break;
|
||||
|
||||
if (triggerType == TRIGGER_TYPES::SWITCH && timer && switchOff)
|
||||
if (switchOff)
|
||||
break;
|
||||
|
||||
if (Camera.number != Camera.last || triggerType == TRIGGER_TYPES::SWITCH)
|
||||
|
@ -674,6 +665,9 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
if (keyResult == 1)
|
||||
break;
|
||||
|
||||
if (switchOff)
|
||||
break;
|
||||
|
||||
if (triggerType == TRIGGER_TYPES::ANTIPAD ||
|
||||
triggerType == TRIGGER_TYPES::ANTITRIGGER ||
|
||||
triggerType == TRIGGER_TYPES::HEAVYANTITRIGGER)
|
||||
|
@ -748,17 +742,26 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
break;
|
||||
|
||||
case TO_FLIPEFFECT:
|
||||
if (switchOff)
|
||||
break;
|
||||
|
||||
TriggerTimer = timer;
|
||||
newEffect = value;
|
||||
break;
|
||||
|
||||
case TO_FINISH:
|
||||
if (switchOff)
|
||||
break;
|
||||
|
||||
NextLevel = value ? value : (CurrentLevel + 1);
|
||||
RequiredStartPos = timer;
|
||||
break;
|
||||
|
||||
case TO_CD:
|
||||
PlaySoundTrack(value, flags);
|
||||
if (switchOff)
|
||||
break;
|
||||
|
||||
PlaySoundTrack(value, flags & CODE_BITS);
|
||||
break;
|
||||
|
||||
case TO_CUTSCENE:
|
||||
|
@ -766,6 +769,9 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
break;
|
||||
|
||||
case TO_SECRET:
|
||||
if (switchOff)
|
||||
break;
|
||||
|
||||
if (!(SaveGame::Statistics.Level.Secrets & (1 << value)))
|
||||
{
|
||||
PlaySecretTrack();
|
||||
|
@ -777,6 +783,8 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
case TO_VOLUMEEVENT:
|
||||
case TO_GLOBALEVENT:
|
||||
trigger = *(data++);
|
||||
|
||||
if (!switchOff)
|
||||
{
|
||||
auto& list = targetType == TO_VOLUMEEVENT ? g_Level.VolumeEventSets : g_Level.GlobalEventSets;
|
||||
|
||||
|
@ -815,10 +823,10 @@ void TestTriggers(int x, int y, int z, FloorInfo* floor, Activator activator, bo
|
|||
if (cameraItem && (Camera.type == CameraType::Fixed || Camera.type == CameraType::Heavy))
|
||||
Camera.item = cameraItem;
|
||||
|
||||
if (flip != -1)
|
||||
if (flip != NO_VALUE)
|
||||
DoFlipMap(flip);
|
||||
|
||||
if (newEffect != -1 && (flip || !flipAvailable))
|
||||
if (newEffect != NO_VALUE && (flip || !flipAvailable))
|
||||
FlipEffect = newEffect;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ extern int KeyTriggerActive;
|
|||
|
||||
bool GetKeyTrigger(ItemInfo* item);
|
||||
int GetSwitchTrigger(ItemInfo* item, short* itemNumbersPtr, int attatchedToSwitch);
|
||||
int SwitchTrigger(short itemNumber, short timer);
|
||||
bool SwitchTrigger(short itemNumber, short timer);
|
||||
int KeyTrigger(short itemNumber);
|
||||
bool PickupTrigger(short itemNumber);
|
||||
void RefreshCamera(short type, short* data);
|
||||
|
|
|
@ -89,14 +89,16 @@ namespace TEN::Control::Volumes
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void HandleEvent(Event& event, Activator& activator)
|
||||
bool HandleEvent(Event& event, Activator& activator)
|
||||
{
|
||||
if (event.Function.empty() || event.CallCounter == 0 || event.CallCounter < NO_CALL_COUNTER)
|
||||
return;
|
||||
return false;
|
||||
|
||||
g_GameScript->ExecuteFunction(event.Function, activator, event.Data);
|
||||
if (event.CallCounter != NO_CALL_COUNTER)
|
||||
event.CallCounter--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleEvent(const std::string& name, EventType eventType, Activator activator)
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace TEN::Control::Volumes
|
|||
void TestVolumes(short roomNumber, MESH_INFO* mesh);
|
||||
void TestVolumes(CAMERA_INFO* camera);
|
||||
|
||||
void HandleEvent(Event& event, Activator& activator);
|
||||
bool HandleEvent(Event& event, Activator& activator);
|
||||
bool HandleEvent(const std::string& name, EventType eventType, Activator activator);
|
||||
void HandleAllGlobalEvents(EventType type, Activator& activator);
|
||||
bool SetEventState(const std::string& name, EventType eventType, bool enabled);
|
||||
|
|
|
@ -939,22 +939,19 @@ void TriggerSuperJetFlame(ItemInfo* item, int yvel, int deadly)
|
|||
sptr->xVel = (GetRandomControl() & 0xFF) - 128;
|
||||
sptr->zVel = (GetRandomControl() & 0xFF) - 128;
|
||||
|
||||
if (item->Pose.Orientation.y == 0)
|
||||
{
|
||||
sptr->zVel = -(size - (size >> 2));
|
||||
}
|
||||
else if (item->Pose.Orientation.y == ANGLE(90.0f))
|
||||
{
|
||||
sptr->xVel = -(size - (size >> 2));
|
||||
}
|
||||
else if (item->Pose.Orientation.y == ANGLE(-180.0f))
|
||||
{
|
||||
sptr->zVel = size - (size >> 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
sptr->xVel = size - (size >> 2);
|
||||
}
|
||||
float xAngle = item->Pose.Orientation.x + ANGLE(180); // Nullmesh is rotated 180 degrees in editor
|
||||
float yAngle = item->Pose.Orientation.y;
|
||||
|
||||
Vector3 dir;
|
||||
dir.x = phd_cos(xAngle) * phd_sin(yAngle);
|
||||
dir.y = phd_sin(xAngle);
|
||||
dir.z = phd_cos(xAngle) * phd_cos(yAngle);
|
||||
|
||||
dir.Normalize();
|
||||
|
||||
sptr->xVel += dir.x * (size - (size >> 2));
|
||||
sptr->yVel -= dir.y * (size - (size >> 2));
|
||||
sptr->zVel += dir.z * (size - (size >> 2));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Game/animation.h"
|
||||
#include "Game/camera.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/control/volume.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Lara/lara_fire.h"
|
||||
|
@ -1882,7 +1883,7 @@ namespace TEN::Gui
|
|||
AlterFOV(ANGLE(DEFAULT_FOV), false);
|
||||
lara->Inventory.IsBusy = false;
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
UseItem = false;
|
||||
ItemUsed = false;
|
||||
|
||||
if (lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[0].HasInfinite())
|
||||
{
|
||||
|
@ -2036,16 +2037,16 @@ namespace TEN::Gui
|
|||
}
|
||||
}
|
||||
|
||||
void GuiController::UseCurrentItem(ItemInfo* item)
|
||||
void GuiController::UseItem(ItemInfo& item, int objectNumber)
|
||||
{
|
||||
const std::vector<int> CrouchStates =
|
||||
const auto CROUCH_STATES = std::vector<int>
|
||||
{
|
||||
LS_CROUCH_IDLE,
|
||||
LS_CROUCH_TURN_LEFT,
|
||||
LS_CROUCH_TURN_RIGHT,
|
||||
LS_CROUCH_TURN_180
|
||||
};
|
||||
const std::vector<int> CrawlStates =
|
||||
const auto CRAWL_STATES = std::vector<int>
|
||||
{
|
||||
LS_CRAWL_IDLE,
|
||||
LS_CRAWL_FORWARD,
|
||||
|
@ -2056,265 +2057,232 @@ namespace TEN::Gui
|
|||
LS_CRAWL_TO_HANG
|
||||
};
|
||||
|
||||
auto* lara = GetLaraInfo(item);
|
||||
auto& player = GetLaraInfo(item);
|
||||
|
||||
int prevOpticRange = lara->Control.Look.OpticRange;
|
||||
short inventoryObject = Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].CurrentObjectInList].InventoryItem;
|
||||
short gameObject = InventoryObjectTable[inventoryObject].ObjectNumber;
|
||||
short prevOpticRange = player.Control.Look.OpticRange;
|
||||
player.Control.Look.OpticRange = 0;
|
||||
player.Inventory.OldBusy = false;
|
||||
item.MeshBits = ALL_JOINT_BITS;
|
||||
|
||||
item->MeshBits = ALL_JOINT_BITS;
|
||||
lara->Control.Look.OpticRange = 0;
|
||||
lara->Inventory.OldBusy = false;
|
||||
InventoryItemChosen = objectNumber;
|
||||
|
||||
if (lara->Control.WaterStatus == WaterStatus::Dry ||
|
||||
lara->Control.WaterStatus == WaterStatus::Wade)
|
||||
// Use item event handling.
|
||||
g_GameScript->OnUseItem((GAME_OBJECT_ID)InventoryItemChosen);
|
||||
HandleAllGlobalEvents(EventType::UseItem, (Activator)item.Index);
|
||||
|
||||
// Quickly discard further processing if chosen item was reset in script.
|
||||
if (InventoryItemChosen == NO_VALUE)
|
||||
return;
|
||||
|
||||
if (InventoryItemChosen == ID_PISTOLS_ITEM ||
|
||||
InventoryItemChosen == ID_UZI_ITEM ||
|
||||
InventoryItemChosen == ID_REVOLVER_ITEM)
|
||||
{
|
||||
if (gameObject == ID_PISTOLS_ITEM)
|
||||
if (player.Control.WaterStatus != WaterStatus::Dry &&
|
||||
player.Control.WaterStatus != WaterStatus::Wade)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::Pistol;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
return;
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Pistol)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameObject == ID_UZI_ITEM)
|
||||
switch (InventoryItemChosen)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::Uzi;
|
||||
case ID_PISTOLS_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::Pistol;
|
||||
break;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
case ID_UZI_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::Uzi;
|
||||
break;
|
||||
|
||||
case ID_REVOLVER_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::Revolver;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Uzi)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.Control.HandStatus == HandStatus::Free &&
|
||||
player.Control.Weapon.GunType == player.Control.Weapon.RequestGunType)
|
||||
{
|
||||
player.Control.HandStatus = HandStatus::WeaponDraw;
|
||||
}
|
||||
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameObject != ID_SHOTGUN_ITEM &&
|
||||
gameObject != ID_REVOLVER_ITEM &&
|
||||
gameObject != ID_HK_ITEM &&
|
||||
gameObject != ID_CROSSBOW_ITEM &&
|
||||
gameObject != ID_GRENADE_GUN_ITEM &&
|
||||
gameObject != ID_ROCKET_LAUNCHER_ITEM &&
|
||||
gameObject != ID_HARPOON_ITEM)
|
||||
if (InventoryItemChosen == ID_SHOTGUN_ITEM ||
|
||||
InventoryItemChosen == ID_HK_ITEM ||
|
||||
InventoryItemChosen == ID_CROSSBOW_ITEM ||
|
||||
InventoryItemChosen == ID_GRENADE_GUN_ITEM ||
|
||||
InventoryItemChosen == ID_ROCKET_LAUNCHER_ITEM ||
|
||||
InventoryItemChosen == ID_HARPOON_ITEM)
|
||||
{
|
||||
if (gameObject == ID_FLARE_INV_ITEM)
|
||||
if (InventoryItemChosen != ID_HARPOON_ITEM &&
|
||||
player.Control.WaterStatus != WaterStatus::Dry &&
|
||||
player.Control.WaterStatus != WaterStatus::Wade)
|
||||
{
|
||||
if (lara->Control.HandStatus == HandStatus::Free)
|
||||
{
|
||||
if (!TestState(item->Animation.ActiveState, CrawlStates))
|
||||
{
|
||||
if (lara->Control.Weapon.GunType != LaraWeaponType::Flare)
|
||||
{
|
||||
// HACK.
|
||||
ClearAllActions();
|
||||
ActionMap[(int)In::Flare].Update(1.0f);
|
||||
|
||||
HandleWeapon(*item);
|
||||
ClearAllActions();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SayNo();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (inventoryObject)
|
||||
if (TestState(item.Animation.ActiveState, CROUCH_STATES) ||
|
||||
TestState(item.Animation.ActiveState, CRAWL_STATES))
|
||||
{
|
||||
case INV_OBJECT_BINOCULARS:
|
||||
if (((item->Animation.ActiveState == LS_IDLE && item->Animation.AnimNumber == LA_STAND_IDLE) ||
|
||||
(lara->Control.IsLow && !IsHeld(In::Crouch))) &&
|
||||
!UseSpotCam && !TrackCameraInit)
|
||||
{
|
||||
lara->Control.Look.OpticRange = 128;
|
||||
lara->Control.Look.IsUsingBinoculars = true;
|
||||
lara->Inventory.OldBusy = true;
|
||||
|
||||
// TODO: To prevent Lara from crouching or performing other actions, the inherent state of
|
||||
// LA_BINOCULARS_IDLE must be changed to LS_IDLE. @Sezz 2022.05.19
|
||||
//SetAnimation(item, LA_BINOCULARS_IDLE);
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
lara->Control.HandStatus = HandStatus::WeaponUndraw;
|
||||
}
|
||||
|
||||
if (prevOpticRange)
|
||||
{
|
||||
lara->Control.Look.OpticRange = prevOpticRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
BinocularOldCamera = Camera.oldType;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case INV_OBJECT_SMALL_MEDIPACK:
|
||||
|
||||
if ((item->HitPoints <= 0 || item->HitPoints >= LARA_HEALTH_MAX) &&
|
||||
lara->Status.Poison == 0)
|
||||
{
|
||||
SayNo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lara->Inventory.TotalSmallMedipacks != 0)
|
||||
{
|
||||
if (lara->Inventory.TotalSmallMedipacks != -1)
|
||||
lara->Inventory.TotalSmallMedipacks--;
|
||||
|
||||
lara->Status.Poison = 0;
|
||||
item->HitPoints += LARA_HEALTH_MAX / 2;
|
||||
|
||||
if (item->HitPoints > LARA_HEALTH_MAX)
|
||||
item->HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
||||
SaveGame::Statistics.Game.HealthUsed++;
|
||||
}
|
||||
else
|
||||
SayNo();
|
||||
|
||||
return;
|
||||
|
||||
case INV_OBJECT_LARGE_MEDIPACK:
|
||||
|
||||
if ((item->HitPoints <= 0 || item->HitPoints >= LARA_HEALTH_MAX) &&
|
||||
lara->Status.Poison == 0)
|
||||
{
|
||||
SayNo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lara->Inventory.TotalLargeMedipacks != 0)
|
||||
{
|
||||
if (lara->Inventory.TotalLargeMedipacks != -1)
|
||||
lara->Inventory.TotalLargeMedipacks--;
|
||||
|
||||
lara->Status.Poison = 0;
|
||||
item->HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
||||
SaveGame::Statistics.Game.HealthUsed++;
|
||||
}
|
||||
else
|
||||
SayNo();
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
InventoryItemChosen = gameObject;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (InventoryItemChosen)
|
||||
{
|
||||
case ID_SHOTGUN_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::Shotgun;
|
||||
break;
|
||||
|
||||
case ID_REVOLVER_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::Revolver;
|
||||
break;
|
||||
|
||||
case ID_HK_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::HK;
|
||||
break;
|
||||
|
||||
case ID_CROSSBOW_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::Crossbow;
|
||||
break;
|
||||
|
||||
case ID_GRENADE_GUN_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::GrenadeLauncher;
|
||||
break;
|
||||
|
||||
case ID_HARPOON_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::HarpoonGun;
|
||||
break;
|
||||
|
||||
case ID_ROCKET_LAUNCHER_ITEM:
|
||||
player.Control.Weapon.RequestGunType = LaraWeaponType::RocketLauncher;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.Control.HandStatus == HandStatus::Free &&
|
||||
player.Control.Weapon.GunType == player.Control.Weapon.RequestGunType)
|
||||
{
|
||||
player.Control.HandStatus = HandStatus::WeaponDraw;
|
||||
}
|
||||
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lara->Control.HandStatus == HandStatus::Busy)
|
||||
switch (InventoryItemChosen)
|
||||
{
|
||||
SayNo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (TestState(item->Animation.ActiveState, CrouchStates) ||
|
||||
TestState(item->Animation.ActiveState, CrawlStates))
|
||||
{
|
||||
SayNo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameObject == ID_SHOTGUN_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::Shotgun;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
case ID_FLARE_INV_ITEM:
|
||||
if (player.Control.HandStatus != HandStatus::Free)
|
||||
return;
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Shotgun)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
if (!TestState(item.Animation.ActiveState, CRAWL_STATES))
|
||||
{
|
||||
if (player.Control.Weapon.GunType != LaraWeaponType::Flare)
|
||||
{
|
||||
// HACK.
|
||||
ClearAllActions();
|
||||
ActionMap[(int)In::Flare].Update(1.0f);
|
||||
|
||||
HandleWeapon(item);
|
||||
ClearAllActions();
|
||||
}
|
||||
}
|
||||
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameObject == ID_REVOLVER_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::Revolver;
|
||||
case ID_BINOCULARS_ITEM:
|
||||
if (((item.Animation.ActiveState == LS_IDLE && item.Animation.AnimNumber == LA_STAND_IDLE) ||
|
||||
(player.Control.IsLow && !IsHeld(In::Crouch))) &&
|
||||
!UseSpotCam && !TrackCameraInit)
|
||||
{
|
||||
player.Control.Look.OpticRange = ANGLE(0.7f);
|
||||
player.Control.Look.IsUsingBinoculars = true;
|
||||
player.Inventory.OldBusy = true;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
return;
|
||||
// TODO: To prevent Lara from crouching or performing other actions, the inherent state of
|
||||
// LA_BINOCULARS_IDLE must be changed to LS_IDLE. @Sezz 2022.05.19
|
||||
//SetAnimation(item, LA_BINOCULARS_IDLE);
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Revolver)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
if (player.Control.HandStatus != HandStatus::Free)
|
||||
player.Control.HandStatus = HandStatus::WeaponUndraw;
|
||||
}
|
||||
|
||||
if (prevOpticRange != ANGLE(0.0f))
|
||||
{
|
||||
player.Control.Look.OpticRange = prevOpticRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
BinocularOldCamera = Camera.oldType;
|
||||
}
|
||||
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
return;
|
||||
}
|
||||
else if (gameObject == ID_HK_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::HK;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
case ID_SMALLMEDI_ITEM:
|
||||
if ((item.HitPoints <= 0 || item.HitPoints >= LARA_HEALTH_MAX) &&
|
||||
player.Status.Poison == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::HK)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
if (player.Inventory.TotalSmallMedipacks != 0)
|
||||
{
|
||||
if (player.Inventory.TotalSmallMedipacks != NO_VALUE)
|
||||
player.Inventory.TotalSmallMedipacks--;
|
||||
|
||||
player.Status.Poison = 0;
|
||||
item.HitPoints += LARA_HEALTH_MAX / 2;
|
||||
|
||||
if (item.HitPoints > LARA_HEALTH_MAX)
|
||||
item.HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
||||
SaveGame::Statistics.Game.HealthUsed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
return;
|
||||
}
|
||||
else if (gameObject == ID_CROSSBOW_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::Crossbow;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
case ID_BIGMEDI_ITEM:
|
||||
if ((item.HitPoints <= 0 || item.HitPoints >= LARA_HEALTH_MAX) &&
|
||||
player.Status.Poison == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Crossbow)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
if (player.Inventory.TotalLargeMedipacks != 0)
|
||||
{
|
||||
if (player.Inventory.TotalLargeMedipacks != NO_VALUE)
|
||||
player.Inventory.TotalLargeMedipacks--;
|
||||
|
||||
player.Status.Poison = 0;
|
||||
item.HitPoints = LARA_HEALTH_MAX;
|
||||
|
||||
SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
|
||||
SaveGame::Statistics.Game.HealthUsed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryItemChosen = NO_VALUE;
|
||||
return;
|
||||
}
|
||||
else if (gameObject == ID_GRENADE_GUN_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::GrenadeLauncher;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
return;
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::GrenadeLauncher)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (gameObject == ID_HARPOON_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::HarpoonGun;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
return;
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::HarpoonGun)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (gameObject == ID_ROCKET_LAUNCHER_ITEM)
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::RocketLauncher;
|
||||
|
||||
if (lara->Control.HandStatus != HandStatus::Free)
|
||||
return;
|
||||
|
||||
if (lara->Control.Weapon.GunType == LaraWeaponType::RocketLauncher)
|
||||
lara->Control.HandStatus = HandStatus::WeaponDraw;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2660,7 +2628,7 @@ namespace TEN::Gui
|
|||
case MenuType::Equip:
|
||||
case MenuType::Use:
|
||||
MenuActive = false;
|
||||
UseItem = true;
|
||||
ItemUsed = true;
|
||||
break;
|
||||
|
||||
case MenuType::Diary:
|
||||
|
@ -3391,7 +3359,7 @@ namespace TEN::Gui
|
|||
break;
|
||||
}
|
||||
|
||||
if (UseItem && NoAction())
|
||||
if (ItemUsed && NoAction())
|
||||
exitLoop = true;
|
||||
|
||||
SetEnterInventory(NO_VALUE);
|
||||
|
@ -3402,8 +3370,8 @@ namespace TEN::Gui
|
|||
LastInvItem = Rings[(int)RingTypes::Inventory].CurrentObjectList[Rings[(int)RingTypes::Inventory].CurrentObjectInList].InventoryItem;
|
||||
UpdateWeaponStatus(item);
|
||||
|
||||
if (UseItem)
|
||||
UseCurrentItem(item);
|
||||
if (ItemUsed)
|
||||
UseItem(*item, InventoryObjectTable[LastInvItem].ObjectNumber);
|
||||
|
||||
AlterFOV(LastFOV);
|
||||
ResumeAllSounds(SoundPauseMode::Inventory);
|
||||
|
@ -3438,6 +3406,15 @@ namespace TEN::Gui
|
|||
}
|
||||
}
|
||||
|
||||
void GuiController::CancelInventorySelection()
|
||||
{
|
||||
if (GetInventoryItemChosen() != NO_VALUE)
|
||||
{
|
||||
SetInventoryItemChosen(NO_VALUE);
|
||||
SayNo();
|
||||
}
|
||||
}
|
||||
|
||||
void GuiController::DrawCompass(ItemInfo* item)
|
||||
{
|
||||
constexpr auto POS_2D = Vector2(130.0f, 450.0f);
|
||||
|
|
|
@ -139,7 +139,7 @@ namespace TEN::Gui
|
|||
// Inventory variables
|
||||
short CombineObject1;
|
||||
short CombineObject2;
|
||||
bool UseItem;
|
||||
bool ItemUsed;
|
||||
char SeperateTypeFlag;
|
||||
char CombineTypeFlag;
|
||||
InventoryRing Rings[2];
|
||||
|
@ -180,6 +180,8 @@ namespace TEN::Gui
|
|||
void DrawAmmoSelector();
|
||||
bool PerformWaterskinCombine(ItemInfo* item, bool flag);
|
||||
void DrawCompass(ItemInfo* item);
|
||||
void CancelInventorySelection();
|
||||
void UseItem(ItemInfo& item, int objectNumber);
|
||||
|
||||
// Getters
|
||||
const InventoryRing& GetRing(RingTypes ringType);
|
||||
|
@ -220,7 +222,6 @@ namespace TEN::Gui
|
|||
void SeparateObject(ItemInfo* item, int objectNumber);
|
||||
void InsertObjectIntoList(int objectNumber);
|
||||
void InsertObjectIntoList_v2(int objectNumber);
|
||||
void UseCurrentItem(ItemInfo* item);
|
||||
void SpinBack(EulerAngles& orient);
|
||||
void UpdateWeaponStatus(ItemInfo* item);
|
||||
void DoStatisticsMode();
|
||||
|
|
|
@ -40,7 +40,7 @@ void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature)
|
|||
}
|
||||
}
|
||||
|
||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist)
|
||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat)
|
||||
{
|
||||
auto projectedPos = Geometry::TranslatePoint(item.Pose.Position, dir, dist);
|
||||
auto pointColl = GetCollision(item.Pose.Position, item.RoomNumber, dir, dist);
|
||||
|
@ -59,16 +59,29 @@ bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist)
|
|||
{
|
||||
// Test for step.
|
||||
int relFloorHeight = abs(pointColl.Position.Floor - item.Pose.Position.y);
|
||||
if (relFloorHeight >= CLICK(1) && item.Pose.Position.y >= pointColl.Position.Floor)
|
||||
|
||||
if (relFloorHeight >= CLICK(1) && item.Pose.Position.y >= pointColl.Position.Floor && canFloat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (relFloorHeight >= CLICK(1) && !canFloat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Sloped floor.
|
||||
else
|
||||
{
|
||||
// Half block.
|
||||
int relFloorHeight = abs(pointColl.Position.Floor - item.Pose.Position.y);
|
||||
if (relFloorHeight > CLICK(1))
|
||||
if (relFloorHeight > CLICK(1) && canFloat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (relFloorHeight > CLICK(2) && !canFloat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
short slopeAngle = ANGLE(0.0f);
|
||||
if (pointColl.FloorTilt.x > 0)
|
||||
|
@ -104,8 +117,16 @@ bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist)
|
|||
// Test ceiling height.
|
||||
int relCeilHeight = abs(pointColl.Position.Ceiling - pointColl.Position.Floor);
|
||||
|
||||
if (relCeilHeight <= height)
|
||||
return false;
|
||||
if (canFloat)
|
||||
{
|
||||
if (relCeilHeight <= height)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (relCeilHeight < BLOCK(1))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for blocked grey box.
|
||||
if (g_Level.Boxes[pointColl.Block->Box].flags & BLOCKABLE)
|
||||
|
@ -123,4 +144,4 @@ bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist)
|
|||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,4 +19,4 @@ enum LaraMeshMask
|
|||
|
||||
CreatureInfo* GetCreatureInfo(ItemInfo* item);
|
||||
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature);
|
||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist);
|
||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat);
|
||||
|
|
|
@ -21,16 +21,19 @@ namespace TEN::Effects::EmberEmitter
|
|||
unsigned char b = 0;
|
||||
|
||||
float brightnessShift = Random::GenerateFloat(-0.1f, 0.1f);
|
||||
r = std::clamp(item.Model.Color.x + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
|
||||
g = std::clamp(item.Model.Color.y + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
|
||||
b = std::clamp(item.Model.Color.z + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
|
||||
r = std::clamp(item.Model.Color.x / 2.0f + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
|
||||
g = std::clamp(item.Model.Color.y / 2.0f + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
|
||||
b = std::clamp(item.Model.Color.z / 2.0f + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
|
||||
|
||||
if (item.TriggerFlags < 0)
|
||||
{
|
||||
if (item.TriggerFlags > -11)
|
||||
item.TriggerFlags = -11;
|
||||
|
||||
if (!item.ItemFlags[2])
|
||||
{
|
||||
int div = abs(item.TriggerFlags) % 10 << 10;
|
||||
int mod = abs(item.TriggerFlags) / 10 << 10;
|
||||
int div = (abs(item.TriggerFlags) % 10) << 10;
|
||||
int mod = (abs(item.TriggerFlags) / 10) << 10;
|
||||
|
||||
// TODO: Use Random::GenerateInt()
|
||||
item.ItemFlags[0] = GetRandomControl() % div;
|
||||
|
|
|
@ -131,6 +131,9 @@ namespace TEN::Entities::Creatures::TR2
|
|||
int skidooItemNumber = (short)riderItem.ItemFlags[0];
|
||||
auto* skidooItem = &g_Level.Items[skidooItemNumber];
|
||||
|
||||
if (!CreatureActive(skidooItemNumber))
|
||||
return;
|
||||
|
||||
if (!skidooItem->Data)
|
||||
{
|
||||
EnableEntityAI(skidooItemNumber, true);
|
||||
|
|
|
@ -5,29 +5,61 @@
|
|||
#include "Game/control/box.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/itemdata/creature_info.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/misc.h"
|
||||
#include "Game/people.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Math;
|
||||
|
||||
namespace TEN::Entities::Creatures::TR2
|
||||
{
|
||||
constexpr auto WORKER_SHOTGUN_NUM_SHOTS = 6;
|
||||
|
||||
const auto WorkerShotgunBite = CreatureBiteInfo(Vector3(0, 350, 40), 9);
|
||||
|
||||
// TODO
|
||||
enum ShotgunWorkerState
|
||||
{
|
||||
|
||||
// No state 0.
|
||||
WORKER_SHOTGUN_STATE_WALK = 1,
|
||||
WORKER_SHOTGUN_STATE_IDLE = 2,
|
||||
WORKER_SHOTGUN_STATE_REST = 3,
|
||||
WORKER_SHOTGUN_STATE_STANDING_ATTACK = 4,
|
||||
WORKER_SHOTGUN_STATE_RUN = 5,
|
||||
WORKER_SHOTGUN_STATE_WALKING_ATTACK = 6,
|
||||
WORKER_SHOTGUN_STATE_DEATH = 7,
|
||||
WORKER_SHOTGUN_STATE_STANDING_ATTACK_AIM = 8,
|
||||
WORKER_SHOTGUN_STATE_KNEEL_ATTACK_AIM = 9,
|
||||
WORKER_SHOTGUN_STATE_KNEEL_ATTACK = 10
|
||||
};
|
||||
|
||||
// TODO
|
||||
enum ShotgunWorkerAnim
|
||||
{
|
||||
|
||||
WORKER_SHOTGUN_ANIM_WALK = 0,
|
||||
WORKER_SHOTGUN_ANIM_STANDING_ATTACK_AIM = 1,
|
||||
WORKER_SHOTGUN_ANIM_STANDING_ATTACK_SHOOT = 2,
|
||||
WORKER_SHOTGUN_ANIM_STANDING_ATTACK_STOP = 3,
|
||||
WORKER_SHOTGUN_ANIM_WALK_TO_IDLE = 4,
|
||||
WORKER_SHOTGUN_ANIM_IDLE = 5,
|
||||
WORKER_SHOTGUN_ANIM_IDLE_TO_WALK = 6,
|
||||
WORKER_SHOTGUN_ANIM_WALKING_ATTACK_AIM = 7,
|
||||
WORKER_SHOTGUN_ANIM_WALKING_ATTACK_SHOOT = 8,
|
||||
WORKER_SHOTGUN_ANIM_REST_TO_IDLE = 9,
|
||||
WORKER_SHOTGUN_ANIM_REST = 10,
|
||||
WORKER_SHOTGUN_ANIM_REST_TO_STANDING_ATTACK = 11,
|
||||
WORKER_SHOTGUN_ANIM_IDLE_TO_REST = 12,
|
||||
WORKER_SHOTGUN_ANIM_STANDING_ATTACK_TO_IDLE = 13,
|
||||
WORKER_SHOTGUN_ANIM_WALK_TO_RUN = 14,
|
||||
WORKER_SHOTGUN_ANIM_RUN_TO_WALK = 15,
|
||||
WORKER_SHOTGUN_ANIM_IDLE_TO_RUN = 16,
|
||||
WORKER_SHOTGUN_ANIM_RUN = 17,
|
||||
WORKER_SHOTGUN_ANIM_DEATH = 18,
|
||||
WORKER_SHOTGUN_ANIM_KNEEL_ATTACK_AIM = 19,
|
||||
WORKER_SHOTGUN_ANIM_KNEEL_ATTACK_SHOOT = 20,
|
||||
WORKER_SHOTGUN_ANIM_KNEEL_ATTACK_STOP = 21
|
||||
};
|
||||
|
||||
static void ShootWorkerShotgun(ItemInfo& item, AI_INFO& ai, const CreatureBiteInfo& bite, short headingAngle, int damage)
|
||||
|
@ -62,8 +94,8 @@ namespace TEN::Entities::Creatures::TR2
|
|||
|
||||
if (item->HitPoints <= 0)
|
||||
{
|
||||
if (item->Animation.ActiveState != 7)
|
||||
SetAnimation(item, 18);
|
||||
if (item->Animation.ActiveState != WORKER_SHOTGUN_STATE_DEATH)
|
||||
SetAnimation(item, WORKER_SHOTGUN_ANIM_DEATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -77,7 +109,7 @@ namespace TEN::Entities::Creatures::TR2
|
|||
|
||||
switch (item->Animation.ActiveState)
|
||||
{
|
||||
case 2:
|
||||
case WORKER_SHOTGUN_STATE_IDLE:
|
||||
creature->MaxTurn = 0;
|
||||
creature->Flags = 0;
|
||||
|
||||
|
@ -89,38 +121,38 @@ namespace TEN::Entities::Creatures::TR2
|
|||
|
||||
if (creature->Mood == MoodType::Escape)
|
||||
{
|
||||
item->Animation.TargetState = 5;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_RUN;
|
||||
}
|
||||
else if (Targetable(item, &ai))
|
||||
{
|
||||
if (ai.distance < SQUARE(BLOCK(3)) || ai.zoneNumber != ai.enemyZone)
|
||||
{
|
||||
item->Animation.TargetState = (GetRandomControl() >= 0x4000) ? 9 : 8;
|
||||
item->Animation.TargetState = Random::TestProbability(1 / 2.0f) ? WORKER_SHOTGUN_STATE_KNEEL_ATTACK_AIM : WORKER_SHOTGUN_STATE_STANDING_ATTACK_AIM;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Animation.TargetState = 1;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_WALK;
|
||||
}
|
||||
}
|
||||
else if (creature->Mood == MoodType::Attack || !ai.ahead)
|
||||
{
|
||||
if (ai.distance <= SQUARE(BLOCK(2)))
|
||||
{
|
||||
item->Animation.TargetState = 1;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_WALK;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Animation.TargetState = 5;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_RUN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Animation.TargetState = 3;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_REST;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case WORKER_SHOTGUN_STATE_REST:
|
||||
if (ai.ahead)
|
||||
{
|
||||
extraHeadRot.x = ai.xAngle;
|
||||
|
@ -129,16 +161,16 @@ namespace TEN::Entities::Creatures::TR2
|
|||
|
||||
if (Targetable(item, &ai))
|
||||
{
|
||||
item->Animation.TargetState = 4;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_STANDING_ATTACK;
|
||||
}
|
||||
else if (creature->Mood == MoodType::Attack || !ai.ahead)
|
||||
{
|
||||
item->Animation.TargetState = 2;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case WORKER_SHOTGUN_STATE_WALK:
|
||||
creature->MaxTurn = ANGLE(3.0f);
|
||||
|
||||
if (ai.ahead)
|
||||
|
@ -149,32 +181,33 @@ namespace TEN::Entities::Creatures::TR2
|
|||
|
||||
if (creature->Mood == MoodType::Escape)
|
||||
{
|
||||
item->Animation.TargetState = 5;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_RUN;
|
||||
}
|
||||
else if (Targetable(item, &ai))
|
||||
{
|
||||
if (ai.distance < SQUARE(BLOCK(3)) || ai.zoneNumber != ai.enemyZone)
|
||||
{
|
||||
item->Animation.TargetState = 2;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Animation.TargetState = 6;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_WALKING_ATTACK;
|
||||
creature->Flags = 0;
|
||||
}
|
||||
}
|
||||
else if (creature->Mood == MoodType::Attack || !ai.ahead)
|
||||
{
|
||||
if (ai.distance > SQUARE(BLOCK(2)))
|
||||
item->Animation.TargetState = 5;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_RUN;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Animation.TargetState = 2;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case WORKER_SHOTGUN_STATE_RUN:
|
||||
creature->MaxTurn = ANGLE(5.0f);
|
||||
tiltAngle = headingAngle / 2;
|
||||
|
||||
|
@ -188,18 +221,18 @@ namespace TEN::Entities::Creatures::TR2
|
|||
{
|
||||
if (Targetable(item, &ai))
|
||||
{
|
||||
item->Animation.TargetState = 1;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_WALK;
|
||||
}
|
||||
else if (creature->Mood == MoodType::Bored || creature->Mood == MoodType::Stalk)
|
||||
{
|
||||
item->Animation.TargetState = 1;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_WALK;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case 9:
|
||||
case WORKER_SHOTGUN_STATE_STANDING_ATTACK_AIM:
|
||||
case WORKER_SHOTGUN_STATE_KNEEL_ATTACK_AIM:
|
||||
creature->Flags = 0;
|
||||
|
||||
if (ai.ahead)
|
||||
|
@ -210,20 +243,20 @@ namespace TEN::Entities::Creatures::TR2
|
|||
|
||||
if (Targetable(item, &ai))
|
||||
{
|
||||
if (item->Animation.ActiveState == 8)
|
||||
if (item->Animation.ActiveState == WORKER_SHOTGUN_STATE_STANDING_ATTACK_AIM)
|
||||
{
|
||||
item->Animation.TargetState = 4;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_STANDING_ATTACK;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Animation.TargetState = 10;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_KNEEL_ATTACK;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 10:
|
||||
case WORKER_SHOTGUN_STATE_STANDING_ATTACK:
|
||||
case WORKER_SHOTGUN_STATE_KNEEL_ATTACK:
|
||||
if (ai.ahead)
|
||||
{
|
||||
extraTorsoRot.x = ai.xAngle;
|
||||
|
@ -238,15 +271,15 @@ namespace TEN::Entities::Creatures::TR2
|
|||
creature->Flags = 1;
|
||||
}
|
||||
|
||||
if (item->Animation.ActiveState == 4 && item->Animation.TargetState != 2 &&
|
||||
if (item->Animation.ActiveState == WORKER_SHOTGUN_STATE_STANDING_ATTACK && item->Animation.TargetState != WORKER_SHOTGUN_STATE_IDLE &&
|
||||
(creature->Mood == MoodType::Escape || ai.distance > SQUARE(BLOCK(3)) || !Targetable(item, &ai)))
|
||||
{
|
||||
item->Animation.TargetState = 2;
|
||||
item->Animation.TargetState = WORKER_SHOTGUN_STATE_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case WORKER_SHOTGUN_STATE_WALKING_ATTACK:
|
||||
if (ai.ahead)
|
||||
{
|
||||
extraTorsoRot.x = ai.xAngle;
|
||||
|
|
|
@ -72,13 +72,13 @@ namespace TEN::Entities::Traps
|
|||
|
||||
static Vector3 GetElectricCleanerMovementDirection(const ItemInfo& item, const Vector3& dir0, const Vector3& dir1, const Vector3& dir2)
|
||||
{
|
||||
if (IsNextSectorValid(item, dir0, BLOCK(1)))
|
||||
if (IsNextSectorValid(item, dir0, BLOCK(1), false))
|
||||
return dir0;
|
||||
|
||||
if (IsNextSectorValid(item, dir1, BLOCK(1)))
|
||||
if (IsNextSectorValid(item, dir1, BLOCK(1), false))
|
||||
return dir1;
|
||||
|
||||
if (IsNextSectorValid(item, dir2, BLOCK(1)))
|
||||
if (IsNextSectorValid(item, dir2, BLOCK(1), false))
|
||||
return dir2;
|
||||
|
||||
return Vector3::Zero;
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace TEN::Entities::Traps
|
|||
if (pointColl.RoomNumber != item.RoomNumber)
|
||||
ItemNewRoom(itemNumber, pointColl.RoomNumber);
|
||||
|
||||
if (!IsNextSectorValid(item, forwardDir, BLOCK(0.5f)))
|
||||
if (!IsNextSectorValid(item, forwardDir, BLOCK(0.5f), true))
|
||||
{
|
||||
switch (headingAngle)
|
||||
{
|
||||
|
|
|
@ -36,9 +36,9 @@ void PulseLightControl(short itemNumber)
|
|||
item->Pose.Position.y,
|
||||
item->Pose.Position.z,
|
||||
24,
|
||||
(pulse * item->Model.Color.x * UCHAR_MAX) / 512,
|
||||
(pulse * item->Model.Color.y * UCHAR_MAX) / 512,
|
||||
(pulse * item->Model.Color.z * UCHAR_MAX) / 512);
|
||||
(pulse * item->Model.Color.x * SCHAR_MAX) / 512,
|
||||
(pulse * item->Model.Color.y * SCHAR_MAX) / 512,
|
||||
(pulse * item->Model.Color.z * SCHAR_MAX) / 512);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,9 @@ void StrobeLightControl(short itemNumber)
|
|||
{
|
||||
item->Pose.Orientation.y += ANGLE(16.0f);
|
||||
|
||||
byte r = item->Model.Color.x * UCHAR_MAX;
|
||||
byte g = item->Model.Color.y * UCHAR_MAX;
|
||||
byte b = item->Model.Color.z * UCHAR_MAX;
|
||||
byte r = item->Model.Color.x * SCHAR_MAX;
|
||||
byte g = item->Model.Color.y * SCHAR_MAX;
|
||||
byte b = item->Model.Color.z * SCHAR_MAX;
|
||||
|
||||
TriggerAlertLight(
|
||||
item->Pose.Position.x,
|
||||
|
@ -94,9 +94,9 @@ void ColorLightControl(short itemNumber)
|
|||
item->Pose.Position.y,
|
||||
item->Pose.Position.z,
|
||||
24,
|
||||
item->Model.Color.x * UCHAR_MAX,
|
||||
item->Model.Color.y * UCHAR_MAX,
|
||||
item->Model.Color.z * UCHAR_MAX);
|
||||
item->Model.Color.x * SCHAR_MAX,
|
||||
item->Model.Color.y * SCHAR_MAX,
|
||||
item->Model.Color.z * SCHAR_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,9 +228,9 @@ void BlinkingLightControl(short itemNumber)
|
|||
TriggerDynamicLight(
|
||||
pos.x, pos.y, pos.z,
|
||||
16,
|
||||
item->Model.Color.x * UCHAR_MAX,
|
||||
item->Model.Color.y * UCHAR_MAX,
|
||||
item->Model.Color.z * UCHAR_MAX);
|
||||
item->Model.Color.x * SCHAR_MAX,
|
||||
item->Model.Color.y * SCHAR_MAX,
|
||||
item->Model.Color.z * SCHAR_MAX);
|
||||
|
||||
item->MeshBits = 2;
|
||||
|
||||
|
|
|
@ -1454,14 +1454,13 @@ namespace TEN::Renderer
|
|||
}
|
||||
}
|
||||
|
||||
SetCullMode(CullMode::CounterClockwise);
|
||||
}
|
||||
// TODO: temporary fix, we need to remove every use of SpriteBatch and PrimitiveBatch because
|
||||
// they mess up render states cache.
|
||||
|
||||
// TODO: temporary fix, we need to remove every use of SpriteBatch and PrimitiveBatch because
|
||||
// they mess up render states cache
|
||||
SetBlendMode(BlendMode::Opaque, true);
|
||||
SetDepthState(DepthState::Write, true);
|
||||
SetCullMode(CullMode::CounterClockwise, true);
|
||||
SetBlendMode(BlendMode::Opaque, true);
|
||||
SetDepthState(DepthState::Write, true);
|
||||
SetCullMode(CullMode::CounterClockwise, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::PrepareSmokeParticles(RenderView& view)
|
||||
|
|
|
@ -57,8 +57,9 @@ public:
|
|||
virtual void OnLoop(float deltaTime, bool postLoop) = 0;
|
||||
virtual void OnSave() = 0;
|
||||
virtual void OnEnd(GameStatus reason) = 0;
|
||||
virtual void ShortenTENCalls() = 0;
|
||||
virtual void OnUseItem(GAME_OBJECT_ID objectNumber) = 0;
|
||||
|
||||
virtual void ShortenTENCalls() = 0;
|
||||
virtual void FreeLevelScripts() = 0;
|
||||
virtual void ResetScripts(bool clearGameVars) = 0;
|
||||
virtual void ExecuteScriptFile(const std::string& luaFileName) = 0;
|
||||
|
|
|
@ -53,14 +53,6 @@ static constexpr char ScriptReserved_DisplayStringSetScale[] = "SetScale";
|
|||
static constexpr char ScriptReserved_DisplayStringSetColor[] = "SetColor";
|
||||
static constexpr char ScriptReserved_DisplaySpriteDraw[] = "Draw";
|
||||
|
||||
// Built-in LevelFuncs
|
||||
static constexpr char ScriptReserved_OnStart[] = "OnStart";
|
||||
static constexpr char ScriptReserved_OnLoad[] = "OnLoad";
|
||||
static constexpr char ScriptReserved_OnLoop[] = "OnLoop";
|
||||
static constexpr char ScriptReserved_OnControlPhase[] = "OnControlPhase"; // DEPRECATED
|
||||
static constexpr char ScriptReserved_OnSave[] = "OnSave";
|
||||
static constexpr char ScriptReserved_OnEnd[] = "OnEnd";
|
||||
|
||||
static constexpr char ScriptReserved_EndReasonExitToTitle[] = "EXITTOTITLE";
|
||||
static constexpr char ScriptReserved_EndReasonLevelComplete[] = "LEVELCOMPLETE";
|
||||
static constexpr char ScriptReserved_EndReasonLoadGame[] = "LOADGAME";
|
||||
|
@ -81,15 +73,25 @@ static constexpr char ScriptReserved_PostLoop[] = "POSTLOOP";
|
|||
static constexpr char ScriptReserved_PreControlPhase[] = "PRECONTROLPHASE";
|
||||
static constexpr char ScriptReserved_PostControlPhase[] = "POSTCONTROLPHASE";
|
||||
|
||||
// Event types
|
||||
static constexpr char ScriptReserved_EventOnEnter[] = "ENTER";
|
||||
static constexpr char ScriptReserved_EventOnInside[] = "INSIDE";
|
||||
static constexpr char ScriptReserved_EventOnLeave[] = "LEAVE";
|
||||
static constexpr char ScriptReserved_EventOnLoad[] = "LOAD";
|
||||
static constexpr char ScriptReserved_EventOnSave[] = "SAVE";
|
||||
static constexpr char ScriptReserved_EventOnStart[] = "START";
|
||||
static constexpr char ScriptReserved_EventOnEnd[] = "END";
|
||||
static constexpr char ScriptReserved_EventOnLoop[] = "LOOP";
|
||||
// Built-in LevelFuncs
|
||||
static constexpr char ScriptReserved_OnStart[] = "OnStart";
|
||||
static constexpr char ScriptReserved_OnLoad[] = "OnLoad";
|
||||
static constexpr char ScriptReserved_OnLoop[] = "OnLoop";
|
||||
static constexpr char ScriptReserved_OnControlPhase[] = "OnControlPhase"; // DEPRECATED
|
||||
static constexpr char ScriptReserved_OnSave[] = "OnSave";
|
||||
static constexpr char ScriptReserved_OnEnd[] = "OnEnd";
|
||||
static constexpr char ScriptReserved_OnUseItem[] = "OnUseItem";
|
||||
|
||||
// Event types (volume events + global events)
|
||||
static constexpr char ScriptReserved_EventOnEnter[] = "ENTER";
|
||||
static constexpr char ScriptReserved_EventOnInside[] = "INSIDE";
|
||||
static constexpr char ScriptReserved_EventOnLeave[] = "LEAVE";
|
||||
static constexpr char ScriptReserved_EventOnStart[] = "START";
|
||||
static constexpr char ScriptReserved_EventOnLoad[] = "LOAD";
|
||||
static constexpr char ScriptReserved_EventOnLoop[] = "LOOP";
|
||||
static constexpr char ScriptReserved_EventOnSave[] = "SAVE";
|
||||
static constexpr char ScriptReserved_EventOnEnd[] = "END";
|
||||
static constexpr char ScriptReserved_EventOnUseItem[] = "USEITEM";
|
||||
|
||||
// Member functions
|
||||
static constexpr char ScriptReserved_New[] = "New";
|
||||
|
@ -259,6 +261,9 @@ static constexpr char ScriptReserved_GiveInvItem[] = "GiveItem";
|
|||
static constexpr char ScriptReserved_TakeInvItem[] = "TakeItem";
|
||||
static constexpr char ScriptReserved_GetInvItemCount[] = "GetItemCount";
|
||||
static constexpr char ScriptReserved_SetInvItemCount[] = "SetItemCount";
|
||||
static constexpr char ScriptReserved_GetUsedItem[] = "GetUsedItem";
|
||||
static constexpr char ScriptReserved_SetUsedItem[] = "SetUsedItem";
|
||||
static constexpr char ScriptReserved_ClearUsedItem[] = "ClearUsedItem";
|
||||
static constexpr char ScriptReserved_GetMoveableByName[] = "GetMoveableByName";
|
||||
static constexpr char ScriptReserved_GetStaticByName[] = "GetStaticByName";
|
||||
static constexpr char ScriptReserved_GetMoveablesBySlot[] = "GetMoveablesBySlot";
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include "framework.h"
|
||||
#include "Scripting/Internal/TEN/Inventory/InventoryHandler.h"
|
||||
|
||||
#include "Game/gui.h"
|
||||
#include "Game/Hud/Hud.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/pickup/pickup.h"
|
||||
#include "Scripting/Internal/ReservedScriptNames.h"
|
||||
|
||||
using namespace TEN::Hud;
|
||||
using namespace TEN::Gui;
|
||||
|
||||
/***
|
||||
Inventory manipulation
|
||||
|
@ -59,6 +61,36 @@ namespace TEN::Scripting::InventoryHandler
|
|||
SetInventoryCount(objectID, count);
|
||||
}
|
||||
|
||||
/// Get last item used in the player's inventory.
|
||||
// This value will be valid only for a single frame after exiting inventory, after which Lara says "No".
|
||||
// Therefore, this function must be preferably used either in OnLoop or OnUseItem events.
|
||||
//@function GetUsedItem
|
||||
//@treturn Objects.ObjID Last item used in the inventory.
|
||||
static GAME_OBJECT_ID GetUsedItem()
|
||||
{
|
||||
return (GAME_OBJECT_ID)g_Gui.GetInventoryItemChosen();
|
||||
}
|
||||
|
||||
/// Set last item used in the player's inventory.
|
||||
// You will be able to specify only objects which already exist in the inventory.
|
||||
// Will only be valid for the next frame. If not processed by the game, Lara will say "No".
|
||||
//@function SetUsedItem
|
||||
//@tparam Objects.ObjID objectID Object ID of the item to select from inventory.
|
||||
static void SetUsedItem(GAME_OBJECT_ID objectID)
|
||||
{
|
||||
if (g_Gui.IsObjectInInventory(objectID))
|
||||
g_Gui.SetInventoryItemChosen(objectID);
|
||||
}
|
||||
|
||||
/// Clear last item used in the player's inventory.
|
||||
// When this function is used in OnUseItem level function, it allows to override existing item functionality.
|
||||
// For items without existing functionality, this function is needed to avoid Lara saying "No" after using it.
|
||||
//@function ClearUsedItem
|
||||
static void ClearUsedItem()
|
||||
{
|
||||
g_Gui.SetInventoryItemChosen(GAME_OBJECT_ID::ID_NO_OBJECT);
|
||||
}
|
||||
|
||||
void Register(sol::state* state, sol::table& parent)
|
||||
{
|
||||
auto tableInventory = sol::table{ state->lua_state(), sol::create };
|
||||
|
@ -68,5 +100,8 @@ namespace TEN::Scripting::InventoryHandler
|
|||
tableInventory.set_function(ScriptReserved_TakeInvItem, &TakeItem);
|
||||
tableInventory.set_function(ScriptReserved_GetInvItemCount, &GetItemCount);
|
||||
tableInventory.set_function(ScriptReserved_SetInvItemCount, &SetItemCount);
|
||||
tableInventory.set_function(ScriptReserved_SetUsedItem, &SetUsedItem);
|
||||
tableInventory.set_function(ScriptReserved_GetUsedItem, &GetUsedItem);
|
||||
tableInventory.set_function(ScriptReserved_ClearUsedItem, &ClearUsedItem);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,8 @@ static const std::unordered_map<std::string, EventType> EVENT_TYPES
|
|||
{ ScriptReserved_EventOnLoad, EventType::Load },
|
||||
{ ScriptReserved_EventOnSave, EventType::Save },
|
||||
{ ScriptReserved_EventOnStart, EventType::Start },
|
||||
{ ScriptReserved_EventOnEnd, EventType::End }
|
||||
{ ScriptReserved_EventOnEnd, EventType::End },
|
||||
{ ScriptReserved_EventOnUseItem, EventType::UseItem }
|
||||
};
|
||||
|
||||
enum class LevelEndReason
|
||||
|
@ -293,6 +294,7 @@ Possible event type values:
|
|||
START
|
||||
END
|
||||
LOOP
|
||||
USEITEM
|
||||
|
||||
@function HandleEvent
|
||||
@tparam string name Name of the event set to find.
|
||||
|
@ -457,6 +459,7 @@ void LogicHandler::FreeLevelScripts()
|
|||
m_onLoop = sol::nil;
|
||||
m_onSave = sol::nil;
|
||||
m_onEnd = sol::nil;
|
||||
m_onUseItem = sol::nil;
|
||||
m_handler.GetState()->collect_garbage();
|
||||
}
|
||||
|
||||
|
@ -999,6 +1002,12 @@ void LogicHandler::OnEnd(GameStatus reason)
|
|||
CallLevelFuncByName(name, endReason);
|
||||
}
|
||||
|
||||
void LogicHandler::OnUseItem(GAME_OBJECT_ID objectNumber)
|
||||
{
|
||||
if (m_onUseItem.valid())
|
||||
CallLevelFunc(m_onUseItem, objectNumber);
|
||||
}
|
||||
|
||||
/*** Special tables
|
||||
|
||||
TombEngine uses the following tables for specific things.
|
||||
|
@ -1142,4 +1151,5 @@ void LogicHandler::InitCallbacks()
|
|||
assignCB(m_onLoop, ScriptReserved_OnLoop);
|
||||
assignCB(m_onSave, ScriptReserved_OnSave);
|
||||
assignCB(m_onEnd, ScriptReserved_OnEnd);
|
||||
assignCB(m_onUseItem, ScriptReserved_OnUseItem);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ private:
|
|||
sol::protected_function m_onLoop{};
|
||||
sol::protected_function m_onSave{};
|
||||
sol::protected_function m_onEnd{};
|
||||
sol::protected_function m_onUseItem{};
|
||||
|
||||
std::unordered_set<std::string> m_callbacksPreSave;
|
||||
std::unordered_set<std::string> m_callbacksPostSave;
|
||||
|
@ -170,4 +171,5 @@ public:
|
|||
void OnLoop(float deltaTime, bool postLoop) override;
|
||||
void OnSave() override;
|
||||
void OnEnd(GameStatus reason) override;
|
||||
void OnUseItem(GAME_OBJECT_ID item) override;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue