mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
Merge branch 'MontyTRC89:develop' into develop
This commit is contained in:
commit
c3b4ecf9b6
80 changed files with 2295 additions and 1786 deletions
|
@ -20,7 +20,8 @@ This is the credit list of **all** the people who contributed to TombEngine in a
|
||||||
- TokyoSU (entity and vehicle decompilation)
|
- TokyoSU (entity and vehicle decompilation)
|
||||||
- Tomo (general coding, bug fixing)
|
- Tomo (general coding, bug fixing)
|
||||||
- Troye (general coding, refactoring)
|
- Troye (general coding, refactoring)
|
||||||
- WolfCheese (general coding)
|
- Nickelony (general coding)
|
||||||
|
- JesseG, aka WolfCheese (general coding)
|
||||||
|
|
||||||
## Testers
|
## Testers
|
||||||
- Adngel
|
- Adngel
|
||||||
|
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -25,6 +25,7 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
|
||||||
* Fixed sentry gun joint rotation.
|
* Fixed sentry gun joint rotation.
|
||||||
* Fixed teeth spikes not triggering the player impale animation.
|
* Fixed teeth spikes not triggering the player impale animation.
|
||||||
* Fixed TR4 mine crash with OCB 1 when triggered.
|
* Fixed TR4 mine crash with OCB 1 when triggered.
|
||||||
|
* Fixed cases where Atlantean mutant's bombs cause the game to crash.
|
||||||
|
|
||||||
### Features/Amendments
|
### Features/Amendments
|
||||||
* Changed Rome Hammer to not hurt player whilst deactivated.
|
* Changed Rome Hammer to not hurt player whilst deactivated.
|
||||||
|
@ -32,14 +33,25 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
|
||||||
* Enhaced Rolling Spindle detection to avoid them going down through pits.
|
* Enhaced Rolling Spindle detection to avoid them going down through pits.
|
||||||
* Enhaced Sentry Guns, with a new ItemFlags[3], to contain the ID of the inventory item that deactivates the sentry guns ( by default PUZZLE_ITEM5 )
|
* Enhaced Sentry Guns, with a new ItemFlags[3], to contain the ID of the inventory item that deactivates the sentry guns ( by default PUZZLE_ITEM5 )
|
||||||
* Enhaced Dart Emitter, with a new ItemFlags[0], to contain the number of frames between shots ( by default 32 in dart emitter, and 24 in homing dar emitter ).
|
* Enhaced Dart Emitter, with a new ItemFlags[0], to contain the number of frames between shots ( by default 32 in dart emitter, and 24 in homing dar emitter ).
|
||||||
* Add new sound conditions: quicksand and Underwater.
|
* Enhanced raptor behaviour and handling.
|
||||||
|
- OCB 0: Classic behaviour
|
||||||
|
- OCB 1: Can jump up/down up to 4 steps and jump across gaps up to 2 blocks wide.
|
||||||
|
- You must use the download version found on the TombEngine website.
|
||||||
|
* Added TR3 seal mutant.
|
||||||
|
- OCB 0: Normal enemy behaviour. (TR3 RX-Tech mines level)
|
||||||
|
- OCB 1: Trap like behaviour. (TR3 Antarctica level)
|
||||||
|
* Add new sound conditions: Quicksand and Underwater.
|
||||||
- Quicksand - sound effect plays when a moveable is in quicksand.
|
- Quicksand - sound effect plays when a moveable is in quicksand.
|
||||||
- Underwater - sound plays when the camera is submerged.
|
- Underwater - sound plays when the camera is submerged.
|
||||||
* Changed Water sound condition to ShallowWater.
|
* Changed Water sound condition to ShallowWater.
|
||||||
|
* Added option to enable or disable menu option looping.
|
||||||
|
* Menu scrolling using held inputs will stop at the last option until a new input is made.
|
||||||
|
* Added the ability to display "Lara's Home" entry in the main menu.
|
||||||
|
|
||||||
### Lua API changes
|
### Lua API changes
|
||||||
* Added Inventory.GetUsedItem(), Inventory.SetUsedItem() and Inventory.ClearUsedItem() functions.
|
* Added Inventory.GetUsedItem(), Inventory.SetUsedItem() and Inventory.ClearUsedItem() functions.
|
||||||
* Added Input.KeyClearAll()
|
* Added Input.KeyClearAll()
|
||||||
|
* Added Flow.EnableHomeLevel()
|
||||||
* Removed anims.monkeyAutoJump. It is now a player menu configuration.
|
* Removed anims.monkeyAutoJump. It is now a player menu configuration.
|
||||||
* Fixed Volume:GetActive() method
|
* Fixed Volume:GetActive() method
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,10 @@ scripts too.</p>
|
||||||
<td class="summary">Enable or disable level selection in title flyby.</td>
|
<td class="summary">Enable or disable level selection in title flyby.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td class="name" ><a href="#EnableHomeLevel">EnableHomeLevel(enabled)</a></td>
|
||||||
|
<td class="summary">Enable or disable Home Level entry in the main menu.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td class="name" ><a href="#EnableLoadSave">EnableLoadSave(enabled)</a></td>
|
<td class="name" ><a href="#EnableLoadSave">EnableLoadSave(enabled)</a></td>
|
||||||
<td class="summary">Enable or disable saving and loading of savegames.</td>
|
<td class="summary">Enable or disable saving and loading of savegames.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -361,6 +365,28 @@ Must be true or false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "EnableHomeLevel"></a>
|
||||||
|
<strong>EnableHomeLevel(enabled)</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
Enable or disable Home Level entry in the main menu.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Parameters:</h3>
|
||||||
|
<ul>
|
||||||
|
<li><span class="parameter">enabled</span>
|
||||||
|
<span class="types"><span class="type">bool</span></span>
|
||||||
|
true or false.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
<a name = "EnableLoadSave"></a>
|
<a name = "EnableLoadSave"></a>
|
||||||
|
|
|
@ -357,7 +357,7 @@ WASP_MUTANT
|
||||||
SKATEBOARD
|
SKATEBOARD
|
||||||
SKATEBOARD_KID
|
SKATEBOARD_KID
|
||||||
WINSTON
|
WINSTON
|
||||||
ARMY_WINSTON
|
SEAL_MUTANT
|
||||||
SPRINGBOARD
|
SPRINGBOARD
|
||||||
ROLLING_SPINDLE
|
ROLLING_SPINDLE
|
||||||
DISK_SHOOTER
|
DISK_SHOOTER
|
||||||
|
@ -943,6 +943,7 @@ MESHSWAP_ROMAN_GOD1
|
||||||
MESHSWAP_ROMAN_GOD2
|
MESHSWAP_ROMAN_GOD2
|
||||||
MESHSWAP_MONKEY_MEDIPACK
|
MESHSWAP_MONKEY_MEDIPACK
|
||||||
MESHSWAP_MONKEY_KEY
|
MESHSWAP_MONKEY_KEY
|
||||||
|
MESHSWAP_WINSTON_ARMY_OUTFIT
|
||||||
ANIMATING1
|
ANIMATING1
|
||||||
ANIMATING2
|
ANIMATING2
|
||||||
ANIMATING3
|
ANIMATING3
|
||||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 TombEngine Team
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -58,7 +58,7 @@ local strings =
|
||||||
|
|
||||||
-- Level name strings
|
-- Level name strings
|
||||||
|
|
||||||
lara_home = { "Lara's Home" },
|
home_level = { "Home Level" },
|
||||||
test_level = { "Test Level" },
|
test_level = { "Test Level" },
|
||||||
title = { "Title" },
|
title = { "Title" },
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,11 @@ local strings =
|
||||||
low = { "Low" },
|
low = { "Low" },
|
||||||
medium = { "Medium" },
|
medium = { "Medium" },
|
||||||
menu_actions = { "Menu Actions" },
|
menu_actions = { "Menu Actions" },
|
||||||
|
menu_option_looping = { "Menu Option Looping" },
|
||||||
|
menu_option_looping_all_menus = { "All Menus" },
|
||||||
|
menu_option_looping_disabled = { "Disabled" },
|
||||||
|
menu_option_looping_save_load_only = { "Save/Load Only" },
|
||||||
mouse_sensitivity = { "Mouse Sensitivity" },
|
mouse_sensitivity = { "Mouse Sensitivity" },
|
||||||
mouse_smoothing = { "Mouse Smoothing" },
|
|
||||||
music_volume = { "Music Volume" },
|
music_volume = { "Music Volume" },
|
||||||
new_game = { "New Game" },
|
new_game = { "New Game" },
|
||||||
none = { "None" },
|
none = { "None" },
|
||||||
|
|
|
@ -166,7 +166,7 @@ void LookCamera(ItemInfo& item, const CollisionInfo& coll)
|
||||||
bool isInSwamp = TestEnvironment(ENV_FLAG_SWAMP, item.RoomNumber);
|
bool isInSwamp = TestEnvironment(ENV_FLAG_SWAMP, item.RoomNumber);
|
||||||
auto basePos = Vector3i(
|
auto basePos = Vector3i(
|
||||||
item.Pose.Position.x,
|
item.Pose.Position.x,
|
||||||
isInSwamp ? g_Level.Rooms[item.RoomNumber].maxceiling : item.Pose.Position.y,
|
isInSwamp ? g_Level.Rooms[item.RoomNumber].TopHeight : item.Pose.Position.y,
|
||||||
item.Pose.Position.z);
|
item.Pose.Position.z);
|
||||||
|
|
||||||
// Define landmarks.
|
// Define landmarks.
|
||||||
|
@ -343,7 +343,7 @@ void MoveCamera(GameVector* ideal, int speed)
|
||||||
|
|
||||||
int y = Camera.pos.y;
|
int y = Camera.pos.y;
|
||||||
if (TestEnvironment(ENV_FLAG_SWAMP, Camera.pos.RoomNumber))
|
if (TestEnvironment(ENV_FLAG_SWAMP, Camera.pos.RoomNumber))
|
||||||
y = g_Level.Rooms[Camera.pos.RoomNumber].y - CLICK(1);
|
y = g_Level.Rooms[Camera.pos.RoomNumber].Position.y - CLICK(1);
|
||||||
|
|
||||||
auto pointColl = GetPointCollision(Vector3i(Camera.pos.x, y, Camera.pos.z), Camera.pos.RoomNumber);
|
auto pointColl = GetPointCollision(Vector3i(Camera.pos.x, y, Camera.pos.z), Camera.pos.RoomNumber);
|
||||||
if (y < pointColl.GetCeilingHeight() ||
|
if (y < pointColl.GetCeilingHeight() ||
|
||||||
|
@ -534,7 +534,7 @@ void ChaseCamera(ItemInfo* item)
|
||||||
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z), Camera.target.RoomNumber);
|
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z), Camera.target.RoomNumber);
|
||||||
|
|
||||||
if (TestEnvironment(ENV_FLAG_SWAMP, pointColl.GetRoomNumber()))
|
if (TestEnvironment(ENV_FLAG_SWAMP, pointColl.GetRoomNumber()))
|
||||||
Camera.target.y = g_Level.Rooms[pointColl.GetRoomNumber()].maxceiling - CLICK(1);
|
Camera.target.y = g_Level.Rooms[pointColl.GetRoomNumber()].TopHeight - CLICK(1);
|
||||||
|
|
||||||
int y = Camera.target.y;
|
int y = Camera.target.y;
|
||||||
pointColl = GetPointCollision(Vector3i(Camera.target.x, y, Camera.target.z), Camera.target.RoomNumber);
|
pointColl = GetPointCollision(Vector3i(Camera.target.x, y, Camera.target.z), Camera.target.RoomNumber);
|
||||||
|
@ -652,7 +652,7 @@ void CombatCamera(ItemInfo* item)
|
||||||
|
|
||||||
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z), Camera.target.RoomNumber);
|
auto pointColl = GetPointCollision(Vector3i(Camera.target.x, Camera.target.y + CLICK(1), Camera.target.z), Camera.target.RoomNumber);
|
||||||
if (TestEnvironment(ENV_FLAG_SWAMP, pointColl.GetRoomNumber()))
|
if (TestEnvironment(ENV_FLAG_SWAMP, pointColl.GetRoomNumber()))
|
||||||
Camera.target.y = g_Level.Rooms[pointColl.GetRoomNumber()].y - CLICK(1);
|
Camera.target.y = g_Level.Rooms[pointColl.GetRoomNumber()].Position.y - CLICK(1);
|
||||||
|
|
||||||
pointColl = GetPointCollision(Camera.target.ToVector3i(), Camera.target.RoomNumber);
|
pointColl = GetPointCollision(Camera.target.ToVector3i(), Camera.target.RoomNumber);
|
||||||
Camera.target.RoomNumber = pointColl.GetRoomNumber();
|
Camera.target.RoomNumber = pointColl.GetRoomNumber();
|
||||||
|
@ -1393,7 +1393,7 @@ bool CheckItemCollideCamera(ItemInfo* item)
|
||||||
static std::vector<int> FillCollideableItemList()
|
static std::vector<int> FillCollideableItemList()
|
||||||
{
|
{
|
||||||
auto itemList = std::vector<int>{};
|
auto itemList = std::vector<int>{};
|
||||||
auto& roomList = g_Level.Rooms[Camera.pos.RoomNumber].neighbors;
|
auto& roomList = g_Level.Rooms[Camera.pos.RoomNumber].NeighborRoomNumbers;
|
||||||
|
|
||||||
for (short i = 0; i < g_Level.NumItems; i++)
|
for (short i = 0; i < g_Level.NumItems; i++)
|
||||||
{
|
{
|
||||||
|
@ -1443,7 +1443,7 @@ bool CheckStaticCollideCamera(MESH_INFO* mesh)
|
||||||
std::vector<MESH_INFO*> FillCollideableStaticsList()
|
std::vector<MESH_INFO*> FillCollideableStaticsList()
|
||||||
{
|
{
|
||||||
std::vector<MESH_INFO*> staticList;
|
std::vector<MESH_INFO*> staticList;
|
||||||
auto& roomList = g_Level.Rooms[Camera.pos.RoomNumber].neighbors;
|
auto& roomList = g_Level.Rooms[Camera.pos.RoomNumber].NeighborRoomNumbers;
|
||||||
|
|
||||||
for (int i : roomList)
|
for (int i : roomList)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace TEN::Collision::Point
|
||||||
int roomNumber = roomNumberBelow.value_or(bottomSector->RoomNumber);
|
int roomNumber = roomNumberBelow.value_or(bottomSector->RoomNumber);
|
||||||
auto& room = g_Level.Rooms[roomNumber];
|
auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
bottomSector = Room::GetSector(&room, _position.x - room.x, _position.z - room.z);
|
bottomSector = Room::GetSector(&room, _position.x - room.Position.x, _position.z - room.Position.z);
|
||||||
roomNumberBelow = bottomSector->GetNextRoomNumber(_position, true);
|
roomNumberBelow = bottomSector->GetNextRoomNumber(_position, true);
|
||||||
}
|
}
|
||||||
_bottomSector = bottomSector;
|
_bottomSector = bottomSector;
|
||||||
|
@ -78,7 +78,7 @@ namespace TEN::Collision::Point
|
||||||
int roomNumber = roomNumberAbove.value_or(topSector->RoomNumber);
|
int roomNumber = roomNumberAbove.value_or(topSector->RoomNumber);
|
||||||
auto& room = g_Level.Rooms[roomNumber];
|
auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
topSector = Room::GetSector(&room, _position.x - room.x, _position.z - room.z);
|
topSector = Room::GetSector(&room, _position.x - room.Position.x, _position.z - room.Position.z);
|
||||||
roomNumberAbove = topSector->GetNextRoomNumber(_position, false);
|
roomNumberAbove = topSector->GetNextRoomNumber(_position, false);
|
||||||
}
|
}
|
||||||
_topSector = topSector;
|
_topSector = topSector;
|
||||||
|
|
|
@ -123,7 +123,7 @@ CollidedObjectData GetCollidedObjects(ItemInfo& collidingItem, bool onlyVisible,
|
||||||
|
|
||||||
// Run through neighboring rooms.
|
// Run through neighboring rooms.
|
||||||
const auto& room = g_Level.Rooms[collidingItem.RoomNumber];
|
const auto& room = g_Level.Rooms[collidingItem.RoomNumber];
|
||||||
for (int roomNumber : room.neighbors)
|
for (int roomNumber : room.NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
auto& neighborRoom = g_Level.Rooms[roomNumber];
|
auto& neighborRoom = g_Level.Rooms[roomNumber];
|
||||||
if (!neighborRoom.Active())
|
if (!neighborRoom.Active())
|
||||||
|
@ -307,7 +307,7 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
// DrawDebugSphere(origin, 16, Vector4::One, RendererDebugPage::CollisionStats);
|
// DrawDebugSphere(origin, 16, Vector4::One, RendererDebugPage::CollisionStats);
|
||||||
|
|
||||||
for (auto i : g_Level.Rooms[item->RoomNumber].neighbors)
|
for (auto i : g_Level.Rooms[item->RoomNumber].NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
if (!g_Level.Rooms[i].Active())
|
if (!g_Level.Rooms[i].Active())
|
||||||
continue;
|
continue;
|
||||||
|
@ -940,7 +940,7 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
coll->HitTallObject = false;
|
coll->HitTallObject = false;
|
||||||
|
|
||||||
for (auto i : g_Level.Rooms[item->RoomNumber].neighbors)
|
for (auto i : g_Level.Rooms[item->RoomNumber].NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
if (!g_Level.Rooms[i].Active())
|
if (!g_Level.Rooms[i].Active())
|
||||||
continue;
|
continue;
|
||||||
|
@ -1809,7 +1809,7 @@ void DoObjectCollision(ItemInfo* item, CollisionInfo* coll)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto& room = g_Level.Rooms[item->RoomNumber];
|
const auto& room = g_Level.Rooms[item->RoomNumber];
|
||||||
for (int neighborRoomNumber : room.neighbors)
|
for (int neighborRoomNumber : room.NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
||||||
if (!neighborRoom.Active())
|
if (!neighborRoom.Active())
|
||||||
|
|
|
@ -1084,7 +1084,7 @@ int GetDistanceToFloor(int itemNumber, bool precise)
|
||||||
int GetWaterSurface(int x, int y, int z, short roomNumber)
|
int GetWaterSurface(int x, int y, int z, short roomNumber)
|
||||||
{
|
{
|
||||||
auto* room = &g_Level.Rooms[roomNumber];
|
auto* room = &g_Level.Rooms[roomNumber];
|
||||||
auto* sector = GetSector(room, x - room->x, z - room->z);
|
auto* sector = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
|
|
||||||
if (TestEnvironment(ENV_FLAG_WATER, room))
|
if (TestEnvironment(ENV_FLAG_WATER, room))
|
||||||
{
|
{
|
||||||
|
@ -1094,7 +1094,7 @@ int GetWaterSurface(int x, int y, int z, short roomNumber)
|
||||||
if (!TestEnvironment(ENV_FLAG_WATER, room))
|
if (!TestEnvironment(ENV_FLAG_WATER, room))
|
||||||
return (sector->GetSurfaceHeight(x, z, false));
|
return (sector->GetSurfaceHeight(x, z, false));
|
||||||
|
|
||||||
sector = GetSector(room, x - room->x, z - room->z);
|
sector = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_HEIGHT;
|
return NO_HEIGHT;
|
||||||
|
@ -1107,7 +1107,7 @@ int GetWaterSurface(int x, int y, int z, short roomNumber)
|
||||||
if (TestEnvironment(ENV_FLAG_WATER, room))
|
if (TestEnvironment(ENV_FLAG_WATER, room))
|
||||||
return (sector->GetSurfaceHeight(x, z, true));
|
return (sector->GetSurfaceHeight(x, z, true));
|
||||||
|
|
||||||
sector = GetSector(room, x - room->x, z - room->z);
|
sector = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1127,8 +1127,8 @@ int GetWaterDepth(int x, int y, int z, short roomNumber)
|
||||||
int adjoiningRoomNumber = NO_VALUE;
|
int adjoiningRoomNumber = NO_VALUE;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int xFloor = (x - room->x) / BLOCK(1);
|
int xFloor = (x - room->Position.x) / BLOCK(1);
|
||||||
int zFloor = (z - room->z) / BLOCK(1);
|
int zFloor = (z - room->Position.z) / BLOCK(1);
|
||||||
|
|
||||||
if (zFloor <= 0)
|
if (zFloor <= 0)
|
||||||
{
|
{
|
||||||
|
@ -1137,33 +1137,33 @@ int GetWaterDepth(int x, int y, int z, short roomNumber)
|
||||||
{
|
{
|
||||||
xFloor = 1;
|
xFloor = 1;
|
||||||
}
|
}
|
||||||
else if (xFloor > (room->xSize - 2))
|
else if (xFloor > (room->XSize - 2))
|
||||||
{
|
{
|
||||||
xFloor = room->xSize - 2;
|
xFloor = room->XSize - 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (zFloor >= (room->zSize - 1))
|
else if (zFloor >= (room->ZSize - 1))
|
||||||
{
|
{
|
||||||
zFloor = room->zSize - 1;
|
zFloor = room->ZSize - 1;
|
||||||
if (xFloor < 1)
|
if (xFloor < 1)
|
||||||
{
|
{
|
||||||
xFloor = 1;
|
xFloor = 1;
|
||||||
}
|
}
|
||||||
else if (xFloor > (room->xSize - 2))
|
else if (xFloor > (room->XSize - 2))
|
||||||
{
|
{
|
||||||
xFloor = room->xSize - 2;
|
xFloor = room->XSize - 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (xFloor < 0)
|
else if (xFloor < 0)
|
||||||
{
|
{
|
||||||
xFloor = 0;
|
xFloor = 0;
|
||||||
}
|
}
|
||||||
else if (xFloor >= room->xSize)
|
else if (xFloor >= room->XSize)
|
||||||
{
|
{
|
||||||
xFloor = room->xSize - 1;
|
xFloor = room->XSize - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sector = &room->floor[zFloor + (xFloor * room->zSize)];
|
sector = &room->Sectors[zFloor + (xFloor * room->ZSize)];
|
||||||
adjoiningRoomNumber = sector->SidePortalRoomNumber;
|
adjoiningRoomNumber = sector->SidePortalRoomNumber;
|
||||||
if (adjoiningRoomNumber != NO_VALUE)
|
if (adjoiningRoomNumber != NO_VALUE)
|
||||||
{
|
{
|
||||||
|
@ -1188,7 +1188,7 @@ int GetWaterDepth(int x, int y, int z, short roomNumber)
|
||||||
return (floorHeight - waterHeight);
|
return (floorHeight - waterHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
sector = GetSector(room, x - room->x, z - room->z);
|
sector = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return DEEP_WATER;
|
return DEEP_WATER;
|
||||||
|
@ -1207,7 +1207,7 @@ int GetWaterDepth(int x, int y, int z, short roomNumber)
|
||||||
return (GetFloorHeight(sector, x, y, z) - waterHeight);
|
return (GetFloorHeight(sector, x, y, z) - waterHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
sector = GetSector(room, x - room->x, z - room->z);
|
sector = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NO_HEIGHT;
|
return NO_HEIGHT;
|
||||||
|
@ -1227,8 +1227,8 @@ int GetWaterHeight(int x, int y, int z, short roomNumber)
|
||||||
int adjoiningRoomNumber = NO_VALUE;
|
int adjoiningRoomNumber = NO_VALUE;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int xBlock = (x - room->x) / BLOCK(1);
|
int xBlock = (x - room->Position.x) / BLOCK(1);
|
||||||
int zBlock = (z - room->z) / BLOCK(1);
|
int zBlock = (z - room->Position.z) / BLOCK(1);
|
||||||
|
|
||||||
if (zBlock <= 0)
|
if (zBlock <= 0)
|
||||||
{
|
{
|
||||||
|
@ -1237,33 +1237,33 @@ int GetWaterHeight(int x, int y, int z, short roomNumber)
|
||||||
{
|
{
|
||||||
xBlock = 1;
|
xBlock = 1;
|
||||||
}
|
}
|
||||||
else if (xBlock > (room->xSize - 2))
|
else if (xBlock > (room->XSize - 2))
|
||||||
{
|
{
|
||||||
xBlock = room->xSize - 2;
|
xBlock = room->XSize - 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (zBlock >= (room->zSize - 1))
|
else if (zBlock >= (room->ZSize - 1))
|
||||||
{
|
{
|
||||||
zBlock = room->zSize - 1;
|
zBlock = room->ZSize - 1;
|
||||||
if (xBlock < 1)
|
if (xBlock < 1)
|
||||||
{
|
{
|
||||||
xBlock = 1;
|
xBlock = 1;
|
||||||
}
|
}
|
||||||
else if (xBlock > (room->xSize - 2))
|
else if (xBlock > (room->XSize - 2))
|
||||||
{
|
{
|
||||||
xBlock = room->xSize - 2;
|
xBlock = room->XSize - 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (xBlock < 0)
|
else if (xBlock < 0)
|
||||||
{
|
{
|
||||||
xBlock = 0;
|
xBlock = 0;
|
||||||
}
|
}
|
||||||
else if (xBlock >= room->xSize)
|
else if (xBlock >= room->XSize)
|
||||||
{
|
{
|
||||||
xBlock = room->xSize - 1;
|
xBlock = room->XSize - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sector = &room->floor[zBlock + (xBlock * room->zSize)];
|
sector = &room->Sectors[zBlock + (xBlock * room->ZSize)];
|
||||||
adjoiningRoomNumber = sector->SidePortalRoomNumber;
|
adjoiningRoomNumber = sector->SidePortalRoomNumber;
|
||||||
|
|
||||||
if (adjoiningRoomNumber != NO_VALUE)
|
if (adjoiningRoomNumber != NO_VALUE)
|
||||||
|
@ -1290,7 +1290,7 @@ int GetWaterHeight(int x, int y, int z, short roomNumber)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sector = GetSector(room, x - room->x, z - room->z);
|
sector = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sector->GetSurfaceHeight(Vector3i(x, y, z), false);
|
return sector->GetSurfaceHeight(Vector3i(x, y, z), false);
|
||||||
|
@ -1307,7 +1307,7 @@ int GetWaterHeight(int x, int y, int z, short roomNumber)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sector = GetSector(room2, x - room2->x, z - room2->z);
|
sector = GetSector(room2, x - room2->Position.x, z - room2->Position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sector->GetSurfaceHeight(Vector3i(x, y, z), true);
|
return sector->GetSurfaceHeight(Vector3i(x, y, z), true);
|
||||||
|
|
|
@ -368,17 +368,17 @@ namespace TEN::Collision::Floordata
|
||||||
const auto& room = g_Level.Rooms[roomNumber];
|
const auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
// Calculate room grid coord.
|
// Calculate room grid coord.
|
||||||
auto roomGridCoord = Vector2i((x - room.x) / BLOCK(1), (z - room.z) / BLOCK(1));
|
auto roomGridCoord = Vector2i((x - room.Position.x) / BLOCK(1), (z - room.Position.z) / BLOCK(1));
|
||||||
if (x < room.x)
|
if (x < room.Position.x)
|
||||||
roomGridCoord.x -= 1;
|
roomGridCoord.x -= 1;
|
||||||
if (z < room.z)
|
if (z < room.Position.z)
|
||||||
roomGridCoord.y -= 1;
|
roomGridCoord.y -= 1;
|
||||||
|
|
||||||
// Clamp room grid coord to room bounds (if applicable).
|
// Clamp room grid coord to room bounds (if applicable).
|
||||||
if (clampToBounds)
|
if (clampToBounds)
|
||||||
{
|
{
|
||||||
roomGridCoord.x = std::clamp(roomGridCoord.x, 0, room.xSize - 1);
|
roomGridCoord.x = std::clamp(roomGridCoord.x, 0, room.XSize - 1);
|
||||||
roomGridCoord.y = std::clamp(roomGridCoord.y, 0, room.zSize - 1);
|
roomGridCoord.y = std::clamp(roomGridCoord.y, 0, room.ZSize - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return roomGridCoord;
|
return roomGridCoord;
|
||||||
|
@ -397,8 +397,8 @@ namespace TEN::Collision::Floordata
|
||||||
const auto& room = g_Level.Rooms[roomNumber];
|
const auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
// Search area out of range; return empty vector.
|
// Search area out of range; return empty vector.
|
||||||
if (xMax <= 0 || xMin >= (room.xSize - 1) ||
|
if (xMax <= 0 || xMin >= (room.XSize - 1) ||
|
||||||
xMax <= 0 || xMin >= (room.xSize - 1))
|
xMax <= 0 || xMin >= (room.XSize - 1))
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -408,13 +408,13 @@ namespace TEN::Collision::Floordata
|
||||||
for (int x = xMin; x <= xMax; x++)
|
for (int x = xMin; x <= xMax; x++)
|
||||||
{
|
{
|
||||||
// Test if out of room X range.
|
// Test if out of room X range.
|
||||||
if (x <= 0 || x >= (room.xSize - 1))
|
if (x <= 0 || x >= (room.XSize - 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int z = zMin; z <= zMax; z++)
|
for (int z = zMin; z <= zMax; z++)
|
||||||
{
|
{
|
||||||
// Test if out of room Z range.
|
// Test if out of room Z range.
|
||||||
if (z <= 0 || z >= (room.zSize - 1))
|
if (z <= 0 || z >= (room.ZSize - 1))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
roomGridCoords.push_back(Vector2i(x, z));
|
roomGridCoords.push_back(Vector2i(x, z));
|
||||||
|
@ -430,7 +430,7 @@ namespace TEN::Collision::Floordata
|
||||||
|
|
||||||
// Run through neighbor rooms.
|
// Run through neighbor rooms.
|
||||||
auto& room = g_Level.Rooms[roomNumber];
|
auto& room = g_Level.Rooms[roomNumber];
|
||||||
for (int neighborRoomNumber : room.neighbors)
|
for (int neighborRoomNumber : room.NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
// Collect neighbor sectors.
|
// Collect neighbor sectors.
|
||||||
auto roomGridCoords = GetNeighborRoomGridCoords(pos, neighborRoomNumber, searchDepth);
|
auto roomGridCoords = GetNeighborRoomGridCoords(pos, neighborRoomNumber, searchDepth);
|
||||||
|
@ -446,8 +446,8 @@ namespace TEN::Collision::Floordata
|
||||||
{
|
{
|
||||||
auto& room = g_Level.Rooms[roomNumber];
|
auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
int sectorID = (room.zSize * roomGridCoord.x) + roomGridCoord.y;
|
int sectorID = (room.ZSize * roomGridCoord.x) + roomGridCoord.y;
|
||||||
return room.floor[sectorID];
|
return room.Sectors[sectorID];
|
||||||
}
|
}
|
||||||
|
|
||||||
FloorInfo& GetFloor(int roomNumber, int x, int z)
|
FloorInfo& GetFloor(int roomNumber, int x, int z)
|
||||||
|
@ -831,18 +831,18 @@ namespace TEN::Collision::Floordata
|
||||||
const auto& room = g_Level.Rooms[item.RoomNumber];
|
const auto& room = g_Level.Rooms[item.RoomNumber];
|
||||||
|
|
||||||
// Get projected AABB min and max of bridge OBB.
|
// Get projected AABB min and max of bridge OBB.
|
||||||
float xMin = floor((std::min(std::min(std::min(corners[0].x, corners[1].x), corners[4].x), corners[5].x) - room.x) / BLOCK(1));
|
float xMin = floor((std::min(std::min(std::min(corners[0].x, corners[1].x), corners[4].x), corners[5].x) - room.Position.x) / BLOCK(1));
|
||||||
float zMin = floor((std::min(std::min(std::min(corners[0].z, corners[1].z), corners[4].z), corners[5].z) - room.z) / BLOCK(1));
|
float zMin = floor((std::min(std::min(std::min(corners[0].z, corners[1].z), corners[4].z), corners[5].z) - room.Position.z) / BLOCK(1));
|
||||||
float xMax = ceil((std::max(std::max(std::max(corners[0].x, corners[1].x), corners[4].x), corners[5].x) - room.x) / BLOCK(1));
|
float xMax = ceil((std::max(std::max(std::max(corners[0].x, corners[1].x), corners[4].x), corners[5].x) - room.Position.x) / BLOCK(1));
|
||||||
float zMax = ceil((std::max(std::max(std::max(corners[0].z, corners[1].z), corners[4].z), corners[5].z) - room.z) / BLOCK(1));
|
float zMax = ceil((std::max(std::max(std::max(corners[0].z, corners[1].z), corners[4].z), corners[5].z) - room.Position.z) / BLOCK(1));
|
||||||
|
|
||||||
// Run through sectors enclosed in projected bridge AABB.
|
// Run through sectors enclosed in projected bridge AABB.
|
||||||
for (int x = 0; x < room.xSize; x++)
|
for (int x = 0; x < room.XSize; x++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < room.zSize; z++)
|
for (int z = 0; z < room.ZSize; z++)
|
||||||
{
|
{
|
||||||
float pX = (room.x + BLOCK(x)) + BLOCK(0.5f);
|
float pX = (room.Position.x + BLOCK(x)) + BLOCK(0.5f);
|
||||||
float pZ = (room.z + BLOCK(z)) + BLOCK(0.5f);
|
float pZ = (room.Position.z + BLOCK(z)) + BLOCK(0.5f);
|
||||||
float offX = pX - item.Pose.Position.x;
|
float offX = pX - item.Pose.Position.x;
|
||||||
float offZ = pZ - item.Pose.Position.z;
|
float offZ = pZ - item.Pose.Position.z;
|
||||||
|
|
||||||
|
@ -911,7 +911,7 @@ namespace TEN::Collision::Floordata
|
||||||
|
|
||||||
// Run through neighboring rooms.
|
// Run through neighboring rooms.
|
||||||
const auto& room = g_Level.Rooms[item.RoomNumber];
|
const auto& room = g_Level.Rooms[item.RoomNumber];
|
||||||
for (int neighborRoomNumber : room.neighbors)
|
for (int neighborRoomNumber : room.NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
const auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
const auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
||||||
|
|
||||||
|
@ -919,8 +919,8 @@ namespace TEN::Collision::Floordata
|
||||||
auto roomGridCoords = GetNeighborRoomGridCoords(item.Pose.Position, neighborRoomNumber, SECTOR_SEARCH_DEPTH);
|
auto roomGridCoords = GetNeighborRoomGridCoords(item.Pose.Position, neighborRoomNumber, SECTOR_SEARCH_DEPTH);
|
||||||
for (const auto& roomGridCoord : roomGridCoords)
|
for (const auto& roomGridCoord : roomGridCoords)
|
||||||
{
|
{
|
||||||
pos.x = BLOCK(roomGridCoord.x) + neighborRoom.x;
|
pos.x = BLOCK(roomGridCoord.x) + neighborRoom.Position.x;
|
||||||
pos.z = BLOCK(roomGridCoord.y) + neighborRoom.z;
|
pos.z = BLOCK(roomGridCoord.y) + neighborRoom.Position.z;
|
||||||
|
|
||||||
pointColl = GetPointCollision(pos, neighborRoomNumber);
|
pointColl = GetPointCollision(pos, neighborRoomNumber);
|
||||||
pos.y = pointColl.GetFloorHeight();
|
pos.y = pointColl.GetFloorHeight();
|
||||||
|
|
|
@ -154,13 +154,13 @@ bool SameZone(CreatureInfo* creature, ItemInfo* target)
|
||||||
auto* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
auto* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
||||||
|
|
||||||
auto& roomSource = g_Level.Rooms[item.RoomNumber];
|
auto& roomSource = g_Level.Rooms[item.RoomNumber];
|
||||||
auto& boxSource = GetSector(&roomSource, item.Pose.Position.x - roomSource.x, item.Pose.Position.z - roomSource.z)->PathfindingBoxID;
|
auto& boxSource = GetSector(&roomSource, item.Pose.Position.x - roomSource.Position.x, item.Pose.Position.z - roomSource.Position.z)->PathfindingBoxID;
|
||||||
if (boxSource == NO_VALUE)
|
if (boxSource == NO_VALUE)
|
||||||
return false;
|
return false;
|
||||||
item.BoxNumber = boxSource;
|
item.BoxNumber = boxSource;
|
||||||
|
|
||||||
auto& roomTarget = g_Level.Rooms[target->RoomNumber];
|
auto& roomTarget = g_Level.Rooms[target->RoomNumber];
|
||||||
auto& boxTarget = GetSector(&roomTarget, target->Pose.Position.x - roomTarget.x, target->Pose.Position.z - roomTarget.z)->PathfindingBoxID;
|
auto& boxTarget = GetSector(&roomTarget, target->Pose.Position.x - roomTarget.Position.x, target->Pose.Position.z - roomTarget.Position.z)->PathfindingBoxID;
|
||||||
if (boxTarget == NO_VALUE)
|
if (boxTarget == NO_VALUE)
|
||||||
return false;
|
return false;
|
||||||
target->BoxNumber = boxTarget;
|
target->BoxNumber = boxTarget;
|
||||||
|
@ -1460,9 +1460,9 @@ void FindAITargetObject(CreatureInfo* creature, int objectNumber, int ocb, bool
|
||||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
int* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
||||||
auto* room = &g_Level.Rooms[item.RoomNumber];
|
auto* room = &g_Level.Rooms[item.RoomNumber];
|
||||||
|
|
||||||
item.BoxNumber = GetSector(room, item.Pose.Position.x - room->x, item.Pose.Position.z - room->z)->PathfindingBoxID;
|
item.BoxNumber = GetSector(room, item.Pose.Position.x - room->Position.x, item.Pose.Position.z - room->Position.z)->PathfindingBoxID;
|
||||||
room = &g_Level.Rooms[aiObject.roomNumber];
|
room = &g_Level.Rooms[aiObject.roomNumber];
|
||||||
aiObject.boxNumber = GetSector(room, aiObject.pos.Position.x - room->x, aiObject.pos.Position.z - room->z)->PathfindingBoxID;
|
aiObject.boxNumber = GetSector(room, aiObject.pos.Position.x - room->Position.x, aiObject.pos.Position.z - room->Position.z)->PathfindingBoxID;
|
||||||
|
|
||||||
if (item.BoxNumber == NO_VALUE || aiObject.boxNumber == NO_VALUE)
|
if (item.BoxNumber == NO_VALUE || aiObject.boxNumber == NO_VALUE)
|
||||||
return;
|
return;
|
||||||
|
@ -1504,7 +1504,7 @@ int TargetReachable(ItemInfo* item, ItemInfo* enemy)
|
||||||
{
|
{
|
||||||
const auto& creature = *GetCreatureInfo(item);
|
const auto& creature = *GetCreatureInfo(item);
|
||||||
auto& room = g_Level.Rooms[enemy->RoomNumber];
|
auto& room = g_Level.Rooms[enemy->RoomNumber];
|
||||||
auto* floor = GetSector(&room, enemy->Pose.Position.x - room.x, enemy->Pose.Position.z - room.z);
|
auto* floor = GetSector(&room, enemy->Pose.Position.x - room.Position.x, enemy->Pose.Position.z - room.Position.z);
|
||||||
|
|
||||||
// NEW: Only update enemy box number if it is actually reachable by the enemy.
|
// NEW: Only update enemy box number if it is actually reachable by the enemy.
|
||||||
// This prevents enemies from running to the player and attacking nothing when they are hanging or shimmying. -- Lwmte, 27.06.22
|
// This prevents enemies from running to the player and attacking nothing when they are hanging or shimmying. -- Lwmte, 27.06.22
|
||||||
|
@ -1545,7 +1545,7 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI)
|
||||||
auto* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
auto* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
||||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||||
|
|
||||||
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->PathfindingBoxID;
|
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->Position.x, item->Pose.Position.z - room->Position.z)->PathfindingBoxID;
|
||||||
AI->zoneNumber = zone[item->BoxNumber];
|
AI->zoneNumber = zone[item->BoxNumber];
|
||||||
|
|
||||||
enemy->BoxNumber = TargetReachable(item, enemy);
|
enemy->BoxNumber = TargetReachable(item, enemy);
|
||||||
|
@ -2129,14 +2129,14 @@ void AdjustStopperFlag(ItemInfo* item, int direction)
|
||||||
int z = item->Pose.Position.z;
|
int z = item->Pose.Position.z;
|
||||||
|
|
||||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||||
auto* floor = GetSector(room, x - room->x, z - room->z);
|
auto* floor = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
floor->Stopper = !floor->Stopper;
|
floor->Stopper = !floor->Stopper;
|
||||||
|
|
||||||
x = item->Pose.Position.x + BLOCK(1) * phd_sin(direction);
|
x = item->Pose.Position.x + BLOCK(1) * phd_sin(direction);
|
||||||
z = item->Pose.Position.z + BLOCK(1) * phd_cos(direction);
|
z = item->Pose.Position.z + BLOCK(1) * phd_cos(direction);
|
||||||
room = &g_Level.Rooms[GetPointCollision(Vector3i(x, item->Pose.Position.y, z), item->RoomNumber).GetRoomNumber()];
|
room = &g_Level.Rooms[GetPointCollision(Vector3i(x, item->Pose.Position.y, z), item->RoomNumber).GetRoomNumber()];
|
||||||
|
|
||||||
floor = GetSector(room, x - room->x, z - room->z);
|
floor = GetSector(room, x - room->Position.x, z - room->Position.z);
|
||||||
floor->Stopper = !floor->Stopper;
|
floor->Stopper = !floor->Stopper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2151,11 +2151,11 @@ void InitializeItemBoxData()
|
||||||
{
|
{
|
||||||
for (const auto& mesh : room.mesh)
|
for (const auto& mesh : room.mesh)
|
||||||
{
|
{
|
||||||
long index = ((mesh.pos.Position.z - room.z) / BLOCK(1)) + room.zSize * ((mesh.pos.Position.x - room.x) / BLOCK(1));
|
long index = ((mesh.pos.Position.z - room.Position.z) / BLOCK(1)) + room.ZSize * ((mesh.pos.Position.x - room.Position.x) / BLOCK(1));
|
||||||
if (index > room.floor.size())
|
if (index > room.Sectors.size())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto* floor = &room.floor[index];
|
auto* floor = &room.Sectors[index];
|
||||||
if (floor->PathfindingBoxID == NO_VALUE)
|
if (floor->PathfindingBoxID == NO_VALUE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -2184,19 +2184,7 @@ bool CanCreatureJump(ItemInfo& item, JumpDistance jumpDistType)
|
||||||
if (creature.Enemy == nullptr)
|
if (creature.Enemy == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float stepDist = 0.0f;
|
float stepDist = BLOCK(0.92f);
|
||||||
switch (jumpDistType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case JumpDistance::Block1:
|
|
||||||
stepDist = BLOCK(0.51f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JumpDistance::Block2:
|
|
||||||
stepDist = BLOCK(0.76f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vPos = item.Pose.Position.y;
|
int vPos = item.Pose.Position.y;
|
||||||
auto pointCollA = GetPointCollision(item, item.Pose.Orientation.y, stepDist);
|
auto pointCollA = GetPointCollision(item, item.Pose.Orientation.y, stepDist);
|
||||||
auto pointCollB = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 2);
|
auto pointCollB = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 2);
|
||||||
|
|
|
@ -397,6 +397,7 @@ void KillMoveEffects()
|
||||||
ItemNewRoomNo = 0;
|
ItemNewRoomNo = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: No one should use this ever again.
|
||||||
int GetRandomControl()
|
int GetRandomControl()
|
||||||
{
|
{
|
||||||
return Random::GenerateInt();
|
return Random::GenerateInt();
|
||||||
|
@ -578,6 +579,10 @@ GameStatus DoGameLoop(int levelIndex)
|
||||||
status = GameStatus::NewGame;
|
status = GameStatus::NewGame;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InventoryResult::HomeLevel:
|
||||||
|
status = GameStatus::HomeLevel;
|
||||||
|
break;
|
||||||
|
|
||||||
case InventoryResult::LoadGame:
|
case InventoryResult::LoadGame:
|
||||||
status = GameStatus::LoadGame;
|
status = GameStatus::LoadGame;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,6 +17,7 @@ enum class GameStatus
|
||||||
{
|
{
|
||||||
Normal,
|
Normal,
|
||||||
NewGame,
|
NewGame,
|
||||||
|
HomeLevel,
|
||||||
LoadGame,
|
LoadGame,
|
||||||
SaveGame,
|
SaveGame,
|
||||||
ExitToTitle,
|
ExitToTitle,
|
||||||
|
|
|
@ -784,7 +784,7 @@ std::optional<Vector3> GetStaticObjectLos(const Vector3& origin, int roomNumber,
|
||||||
{
|
{
|
||||||
// Run through neighbor rooms.
|
// Run through neighbor rooms.
|
||||||
const auto& room = g_Level.Rooms[roomNumber];
|
const auto& room = g_Level.Rooms[roomNumber];
|
||||||
for (int neighborRoomNumber : room.neighbors)
|
for (int neighborRoomNumber : room.NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
// Get neighbor room.
|
// Get neighbor room.
|
||||||
const auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
const auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
||||||
|
|
|
@ -240,7 +240,7 @@ void CreateZone(ItemInfo* item)
|
||||||
auto* creature = GetCreatureInfo(item);
|
auto* creature = GetCreatureInfo(item);
|
||||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||||
|
|
||||||
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->PathfindingBoxID;
|
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->Position.x, item->Pose.Position.z - room->Position.z)->PathfindingBoxID;
|
||||||
|
|
||||||
if (creature->LOT.Fly)
|
if (creature->LOT.Fly)
|
||||||
{
|
{
|
||||||
|
|
|
@ -139,14 +139,14 @@ namespace TEN::Control::Volumes
|
||||||
if (roomNumber == NO_VALUE)
|
if (roomNumber == NO_VALUE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int currentRoomIndex : g_Level.Rooms[roomNumber].neighbors)
|
for (int currentRoomIndex : g_Level.Rooms[roomNumber].NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
auto& room = g_Level.Rooms[currentRoomIndex];
|
auto& room = g_Level.Rooms[currentRoomIndex];
|
||||||
|
|
||||||
if (!room.Active())
|
if (!room.Active())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (auto& volume : room.triggerVolumes)
|
for (auto& volume : room.TriggerVolumes)
|
||||||
{
|
{
|
||||||
if (!volume.Enabled)
|
if (!volume.Enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -158,7 +158,7 @@ namespace TEN::Effects::Bubble
|
||||||
{
|
{
|
||||||
// Hit water surface; spawn ripple.
|
// Hit water surface; spawn ripple.
|
||||||
SpawnRipple(
|
SpawnRipple(
|
||||||
Vector3(bubble.Position.x, g_Level.Rooms[prevRoomNumber].maxceiling, bubble.Position.z),
|
Vector3(bubble.Position.x, g_Level.Rooms[prevRoomNumber].TopHeight, bubble.Position.z),
|
||||||
roomNumber,
|
roomNumber,
|
||||||
((bubble.SizeMax.x + bubble.SizeMax.y) / 2) * 0.5f,
|
((bubble.SizeMax.x + bubble.SizeMax.y) / 2) * 0.5f,
|
||||||
(int)RippleFlags::SlowFade);
|
(int)RippleFlags::SlowFade);
|
||||||
|
@ -168,7 +168,7 @@ namespace TEN::Effects::Bubble
|
||||||
}
|
}
|
||||||
// Hit ceiling. NOTE: This is a hacky check. New collision fetching should provide fast info on a need-to-know basis.
|
// Hit ceiling. NOTE: This is a hacky check. New collision fetching should provide fast info on a need-to-know basis.
|
||||||
else if (bubble.RoomNumber == prevRoomNumber &&
|
else if (bubble.RoomNumber == prevRoomNumber &&
|
||||||
bubble.Position.y <= g_Level.Rooms[prevRoomNumber].maxceiling)
|
bubble.Position.y <= g_Level.Rooms[prevRoomNumber].TopHeight)
|
||||||
{
|
{
|
||||||
bubble.Life = 0.0f;
|
bubble.Life = 0.0f;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -256,30 +256,23 @@ void TriggerPilotFlame(int itemNumber, int nodeIndex)
|
||||||
spark->dSize = size;
|
spark->dSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Particle* SetupPoisonSpark(Vector3 color)
|
static Particle& SetupPoisonParticle(const Color& colorStart, const Color& colorEnd)
|
||||||
{
|
{
|
||||||
auto* spark = GetFreeParticle();
|
auto& part = *GetFreeParticle();
|
||||||
|
part.sR = std::clamp<unsigned char>(colorStart.x * UCHAR_MAX, 0, UCHAR_MAX);
|
||||||
|
part.sG = std::clamp<unsigned char>(colorStart.y * UCHAR_MAX, 0, UCHAR_MAX);
|
||||||
|
part.sB = std::clamp<unsigned char>(colorStart.z * UCHAR_MAX, 0, UCHAR_MAX);
|
||||||
|
part.dR = std::clamp<unsigned char>(colorEnd.x * UCHAR_MAX, 0, UCHAR_MAX);
|
||||||
|
part.dG = std::clamp<unsigned char>(colorEnd.y * UCHAR_MAX, 0, UCHAR_MAX);
|
||||||
|
part.dB = std::clamp<unsigned char>(colorEnd.z * UCHAR_MAX, 0, UCHAR_MAX);
|
||||||
|
part.colFadeSpeed = 14;
|
||||||
|
part.fadeToBlack = 8;
|
||||||
|
part.blendMode = BlendMode::Screen;
|
||||||
|
|
||||||
bool rMax = color.x > color.y && color.x > color.z;
|
return part;
|
||||||
bool gMax = color.y > color.x && color.y > color.z;
|
|
||||||
bool bMax = color.z > color.x && color.z > color.y;
|
|
||||||
|
|
||||||
char seed = (GetRandomControl() & 0x1F) + 220;
|
|
||||||
|
|
||||||
spark->sR = (rMax ? seed : 255) * (color.x * 0.4);
|
|
||||||
spark->sG = (gMax ? seed : 255) * (color.y * 0.4);
|
|
||||||
spark->sB = (bMax ? seed : 255) * (color.z * 0.4);
|
|
||||||
spark->dR = 255 * color.x;
|
|
||||||
spark->dG = 255 * color.y;
|
|
||||||
spark->dB = 255 * color.z;
|
|
||||||
spark->colFadeSpeed = 14;
|
|
||||||
spark->fadeToBlack = 8;
|
|
||||||
spark->blendMode = BlendMode::Screen;
|
|
||||||
|
|
||||||
return spark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Particle* SetupFireSpark()
|
static Particle* SetupFireSpark()
|
||||||
{
|
{
|
||||||
auto* spark = GetFreeParticle();
|
auto* spark = GetFreeParticle();
|
||||||
|
|
||||||
|
@ -296,19 +289,20 @@ Particle* SetupFireSpark()
|
||||||
return spark;
|
return spark;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachAndCreateSpark(Particle* spark, ItemInfo* item, int meshIndex, Vector3i offset, Vector3i vel)
|
static void AttachAndCreateSpark(Particle* spark, const ItemInfo* item, int meshID, Vector3i offset, Vector3i vel, int spriteID = 0)
|
||||||
{
|
{
|
||||||
auto pos1 = GetJointPosition(item, meshIndex, Vector3i(-4, -30, -4) + offset);
|
auto pos1 = GetJointPosition(*item, meshID, Vector3i(-4, -30, -4) + offset);
|
||||||
|
|
||||||
spark->x = (GetRandomControl() & 0x1F) + pos1.x - 16;
|
spark->x = (GetRandomControl() & 0x1F) + pos1.x - 16;
|
||||||
spark->y = (GetRandomControl() & 0x1F) + pos1.y - 16;
|
spark->y = (GetRandomControl() & 0x1F) + pos1.y - 16;
|
||||||
spark->z = (GetRandomControl() & 0x1F) + pos1.z - 16;
|
spark->z = (GetRandomControl() & 0x1F) + pos1.z - 16;
|
||||||
|
|
||||||
auto pos2 = GetJointPosition(item, meshIndex, Vector3i(-4, -30, -4) + offset + vel);
|
auto pos2 = GetJointPosition(*item, meshID, Vector3i(-4, -30, -4) + offset + vel);
|
||||||
|
|
||||||
int v = (GetRandomControl() & 0x3F) + 192;
|
int v = (GetRandomControl() & 0x3F) + 192;
|
||||||
|
|
||||||
spark->life = spark->sLife = v / 6;
|
spark->life = spark->sLife = v / 6;
|
||||||
|
spark->spriteIndex = Objects[ID_DEFAULT_SPRITES].meshIndex + spriteID;
|
||||||
|
|
||||||
spark->xVel = v * (pos2.x - pos1.x) / 10;
|
spark->xVel = v * (pos2.x - pos1.x) / 10;
|
||||||
spark->yVel = v * (pos2.y - pos1.y) / 10;
|
spark->yVel = v * (pos2.y - pos1.y) / 10;
|
||||||
|
@ -327,39 +321,39 @@ void AttachAndCreateSpark(Particle* spark, ItemInfo* item, int meshIndex, Vector
|
||||||
spark->on = 1;
|
spark->on = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThrowFire(int itemNumber, int meshIndex, const Vector3i& offset, const Vector3i& vel)
|
void ThrowFire(int itemNumber, int meshID, const Vector3i& offset, const Vector3i& vel, int spriteID)
|
||||||
{
|
{
|
||||||
auto& item = g_Level.Items[itemNumber];
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
auto& spark = *SetupFireSpark();
|
auto& part = *SetupFireSpark();
|
||||||
AttachAndCreateSpark(&spark, &item, meshIndex, offset, vel);
|
AttachAndCreateSpark(&part, &item, meshID, offset, vel, spriteID);
|
||||||
|
|
||||||
spark.flags = SP_FIRE | SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF;
|
part.flags = SP_FIRE | SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThrowFire(int itemNumber, const CreatureBiteInfo& bite, const Vector3i& vel)
|
void ThrowFire(int itemNumber, const CreatureBiteInfo& bite, const Vector3i& vel, int spriteID)
|
||||||
{
|
{
|
||||||
ThrowFire(itemNumber, bite.BoneID, bite.Position, vel);
|
ThrowFire(itemNumber, bite.BoneID, bite.Position, vel, spriteID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThrowPoison(int itemNumber, int meshIndex, const Vector3i& offset, const Vector3i& vel, const Vector3& color)
|
void ThrowPoison(const ItemInfo& item, int boneID, const Vector3& offset, const Vector3& vel, const Color& colorStart, const Color& colorEnd, int spriteID)
|
||||||
{
|
{
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
constexpr auto COUNT = 2;
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < COUNT; i++)
|
||||||
{
|
{
|
||||||
auto* spark = SetupPoisonSpark(color);
|
auto& part = SetupPoisonParticle(colorStart, colorEnd);
|
||||||
AttachAndCreateSpark(spark, item, meshIndex, offset, vel);
|
AttachAndCreateSpark(&part, &item, boneID, offset, vel, spriteID);
|
||||||
spark->flags = SP_POISON | SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF;
|
part.flags = SP_POISON | SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThrowPoison(int itemNumber, const CreatureBiteInfo& bite, const Vector3i& vel, const Vector3& color)
|
void ThrowPoison(const ItemInfo& item, const CreatureBiteInfo& bite, const Vector3& vel, const Color& colorStart, const Color& colorEnd, int spriteID)
|
||||||
{
|
{
|
||||||
ThrowPoison(itemNumber, bite.BoneID, bite.Position, vel, color);
|
ThrowPoison(item, bite.BoneID, bite.Position, vel, colorStart, colorEnd, spriteID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateFireProgress()
|
void UpdateFireProgress()
|
||||||
|
@ -993,10 +987,10 @@ void UpdateGunShells()
|
||||||
!TestEnvironment(ENV_FLAG_WATER, prevRoomNumber))
|
!TestEnvironment(ENV_FLAG_WATER, prevRoomNumber))
|
||||||
{
|
{
|
||||||
|
|
||||||
SpawnSplashDrips(Vector3(gunshell->pos.Position.x, g_Level.Rooms[gunshell->roomNumber].maxceiling, gunshell->pos.Position.z), gunshell->roomNumber, 3, true);
|
SpawnSplashDrips(Vector3(gunshell->pos.Position.x, g_Level.Rooms[gunshell->roomNumber].TopHeight, gunshell->pos.Position.z), gunshell->roomNumber, 3, true);
|
||||||
//AddWaterSparks(gs->pos.Position.x, g_Level.Rooms[gs->roomNumber].maxceiling, gs->pos.Position.z, 8);
|
//AddWaterSparks(gs->pos.Position.x, g_Level.Rooms[gs->roomNumber].maxceiling, gs->pos.Position.z, 8);
|
||||||
SpawnRipple(
|
SpawnRipple(
|
||||||
Vector3(gunshell->pos.Position.x, g_Level.Rooms[gunshell->roomNumber].maxceiling, gunshell->pos.Position.z),
|
Vector3(gunshell->pos.Position.x, g_Level.Rooms[gunshell->roomNumber].TopHeight, gunshell->pos.Position.z),
|
||||||
gunshell->roomNumber,
|
gunshell->roomNumber,
|
||||||
Random::GenerateFloat(8.0f, 12.0f),
|
Random::GenerateFloat(8.0f, 12.0f),
|
||||||
(int)RippleFlags::SlowFade);
|
(int)RippleFlags::SlowFade);
|
||||||
|
|
|
@ -230,10 +230,10 @@ void TriggerGlobalStaticFlame();
|
||||||
void TriggerGlobalFireSmoke();
|
void TriggerGlobalFireSmoke();
|
||||||
void TriggerGlobalFireFlame();
|
void TriggerGlobalFireFlame();
|
||||||
void TriggerPilotFlame(int itemNumber, int nodeIndex);
|
void TriggerPilotFlame(int itemNumber, int nodeIndex);
|
||||||
void ThrowFire(int itemNumber, int meshIndex, const Vector3i& offset, const Vector3i& vel);
|
void ThrowFire(int itemNumber, int meshID, const Vector3i& offset, const Vector3i& vel, int spriteID = 0);
|
||||||
void ThrowFire(int itemNumber, const CreatureBiteInfo& bite, const Vector3i& vel);
|
void ThrowFire(int itemNumber, const CreatureBiteInfo& bite, const Vector3i& vel, int spriteID = 0);
|
||||||
void ThrowPoison(int itemNumber, int meshIndex, const Vector3i& offset, const Vector3i& vel, const Vector3& color);
|
void ThrowPoison(const ItemInfo& item, int boneID, const Vector3& offset, const Vector3& vel, const Color& colorStart, const Color& colorEnd, int spriteID = 0);
|
||||||
void ThrowPoison(int itemNumber, const CreatureBiteInfo& bite, const Vector3i& vel, const Vector3& color);
|
void ThrowPoison(const ItemInfo& item, const CreatureBiteInfo& bite, const Vector3& vel, const Color& colorStart, const Color& colorEnd, int spriteID = 0);
|
||||||
void UpdateFireProgress();
|
void UpdateFireProgress();
|
||||||
void ClearFires();
|
void ClearFires();
|
||||||
void AddFire(int x, int y, int z, short roomNum, float size, short fade);
|
void AddFire(int x, int y, int z, short roomNum, float size, short fade);
|
||||||
|
|
|
@ -173,7 +173,7 @@ namespace TEN::Gui
|
||||||
return ((IsReleased(In::Select) || IsReleased(In::Action)) && CanSelect());
|
return ((IsReleased(In::Select) || IsReleased(In::Action)) && CanSelect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiController::GuiIsDeselected() const
|
bool GuiController::GuiIsDeselected() const
|
||||||
{
|
{
|
||||||
return ((IsClicked(In::Deselect) || IsClicked(In::Draw)) && CanDeselect());
|
return ((IsClicked(In::Deselect) || IsClicked(In::Draw)) && CanDeselect());
|
||||||
|
@ -281,14 +281,17 @@ namespace TEN::Gui
|
||||||
enum TitleOption
|
enum TitleOption
|
||||||
{
|
{
|
||||||
NewGame,
|
NewGame,
|
||||||
|
HomeLevel,
|
||||||
LoadGame,
|
LoadGame,
|
||||||
Options,
|
Options,
|
||||||
ExitGame
|
ExitGame,
|
||||||
|
|
||||||
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int numTitleOptions = 3;
|
constexpr auto TITLE_OPTION_COUNT = TitleOption::Count - 1;
|
||||||
static const int numLoadGameOptions = SAVEGAME_MAX - 1;
|
constexpr auto LOAD_GAME_OPTION_COUNT = SAVEGAME_MAX - 1;
|
||||||
static const int numOptionsOptions = 2;
|
constexpr auto OPTION_OPTION_COUNT = 2;
|
||||||
|
|
||||||
static int selectedOptionBackup;
|
static int selectedOptionBackup;
|
||||||
auto inventoryResult = InventoryResult::None;
|
auto inventoryResult = InventoryResult::None;
|
||||||
|
@ -300,20 +303,31 @@ namespace TEN::Gui
|
||||||
switch (MenuToDisplay)
|
switch (MenuToDisplay)
|
||||||
{
|
{
|
||||||
case Menu::Title:
|
case Menu::Title:
|
||||||
OptionCount = g_GameFlow->IsLoadSaveEnabled() ? numTitleOptions : (numTitleOptions - 1);
|
OptionCount = TITLE_OPTION_COUNT;
|
||||||
|
|
||||||
|
if (!g_GameFlow->IsHomeLevelEnabled())
|
||||||
|
OptionCount--;
|
||||||
|
|
||||||
|
if (!g_GameFlow->IsLoadSaveEnabled())
|
||||||
|
OptionCount--;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Menu::SelectLevel:
|
case Menu::SelectLevel:
|
||||||
inventoryResult = InventoryResult::None;
|
inventoryResult = InventoryResult::None;
|
||||||
OptionCount = g_GameFlow->GetNumLevels() - 2;
|
OptionCount = g_GameFlow->GetNumLevels() - 2;
|
||||||
|
|
||||||
|
if (g_GameFlow->IsHomeLevelEnabled())
|
||||||
|
OptionCount--;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Menu::LoadGame:
|
case Menu::LoadGame:
|
||||||
OptionCount = numLoadGameOptions;
|
OptionCount = LOAD_GAME_OPTION_COUNT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Menu::Options:
|
case Menu::Options:
|
||||||
OptionCount = numOptionsOptions;
|
OptionCount = OPTION_OPTION_COUNT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Menu::Display:
|
case Menu::Display:
|
||||||
|
@ -354,21 +368,7 @@ namespace TEN::Gui
|
||||||
MenuToDisplay == Menu::SelectLevel ||
|
MenuToDisplay == Menu::SelectLevel ||
|
||||||
MenuToDisplay == Menu::Options)
|
MenuToDisplay == Menu::Options)
|
||||||
{
|
{
|
||||||
if (GuiIsPulsed(In::Forward))
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
||||||
{
|
|
||||||
SelectedOption = (SelectedOption <= 0) ? OptionCount : (SelectedOption - 1);
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (SelectedOption < OptionCount)
|
|
||||||
SelectedOption++;
|
|
||||||
else
|
|
||||||
SelectedOption -= OptionCount;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsDeselected() && MenuToDisplay != Menu::Title)
|
if (GuiIsDeselected() && MenuToDisplay != Menu::Title)
|
||||||
{
|
{
|
||||||
|
@ -383,9 +383,14 @@ namespace TEN::Gui
|
||||||
|
|
||||||
if (MenuToDisplay == Menu::Title)
|
if (MenuToDisplay == Menu::Title)
|
||||||
{
|
{
|
||||||
// Skip load game entry if loading and saving is disabled.
|
|
||||||
int realSelectedOption = SelectedOption;
|
int realSelectedOption = SelectedOption;
|
||||||
if (!g_GameFlow->IsLoadSaveEnabled() && SelectedOption > TitleOption::NewGame)
|
|
||||||
|
// Skip Home Level entry if home level is disabled.
|
||||||
|
if (!g_GameFlow->IsHomeLevelEnabled() && realSelectedOption > TitleOption::NewGame)
|
||||||
|
realSelectedOption++;
|
||||||
|
|
||||||
|
// Skip Load Game entry if loading and saving is disabled.
|
||||||
|
if (!g_GameFlow->IsLoadSaveEnabled() && realSelectedOption > TitleOption::HomeLevel)
|
||||||
realSelectedOption++;
|
realSelectedOption++;
|
||||||
|
|
||||||
switch (realSelectedOption)
|
switch (realSelectedOption)
|
||||||
|
@ -404,6 +409,10 @@ namespace TEN::Gui
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TitleOption::HomeLevel:
|
||||||
|
inventoryResult = InventoryResult::HomeLevel;
|
||||||
|
break;
|
||||||
|
|
||||||
case TitleOption::LoadGame:
|
case TitleOption::LoadGame:
|
||||||
selectedOptionBackup = SelectedOption;
|
selectedOptionBackup = SelectedOption;
|
||||||
SelectedOption = 0;
|
SelectedOption = 0;
|
||||||
|
@ -424,8 +433,13 @@ namespace TEN::Gui
|
||||||
}
|
}
|
||||||
else if (MenuToDisplay == Menu::SelectLevel)
|
else if (MenuToDisplay == Menu::SelectLevel)
|
||||||
{
|
{
|
||||||
// Level 0 is the title level, so increment the option by 1 to offset it.
|
// Level 0 is Title Level; increment option to offset it.
|
||||||
g_GameFlow->SelectedLevelForNewGame = SelectedOption + 1;
|
g_GameFlow->SelectedLevelForNewGame = SelectedOption + 1;
|
||||||
|
|
||||||
|
// Level 1 reserved for Home Level; increment option if enabled to offset it.
|
||||||
|
if (g_GameFlow->IsHomeLevelEnabled())
|
||||||
|
g_GameFlow->SelectedLevelForNewGame++;
|
||||||
|
|
||||||
MenuToDisplay = Menu::Title;
|
MenuToDisplay = Menu::Title;
|
||||||
SelectedOption = 0;
|
SelectedOption = 0;
|
||||||
inventoryResult = InventoryResult::NewGameSelectedLevel;
|
inventoryResult = InventoryResult::NewGameSelectedLevel;
|
||||||
|
@ -577,25 +591,7 @@ namespace TEN::Gui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Forward))
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
||||||
{
|
|
||||||
if (SelectedOption <= 0)
|
|
||||||
SelectedOption += OptionCount;
|
|
||||||
else
|
|
||||||
SelectedOption--;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (SelectedOption < OptionCount)
|
|
||||||
SelectedOption++;
|
|
||||||
else
|
|
||||||
SelectedOption -= OptionCount;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsSelected())
|
if (GuiIsSelected())
|
||||||
{
|
{
|
||||||
|
@ -612,7 +608,7 @@ namespace TEN::Gui
|
||||||
SaveConfiguration();
|
SaveConfiguration();
|
||||||
|
|
||||||
// Reset screen and go back.
|
// Reset screen and go back.
|
||||||
g_Renderer.ChangeScreenResolution(CurrentSettings.Configuration.ScreenWidth, CurrentSettings.Configuration.ScreenHeight,
|
g_Renderer.ChangeScreenResolution(CurrentSettings.Configuration.ScreenWidth, CurrentSettings.Configuration.ScreenHeight,
|
||||||
CurrentSettings.Configuration.EnableWindowedMode);
|
CurrentSettings.Configuration.EnableWindowedMode);
|
||||||
|
|
||||||
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
|
||||||
|
@ -743,25 +739,7 @@ namespace TEN::Gui
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (GuiIsPulsed(In::Forward))
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
||||||
{
|
|
||||||
if (SelectedOption <= 0)
|
|
||||||
SelectedOption += OptionCount;
|
|
||||||
else
|
|
||||||
SelectedOption--;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (SelectedOption < OptionCount)
|
|
||||||
SelectedOption++;
|
|
||||||
else
|
|
||||||
SelectedOption -= OptionCount;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: Menu screen scroll.
|
// HACK: Menu screen scroll.
|
||||||
if (GuiIsPulsed(In::Left) || GuiIsPulsed(In::Right))
|
if (GuiIsPulsed(In::Left) || GuiIsPulsed(In::Right))
|
||||||
|
@ -893,8 +871,9 @@ namespace TEN::Gui
|
||||||
TargetHighlighter,
|
TargetHighlighter,
|
||||||
ToggleRumble,
|
ToggleRumble,
|
||||||
ThumbstickCameraControl,
|
ThumbstickCameraControl,
|
||||||
|
|
||||||
MouseSensitivity,
|
MouseSensitivity,
|
||||||
MouseSmoothing,
|
MenuOptionLooping,
|
||||||
|
|
||||||
Apply,
|
Apply,
|
||||||
Cancel,
|
Cancel,
|
||||||
|
@ -929,7 +908,7 @@ namespace TEN::Gui
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
CurrentSettings.Configuration.EnableAutoMonkeySwingJump = !CurrentSettings.Configuration.EnableAutoMonkeySwingJump;
|
CurrentSettings.Configuration.EnableAutoMonkeySwingJump = !CurrentSettings.Configuration.EnableAutoMonkeySwingJump;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OtherSettingsOption::Subtitles:
|
case OtherSettingsOption::Subtitles:
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles;
|
CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles;
|
||||||
|
@ -944,7 +923,7 @@ namespace TEN::Gui
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
CurrentSettings.Configuration.EnableTargetHighlighter = !CurrentSettings.Configuration.EnableTargetHighlighter;
|
CurrentSettings.Configuration.EnableTargetHighlighter = !CurrentSettings.Configuration.EnableTargetHighlighter;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OtherSettingsOption::ToggleRumble:
|
case OtherSettingsOption::ToggleRumble:
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
CurrentSettings.Configuration.EnableRumble = !CurrentSettings.Configuration.EnableRumble;
|
CurrentSettings.Configuration.EnableRumble = !CurrentSettings.Configuration.EnableRumble;
|
||||||
|
@ -1000,14 +979,23 @@ namespace TEN::Gui
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OtherSettingsOption::MouseSmoothing:
|
case OtherSettingsOption::MenuOptionLooping:
|
||||||
if (CurrentSettings.Configuration.MouseSmoothing > MOUSE_SMOOTHING_MIN)
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
{
|
|
||||||
CurrentSettings.Configuration.MouseSmoothing -= 1;
|
|
||||||
if (CurrentSettings.Configuration.MouseSmoothing < MOUSE_SMOOTHING_MIN)
|
|
||||||
CurrentSettings.Configuration.MouseSmoothing = MOUSE_SMOOTHING_MIN;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
switch (CurrentSettings.Configuration.MenuOptionLoopingMode)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case MenuOptionLoopingMode::AllMenus:
|
||||||
|
CurrentSettings.Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::Disabled;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuOptionLoopingMode::SaveLoadOnly:
|
||||||
|
CurrentSettings.Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::AllMenus;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuOptionLoopingMode::Disabled:
|
||||||
|
CurrentSettings.Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::SaveLoadOnly;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1063,14 +1051,23 @@ namespace TEN::Gui
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OtherSettingsOption::MouseSmoothing:
|
case OtherSettingsOption::MenuOptionLooping:
|
||||||
if (CurrentSettings.Configuration.MouseSmoothing < MOUSE_SMOOTHING_MAX)
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
|
|
||||||
|
switch (CurrentSettings.Configuration.MenuOptionLoopingMode)
|
||||||
{
|
{
|
||||||
CurrentSettings.Configuration.MouseSmoothing += 1;
|
default:
|
||||||
if (CurrentSettings.Configuration.MouseSmoothing > MOUSE_SMOOTHING_MAX)
|
case MenuOptionLoopingMode::AllMenus:
|
||||||
CurrentSettings.Configuration.MouseSmoothing = MOUSE_SMOOTHING_MAX;
|
CurrentSettings.Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::SaveLoadOnly;
|
||||||
|
break;
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
case MenuOptionLoopingMode::SaveLoadOnly:
|
||||||
|
CurrentSettings.Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::Disabled;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MenuOptionLoopingMode::Disabled:
|
||||||
|
CurrentSettings.Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::AllMenus;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1083,33 +1080,7 @@ namespace TEN::Gui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Forward))
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
||||||
{
|
|
||||||
if (SelectedOption <= 0)
|
|
||||||
{
|
|
||||||
SelectedOption += OptionCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedOption--;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (SelectedOption < OptionCount)
|
|
||||||
{
|
|
||||||
SelectedOption++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedOption -= OptionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsSelected())
|
if (GuiIsSelected())
|
||||||
{
|
{
|
||||||
|
@ -1191,25 +1162,7 @@ namespace TEN::Gui
|
||||||
if (MenuToDisplay == Menu::Pause ||
|
if (MenuToDisplay == Menu::Pause ||
|
||||||
MenuToDisplay == Menu::Options)
|
MenuToDisplay == Menu::Options)
|
||||||
{
|
{
|
||||||
if (GuiIsPulsed(In::Forward))
|
SelectedOption = GetLoopedSelectedOption(SelectedOption, OptionCount, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
||||||
{
|
|
||||||
if (SelectedOption <= 0)
|
|
||||||
SelectedOption += OptionCount;
|
|
||||||
else
|
|
||||||
SelectedOption--;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (SelectedOption < OptionCount)
|
|
||||||
SelectedOption++;
|
|
||||||
else
|
|
||||||
SelectedOption -= OptionCount;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GuiIsDeselected() || IsClicked(In::Pause))
|
if (GuiIsDeselected() || IsClicked(In::Pause))
|
||||||
|
@ -1409,7 +1362,7 @@ namespace TEN::Gui
|
||||||
|
|
||||||
if (Rings[(int)RingTypes::Ammo].RingActive)
|
if (Rings[(int)RingTypes::Ammo].RingActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AmmoObjectList[0].Orientation = EulerAngles::Identity;
|
AmmoObjectList[0].Orientation = EulerAngles::Identity;
|
||||||
AmmoObjectList[1].Orientation = EulerAngles::Identity;
|
AmmoObjectList[1].Orientation = EulerAngles::Identity;
|
||||||
AmmoObjectList[2].Orientation = EulerAngles::Identity;
|
AmmoObjectList[2].Orientation = EulerAngles::Identity;
|
||||||
|
@ -1903,7 +1856,7 @@ namespace TEN::Gui
|
||||||
{
|
{
|
||||||
Ammo.AmountShotGunAmmo2 = lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[1].GetCount() / 6;
|
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.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.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.AmountHKAmmo1 = lara->Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].HasInfinite() ? -1 : lara->Weapons[(int)LaraWeaponType::HK].Ammo[(int)WeaponAmmoType::Ammo1].GetCount();
|
||||||
|
@ -2108,7 +2061,7 @@ namespace TEN::Gui
|
||||||
{
|
{
|
||||||
player.Control.HandStatus = HandStatus::WeaponDraw;
|
player.Control.HandStatus = HandStatus::WeaponDraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryItemChosen = NO_VALUE;
|
InventoryItemChosen = NO_VALUE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2515,51 +2468,10 @@ namespace TEN::Gui
|
||||||
!invRing.ObjectListMovement &&
|
!invRing.ObjectListMovement &&
|
||||||
!ammoRing.ObjectListMovement)
|
!ammoRing.ObjectListMovement)
|
||||||
{
|
{
|
||||||
|
CurrentSelectedOption = GetLoopedSelectedOption(CurrentSelectedOption, n - 1, g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus);
|
||||||
|
|
||||||
if (AmmoActive)
|
if (AmmoActive)
|
||||||
{
|
|
||||||
if (GuiIsPulsed(In::Forward))
|
|
||||||
{
|
|
||||||
if (CurrentSelectedOption <= 0)
|
|
||||||
CurrentSelectedOption = n - 1;
|
|
||||||
else
|
|
||||||
CurrentSelectedOption--;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (CurrentSelectedOption >= (n - 1))
|
|
||||||
CurrentSelectedOption = 0;
|
|
||||||
else
|
|
||||||
CurrentSelectedOption++;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
|
|
||||||
*CurrentAmmoType = CurrentSelectedOption;
|
*CurrentAmmoType = CurrentSelectedOption;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (GuiIsPulsed(In::Forward))
|
|
||||||
{
|
|
||||||
if (CurrentSelectedOption <= 0)
|
|
||||||
CurrentSelectedOption = n - 1;
|
|
||||||
else
|
|
||||||
CurrentSelectedOption--;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
else if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
if (CurrentSelectedOption >= (n - 1))
|
|
||||||
CurrentSelectedOption = 0;
|
|
||||||
else
|
|
||||||
CurrentSelectedOption++;
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_MENU_SELECT, nullptr, SoundEnvironment::Always);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsSelected(false))
|
if (GuiIsSelected(false))
|
||||||
{
|
{
|
||||||
|
@ -2719,7 +2631,7 @@ namespace TEN::Gui
|
||||||
{
|
{
|
||||||
if (!AmmoSelectorFlag)
|
if (!AmmoSelectorFlag)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int xPos = (2 * PHD_CENTER_X - OBJLIST_SPACING) / 2;
|
int xPos = (2 * PHD_CENTER_X - OBJLIST_SPACING) / 2;
|
||||||
if (NumAmmoSlots == 2)
|
if (NumAmmoSlots == 2)
|
||||||
xPos -= OBJLIST_SPACING / 2;
|
xPos -= OBJLIST_SPACING / 2;
|
||||||
|
@ -2767,7 +2679,7 @@ namespace TEN::Gui
|
||||||
// CHECK: AmmoSelectorFadeVal is never true and therefore the string is never printed.
|
// CHECK: AmmoSelectorFadeVal is never true and therefore the string is never printed.
|
||||||
//if (AmmoSelectorFadeVal)
|
//if (AmmoSelectorFadeVal)
|
||||||
g_Renderer.AddString(PHD_CENTER_X, 380, &invTextBuffer[0], PRINTSTRING_COLOR_YELLOW, (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
g_Renderer.AddString(PHD_CENTER_X, 380, &invTextBuffer[0], PRINTSTRING_COLOR_YELLOW, (int)PrintStringFlags::Center | (int)PrintStringFlags::Outline);
|
||||||
|
|
||||||
if (n == *CurrentAmmoType)
|
if (n == *CurrentAmmoType)
|
||||||
g_Renderer.DrawObjectIn2DSpace(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
|
g_Renderer.DrawObjectIn2DSpace(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
|
||||||
else
|
else
|
||||||
|
@ -3459,27 +3371,49 @@ namespace TEN::Gui
|
||||||
return SelectedSaveSlot;
|
return SelectedSaveSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadResult GuiController::DoLoad()
|
int GuiController::GetLoopedSelectedOption(int selectedOption, int optionCount, bool canLoop)
|
||||||
{
|
{
|
||||||
if (GuiIsPulsed(In::Back))
|
|
||||||
{
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
|
|
||||||
if (SelectedSaveSlot == (SAVEGAME_MAX - 1))
|
|
||||||
SelectedSaveSlot -= SAVEGAME_MAX - 1;
|
|
||||||
else
|
|
||||||
SelectedSaveSlot++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Forward))
|
if (GuiIsPulsed(In::Forward))
|
||||||
{
|
{
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
if (selectedOption <= 0)
|
||||||
|
{
|
||||||
if (SelectedSaveSlot == 0)
|
if (IsClicked(In::Forward) && canLoop)
|
||||||
SelectedSaveSlot += SAVEGAME_MAX - 1;
|
{
|
||||||
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
|
return optionCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SelectedSaveSlot--;
|
{
|
||||||
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
|
return (selectedOption - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (GuiIsPulsed(In::Back))
|
||||||
|
{
|
||||||
|
if (selectedOption >= optionCount)
|
||||||
|
{
|
||||||
|
if (IsClicked(In::Back) && canLoop)
|
||||||
|
{
|
||||||
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
|
return (selectedOption + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadResult GuiController::DoLoad()
|
||||||
|
{
|
||||||
|
bool canLoop = g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::SaveLoadOnly ||
|
||||||
|
g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus;
|
||||||
|
SelectedSaveSlot = GetLoopedSelectedOption(SelectedSaveSlot, SAVEGAME_MAX - 1, canLoop);
|
||||||
|
|
||||||
if (GuiIsSelected())
|
if (GuiIsSelected())
|
||||||
{
|
{
|
||||||
|
@ -3501,25 +3435,9 @@ namespace TEN::Gui
|
||||||
|
|
||||||
bool GuiController::DoSave()
|
bool GuiController::DoSave()
|
||||||
{
|
{
|
||||||
if (GuiIsPulsed(In::Back))
|
bool canLoop = g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::SaveLoadOnly ||
|
||||||
{
|
g_Configuration.MenuOptionLoopingMode == MenuOptionLoopingMode::AllMenus;
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
SelectedSaveSlot = GetLoopedSelectedOption(SelectedSaveSlot, SAVEGAME_MAX - 1, canLoop);
|
||||||
|
|
||||||
if (SelectedSaveSlot == (SAVEGAME_MAX - 1))
|
|
||||||
SelectedSaveSlot -= SAVEGAME_MAX - 1;
|
|
||||||
else
|
|
||||||
SelectedSaveSlot++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsPulsed(In::Forward))
|
|
||||||
{
|
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
|
||||||
|
|
||||||
if (SelectedSaveSlot == 0)
|
|
||||||
SelectedSaveSlot += SAVEGAME_MAX - 1;
|
|
||||||
else
|
|
||||||
SelectedSaveSlot--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GuiIsSelected())
|
if (GuiIsSelected())
|
||||||
{
|
{
|
||||||
|
@ -3569,7 +3487,7 @@ namespace TEN::Gui
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Small one isn't empty and the big one isn't full.
|
// Small one isn't empty and the big one isn't full.
|
||||||
if (lara->Inventory.SmallWaterskin != 1 && bigCapacity)
|
if (lara->Inventory.SmallWaterskin != 1 && bigCapacity)
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace TEN::Gui
|
||||||
None,
|
None,
|
||||||
UseItem,
|
UseItem,
|
||||||
NewGame,
|
NewGame,
|
||||||
|
HomeLevel,
|
||||||
LoadGame,
|
LoadGame,
|
||||||
SaveGame,
|
SaveGame,
|
||||||
ExitGame,
|
ExitGame,
|
||||||
|
@ -184,6 +185,7 @@ namespace TEN::Gui
|
||||||
void UseItem(ItemInfo& item, int objectNumber);
|
void UseItem(ItemInfo& item, int objectNumber);
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
const InventoryRing& GetRing(RingTypes ringType);
|
const InventoryRing& GetRing(RingTypes ringType);
|
||||||
int GetSelectedOption();
|
int GetSelectedOption();
|
||||||
Menu GetMenuToDisplay();
|
Menu GetMenuToDisplay();
|
||||||
|
@ -193,8 +195,10 @@ namespace TEN::Gui
|
||||||
int GetLastInventoryItem();
|
int GetLastInventoryItem();
|
||||||
SettingsData& GetCurrentSettings();
|
SettingsData& GetCurrentSettings();
|
||||||
int GetLoadSaveSelection();
|
int GetLoadSaveSelection();
|
||||||
|
int GetLoopedSelectedOption(int selectedOption, int optionCount, bool canLoop);
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
||||||
void SetSelectedOption(int menu);
|
void SetSelectedOption(int menu);
|
||||||
void SetMenuToDisplay(Menu menu);
|
void SetMenuToDisplay(Menu menu);
|
||||||
void SetInventoryMode(InventoryMode mode);
|
void SetInventoryMode(InventoryMode mode);
|
||||||
|
|
|
@ -83,12 +83,6 @@ struct CreatureBiteInfo
|
||||||
Position = pos;
|
Position = pos;
|
||||||
BoneID = boneID;
|
BoneID = boneID;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatureBiteInfo(float x, float y, float z, int boneID)
|
|
||||||
{
|
|
||||||
Position = Vector3(x, y, z);
|
|
||||||
BoneID = boneID;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CreatureMuzzleFlashInfo
|
struct CreatureMuzzleFlashInfo
|
||||||
|
|
|
@ -584,7 +584,7 @@ void InitializeItem(short itemNumber)
|
||||||
item->NextItem = room->itemNumber;
|
item->NextItem = room->itemNumber;
|
||||||
room->itemNumber = itemNumber;
|
room->itemNumber = itemNumber;
|
||||||
|
|
||||||
FloorInfo* floor = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z);
|
FloorInfo* floor = GetSector(room, item->Pose.Position.x - room->Position.x, item->Pose.Position.z - room->Position.z);
|
||||||
item->Floor = floor->GetSurfaceHeight(item->Pose.Position.x, item->Pose.Position.z, true);
|
item->Floor = floor->GetSurfaceHeight(item->Pose.Position.x, item->Pose.Position.z, true);
|
||||||
item->BoxNumber = floor->PathfindingBoxID;
|
item->BoxNumber = floor->PathfindingBoxID;
|
||||||
|
|
||||||
|
|
|
@ -8,34 +8,36 @@
|
||||||
#include "Game/items.h"
|
#include "Game/items.h"
|
||||||
#include "Game/Setup.h"
|
#include "Game/Setup.h"
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
|
#include "Specific/trutils.h"
|
||||||
|
|
||||||
using namespace TEN::Collision::Point;
|
using namespace TEN::Collision::Point;
|
||||||
|
using namespace TEN::Utils;
|
||||||
|
|
||||||
CreatureInfo* GetCreatureInfo(ItemInfo* item)
|
CreatureInfo* GetCreatureInfo(ItemInfo* item)
|
||||||
{
|
{
|
||||||
return (CreatureInfo*)item->Data;
|
return (CreatureInfo*)item->Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature)
|
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature, const std::vector<GAME_OBJECT_ID>& keyObjectIds, bool ignoreKeyObjectIds)
|
||||||
{
|
{
|
||||||
float nearestDistance = INFINITY;
|
float closestDistSqr = INFINITY;
|
||||||
|
for (int itemNumber = 0; itemNumber < g_Level.NumItems; itemNumber++)
|
||||||
for (int i = 0; i < g_Level.NumItems; i++)
|
|
||||||
{
|
{
|
||||||
auto* targetEntity = &g_Level.Items[i];
|
auto* targetItem = &g_Level.Items[itemNumber];
|
||||||
|
if (targetItem == nullptr || targetItem->Index == item->Index)
|
||||||
if (targetEntity == nullptr)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (targetEntity != item &&
|
// Ignore or specifically target key object IDs.
|
||||||
targetEntity->HitPoints > 0 &&
|
if (ignoreKeyObjectIds ? Contains(keyObjectIds, targetItem->ObjectNumber) : !Contains(keyObjectIds, targetItem->ObjectNumber))
|
||||||
targetEntity->Status != ITEM_INVISIBLE)
|
continue;
|
||||||
|
|
||||||
|
if (targetItem != item && targetItem->HitPoints > 0 && targetItem->Status != ITEM_INVISIBLE)
|
||||||
{
|
{
|
||||||
float distance = Vector3i::Distance(item->Pose.Position, targetEntity->Pose.Position);
|
float distSqr = Vector3i::DistanceSquared(item->Pose.Position, targetItem->Pose.Position);
|
||||||
if (distance < nearestDistance)
|
if (distSqr < closestDistSqr)
|
||||||
{
|
{
|
||||||
creature->Enemy = targetEntity;
|
creature->Enemy = targetItem;
|
||||||
nearestDistance = distance;
|
closestDistSqr = distSqr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,5 +18,5 @@ enum LaraMeshMask
|
||||||
};
|
};
|
||||||
|
|
||||||
CreatureInfo* GetCreatureInfo(ItemInfo* item);
|
CreatureInfo* GetCreatureInfo(ItemInfo* item);
|
||||||
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature);
|
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature, const std::vector<GAME_OBJECT_ID>& keyObjectIds = {}, bool ignoreKeyObjectIds = true);
|
||||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat);
|
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat);
|
||||||
|
|
|
@ -66,6 +66,7 @@ void ControlMissile(short fxNumber)
|
||||||
// Check whether something was hit.
|
// Check whether something was hit.
|
||||||
if (fx.pos.Position.y >= pointColl.GetFloorHeight() ||
|
if (fx.pos.Position.y >= pointColl.GetFloorHeight() ||
|
||||||
fx.pos.Position.y <= pointColl.GetCeilingHeight() ||
|
fx.pos.Position.y <= pointColl.GetCeilingHeight() ||
|
||||||
|
pointColl.IsWall() ||
|
||||||
hasHitPlayer)
|
hasHitPlayer)
|
||||||
{
|
{
|
||||||
if (fx.objectNumber == ID_KNIFETHROWER_KNIFE ||
|
if (fx.objectNumber == ID_KNIFETHROWER_KNIFE ||
|
||||||
|
@ -111,6 +112,7 @@ void ControlMissile(short fxNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
KillEffect(fxNumber);
|
KillEffect(fxNumber);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pointColl.GetRoomNumber() != fx.roomNumber)
|
if (pointColl.GetRoomNumber() != fx.roomNumber)
|
||||||
|
|
|
@ -169,8 +169,8 @@ bool TargetVisible(ItemInfo* item, AI_INFO* ai, float maxAngleInDegrees)
|
||||||
auto target = GameVector(
|
auto target = GameVector(
|
||||||
enemy->Pose.Position.x,
|
enemy->Pose.Position.x,
|
||||||
enemy->Pose.Position.y + ((((bounds.Y1 * 2) + bounds.Y1) + bounds.Y2) / 4),
|
enemy->Pose.Position.y + ((((bounds.Y1 * 2) + bounds.Y1) + bounds.Y2) / 4),
|
||||||
enemy->Pose.Position.z,
|
enemy->Pose.Position.z);
|
||||||
enemy->RoomNumber); // TODO: Check why this line didn't exist before. -- TokyoSU, 10/8/2022
|
|
||||||
return LOS(&origin, &target);
|
return LOS(&origin, &target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ bool ROOM_INFO::Active() const
|
||||||
// Since engine swaps whole room memory block but substitutes flippedRoom,
|
// Since engine swaps whole room memory block but substitutes flippedRoom,
|
||||||
// must check both original room number and flippedRoom equality,
|
// must check both original room number and flippedRoom equality,
|
||||||
// as well as NO_VALUE if checking non-flipped rooms.
|
// as well as NO_VALUE if checking non-flipped rooms.
|
||||||
return (!FlipStats[flipNumber] && flippedRoom != index && flippedRoom != NO_VALUE) ||
|
return (!FlipStats[flipNumber] && flippedRoom != RoomNumber && flippedRoom != NO_VALUE) ||
|
||||||
( FlipStats[flipNumber] && flippedRoom == index);
|
( FlipStats[flipNumber] && flippedRoom == RoomNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AddRoomFlipItems(const ROOM_INFO& room)
|
static void AddRoomFlipItems(const ROOM_INFO& room)
|
||||||
|
@ -105,11 +105,11 @@ void DoFlipMap(int group)
|
||||||
g_Renderer.FlipRooms(roomNumber, room.flippedRoom);
|
g_Renderer.FlipRooms(roomNumber, room.flippedRoom);
|
||||||
|
|
||||||
// Update active room sectors.
|
// Update active room sectors.
|
||||||
for (auto& sector : room.floor)
|
for (auto& sector : room.Sectors)
|
||||||
sector.RoomNumber = roomNumber;
|
sector.RoomNumber = roomNumber;
|
||||||
|
|
||||||
// Update flipped room sectors.
|
// Update flipped room sectors.
|
||||||
for (auto& sector : flippedRoom.floor)
|
for (auto& sector : flippedRoom.Sectors)
|
||||||
sector.RoomNumber = room.flippedRoom;
|
sector.RoomNumber = room.flippedRoom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,9 +158,9 @@ int IsRoomOutside(int x, int y, int z)
|
||||||
int roomNumber = OutsideRoomTable[xTable][zTable][i];
|
int roomNumber = OutsideRoomTable[xTable][zTable][i];
|
||||||
const auto& room = g_Level.Rooms[roomNumber];
|
const auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
if ((x > (room.x + BLOCK(1)) && x < (room.x + (room.xSize - 1) * BLOCK(1))) &&
|
if ((x > (room.Position.x + BLOCK(1)) && x < (room.Position.x + (room.XSize - 1) * BLOCK(1))) &&
|
||||||
(y > room.maxceiling && y < room.minfloor) &&
|
(y > room.TopHeight && y < room.BottomHeight) &&
|
||||||
(z > (room.z + BLOCK(1)) && z < (room.z + (room.zSize - 1) * BLOCK(1))))
|
(z > (room.Position.z + BLOCK(1)) && z < (room.Position.z + (room.ZSize - 1) * BLOCK(1))))
|
||||||
{
|
{
|
||||||
auto pointColl = GetPointCollision(Vector3i(x, y, z), roomNumber);
|
auto pointColl = GetPointCollision(Vector3i(x, y, z), roomNumber);
|
||||||
|
|
||||||
|
@ -188,14 +188,14 @@ namespace TEN::Collision::Room
|
||||||
// TODO: Can use floordata's GetRoomGridCoord()?
|
// TODO: Can use floordata's GetRoomGridCoord()?
|
||||||
FloorInfo* GetSector(ROOM_INFO* room, int x, int z)
|
FloorInfo* GetSector(ROOM_INFO* room, int x, int z)
|
||||||
{
|
{
|
||||||
int sectorX = std::clamp(x / BLOCK(1), 0, room->xSize - 1);
|
int sectorX = std::clamp(x / BLOCK(1), 0, room->XSize - 1);
|
||||||
int sectorZ = std::clamp(z / BLOCK(1), 0, room->zSize - 1);
|
int sectorZ = std::clamp(z / BLOCK(1), 0, room->ZSize - 1);
|
||||||
|
|
||||||
int sectorID = sectorZ + (sectorX * room->zSize);
|
int sectorID = sectorZ + (sectorX * room->ZSize);
|
||||||
if (sectorID > room->floor.size())
|
if (sectorID > room->Sectors.size())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return &room->floor[sectorID];
|
return &room->Sectors[sectorID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,9 +219,9 @@ bool IsPointInRoom(const Vector3i& pos, int roomNumber)
|
||||||
{
|
{
|
||||||
const auto& room = g_Level.Rooms[roomNumber];
|
const auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
if (pos.z >= (room.z + BLOCK(1)) && pos.z <= (room.z + BLOCK(room.zSize - 1)) &&
|
if (pos.z >= (room.Position.z + BLOCK(1)) && pos.z <= (room.Position.z + BLOCK(room.ZSize - 1)) &&
|
||||||
pos.y <= room.minfloor && pos.y > room.maxceiling &&
|
pos.y <= room.BottomHeight && pos.y > room.TopHeight &&
|
||||||
pos.x >= (room.x + BLOCK(1)) && pos.x <= (room.x + BLOCK(room.xSize - 1)))
|
pos.x >= (room.Position.x + BLOCK(1)) && pos.x <= (room.Position.x + BLOCK(room.XSize - 1)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ int FindRoomNumber(const Vector3i& pos, int startRoomNumber)
|
||||||
if (startRoomNumber != NO_VALUE && startRoomNumber < g_Level.Rooms.size())
|
if (startRoomNumber != NO_VALUE && startRoomNumber < g_Level.Rooms.size())
|
||||||
{
|
{
|
||||||
const auto& room = g_Level.Rooms[startRoomNumber];
|
const auto& room = g_Level.Rooms[startRoomNumber];
|
||||||
for (int neighborRoomNumber : room.neighbors)
|
for (int neighborRoomNumber : room.NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
const auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
const auto& neighborRoom = g_Level.Rooms[neighborRoomNumber];
|
||||||
if (neighborRoomNumber != startRoomNumber && neighborRoom.Active() &&
|
if (neighborRoomNumber != startRoomNumber && neighborRoom.Active() &&
|
||||||
|
@ -258,15 +258,15 @@ Vector3i GetRoomCenter(int roomNumber)
|
||||||
{
|
{
|
||||||
const auto& room = g_Level.Rooms[roomNumber];
|
const auto& room = g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
int halfLength = BLOCK(room.xSize) / 2;
|
int halfLength = BLOCK(room.XSize) / 2;
|
||||||
int halfDepth = BLOCK(room.zSize) / 2;
|
int halfDepth = BLOCK(room.ZSize) / 2;
|
||||||
int halfHeight = (room.maxceiling - room.minfloor) / 2;
|
int halfHeight = (room.TopHeight - room.BottomHeight) / 2;
|
||||||
|
|
||||||
// Calculate and return center.
|
// Calculate and return center.
|
||||||
return Vector3i(
|
return Vector3i(
|
||||||
room.x + halfLength,
|
room.Position.x + halfLength,
|
||||||
room.minfloor + halfHeight,
|
room.BottomHeight + halfHeight,
|
||||||
room.z + halfDepth);
|
room.Position.z + halfDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<int> GetNeighborRoomNumbers(int roomNumber, unsigned int searchDepth, std::vector<int>& visitedRoomNumbers = std::vector<int>{})
|
static std::vector<int> GetNeighborRoomNumbers(int roomNumber, unsigned int searchDepth, std::vector<int>& visitedRoomNumbers = std::vector<int>{})
|
||||||
|
@ -316,7 +316,7 @@ void InitializeNeighborRoomList()
|
||||||
for (int roomNumber = 0; roomNumber < g_Level.Rooms.size(); roomNumber++)
|
for (int roomNumber = 0; roomNumber < g_Level.Rooms.size(); roomNumber++)
|
||||||
{
|
{
|
||||||
auto& room = g_Level.Rooms[roomNumber];
|
auto& room = g_Level.Rooms[roomNumber];
|
||||||
room.neighbors = GetNeighborRoomNumbers(roomNumber, NEIGHBOR_ROOM_SEARCH_DEPTH);
|
room.NeighborRoomNumbers = GetNeighborRoomNumbers(roomNumber, NEIGHBOR_ROOM_SEARCH_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add flipped variations of itself.
|
// Add flipped variations of itself.
|
||||||
|
@ -326,11 +326,11 @@ void InitializeNeighborRoomList()
|
||||||
if (room.flippedRoom == NO_VALUE)
|
if (room.flippedRoom == NO_VALUE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!Contains(room.neighbors, room.flippedRoom))
|
if (!Contains(room.NeighborRoomNumbers, room.flippedRoom))
|
||||||
room.neighbors.push_back(room.flippedRoom);
|
room.NeighborRoomNumbers.push_back(room.flippedRoom);
|
||||||
|
|
||||||
auto& flippedRoom = g_Level.Rooms[room.flippedRoom];
|
auto& flippedRoom = g_Level.Rooms[room.flippedRoom];
|
||||||
if (!Contains(flippedRoom.neighbors, roomNumber))
|
if (!Contains(flippedRoom.NeighborRoomNumbers, roomNumber))
|
||||||
flippedRoom.neighbors.push_back(roomNumber);
|
flippedRoom.NeighborRoomNumbers.push_back(roomNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,31 +87,32 @@ struct MESH_INFO
|
||||||
|
|
||||||
struct ROOM_INFO
|
struct ROOM_INFO
|
||||||
{
|
{
|
||||||
int index;
|
int RoomNumber = 0;
|
||||||
int x;
|
std::string Name = {};
|
||||||
int y;
|
std::vector<std::string> Tags = {};
|
||||||
int z;
|
|
||||||
int minfloor;
|
Vector3i Position = Vector3i::Zero;
|
||||||
int maxceiling;
|
int BottomHeight = 0;
|
||||||
int xSize;
|
int TopHeight = 0;
|
||||||
int zSize;
|
int XSize = 0;
|
||||||
|
int ZSize = 0;
|
||||||
|
|
||||||
Vector3 ambient;
|
Vector3 ambient;
|
||||||
int flippedRoom;
|
|
||||||
int flags;
|
int flags;
|
||||||
int meshEffect;
|
int meshEffect;
|
||||||
ReverbType reverbType;
|
ReverbType reverbType;
|
||||||
|
int flippedRoom;
|
||||||
int flipNumber;
|
int flipNumber;
|
||||||
short itemNumber;
|
short itemNumber;
|
||||||
short fxNumber;
|
short fxNumber;
|
||||||
bool boundActive;
|
bool boundActive;
|
||||||
|
|
||||||
std::string name = {};
|
std::vector<int> NeighborRoomNumbers = {};
|
||||||
std::vector<std::string> tags = {};
|
|
||||||
|
|
||||||
std::vector<FloorInfo> floor = {};
|
std::vector<FloorInfo> Sectors = {};
|
||||||
std::vector<ROOM_LIGHT> lights = {};
|
std::vector<ROOM_LIGHT> lights = {};
|
||||||
std::vector<MESH_INFO> mesh = {};
|
std::vector<MESH_INFO> mesh = {}; // Statics
|
||||||
std::vector<TriggerVolume> triggerVolumes = {};
|
std::vector<TriggerVolume> TriggerVolumes = {};
|
||||||
|
|
||||||
std::vector<Vector3> positions = {};
|
std::vector<Vector3> positions = {};
|
||||||
std::vector<Vector3> normals = {};
|
std::vector<Vector3> normals = {};
|
||||||
|
@ -120,8 +121,6 @@ struct ROOM_INFO
|
||||||
std::vector<BUCKET> buckets = {};
|
std::vector<BUCKET> buckets = {};
|
||||||
std::vector<ROOM_DOOR> doors = {};
|
std::vector<ROOM_DOOR> doors = {};
|
||||||
|
|
||||||
std::vector<int> neighbors = {};
|
|
||||||
|
|
||||||
bool Active() const;
|
bool Active() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -544,11 +544,11 @@ const std::vector<byte> SaveGame::Build()
|
||||||
std::vector<flatbuffers::Offset<Save::Room>> rooms;
|
std::vector<flatbuffers::Offset<Save::Room>> rooms;
|
||||||
for (auto& room : g_Level.Rooms)
|
for (auto& room : g_Level.Rooms)
|
||||||
{
|
{
|
||||||
auto nameOffset = fbb.CreateString(room.name);
|
auto nameOffset = fbb.CreateString(room.Name);
|
||||||
|
|
||||||
Save::RoomBuilder serializedInfo{ fbb };
|
Save::RoomBuilder serializedInfo{ fbb };
|
||||||
serializedInfo.add_name(nameOffset);
|
serializedInfo.add_name(nameOffset);
|
||||||
serializedInfo.add_index(room.index);
|
serializedInfo.add_index(room.RoomNumber);
|
||||||
serializedInfo.add_reverb_type((int)room.reverbType);
|
serializedInfo.add_reverb_type((int)room.reverbType);
|
||||||
serializedInfo.add_flags(room.flags);
|
serializedInfo.add_flags(room.flags);
|
||||||
auto serializedInfoOffset = serializedInfo.Finish();
|
auto serializedInfoOffset = serializedInfo.Finish();
|
||||||
|
@ -991,14 +991,14 @@ const std::vector<byte> SaveGame::Build()
|
||||||
|
|
||||||
staticMesh.add_flags(room->mesh[j].flags);
|
staticMesh.add_flags(room->mesh[j].flags);
|
||||||
staticMesh.add_hit_points(room->mesh[j].HitPoints);
|
staticMesh.add_hit_points(room->mesh[j].HitPoints);
|
||||||
staticMesh.add_room_number(room->index);
|
staticMesh.add_room_number(room->RoomNumber);
|
||||||
staticMesh.add_number(j);
|
staticMesh.add_number(j);
|
||||||
staticMeshes.push_back(staticMesh.Finish());
|
staticMeshes.push_back(staticMesh.Finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < room->triggerVolumes.size(); j++)
|
for (int j = 0; j < room->TriggerVolumes.size(); j++)
|
||||||
{
|
{
|
||||||
auto& currVolume = room->triggerVolumes[j];
|
auto& currVolume = room->TriggerVolumes[j];
|
||||||
|
|
||||||
std::vector<flatbuffers::Offset<Save::VolumeState>> queue;
|
std::vector<flatbuffers::Offset<Save::VolumeState>> queue;
|
||||||
for (int k = 0; k < currVolume.StateQueue.size(); k++)
|
for (int k = 0; k < currVolume.StateQueue.size(); k++)
|
||||||
|
@ -1022,7 +1022,7 @@ const std::vector<byte> SaveGame::Build()
|
||||||
auto nameOffset = fbb.CreateString(currVolume.Name);
|
auto nameOffset = fbb.CreateString(currVolume.Name);
|
||||||
|
|
||||||
Save::VolumeBuilder volume{ fbb };
|
Save::VolumeBuilder volume{ fbb };
|
||||||
volume.add_room_number(room->index);
|
volume.add_room_number(room->RoomNumber);
|
||||||
volume.add_number(j);
|
volume.add_number(j);
|
||||||
volume.add_name(nameOffset);
|
volume.add_name(nameOffset);
|
||||||
volume.add_enabled(currVolume.Enabled);
|
volume.add_enabled(currVolume.Enabled);
|
||||||
|
@ -2155,7 +2155,7 @@ static void ParseLevel(const Save::SaveGame* s, bool hubMode)
|
||||||
for (int i = 0; i < s->rooms()->size(); i++)
|
for (int i = 0; i < s->rooms()->size(); i++)
|
||||||
{
|
{
|
||||||
auto room = s->rooms()->Get(i);
|
auto room = s->rooms()->Get(i);
|
||||||
g_Level.Rooms[room->index()].name = room->name()->str();
|
g_Level.Rooms[room->index()].Name = room->name()->str();
|
||||||
g_Level.Rooms[room->index()].flags = room->flags();
|
g_Level.Rooms[room->index()].flags = room->flags();
|
||||||
g_Level.Rooms[room->index()].reverbType = (ReverbType)room->reverb_type();
|
g_Level.Rooms[room->index()].reverbType = (ReverbType)room->reverb_type();
|
||||||
}
|
}
|
||||||
|
@ -2191,18 +2191,18 @@ static void ParseLevel(const Save::SaveGame* s, bool hubMode)
|
||||||
auto room = &g_Level.Rooms[volume->room_number()];
|
auto room = &g_Level.Rooms[volume->room_number()];
|
||||||
int number = volume->number();
|
int number = volume->number();
|
||||||
|
|
||||||
room->triggerVolumes[number].Enabled = volume->enabled();
|
room->TriggerVolumes[number].Enabled = volume->enabled();
|
||||||
room->triggerVolumes[number].Name = volume->name()->str();
|
room->TriggerVolumes[number].Name = volume->name()->str();
|
||||||
room->triggerVolumes[number].Box.Center =
|
room->TriggerVolumes[number].Box.Center =
|
||||||
room->triggerVolumes[number].Sphere.Center = ToVector3(volume->position());
|
room->TriggerVolumes[number].Sphere.Center = ToVector3(volume->position());
|
||||||
room->triggerVolumes[number].Box.Orientation = ToVector4(volume->rotation());
|
room->TriggerVolumes[number].Box.Orientation = ToVector4(volume->rotation());
|
||||||
room->triggerVolumes[number].Box.Extents = ToVector3(volume->scale());
|
room->TriggerVolumes[number].Box.Extents = ToVector3(volume->scale());
|
||||||
room->triggerVolumes[number].Sphere.Radius = room->triggerVolumes[number].Box.Extents.x;
|
room->TriggerVolumes[number].Sphere.Radius = room->TriggerVolumes[number].Box.Extents.x;
|
||||||
|
|
||||||
for (int j = 0; j < volume->queue()->size(); j++)
|
for (int j = 0; j < volume->queue()->size(); j++)
|
||||||
{
|
{
|
||||||
auto state = volume->queue()->Get(j);
|
auto state = volume->queue()->Get(j);
|
||||||
room->triggerVolumes[number].StateQueue.push_back(
|
room->TriggerVolumes[number].StateQueue.push_back(
|
||||||
VolumeState
|
VolumeState
|
||||||
{
|
{
|
||||||
(VolumeStateStatus)state->status(),
|
(VolumeStateStatus)state->status(),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Math/Constants.h"
|
#include "Math/Constants.h"
|
||||||
|
|
||||||
constexpr auto FP_SHIFT = 16;
|
constexpr auto FP_SHIFT = 16;
|
||||||
|
@ -8,14 +9,19 @@ constexpr auto PREDICTIVE_SCALE_FACTOR = 14;
|
||||||
constexpr auto SHORTS_TO_1_DEGREE = 65536.0f / 360.0f;
|
constexpr auto SHORTS_TO_1_DEGREE = 65536.0f / 360.0f;
|
||||||
constexpr auto DEGREES_TO_1_SHORT = 360.0f / 65536.0f;
|
constexpr auto DEGREES_TO_1_SHORT = 360.0f / 65536.0f;
|
||||||
|
|
||||||
|
constexpr float ROUND(float value)
|
||||||
|
{
|
||||||
|
return ((value > 0.0f) ? int(value + 0.5f) : int(value - 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
constexpr short ANGLE(float degrees)
|
constexpr short ANGLE(float degrees)
|
||||||
{
|
{
|
||||||
return short(degrees * SHORTS_TO_1_DEGREE);
|
return (short)ROUND(degrees * SHORTS_TO_1_DEGREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr short FROM_RAD(float radians)
|
constexpr short FROM_RAD(float radians)
|
||||||
{
|
{
|
||||||
return short((radians / RADIAN) * SHORTS_TO_1_DEGREE);
|
return (short)ROUND((radians / RADIAN) * SHORTS_TO_1_DEGREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr float TO_DEGREES(short shortAngle)
|
constexpr float TO_DEGREES(short shortAngle)
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace TEN::Entities::Doors
|
||||||
xOffset = BLOCK(1);
|
xOffset = BLOCK(1);
|
||||||
|
|
||||||
auto* r = &g_Level.Rooms[doorItem->RoomNumber];
|
auto* r = &g_Level.Rooms[doorItem->RoomNumber];
|
||||||
doorData->d1.floor = GetSector(r, doorItem->Pose.Position.x - r->x + xOffset, doorItem->Pose.Position.z - r->z + zOffset);
|
doorData->d1.floor = GetSector(r, doorItem->Pose.Position.x - r->Position.x + xOffset, doorItem->Pose.Position.z - r->Position.z + zOffset);
|
||||||
|
|
||||||
auto roomNumber = doorData->d1.floor->SidePortalRoomNumber;
|
auto roomNumber = doorData->d1.floor->SidePortalRoomNumber;
|
||||||
if (roomNumber == NO_VALUE)
|
if (roomNumber == NO_VALUE)
|
||||||
|
@ -85,7 +85,7 @@ namespace TEN::Entities::Doors
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto* b = &g_Level.Rooms[roomNumber];
|
auto* b = &g_Level.Rooms[roomNumber];
|
||||||
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->x + xOffset, doorItem->Pose.Position.z - b->z + zOffset)->PathfindingBoxID;
|
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->Position.x + xOffset, doorItem->Pose.Position.z - b->Position.z + zOffset)->PathfindingBoxID;
|
||||||
}
|
}
|
||||||
|
|
||||||
doorData->d1.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
doorData->d1.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
||||||
|
@ -94,7 +94,7 @@ namespace TEN::Entities::Doors
|
||||||
if (r->flippedRoom != -1)
|
if (r->flippedRoom != -1)
|
||||||
{
|
{
|
||||||
r = &g_Level.Rooms[r->flippedRoom];
|
r = &g_Level.Rooms[r->flippedRoom];
|
||||||
doorData->d1flip.floor = GetSector(r, doorItem->Pose.Position.x - r->x + xOffset, doorItem->Pose.Position.z - r->z + zOffset);
|
doorData->d1flip.floor = GetSector(r, doorItem->Pose.Position.x - r->Position.x + xOffset, doorItem->Pose.Position.z - r->Position.z + zOffset);
|
||||||
|
|
||||||
roomNumber = doorData->d1flip.floor->SidePortalRoomNumber;
|
roomNumber = doorData->d1flip.floor->SidePortalRoomNumber;
|
||||||
if (roomNumber == NO_VALUE)
|
if (roomNumber == NO_VALUE)
|
||||||
|
@ -102,7 +102,7 @@ namespace TEN::Entities::Doors
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto* b = &g_Level.Rooms[roomNumber];
|
auto* b = &g_Level.Rooms[roomNumber];
|
||||||
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->x + xOffset, doorItem->Pose.Position.z - b->z + zOffset)->PathfindingBoxID;
|
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->Position.x + xOffset, doorItem->Pose.Position.z - b->Position.z + zOffset)->PathfindingBoxID;
|
||||||
}
|
}
|
||||||
|
|
||||||
doorData->d1flip.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
doorData->d1flip.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
||||||
|
@ -124,7 +124,7 @@ namespace TEN::Entities::Doors
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
r = &g_Level.Rooms[twoRoom];
|
r = &g_Level.Rooms[twoRoom];
|
||||||
doorData->d2.floor = GetSector(r, doorItem->Pose.Position.x - r->x, doorItem->Pose.Position.z - r->z);
|
doorData->d2.floor = GetSector(r, doorItem->Pose.Position.x - r->Position.x, doorItem->Pose.Position.z - r->Position.z);
|
||||||
|
|
||||||
roomNumber = doorData->d2.floor->SidePortalRoomNumber;
|
roomNumber = doorData->d2.floor->SidePortalRoomNumber;
|
||||||
if (roomNumber == NO_VALUE)
|
if (roomNumber == NO_VALUE)
|
||||||
|
@ -132,7 +132,7 @@ namespace TEN::Entities::Doors
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto* b = &g_Level.Rooms[roomNumber];
|
auto* b = &g_Level.Rooms[roomNumber];
|
||||||
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->x, doorItem->Pose.Position.z - b->z)->PathfindingBoxID;
|
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->Position.x, doorItem->Pose.Position.z - b->Position.z)->PathfindingBoxID;
|
||||||
}
|
}
|
||||||
|
|
||||||
doorData->d2.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
doorData->d2.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
||||||
|
@ -141,7 +141,7 @@ namespace TEN::Entities::Doors
|
||||||
if (r->flippedRoom != -1)
|
if (r->flippedRoom != -1)
|
||||||
{
|
{
|
||||||
r = &g_Level.Rooms[r->flippedRoom];
|
r = &g_Level.Rooms[r->flippedRoom];
|
||||||
doorData->d2flip.floor = GetSector(r, doorItem->Pose.Position.x - r->x, doorItem->Pose.Position.z - r->z);
|
doorData->d2flip.floor = GetSector(r, doorItem->Pose.Position.x - r->Position.x, doorItem->Pose.Position.z - r->Position.z);
|
||||||
|
|
||||||
roomNumber = doorData->d2flip.floor->SidePortalRoomNumber;
|
roomNumber = doorData->d2flip.floor->SidePortalRoomNumber;
|
||||||
if (roomNumber == NO_VALUE)
|
if (roomNumber == NO_VALUE)
|
||||||
|
@ -149,7 +149,7 @@ namespace TEN::Entities::Doors
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto* b = &g_Level.Rooms[roomNumber];
|
auto* b = &g_Level.Rooms[roomNumber];
|
||||||
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->x, doorItem->Pose.Position.z - b->z)->PathfindingBoxID;
|
boxNumber = GetSector(b, doorItem->Pose.Position.x - b->Position.x, doorItem->Pose.Position.z - b->Position.z)->PathfindingBoxID;
|
||||||
}
|
}
|
||||||
|
|
||||||
doorData->d2flip.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
doorData->d2flip.block = (boxNumber != NO_VALUE && g_Level.PathfindingBoxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_VALUE;
|
||||||
|
|
|
@ -315,7 +315,7 @@ namespace TEN::Entities::Generic
|
||||||
waterHeight = pointColl.GetWaterSurfaceHeight();
|
waterHeight = pointColl.GetWaterSurfaceHeight();
|
||||||
|
|
||||||
if (waterHeight == NO_HEIGHT && TestEnvironment(ENV_FLAG_SWAMP, item.RoomNumber))
|
if (waterHeight == NO_HEIGHT && TestEnvironment(ENV_FLAG_SWAMP, item.RoomNumber))
|
||||||
waterHeight = g_Level.Rooms[item.RoomNumber].maxceiling;
|
waterHeight = g_Level.Rooms[item.RoomNumber].TopHeight;
|
||||||
|
|
||||||
AddPushableBridge(item);
|
AddPushableBridge(item);
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ namespace TEN::Entities::Generic
|
||||||
waterHeight = pointColl.GetWaterSurfaceHeight();
|
waterHeight = pointColl.GetWaterSurfaceHeight();
|
||||||
|
|
||||||
if (waterHeight == NO_HEIGHT && TestEnvironment(ENV_FLAG_SWAMP, item.RoomNumber))
|
if (waterHeight == NO_HEIGHT && TestEnvironment(ENV_FLAG_SWAMP, item.RoomNumber))
|
||||||
waterHeight = g_Level.Rooms[item.RoomNumber].maxceiling;
|
waterHeight = g_Level.Rooms[item.RoomNumber].TopHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pushableColl = PushableCollisionData{};
|
auto pushableColl = PushableCollisionData{};
|
||||||
|
|
|
@ -187,8 +187,8 @@ namespace TEN::Entities::Generic
|
||||||
ForcedFixedCamera.x = trapDoorItem->Pose.Position.x - phd_sin(trapDoorItem->Pose.Orientation.y) * 2048;
|
ForcedFixedCamera.x = trapDoorItem->Pose.Position.x - phd_sin(trapDoorItem->Pose.Orientation.y) * 2048;
|
||||||
ForcedFixedCamera.y = trapDoorItem->Pose.Position.y - 2048;
|
ForcedFixedCamera.y = trapDoorItem->Pose.Position.y - 2048;
|
||||||
|
|
||||||
if (ForcedFixedCamera.y < g_Level.Rooms[trapDoorItem->RoomNumber].maxceiling)
|
if (ForcedFixedCamera.y < g_Level.Rooms[trapDoorItem->RoomNumber].TopHeight)
|
||||||
ForcedFixedCamera.y = g_Level.Rooms[trapDoorItem->RoomNumber].maxceiling;
|
ForcedFixedCamera.y = g_Level.Rooms[trapDoorItem->RoomNumber].TopHeight;
|
||||||
|
|
||||||
ForcedFixedCamera.z = trapDoorItem->Pose.Position.z - phd_cos(trapDoorItem->Pose.Orientation.y) * 2048;
|
ForcedFixedCamera.z = trapDoorItem->Pose.Position.z - phd_cos(trapDoorItem->Pose.Orientation.y) * 2048;
|
||||||
ForcedFixedCamera.RoomNumber = trapDoorItem->RoomNumber;
|
ForcedFixedCamera.RoomNumber = trapDoorItem->RoomNumber;
|
||||||
|
|
182
TombEngine/Objects/TR1/Entity/Centaur.cpp
Normal file
182
TombEngine/Objects/TR1/Entity/Centaur.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "Objects/TR1/Entity/Centaur.h"
|
||||||
|
|
||||||
|
#include "Game/animation.h"
|
||||||
|
#include "Game/control/box.h"
|
||||||
|
#include "Game/collision/collide_item.h"
|
||||||
|
#include "Game/collision/collide_room.h"
|
||||||
|
#include "Game/effects/effects.h"
|
||||||
|
#include "Game/effects/tomb4fx.h"
|
||||||
|
#include "Game/items.h"
|
||||||
|
#include "Game/Lara/lara.h"
|
||||||
|
#include "Game/Lara/lara_one_gun.h"
|
||||||
|
#include "Game/misc.h"
|
||||||
|
#include "Game/missile.h"
|
||||||
|
#include "Game/people.h"
|
||||||
|
#include "Game/Setup.h"
|
||||||
|
#include "Math/Math.h"
|
||||||
|
#include "Sound/sound.h"
|
||||||
|
#include "Specific/level.h"
|
||||||
|
|
||||||
|
using namespace TEN::Math;
|
||||||
|
|
||||||
|
namespace TEN::Entities::Creatures::TR1
|
||||||
|
{
|
||||||
|
constexpr auto CENTAUR_REAR_DAMAGE = 200;
|
||||||
|
constexpr auto CENTAUR_REAR_RANGE = SQUARE(BLOCK(3 / 2.0f));
|
||||||
|
constexpr auto CENTAUR_REAR_CHANCE = 1 / 340.0f;
|
||||||
|
constexpr auto CENTAUR_BOMB_VELOCITY = CLICK(1);
|
||||||
|
|
||||||
|
constexpr auto CENTAUR_TURN_RATE_MAX = ANGLE(4.0f);
|
||||||
|
|
||||||
|
const auto CentaurRocketBite = CreatureBiteInfo(Vector3(11, 415, 41), 13);
|
||||||
|
const auto CentaurRearBite = CreatureBiteInfo(Vector3(50, 30, 0), 5);
|
||||||
|
const auto CentaurAttackJoints = std::vector<unsigned int>{ 0, 3, 4, 7, 8, 16, 17 };
|
||||||
|
|
||||||
|
enum CentaurState
|
||||||
|
{
|
||||||
|
// No state 0.
|
||||||
|
CENTAUR_STATE_IDLE = 1,
|
||||||
|
CENTAUR_PROJECTILE_ATTACK = 2,
|
||||||
|
CENTAUR_STATE_RUN_FORWARD = 3,
|
||||||
|
CENTAUR_STATE_AIM = 4,
|
||||||
|
CENTAUR_STATE_DEATH = 5,
|
||||||
|
CENTAUR_STATE_WARNING = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
enum CentaurAnim
|
||||||
|
{
|
||||||
|
CENTAUR_ANIM_DEATH = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ControlCentaur(short itemNumber)
|
||||||
|
{
|
||||||
|
if (!CreatureActive(itemNumber))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
auto& creature = *GetCreatureInfo(&item);
|
||||||
|
|
||||||
|
short headingAngle = 0;
|
||||||
|
auto headOrient = EulerAngles::Identity;
|
||||||
|
auto torsoOrient = EulerAngles::Identity;
|
||||||
|
|
||||||
|
if (item.HitPoints <= 0)
|
||||||
|
{
|
||||||
|
if (item.Animation.ActiveState != CENTAUR_STATE_DEATH)
|
||||||
|
SetAnimation(item, CENTAUR_ANIM_DEATH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AI_INFO ai;
|
||||||
|
CreatureAIInfo(&item, &ai);
|
||||||
|
|
||||||
|
if (ai.ahead)
|
||||||
|
{
|
||||||
|
headOrient.x = ai.xAngle;
|
||||||
|
headOrient.y = ai.angle;
|
||||||
|
torsoOrient.x = ai.xAngle / 2;
|
||||||
|
torsoOrient.y = ai.angle / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCreatureMood(&item, &ai, true);
|
||||||
|
CreatureMood(&item, &ai, true);
|
||||||
|
headingAngle = CreatureTurn(&item, CENTAUR_TURN_RATE_MAX);
|
||||||
|
|
||||||
|
switch (item.Animation.ActiveState)
|
||||||
|
{
|
||||||
|
case CENTAUR_STATE_IDLE:
|
||||||
|
if (item.Animation.RequiredState != NO_VALUE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = item.Animation.RequiredState;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < CENTAUR_REAR_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_RUN_FORWARD;
|
||||||
|
}
|
||||||
|
else if (Targetable(&item, &ai))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_AIM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_RUN_FORWARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CENTAUR_STATE_RUN_FORWARD:
|
||||||
|
torsoOrient = EulerAngles::Identity;
|
||||||
|
|
||||||
|
if (ai.bite && ai.distance < CENTAUR_REAR_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_IDLE;
|
||||||
|
item.Animation.RequiredState = CENTAUR_STATE_WARNING;
|
||||||
|
}
|
||||||
|
else if (Targetable(&item, &ai))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_IDLE;
|
||||||
|
item.Animation.RequiredState = CENTAUR_STATE_AIM;
|
||||||
|
}
|
||||||
|
else if (Random::TestProbability(CENTAUR_REAR_CHANCE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_IDLE;
|
||||||
|
item.Animation.RequiredState = CENTAUR_STATE_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CENTAUR_STATE_AIM:
|
||||||
|
if (item.Animation.RequiredState != NO_VALUE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = item.Animation.RequiredState;
|
||||||
|
}
|
||||||
|
else if (Targetable(&item, &ai))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_PROJECTILE_ATTACK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = CENTAUR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CENTAUR_PROJECTILE_ATTACK:
|
||||||
|
if (item.Animation.RequiredState == NO_VALUE)
|
||||||
|
{
|
||||||
|
item.Animation.RequiredState = CENTAUR_STATE_AIM;
|
||||||
|
CreatureEffect2(&item, CentaurRocketBite, CENTAUR_BOMB_VELOCITY, headOrient.y, BombGun);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CENTAUR_STATE_WARNING:
|
||||||
|
if (item.Animation.RequiredState == NO_VALUE &&
|
||||||
|
item.TouchBits.Test(CentaurAttackJoints))
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, CENTAUR_REAR_DAMAGE);
|
||||||
|
CreatureEffect(&item, CentaurRearBite, DoBloodSplat);
|
||||||
|
item.Animation.RequiredState = CENTAUR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureJoint(&item, 0, headOrient.y);
|
||||||
|
CreatureJoint(&item, 1, -headOrient.x);
|
||||||
|
CreatureJoint(&item, 2, torsoOrient.y);
|
||||||
|
CreatureJoint(&item, 3, -torsoOrient.x);
|
||||||
|
CreatureAnimation(itemNumber, headingAngle, 0);
|
||||||
|
|
||||||
|
if (item.Status == ITEM_DEACTIVATED)
|
||||||
|
{
|
||||||
|
SoundEffect(SFX_TR1_ATLANTEAN_DEATH, &item.Pose);
|
||||||
|
ExplodingDeath(itemNumber, BODY_DO_EXPLOSION);
|
||||||
|
KillItem(itemNumber);
|
||||||
|
item.Status = ITEM_DEACTIVATED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
namespace TEN::Entities::Creatures::TR1
|
namespace TEN::Entities::Creatures::TR1
|
||||||
{
|
{
|
||||||
constexpr auto SHARD_VELOCITY = 250;
|
constexpr auto SHARD_VELOCITY = 250;
|
||||||
constexpr auto BOMB_VELOCITY = 220;
|
constexpr auto BOMB_VELOCITY = 220;
|
||||||
|
|
||||||
void CentaurControl(short itemNumber);
|
void ControlCentaur(short itemNumber);
|
||||||
}
|
}
|
573
TombEngine/Objects/TR1/Entity/WingedMutant.cpp
Normal file
573
TombEngine/Objects/TR1/Entity/WingedMutant.cpp
Normal file
|
@ -0,0 +1,573 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "Objects/TR1/Entity/WingedMutant.h"
|
||||||
|
|
||||||
|
#include "Game/collision/collide_room.h"
|
||||||
|
#include "Game/control/box.h"
|
||||||
|
#include "Game/control/lot.h"
|
||||||
|
#include "Game/effects/effects.h"
|
||||||
|
#include "Game/effects/tomb4fx.h"
|
||||||
|
#include "Game/itemdata/creature_info.h"
|
||||||
|
#include "Game/items.h"
|
||||||
|
#include "Game/misc.h"
|
||||||
|
#include "Game/missile.h"
|
||||||
|
#include "Game/people.h"
|
||||||
|
#include "Math/Math.h"
|
||||||
|
#include "Sound/sound.h"
|
||||||
|
#include "Specific/level.h"
|
||||||
|
|
||||||
|
using namespace TEN::Math;
|
||||||
|
|
||||||
|
namespace TEN::Entities::Creatures::TR1
|
||||||
|
{
|
||||||
|
constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE = 150;
|
||||||
|
constexpr auto WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE = 100;
|
||||||
|
constexpr auto WINGED_MUTANT_SWIPE_ATTACK_DAMAGE = 200;
|
||||||
|
|
||||||
|
constexpr auto WINGED_MUTANT_WALK_RANGE = SQUARE(BLOCK(4.5f));
|
||||||
|
constexpr auto WINGED_MUTANT_SWIPE_ATTACK_RANGE = SQUARE(BLOCK(0.3f));
|
||||||
|
constexpr auto WINGED_MUTANT_RUN_JUMP_ATTACK_RANGE = SQUARE(BLOCK(0.65f));
|
||||||
|
constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_RANGE = SQUARE(BLOCK(2.5f));
|
||||||
|
constexpr auto WINGED_MUTANT_PROJECTILE_ATTACK_RANGE = SQUARE(BLOCK(3.0f));
|
||||||
|
constexpr auto WINGED_MUTANT_POSE_RANGE = SQUARE(BLOCK(4.5f));
|
||||||
|
|
||||||
|
constexpr auto WINGED_MUTANT_POSE_CHANCE = 1 / 400.0f;
|
||||||
|
constexpr auto WINGED_MUTANT_UNPOSE_CHANCE = 1 / 164.0f;
|
||||||
|
|
||||||
|
constexpr auto WINGED_MUTANT_FLY_VELOCITY = BLOCK(1 / 32.0f);
|
||||||
|
constexpr auto WINGED_MUTANT_SHARD_VELOCITY = 250;
|
||||||
|
constexpr auto WINGED_MUTANT_BOMB_VELOCITY = 220;
|
||||||
|
|
||||||
|
constexpr auto WINGED_MUTANT_WALK_TURN_RATE_MAX = ANGLE(2.0f);
|
||||||
|
constexpr auto WINGED_MUTANT_RUN_TURN_RATE_MAX = ANGLE(6.0f);
|
||||||
|
|
||||||
|
const auto WingedMutantBiteLeftHand = CreatureBiteInfo(Vector3(0, 0, 0), 7);
|
||||||
|
const auto WingedMutantBiteRightHand = CreatureBiteInfo(Vector3(0, 0, 0), 10);
|
||||||
|
const auto WingedMutantRocketBite = CreatureBiteInfo(Vector3(0, 200, 20), 6);
|
||||||
|
const auto WingedMutantShardBite = CreatureBiteInfo(Vector3(0, 200, 20), 9);
|
||||||
|
const auto WingedMutantHeadJoints = std::vector<unsigned int>{ 3 };
|
||||||
|
const auto WingedMutantHandsJoints = std::vector<unsigned int>{ 7, 10 };
|
||||||
|
const auto WingedMutantWingsJoints = std::vector<unsigned int>{ 15, 16, 17, 18, 19, 20 };
|
||||||
|
|
||||||
|
enum WingedMutantState
|
||||||
|
{
|
||||||
|
// No state 0.
|
||||||
|
WMUTANT_STATE_IDLE = 1,
|
||||||
|
WMUTANT_STATE_WALK_FORWARD = 2,
|
||||||
|
WMUTANT_STATE_RUN_FORWARD = 3,
|
||||||
|
WMUTANT_STATE_IDLE_JUMP_ATTACK = 4,
|
||||||
|
WMUTANT_STATE_DEATH = 5,
|
||||||
|
WMUTANT_STATE_POSE = 6,
|
||||||
|
WMUTANT_STATE_RUN_JUMP_ATTACK = 7,
|
||||||
|
WMUTANT_STATE_SWIPE_ATTACK = 8,
|
||||||
|
WMUTANT_STATE_AIM_DART = 9,
|
||||||
|
WMUTANT_STATE_AIM_BOMB = 10,
|
||||||
|
WMUTANT_STATE_SHOOT = 11,
|
||||||
|
WMUTANT_STATE_INACTIVE = 12,
|
||||||
|
WMUTANT_STATE_FLY = 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WingedMutantAnim
|
||||||
|
{
|
||||||
|
WMUTANT_ANIM_INACTIVE = 0,
|
||||||
|
WMUTANT_ANIM_INACTIVE_TO_IDLE = 1,
|
||||||
|
WMUTANT_ANIM_IDLE = 2,
|
||||||
|
WMUTANT_ANIM_IDLE_TO_RUN = 3,
|
||||||
|
WMUTANT_ANIM_RUN_FORWARD = 4,
|
||||||
|
WMUTANT_ANIM_IDLE_JUMP_ATTACK_START = 5,
|
||||||
|
WMUTANT_ANIM_IDLE_JUMP_ATTACK_END = 6,
|
||||||
|
WMUTANT_ANIM_IDLE_TO_POSE = 7,
|
||||||
|
WMUTANT_ANIM_POSE = 8,
|
||||||
|
WMUTANT_ANIM_POSE_TO_IDLE = 9,
|
||||||
|
WMUTANT_ANIM_POSE_TO_WALK_FORWARD = 10,
|
||||||
|
WMUTANT_ANIM_WALK_FORWARD = 11,
|
||||||
|
WMUTANT_ANIM_WALK_FORWARD_TO_IDLE = 12,
|
||||||
|
WMUTANT_ANIM_WALK_FORWARD_TO_POSE = 13,
|
||||||
|
WMUTANT_ANIM_RUN_JUMP_ATTACK = 14,
|
||||||
|
WMUTANT_ANIM_IDLE_TO_AIM_1 = 15,
|
||||||
|
WMUTANT_ANIM_AIM_DART = 16,
|
||||||
|
WMUTANT_ANIM_SHOOT_DART = 17,
|
||||||
|
WMUTANT_ANIM_AIM_DART_TO_IDLE = 18,
|
||||||
|
WMUTANT_ANIM_IDLE_TO_AIM_BOMB = 19,
|
||||||
|
WMUTANT_ANIM_SHOOT_BOMB = 20,
|
||||||
|
WMUTANT_ANIM_RUN_FORWARD_TO_IDLE = 21,
|
||||||
|
WMUTANT_ANIM_AIM_BOMB_TO_IDLE = 22,
|
||||||
|
WMUTANT_ANIM_IDLE_TO_FLY = 23,
|
||||||
|
WMUTANT_ANIM_FLY = 24,
|
||||||
|
WMUTANT_ANIM_FLY_TO_IDLE = 25,
|
||||||
|
WMUTANT_ANIM_SWIPE_ATTACK = 26
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WingedMutantPathFinding
|
||||||
|
{
|
||||||
|
WMUTANT_PATH_GROUND = 1,
|
||||||
|
WMUTANT_PATH_AERIAL = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: Originally, winged mutants did not have OCBs. -- TokyoSU 5/8/2022
|
||||||
|
enum WingedMutantOcb
|
||||||
|
{
|
||||||
|
WMUTANT_OCB_START_AERIAL = (1 << 0),
|
||||||
|
WMUTANT_OCB_START_INACTIVE = (1 << 1),
|
||||||
|
WMUTANT_OCB_START_POSE = (1 << 2),
|
||||||
|
WMUTANT_OCB_NO_WINGS = (1 << 3),
|
||||||
|
WMUTANT_OCB_DISABLE_DART_WEAPON = (1 << 4),
|
||||||
|
WMUTANT_OCB_DISABLE_BOMB_WEAPON = (1 << 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WingedMutantProjectileType
|
||||||
|
{
|
||||||
|
WMUTANT_PROJ_NONE,
|
||||||
|
WMUTANT_PROJ_DART,
|
||||||
|
WMUTANT_PROJ_BOMB
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WingedMutantConfig
|
||||||
|
{
|
||||||
|
WMUTANT_CONF_CAN_FLY,
|
||||||
|
WMUTANT_CONF_PATHFINDING_MODE,
|
||||||
|
WMUTANT_CONF_PROJECTILE_MODE,
|
||||||
|
WMUTANT_CONF_NO_WINGS,
|
||||||
|
WMUTANT_CONF_DISABLE_DART_WEAPON,
|
||||||
|
WMUTANT_CONF_DISABLE_BOMB_WEAPON
|
||||||
|
};
|
||||||
|
|
||||||
|
static void SwitchPathfinding(ItemInfo& item, WingedMutantPathFinding path)
|
||||||
|
{
|
||||||
|
auto& creature = *GetCreatureInfo(&item);
|
||||||
|
|
||||||
|
switch (path)
|
||||||
|
{
|
||||||
|
case WMUTANT_PATH_GROUND:
|
||||||
|
creature.LOT.Step = CLICK(1);
|
||||||
|
creature.LOT.Drop = -CLICK(1);
|
||||||
|
creature.LOT.Fly = NO_FLYING;
|
||||||
|
creature.LOT.Zone = ZoneType::Basic;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_PATH_AERIAL:
|
||||||
|
creature.LOT.Step = BLOCK(20);
|
||||||
|
creature.LOT.Drop = -BLOCK(20);
|
||||||
|
creature.LOT.Fly = WINGED_MUTANT_FLY_VELOCITY;
|
||||||
|
creature.LOT.Zone = ZoneType::Flyer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static WingedMutantProjectileType CanTargetPlayer(ItemInfo& item, AI_INFO& ai)
|
||||||
|
{
|
||||||
|
if (Targetable(&item, &ai) &&
|
||||||
|
(ai.zoneNumber != ai.enemyZone || ai.distance > WINGED_MUTANT_PROJECTILE_ATTACK_RANGE))
|
||||||
|
{
|
||||||
|
if ((ai.angle > 0 && ai.angle < ANGLE(45.0f)) &&
|
||||||
|
item.TestFlagField(WMUTANT_CONF_DISABLE_DART_WEAPON, false))
|
||||||
|
{
|
||||||
|
return WMUTANT_PROJ_DART;
|
||||||
|
}
|
||||||
|
else if ((ai.angle < 0 && ai.angle > ANGLE(-45.0f)) &&
|
||||||
|
item.TestFlagField(WMUTANT_CONF_DISABLE_BOMB_WEAPON, false))
|
||||||
|
{
|
||||||
|
return WMUTANT_PROJ_BOMB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot be targeted.
|
||||||
|
return WMUTANT_PROJ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitializeWingedMutantOCB(ItemInfo& item)
|
||||||
|
{
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_START_AERIAL))
|
||||||
|
{
|
||||||
|
SwitchPathfinding(item, WMUTANT_PATH_AERIAL);
|
||||||
|
SetAnimation(item, WMUTANT_ANIM_FLY);
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_AERIAL);
|
||||||
|
}
|
||||||
|
else if (item.TestOcb(WMUTANT_OCB_START_INACTIVE))
|
||||||
|
{
|
||||||
|
SwitchPathfinding(item, WMUTANT_PATH_GROUND);
|
||||||
|
SetAnimation(item, WMUTANT_ANIM_INACTIVE);
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
||||||
|
}
|
||||||
|
else if (item.TestOcb(WMUTANT_OCB_START_POSE))
|
||||||
|
{
|
||||||
|
SwitchPathfinding(item, WMUTANT_PATH_GROUND);
|
||||||
|
SetAnimation(item, WMUTANT_ANIM_INACTIVE);
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove unnecessary OCBs.
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_START_AERIAL))
|
||||||
|
item.RemoveOcb(WMUTANT_OCB_START_AERIAL);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_START_INACTIVE))
|
||||||
|
item.RemoveOcb(WMUTANT_OCB_START_INACTIVE);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_START_POSE))
|
||||||
|
item.RemoveOcb(WMUTANT_OCB_START_POSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeWingedMutant(short itemNumber)
|
||||||
|
{
|
||||||
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
|
||||||
|
InitializeCreature(itemNumber);
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_NONE);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_NO_WINGS))
|
||||||
|
{
|
||||||
|
item.SetFlagField(WMUTANT_CONF_CAN_FLY, false);
|
||||||
|
item.MeshBits.Clear(WingedMutantWingsJoints);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.SetFlagField(WMUTANT_CONF_CAN_FLY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_DISABLE_BOMB_WEAPON))
|
||||||
|
item.SetFlagField(WMUTANT_CONF_DISABLE_BOMB_WEAPON, true);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_DISABLE_DART_WEAPON))
|
||||||
|
item.SetFlagField(WMUTANT_CONF_DISABLE_DART_WEAPON, true);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_DISABLE_BOMB_WEAPON))
|
||||||
|
item.RemoveOcb(WMUTANT_OCB_DISABLE_BOMB_WEAPON);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_DISABLE_DART_WEAPON))
|
||||||
|
item.RemoveOcb(WMUTANT_OCB_DISABLE_DART_WEAPON);
|
||||||
|
|
||||||
|
if (item.TestOcb(WMUTANT_OCB_NO_WINGS))
|
||||||
|
item.RemoveOcb(WMUTANT_OCB_NO_WINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlWingedMutant(short itemNumber)
|
||||||
|
{
|
||||||
|
if (!CreatureActive(itemNumber))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
auto& creature = *GetCreatureInfo(&item);
|
||||||
|
|
||||||
|
short headingAngle = 0;
|
||||||
|
short headYOrient = 0;
|
||||||
|
short torsoYOrient = 0; // Only when shooting.
|
||||||
|
|
||||||
|
bool enableFlying = item.TestFlagField(WMUTANT_CONF_CAN_FLY, true);
|
||||||
|
bool isFlying = item.TestFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_AERIAL);
|
||||||
|
|
||||||
|
InitializeWingedMutantOCB(item);
|
||||||
|
|
||||||
|
if (item.HitPoints <= 0)
|
||||||
|
{
|
||||||
|
CreatureDie(itemNumber, true, BODY_DO_EXPLOSION | BODY_PART_EXPLODE | BODY_NO_SMOKE | BODY_NO_SHATTER_EFFECT);
|
||||||
|
|
||||||
|
auto pos = item.Pose;
|
||||||
|
pos.Position.y -= CLICK(3);
|
||||||
|
TriggerExplosionSparks(pos.Position.x, pos.Position.y, pos.Position.z, 3, -2, 0, item.RoomNumber);
|
||||||
|
TriggerExplosionSparks(pos.Position.x, pos.Position.y, pos.Position.z, 3, -1, 0, item.RoomNumber);
|
||||||
|
TriggerShockwave(&pos, 48, 304, (GetRandomControl() & 0x1F) + 112, 128, 32, 32, 32, EulerAngles(2048, 0.0f, 0.0f), 0, true, false, false, (int)ShockwaveStyle::Normal);
|
||||||
|
|
||||||
|
SoundEffect(SFX_TR1_ATLANTEAN_EXPLODE, &item.Pose);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AI_INFO ai;
|
||||||
|
SwitchPathfinding(item, WMUTANT_PATH_GROUND);
|
||||||
|
CreatureAIInfo(&item, &ai);
|
||||||
|
|
||||||
|
bool isSameZoneInGroundMode = (ai.zoneNumber == ai.enemyZone);
|
||||||
|
auto projectileType = CanTargetPlayer(item, ai);
|
||||||
|
|
||||||
|
if (enableFlying && item.Animation.ActiveState == WMUTANT_STATE_FLY)
|
||||||
|
{
|
||||||
|
SwitchPathfinding(item, WMUTANT_PATH_AERIAL);
|
||||||
|
CreatureAIInfo(&item, &ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ai.ahead)
|
||||||
|
{
|
||||||
|
headYOrient = ai.angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
headYOrient = 0;
|
||||||
|
torsoYOrient = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCreatureMood(&item, &ai, isFlying);
|
||||||
|
CreatureMood(&item, &ai, isFlying);
|
||||||
|
headingAngle = CreatureTurn(&item, creature.MaxTurn);
|
||||||
|
|
||||||
|
switch (item.Animation.ActiveState)
|
||||||
|
{
|
||||||
|
case WMUTANT_STATE_INACTIVE:
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.Flags = 0;
|
||||||
|
|
||||||
|
if (TargetVisible(&item, &ai) || creature.HurtByLara)
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_IDLE:
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PROJ_NONE);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.Flags = 0;
|
||||||
|
torsoYOrient = 0;
|
||||||
|
|
||||||
|
if (enableFlying && !isSameZoneInGroundMode)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_FLY;
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_AERIAL);
|
||||||
|
}
|
||||||
|
else if (item.TouchBits.Test(WingedMutantHeadJoints))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < WINGED_MUTANT_IDLE_JUMP_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE_JUMP_ATTACK;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < WINGED_MUTANT_SWIPE_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
||||||
|
}
|
||||||
|
else if (projectileType == WMUTANT_PROJ_DART)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_AIM_DART;
|
||||||
|
}
|
||||||
|
else if (projectileType == WMUTANT_PROJ_BOMB)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_AIM_BOMB;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Bored ||
|
||||||
|
(creature.Mood == MoodType::Stalk && ai.distance < WINGED_MUTANT_POSE_RANGE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_POSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_RUN_FORWARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_POSE:
|
||||||
|
creature.Flags = 0;
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
headYOrient = 0; // NOTE: Pose has animation for head.
|
||||||
|
|
||||||
|
if (projectileType != WMUTANT_PROJ_NONE || (isFlying && enableFlying))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Stalk)
|
||||||
|
{
|
||||||
|
if (ai.distance < WINGED_MUTANT_WALK_RANGE)
|
||||||
|
{
|
||||||
|
if (isSameZoneInGroundMode ||
|
||||||
|
Random::TestProbability(WINGED_MUTANT_UNPOSE_CHANCE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_WALK_FORWARD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Bored && Random::TestProbability(WINGED_MUTANT_UNPOSE_CHANCE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_WALK_FORWARD;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Attack ||
|
||||||
|
creature.Mood == MoodType::Escape)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_WALK_FORWARD:
|
||||||
|
creature.MaxTurn = WINGED_MUTANT_WALK_TURN_RATE_MAX;
|
||||||
|
creature.Flags = 0;
|
||||||
|
|
||||||
|
if (projectileType != WMUTANT_PROJ_NONE || (isFlying && enableFlying))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Attack || creature.Mood == MoodType::Escape)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Bored ||
|
||||||
|
(creature.Mood == MoodType::Stalk && !isSameZoneInGroundMode))
|
||||||
|
{
|
||||||
|
if (Random::TestProbability(WINGED_MUTANT_POSE_CHANCE))
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_POSE;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Stalk &&
|
||||||
|
ai.distance > WINGED_MUTANT_WALK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_RUN_FORWARD:
|
||||||
|
creature.MaxTurn = WINGED_MUTANT_RUN_TURN_RATE_MAX;
|
||||||
|
creature.Flags = 0;
|
||||||
|
|
||||||
|
if (enableFlying && !isSameZoneInGroundMode)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (projectileType != WMUTANT_PROJ_NONE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (item.TouchBits.Test(WingedMutantHeadJoints))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < WINGED_MUTANT_RUN_JUMP_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_RUN_JUMP_ATTACK;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < WINGED_MUTANT_SWIPE_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
||||||
|
}
|
||||||
|
else if (ai.ahead && ai.distance < WINGED_MUTANT_SWIPE_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Bored ||
|
||||||
|
(creature.Mood == MoodType::Stalk && ai.distance < WINGED_MUTANT_POSE_RANGE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_IDLE_JUMP_ATTACK:
|
||||||
|
if (item.Animation.RequiredState == NO_VALUE &&
|
||||||
|
(item.TouchBits.Test(WingedMutantHandsJoints) || item.TouchBits.Test(WingedMutantHeadJoints)) && creature.Flags == 0)
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE / 2);
|
||||||
|
CreatureEffect(&item, WingedMutantBiteLeftHand, DoBloodSplat);
|
||||||
|
|
||||||
|
DoDamage(creature.Enemy, WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE / 2);
|
||||||
|
CreatureEffect(&item, WingedMutantBiteRightHand, DoBloodSplat);
|
||||||
|
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
creature.Flags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_RUN_JUMP_ATTACK:
|
||||||
|
if (item.Animation.RequiredState == NO_VALUE &&
|
||||||
|
(item.TouchBits.Test(WingedMutantHandsJoints) || item.TouchBits.Test(WingedMutantHeadJoints)) && creature.Flags == 0)
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE / 2);
|
||||||
|
CreatureEffect(&item, WingedMutantBiteLeftHand, DoBloodSplat);
|
||||||
|
|
||||||
|
DoDamage(creature.Enemy, WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE / 2);
|
||||||
|
CreatureEffect(&item, WingedMutantBiteRightHand, DoBloodSplat);
|
||||||
|
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_RUN_FORWARD;
|
||||||
|
creature.Flags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_SWIPE_ATTACK:
|
||||||
|
if (item.Animation.RequiredState == NO_VALUE &&
|
||||||
|
item.TouchBits.Test(WingedMutantHandsJoints) && creature.Flags == 0)
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, WINGED_MUTANT_SWIPE_ATTACK_DAMAGE / 2);
|
||||||
|
CreatureEffect(&item, WingedMutantBiteLeftHand, DoBloodSplat);
|
||||||
|
|
||||||
|
DoDamage(creature.Enemy, WINGED_MUTANT_SWIPE_ATTACK_DAMAGE / 2);
|
||||||
|
CreatureEffect(&item, WingedMutantBiteRightHand, DoBloodSplat);
|
||||||
|
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
creature.Flags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_AIM_DART:
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_DART);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.Flags = 0;
|
||||||
|
torsoYOrient = ai.angle / 2;
|
||||||
|
|
||||||
|
if (projectileType == WMUTANT_PROJ_DART)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_SHOOT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_AIM_BOMB:
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_BOMB);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.Flags = 0;
|
||||||
|
torsoYOrient = ai.angle / 2;
|
||||||
|
|
||||||
|
if (projectileType == WMUTANT_PROJ_BOMB)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_SHOOT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_SHOOT:
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
torsoYOrient = ai.angle / 2;
|
||||||
|
|
||||||
|
if (creature.Flags == 0)
|
||||||
|
{
|
||||||
|
if (projectileType == WMUTANT_PROJ_DART)
|
||||||
|
{
|
||||||
|
CreatureEffect2(&item, WingedMutantShardBite, WINGED_MUTANT_SHARD_VELOCITY, torsoYOrient, ShardGun);
|
||||||
|
}
|
||||||
|
else if (projectileType == WMUTANT_PROJ_BOMB)
|
||||||
|
{
|
||||||
|
CreatureEffect2(&item, WingedMutantRocketBite, WINGED_MUTANT_BOMB_VELOCITY, torsoYOrient, BombGun);
|
||||||
|
}
|
||||||
|
|
||||||
|
creature.Flags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_NONE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WMUTANT_STATE_FLY:
|
||||||
|
if (creature.Mood != MoodType::Escape && isSameZoneInGroundMode)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = WMUTANT_STATE_IDLE; // Switch to ground mode.
|
||||||
|
item.Pose.Position.y = item.Floor;
|
||||||
|
item.SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureJoint(&item, 0, torsoYOrient);
|
||||||
|
CreatureJoint(&item, 1, headYOrient);
|
||||||
|
CreatureAnimation(itemNumber, headingAngle, 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,5 @@
|
||||||
namespace TEN::Entities::Creatures::TR1
|
namespace TEN::Entities::Creatures::TR1
|
||||||
{
|
{
|
||||||
void InitializeWingedMutant(short itemNumber);
|
void InitializeWingedMutant(short itemNumber);
|
||||||
void WingedMutantControl(short itemNumber);
|
void ControlWingedMutant(short itemNumber);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
#include "framework.h"
|
|
||||||
#include "Objects/TR1/Entity/tr1_centaur.h"
|
|
||||||
|
|
||||||
#include "Game/animation.h"
|
|
||||||
#include "Game/control/box.h"
|
|
||||||
#include "Game/collision/collide_item.h"
|
|
||||||
#include "Game/collision/collide_room.h"
|
|
||||||
#include "Game/effects/effects.h"
|
|
||||||
#include "Game/effects/tomb4fx.h"
|
|
||||||
#include "Game/items.h"
|
|
||||||
#include "Game/Lara/lara.h"
|
|
||||||
#include "Game/Lara/lara_one_gun.h"
|
|
||||||
#include "Game/misc.h"
|
|
||||||
#include "Game/missile.h"
|
|
||||||
#include "Game/people.h"
|
|
||||||
#include "Game/Setup.h"
|
|
||||||
#include "Math/Math.h"
|
|
||||||
#include "Sound/sound.h"
|
|
||||||
#include "Specific/level.h"
|
|
||||||
|
|
||||||
using namespace TEN::Math;
|
|
||||||
|
|
||||||
namespace TEN::Entities::Creatures::TR1
|
|
||||||
{
|
|
||||||
constexpr auto CENTAUR_REAR_DAMAGE = 200;
|
|
||||||
constexpr auto CENTAUR_REAR_RANGE = BLOCK(3 / 2.0f);
|
|
||||||
constexpr auto CENTAUR_REAR_CHANCE = 1 / 340.0f;
|
|
||||||
constexpr auto CENTAUR_BOMB_VELOCITY = CLICK(1);
|
|
||||||
|
|
||||||
constexpr auto CENTAUR_TURN_RATE_MAX = ANGLE(4.0f);
|
|
||||||
|
|
||||||
const auto CentaurRocketBite = CreatureBiteInfo(Vector3(11, 415, 41), 13);
|
|
||||||
const auto CentaurRearBite = CreatureBiteInfo(Vector3(50, 30, 0), 5);
|
|
||||||
const auto CentaurAttackJoints = std::vector<unsigned int>{ 0, 3, 4, 7, 8, 16, 17 };
|
|
||||||
|
|
||||||
enum CentaurState
|
|
||||||
{
|
|
||||||
// No state 0.
|
|
||||||
CENTAUR_STATE_IDLE = 1,
|
|
||||||
CENTAUR_PROJECTILE_ATTACK = 2,
|
|
||||||
CENTAUR_STATE_RUN_FORWARD = 3,
|
|
||||||
CENTAUR_STATE_AIM = 4,
|
|
||||||
CENTAUR_STATE_DEATH = 5,
|
|
||||||
CENTAUR_STATE_WARNING = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
enum CentaurAnim
|
|
||||||
{
|
|
||||||
CENTAUR_ANIM_DEATH = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
void CentaurControl(short itemNumber)
|
|
||||||
{
|
|
||||||
if (!CreatureActive(itemNumber))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
|
||||||
auto* creature = GetCreatureInfo(item);
|
|
||||||
|
|
||||||
short angle = 0;
|
|
||||||
short head = 0;
|
|
||||||
|
|
||||||
if (item->HitPoints <= 0)
|
|
||||||
{
|
|
||||||
if (item->Animation.ActiveState != CENTAUR_STATE_DEATH)
|
|
||||||
SetAnimation(item, CENTAUR_ANIM_DEATH);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AI_INFO AI;
|
|
||||||
CreatureAIInfo(item, &AI);
|
|
||||||
|
|
||||||
if (AI.ahead)
|
|
||||||
head = AI.angle;
|
|
||||||
|
|
||||||
CreatureMood(item, &AI, true);
|
|
||||||
|
|
||||||
angle = CreatureTurn(item, CENTAUR_TURN_RATE_MAX);
|
|
||||||
|
|
||||||
switch (item->Animation.ActiveState)
|
|
||||||
{
|
|
||||||
case CENTAUR_STATE_IDLE:
|
|
||||||
CreatureJoint(item, 17, 0);
|
|
||||||
if (item->Animation.RequiredState != NO_VALUE)
|
|
||||||
item->Animation.TargetState = item->Animation.RequiredState;
|
|
||||||
else if (AI.bite && AI.distance < pow(CENTAUR_REAR_RANGE, 2))
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_RUN_FORWARD;
|
|
||||||
else if (Targetable(item, &AI))
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_AIM;
|
|
||||||
else
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_RUN_FORWARD;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CENTAUR_STATE_RUN_FORWARD:
|
|
||||||
if (AI.bite && AI.distance < pow(CENTAUR_REAR_RANGE, 2))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_IDLE;
|
|
||||||
item->Animation.RequiredState = CENTAUR_STATE_WARNING;
|
|
||||||
}
|
|
||||||
else if (Targetable(item, &AI))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_IDLE;
|
|
||||||
item->Animation.RequiredState = CENTAUR_STATE_AIM;
|
|
||||||
}
|
|
||||||
else if (Random::TestProbability(CENTAUR_REAR_CHANCE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_IDLE;
|
|
||||||
item->Animation.RequiredState = CENTAUR_STATE_WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CENTAUR_STATE_AIM:
|
|
||||||
if (item->Animation.RequiredState != NO_VALUE)
|
|
||||||
item->Animation.TargetState = item->Animation.RequiredState;
|
|
||||||
else if (Targetable(item, &AI))
|
|
||||||
item->Animation.TargetState = CENTAUR_PROJECTILE_ATTACK;
|
|
||||||
else
|
|
||||||
item->Animation.TargetState = CENTAUR_STATE_IDLE;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CENTAUR_PROJECTILE_ATTACK:
|
|
||||||
if (item->Animation.RequiredState == NO_VALUE)
|
|
||||||
{
|
|
||||||
item->Animation.RequiredState = CENTAUR_STATE_AIM;
|
|
||||||
CreatureEffect2(item, CentaurRocketBite, CENTAUR_BOMB_VELOCITY, head, BombGun);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CENTAUR_STATE_WARNING:
|
|
||||||
if (item->Animation.RequiredState == NO_VALUE &&
|
|
||||||
item->TouchBits.Test(CentaurAttackJoints))
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, CENTAUR_REAR_DAMAGE);
|
|
||||||
CreatureEffect(item, CentaurRearBite, DoBloodSplat);
|
|
||||||
item->Animation.RequiredState = CENTAUR_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CreatureJoint(item, 0, head);
|
|
||||||
CreatureAnimation(itemNumber, angle, 0);
|
|
||||||
|
|
||||||
if (item->Status == ITEM_DEACTIVATED)
|
|
||||||
{
|
|
||||||
SoundEffect(SFX_TR1_ATLANTEAN_DEATH, &item->Pose);
|
|
||||||
ExplodingDeath(itemNumber, BODY_DO_EXPLOSION);
|
|
||||||
KillItem(itemNumber);
|
|
||||||
item->Status = ITEM_DEACTIVATED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,571 +0,0 @@
|
||||||
#include "framework.h"
|
|
||||||
#include "Objects/TR1/Entity/tr1_winged_mutant.h"
|
|
||||||
|
|
||||||
#include "Game/collision/collide_room.h"
|
|
||||||
#include "Game/control/box.h"
|
|
||||||
#include "Game/control/lot.h"
|
|
||||||
#include "Game/effects/effects.h"
|
|
||||||
#include "Game/effects/tomb4fx.h"
|
|
||||||
#include "Game/itemdata/creature_info.h"
|
|
||||||
#include "Game/items.h"
|
|
||||||
#include "Game/misc.h"
|
|
||||||
#include "Game/missile.h"
|
|
||||||
#include "Game/people.h"
|
|
||||||
#include "Math/Math.h"
|
|
||||||
#include "Sound/sound.h"
|
|
||||||
#include "Specific/level.h"
|
|
||||||
|
|
||||||
using namespace TEN::Math;
|
|
||||||
|
|
||||||
namespace TEN::Entities::Creatures::TR1
|
|
||||||
{
|
|
||||||
constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE = 150;
|
|
||||||
constexpr auto WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE = 100;
|
|
||||||
constexpr auto WINGED_MUTANT_SWIPE_ATTACK_DAMAGE = 200;
|
|
||||||
|
|
||||||
constexpr auto WINGED_MUTANT_WALK_RANGE = SQUARE(BLOCK(4.5f));
|
|
||||||
constexpr auto WINGED_MUTANT_SWIPE_ATTACK_RANGE = SQUARE(BLOCK(0.3f));
|
|
||||||
constexpr auto WINGED_MUTANT_RUN_JUMP_ATTACK_RANGE = SQUARE(BLOCK(0.65f));
|
|
||||||
constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_RANGE = SQUARE(BLOCK(2.5f));
|
|
||||||
constexpr auto WINGED_MUTANT_PROJECTILE_ATTACK_RANGE = SQUARE(BLOCK(3.0f));
|
|
||||||
constexpr auto WINGED_MUTANT_POSE_RANGE = SQUARE(BLOCK(4.5f));
|
|
||||||
|
|
||||||
constexpr auto WINGED_MUTANT_POSE_CHANCE = 1 / 400.0f;
|
|
||||||
constexpr auto WINGED_MUTANT_UNPOSE_CHANCE = 1 / 164.0f;
|
|
||||||
|
|
||||||
constexpr auto WINGED_MUTANT_FLY_VELOCITY = BLOCK(1 / 32.0f);
|
|
||||||
constexpr auto WINGED_MUTANT_SHARD_VELOCITY = 250;
|
|
||||||
constexpr auto WINGED_MUTANT_BOMB_VELOCITY = 220;
|
|
||||||
|
|
||||||
constexpr auto WINGED_MUTANT_WALK_TURN_RATE_MAX = ANGLE(2.0f);
|
|
||||||
constexpr auto WINGED_MUTANT_RUN_TURN_RATE_MAX = ANGLE(6.0f);
|
|
||||||
|
|
||||||
const auto WingedMutantBiteLeftHand = CreatureBiteInfo(Vector3(0, 0, 0), 7);
|
|
||||||
const auto WingedMutantBiteRightHand = CreatureBiteInfo(Vector3(0, 0, 0), 10);
|
|
||||||
const auto WingedMutantRocketBite = CreatureBiteInfo(Vector3(0, 200, 20), 6);
|
|
||||||
const auto WingedMutantShardBite = CreatureBiteInfo(Vector3(0, 200, 20), 9);
|
|
||||||
const auto WingedMutantHeadJoints = std::vector<unsigned int>{ 3 };
|
|
||||||
const auto WingedMutantHandsJoints = std::vector<unsigned int>{ 7, 10 };
|
|
||||||
const auto WingedMutantWingsJoints = std::vector<unsigned int>{ 15, 16, 17, 18, 19, 20 };
|
|
||||||
|
|
||||||
enum WingedMutantState
|
|
||||||
{
|
|
||||||
// No state 0.
|
|
||||||
WMUTANT_STATE_IDLE = 1,
|
|
||||||
WMUTANT_STATE_WALK_FORWARD = 2,
|
|
||||||
WMUTANT_STATE_RUN_FORWARD = 3,
|
|
||||||
WMUTANT_STATE_IDLE_JUMP_ATTACK = 4,
|
|
||||||
WMUTANT_STATE_DEATH = 5,
|
|
||||||
WMUTANT_STATE_POSE = 6,
|
|
||||||
WMUTANT_STATE_RUN_JUMP_ATTACK = 7,
|
|
||||||
WMUTANT_STATE_SWIPE_ATTACK = 8,
|
|
||||||
WMUTANT_STATE_AIM_DART = 9,
|
|
||||||
WMUTANT_STATE_AIM_BOMB = 10,
|
|
||||||
WMUTANT_STATE_SHOOT = 11,
|
|
||||||
WMUTANT_STATE_INACTIVE = 12,
|
|
||||||
WMUTANT_STATE_FLY = 13,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WingedMutantAnim
|
|
||||||
{
|
|
||||||
WMUTANT_ANIM_INACTIVE = 0,
|
|
||||||
WMUTANT_ANIM_INACTIVE_TO_IDLE = 1,
|
|
||||||
WMUTANT_ANIM_IDLE = 2,
|
|
||||||
WMUTANT_ANIM_IDLE_TO_RUN = 3,
|
|
||||||
WMUTANT_ANIM_RUN_FORWARD = 4,
|
|
||||||
WMUTANT_ANIM_IDLE_JUMP_ATTACK_START = 5,
|
|
||||||
WMUTANT_ANIM_IDLE_JUMP_ATTACK_END = 6,
|
|
||||||
WMUTANT_ANIM_IDLE_TO_POSE = 7,
|
|
||||||
WMUTANT_ANIM_POSE = 8,
|
|
||||||
WMUTANT_ANIM_POSE_TO_IDLE = 9,
|
|
||||||
WMUTANT_ANIM_POSE_TO_WALK_FORWARD = 10,
|
|
||||||
WMUTANT_ANIM_WALK_FORWARD = 11,
|
|
||||||
WMUTANT_ANIM_WALK_FORWARD_TO_IDLE = 12,
|
|
||||||
WMUTANT_ANIM_WALK_FORWARD_TO_POSE = 13,
|
|
||||||
WMUTANT_ANIM_RUN_JUMP_ATTACK = 14,
|
|
||||||
WMUTANT_ANIM_IDLE_TO_AIM_1 = 15,
|
|
||||||
WMUTANT_ANIM_AIM_DART = 16,
|
|
||||||
WMUTANT_ANIM_SHOOT_DART = 17,
|
|
||||||
WMUTANT_ANIM_AIM_DART_TO_IDLE = 18,
|
|
||||||
WMUTANT_ANIM_IDLE_TO_AIM_BOMB = 19,
|
|
||||||
WMUTANT_ANIM_SHOOT_BOMB = 20,
|
|
||||||
WMUTANT_ANIM_RUN_FORWARD_TO_IDLE = 21,
|
|
||||||
WMUTANT_ANIM_AIM_BOMB_TO_IDLE = 22,
|
|
||||||
WMUTANT_ANIM_IDLE_TO_FLY = 23,
|
|
||||||
WMUTANT_ANIM_FLY = 24,
|
|
||||||
WMUTANT_ANIM_FLY_TO_IDLE = 25,
|
|
||||||
WMUTANT_ANIM_SWIPE_ATTACK = 26
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WingedMutantPathFinding
|
|
||||||
{
|
|
||||||
WMUTANT_PATH_GROUND = 1,
|
|
||||||
WMUTANT_PATH_AERIAL = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE: Originally, winged mutants did not have OCBs. -- TokyoSU 5/8/2022
|
|
||||||
enum WingedMutantOcb
|
|
||||||
{
|
|
||||||
WMUTANT_OCB_START_AERIAL = (1 << 0),
|
|
||||||
WMUTANT_OCB_START_INACTIVE = (1 << 1),
|
|
||||||
WMUTANT_OCB_START_POSE = (1 << 2),
|
|
||||||
WMUTANT_OCB_NO_WINGS = (1 << 3),
|
|
||||||
WMUTANT_OCB_DISABLE_DART_WEAPON = (1 << 4),
|
|
||||||
WMUTANT_OCB_DISABLE_BOMB_WEAPON = (1 << 5)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WingedMutantProjectileType
|
|
||||||
{
|
|
||||||
WMUTANT_PROJ_NONE,
|
|
||||||
WMUTANT_PROJ_DART,
|
|
||||||
WMUTANT_PROJ_BOMB
|
|
||||||
};
|
|
||||||
|
|
||||||
enum WingedMutantConfig
|
|
||||||
{
|
|
||||||
WMUTANT_CONF_CAN_FLY,
|
|
||||||
WMUTANT_CONF_PATHFINDING_MODE,
|
|
||||||
WMUTANT_CONF_PROJECTILE_MODE,
|
|
||||||
WMUTANT_CONF_NO_WINGS,
|
|
||||||
WMUTANT_CONF_DISABLE_DART_WEAPON,
|
|
||||||
WMUTANT_CONF_DISABLE_BOMB_WEAPON
|
|
||||||
};
|
|
||||||
|
|
||||||
static void SwitchPathfinding(CreatureInfo* creature, WingedMutantPathFinding path)
|
|
||||||
{
|
|
||||||
switch (path)
|
|
||||||
{
|
|
||||||
case WMUTANT_PATH_GROUND:
|
|
||||||
creature->LOT.Step = CLICK(1);
|
|
||||||
creature->LOT.Drop = -CLICK(1);
|
|
||||||
creature->LOT.Fly = NO_FLYING;
|
|
||||||
creature->LOT.Zone = ZoneType::Basic;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_PATH_AERIAL:
|
|
||||||
creature->LOT.Step = BLOCK(20);
|
|
||||||
creature->LOT.Drop = -BLOCK(20);
|
|
||||||
creature->LOT.Fly = WINGED_MUTANT_FLY_VELOCITY;
|
|
||||||
creature->LOT.Zone = ZoneType::Flyer;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static WingedMutantProjectileType CanTargetLara(ItemInfo* item, CreatureInfo* creature, AI_INFO* AI)
|
|
||||||
{
|
|
||||||
if (Targetable(item, AI) &&
|
|
||||||
(AI->zoneNumber != AI->enemyZone || AI->distance > WINGED_MUTANT_PROJECTILE_ATTACK_RANGE))
|
|
||||||
{
|
|
||||||
if ((AI->angle > 0 && AI->angle < ANGLE(45.0f)) &&
|
|
||||||
item->TestFlagField(WMUTANT_CONF_DISABLE_DART_WEAPON, false))
|
|
||||||
{
|
|
||||||
return WMUTANT_PROJ_DART;
|
|
||||||
}
|
|
||||||
else if ((AI->angle < 0 && AI->angle > -ANGLE(45.0f)) &&
|
|
||||||
item->TestFlagField(WMUTANT_CONF_DISABLE_BOMB_WEAPON, false))
|
|
||||||
{
|
|
||||||
return WMUTANT_PROJ_BOMB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cannot be targeted.
|
|
||||||
return WMUTANT_PROJ_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WingedInitOCB(ItemInfo* item, CreatureInfo* creature)
|
|
||||||
{
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_START_AERIAL))
|
|
||||||
{
|
|
||||||
SwitchPathfinding(creature, WMUTANT_PATH_AERIAL);
|
|
||||||
SetAnimation(item, WMUTANT_ANIM_FLY);
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_AERIAL);
|
|
||||||
}
|
|
||||||
else if (item->TestOcb(WMUTANT_OCB_START_INACTIVE))
|
|
||||||
{
|
|
||||||
SwitchPathfinding(creature, WMUTANT_PATH_GROUND);
|
|
||||||
SetAnimation(item, WMUTANT_ANIM_INACTIVE);
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
|
||||||
}
|
|
||||||
else if (item->TestOcb(WMUTANT_OCB_START_POSE))
|
|
||||||
{
|
|
||||||
SwitchPathfinding(creature, WMUTANT_PATH_GROUND);
|
|
||||||
SetAnimation(item, WMUTANT_ANIM_INACTIVE);
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove unnecessary OCBs.
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_START_AERIAL))
|
|
||||||
item->RemoveOcb(WMUTANT_OCB_START_AERIAL);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_START_INACTIVE))
|
|
||||||
item->RemoveOcb(WMUTANT_OCB_START_INACTIVE);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_START_POSE))
|
|
||||||
item->RemoveOcb(WMUTANT_OCB_START_POSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeWingedMutant(short itemNumber)
|
|
||||||
{
|
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
|
||||||
|
|
||||||
InitializeCreature(itemNumber);
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_NONE);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_NO_WINGS))
|
|
||||||
{
|
|
||||||
item->SetFlagField(WMUTANT_CONF_CAN_FLY, false);
|
|
||||||
item->MeshBits.Clear(WingedMutantWingsJoints);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item->SetFlagField(WMUTANT_CONF_CAN_FLY, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_DISABLE_BOMB_WEAPON))
|
|
||||||
item->SetFlagField(WMUTANT_CONF_DISABLE_BOMB_WEAPON, true);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_DISABLE_DART_WEAPON))
|
|
||||||
item->SetFlagField(WMUTANT_CONF_DISABLE_DART_WEAPON, true);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_DISABLE_BOMB_WEAPON))
|
|
||||||
item->RemoveOcb(WMUTANT_OCB_DISABLE_BOMB_WEAPON);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_DISABLE_DART_WEAPON))
|
|
||||||
item->RemoveOcb(WMUTANT_OCB_DISABLE_DART_WEAPON);
|
|
||||||
|
|
||||||
if (item->TestOcb(WMUTANT_OCB_NO_WINGS))
|
|
||||||
item->RemoveOcb(WMUTANT_OCB_NO_WINGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WingedMutantControl(short itemNumber)
|
|
||||||
{
|
|
||||||
if (!CreatureActive(itemNumber))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
|
||||||
auto* creature = GetCreatureInfo(item);
|
|
||||||
|
|
||||||
short angle = 0;
|
|
||||||
short head = 0;
|
|
||||||
short torso = 0; // Only when shooting.
|
|
||||||
|
|
||||||
bool flyEnabled = item->TestFlagField(WMUTANT_CONF_CAN_FLY, true);
|
|
||||||
bool flyStatus = item->TestFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_AERIAL);
|
|
||||||
|
|
||||||
WingedInitOCB(item, creature);
|
|
||||||
|
|
||||||
if (item->HitPoints <= 0)
|
|
||||||
{
|
|
||||||
CreatureDie(itemNumber, true, BODY_DO_EXPLOSION | BODY_PART_EXPLODE | BODY_NO_SMOKE | BODY_NO_SHATTER_EFFECT);
|
|
||||||
|
|
||||||
auto pos = item->Pose;
|
|
||||||
pos.Position.y -= CLICK(3);
|
|
||||||
TriggerExplosionSparks(pos.Position.x, pos.Position.y, pos.Position.z, 3, -2, 0, item->RoomNumber);
|
|
||||||
TriggerExplosionSparks(pos.Position.x, pos.Position.y, pos.Position.z, 3, -1, 0, item->RoomNumber);
|
|
||||||
TriggerShockwave(&pos, 48, 304, (GetRandomControl() & 0x1F) + 112, 128, 32, 32, 32, EulerAngles(2048, 0.0f, 0.0f), 0, true, false, false, (int)ShockwaveStyle::Normal);
|
|
||||||
|
|
||||||
SoundEffect(SFX_TR1_ATLANTEAN_EXPLODE, &item->Pose);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AI_INFO ai;
|
|
||||||
SwitchPathfinding(creature, WMUTANT_PATH_GROUND);
|
|
||||||
CreatureAIInfo(item, &ai);
|
|
||||||
|
|
||||||
bool isSameZoneInGroundMode = (ai.zoneNumber == ai.enemyZone);
|
|
||||||
auto projectileType = CanTargetLara(item, creature, &ai);
|
|
||||||
|
|
||||||
if (flyEnabled && item->Animation.ActiveState == WMUTANT_STATE_FLY)
|
|
||||||
{
|
|
||||||
SwitchPathfinding(creature, WMUTANT_PATH_AERIAL);
|
|
||||||
CreatureAIInfo(item, &ai);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ai.ahead)
|
|
||||||
{
|
|
||||||
head = ai.angle;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
head = 0;
|
|
||||||
torso = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetCreatureMood(item, &ai, flyStatus);
|
|
||||||
CreatureMood(item, &ai, flyStatus);
|
|
||||||
angle = CreatureTurn(item, creature->MaxTurn);
|
|
||||||
|
|
||||||
switch (item->Animation.ActiveState)
|
|
||||||
{
|
|
||||||
case WMUTANT_STATE_INACTIVE:
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
creature->Flags = 0;
|
|
||||||
|
|
||||||
if (TargetVisible(item, &ai) || creature->HurtByLara)
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_IDLE:
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PROJ_NONE);
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
creature->Flags = 0;
|
|
||||||
torso = 0;
|
|
||||||
|
|
||||||
if (flyEnabled && !isSameZoneInGroundMode)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_FLY;
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_AERIAL);
|
|
||||||
}
|
|
||||||
else if (item->TouchBits.Test(WingedMutantHeadJoints))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
|
||||||
}
|
|
||||||
else if (ai.bite && ai.distance < WINGED_MUTANT_IDLE_JUMP_ATTACK_RANGE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE_JUMP_ATTACK;
|
|
||||||
}
|
|
||||||
else if (ai.bite && ai.distance < WINGED_MUTANT_SWIPE_ATTACK_RANGE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
|
||||||
}
|
|
||||||
else if (projectileType == WMUTANT_PROJ_DART)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_AIM_DART;
|
|
||||||
}
|
|
||||||
else if (projectileType == WMUTANT_PROJ_BOMB)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_AIM_BOMB;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Bored ||
|
|
||||||
(creature->Mood == MoodType::Stalk && ai.distance < WINGED_MUTANT_POSE_RANGE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_POSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_RUN_FORWARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_POSE:
|
|
||||||
creature->Flags = 0;
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
head = 0; // NOTE: Pose has animation for head.
|
|
||||||
|
|
||||||
if (projectileType != WMUTANT_PROJ_NONE || (flyStatus && flyEnabled))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Stalk)
|
|
||||||
{
|
|
||||||
if (ai.distance < WINGED_MUTANT_WALK_RANGE)
|
|
||||||
{
|
|
||||||
if (isSameZoneInGroundMode ||
|
|
||||||
Random::TestProbability(WINGED_MUTANT_UNPOSE_CHANCE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_WALK_FORWARD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Bored && Random::TestProbability(WINGED_MUTANT_UNPOSE_CHANCE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_WALK_FORWARD;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Attack ||
|
|
||||||
creature->Mood == MoodType::Escape)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_WALK_FORWARD:
|
|
||||||
creature->MaxTurn = WINGED_MUTANT_WALK_TURN_RATE_MAX;
|
|
||||||
creature->Flags = 0;
|
|
||||||
|
|
||||||
if (projectileType != WMUTANT_PROJ_NONE || (flyStatus && flyEnabled))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Attack || creature->Mood == MoodType::Escape)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Bored ||
|
|
||||||
(creature->Mood == MoodType::Stalk && !isSameZoneInGroundMode))
|
|
||||||
{
|
|
||||||
if (Random::TestProbability(WINGED_MUTANT_POSE_CHANCE))
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_POSE;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Stalk &&
|
|
||||||
ai.distance > WINGED_MUTANT_WALK_RANGE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_RUN_FORWARD:
|
|
||||||
creature->MaxTurn = WINGED_MUTANT_RUN_TURN_RATE_MAX;
|
|
||||||
creature->Flags = 0;
|
|
||||||
|
|
||||||
if (flyEnabled && !isSameZoneInGroundMode)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (projectileType != WMUTANT_PROJ_NONE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (item->TouchBits.Test(WingedMutantHeadJoints))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (ai.bite && ai.distance < WINGED_MUTANT_RUN_JUMP_ATTACK_RANGE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_RUN_JUMP_ATTACK;
|
|
||||||
}
|
|
||||||
else if (ai.bite && ai.distance < WINGED_MUTANT_SWIPE_ATTACK_RANGE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
|
||||||
}
|
|
||||||
else if (ai.ahead && ai.distance < WINGED_MUTANT_SWIPE_ATTACK_RANGE)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_SWIPE_ATTACK;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Bored ||
|
|
||||||
(creature->Mood == MoodType::Stalk && ai.distance < WINGED_MUTANT_POSE_RANGE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_IDLE_JUMP_ATTACK:
|
|
||||||
if (item->Animation.RequiredState == NO_VALUE &&
|
|
||||||
(item->TouchBits.Test(WingedMutantHandsJoints) || item->TouchBits.Test(WingedMutantHeadJoints)) && creature->Flags == 0)
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE / 2);
|
|
||||||
CreatureEffect(item, WingedMutantBiteLeftHand, DoBloodSplat);
|
|
||||||
|
|
||||||
DoDamage(creature->Enemy, WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE / 2);
|
|
||||||
CreatureEffect(item, WingedMutantBiteRightHand, DoBloodSplat);
|
|
||||||
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
creature->Flags = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_RUN_JUMP_ATTACK:
|
|
||||||
if (item->Animation.RequiredState == NO_VALUE &&
|
|
||||||
(item->TouchBits.Test(WingedMutantHandsJoints) || item->TouchBits.Test(WingedMutantHeadJoints)) && creature->Flags == 0)
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE / 2);
|
|
||||||
CreatureEffect(item, WingedMutantBiteLeftHand, DoBloodSplat);
|
|
||||||
|
|
||||||
DoDamage(creature->Enemy, WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE / 2);
|
|
||||||
CreatureEffect(item, WingedMutantBiteRightHand, DoBloodSplat);
|
|
||||||
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_RUN_FORWARD;
|
|
||||||
creature->Flags = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_SWIPE_ATTACK:
|
|
||||||
if (item->Animation.RequiredState == NO_VALUE &&
|
|
||||||
item->TouchBits.Test(WingedMutantHandsJoints) && creature->Flags == 0)
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, WINGED_MUTANT_SWIPE_ATTACK_DAMAGE / 2);
|
|
||||||
CreatureEffect(item, WingedMutantBiteLeftHand, DoBloodSplat);
|
|
||||||
|
|
||||||
DoDamage(creature->Enemy, WINGED_MUTANT_SWIPE_ATTACK_DAMAGE / 2);
|
|
||||||
CreatureEffect(item, WingedMutantBiteRightHand, DoBloodSplat);
|
|
||||||
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
creature->Flags = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_AIM_DART:
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_DART);
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
creature->Flags = 0;
|
|
||||||
torso = ai.angle / 2;
|
|
||||||
|
|
||||||
if (projectileType == WMUTANT_PROJ_DART)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_SHOOT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_AIM_BOMB:
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_BOMB);
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
creature->Flags = 0;
|
|
||||||
torso = ai.angle / 2;
|
|
||||||
|
|
||||||
if (projectileType == WMUTANT_PROJ_BOMB)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_SHOOT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_SHOOT:
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
torso = ai.angle / 2;
|
|
||||||
|
|
||||||
if (creature->Flags == 0)
|
|
||||||
{
|
|
||||||
if (projectileType == WMUTANT_PROJ_DART)
|
|
||||||
{
|
|
||||||
CreatureEffect2(item, WingedMutantShardBite, WINGED_MUTANT_SHARD_VELOCITY, torso, ShardGun);
|
|
||||||
}
|
|
||||||
else if (projectileType == WMUTANT_PROJ_BOMB)
|
|
||||||
{
|
|
||||||
CreatureEffect2(item, WingedMutantRocketBite, WINGED_MUTANT_BOMB_VELOCITY, torso, BombGun);
|
|
||||||
}
|
|
||||||
|
|
||||||
creature->Flags = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PROJECTILE_MODE, WMUTANT_PROJ_NONE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMUTANT_STATE_FLY:
|
|
||||||
if (creature->Mood != MoodType::Escape && isSameZoneInGroundMode)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = WMUTANT_STATE_IDLE; // Switch to ground mode.
|
|
||||||
item->Pose.Position.y = item->Floor;
|
|
||||||
item->SetFlagField(WMUTANT_CONF_PATHFINDING_MODE, WMUTANT_PATH_GROUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CreatureJoint(item, 0, torso);
|
|
||||||
CreatureJoint(item, 1, head);
|
|
||||||
CreatureAnimation(itemNumber, angle, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,18 +10,18 @@
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
|
|
||||||
// Creatures
|
// Creatures
|
||||||
#include "Objects/TR1/Entity/Cowboy.h" // OK
|
#include "Objects/TR1/Entity/Centaur.h"
|
||||||
#include "Objects/TR1/Entity/Kold.h" // OK
|
#include "Objects/TR1/Entity/Cowboy.h"
|
||||||
#include "Objects/TR1/Entity/tr1_ape.h" // OK
|
#include "Objects/TR1/Entity/Kold.h"
|
||||||
#include "Objects/TR1/Entity/tr1_bear.h" // OK
|
#include "Objects/TR1/Entity/SkateboardKid.h"
|
||||||
#include "Objects/TR1/Entity/tr1_doppelganger.h" // OK
|
#include "Objects/TR1/Entity/WingedMutant.h"
|
||||||
#include "Objects/TR1/Entity/tr1_natla.h" // OK
|
#include "Objects/TR1/Entity/tr1_ape.h"
|
||||||
#include "Objects/TR1/Entity/tr1_giant_mutant.h" // OK
|
#include "Objects/TR1/Entity/tr1_bear.h"
|
||||||
#include "Objects/TR1/Entity/tr1_wolf.h" // OK
|
#include "Objects/TR1/Entity/tr1_doppelganger.h"
|
||||||
#include "Objects/TR1/Entity/tr1_big_rat.h" // OK
|
#include "Objects/TR1/Entity/tr1_natla.h"
|
||||||
#include "Objects/TR1/Entity/tr1_centaur.h" // OK
|
#include "Objects/TR1/Entity/tr1_giant_mutant.h"
|
||||||
#include "Objects/TR1/Entity/tr1_winged_mutant.h" // OK
|
#include "Objects/TR1/Entity/tr1_wolf.h"
|
||||||
#include "Objects/TR1/Entity/SkateboardKid.h" // OK
|
#include "Objects/TR1/Entity/tr1_big_rat.h"
|
||||||
#include "Objects/Utils/object_helper.h"
|
#include "Objects/Utils/object_helper.h"
|
||||||
|
|
||||||
// Traps
|
// Traps
|
||||||
|
@ -149,7 +149,7 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->Initialize = InitializeCreature;
|
obj->Initialize = InitializeCreature;
|
||||||
obj->control = CentaurControl;
|
obj->control = ControlCentaur;
|
||||||
obj->collision = CreatureCollision;
|
obj->collision = CreatureCollision;
|
||||||
obj->shadowType = ShadowMode::All;
|
obj->shadowType = ShadowMode::All;
|
||||||
obj->HitPoints = 120;
|
obj->HitPoints = 120;
|
||||||
|
@ -157,7 +157,8 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
obj->radius = BLOCK(1 / 3.0f);
|
obj->radius = BLOCK(1 / 3.0f);
|
||||||
obj->intelligent = true;
|
obj->intelligent = true;
|
||||||
obj->LotType = LotType::Blockable;
|
obj->LotType = LotType::Blockable;
|
||||||
obj->SetBoneRotationFlags(10, ROT_X | ROT_Y);
|
obj->SetBoneRotationFlags(10, ROT_X | ROT_Y); // Torso
|
||||||
|
obj->SetBoneRotationFlags(17, ROT_X | ROT_Y); // Head
|
||||||
obj->SetHitEffect();
|
obj->SetHitEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->Initialize = InitializeWingedMutant;
|
obj->Initialize = InitializeWingedMutant;
|
||||||
obj->control = WingedMutantControl;
|
obj->control = ControlWingedMutant;
|
||||||
obj->collision = CreatureCollision;
|
obj->collision = CreatureCollision;
|
||||||
obj->shadowType = ShadowMode::All;
|
obj->shadowType = ShadowMode::All;
|
||||||
obj->pivotLength = 150;
|
obj->pivotLength = 150;
|
||||||
|
@ -274,7 +275,6 @@ static void StartProjectiles(ObjectInfo* obj)
|
||||||
{
|
{
|
||||||
InitProjectile(obj, ControlMissile, ID_PROJ_SHARD);
|
InitProjectile(obj, ControlMissile, ID_PROJ_SHARD);
|
||||||
InitProjectile(obj, ControlMissile, ID_PROJ_BOMB);
|
InitProjectile(obj, ControlMissile, ID_PROJ_BOMB);
|
||||||
InitProjectile(obj, ControlMissile, ID_PROJ_BOMB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeTR1Objects()
|
void InitializeTR1Objects()
|
||||||
|
|
|
@ -72,14 +72,17 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
(g_Level.PathfindingBoxes[creature.Enemy->BoxNumber].flags & BLOCKABLE));
|
(g_Level.PathfindingBoxes[creature.Enemy->BoxNumber].flags & BLOCKABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SpawnLizardGas(int itemNumber, const CreatureBiteInfo& bite, int speed)
|
static void SpawnLizardGas(const ItemInfo& item, const CreatureBiteInfo& bite, float vel)
|
||||||
{
|
{
|
||||||
constexpr auto THROW_COUNT = 2;
|
constexpr auto THROW_COUNT = 3;
|
||||||
|
|
||||||
|
auto velVector = Vector3(0.0f, -100.0f, vel * 4);
|
||||||
for (int i = 0; i < THROW_COUNT; i++)
|
for (int i = 0; i < THROW_COUNT; i++)
|
||||||
ThrowPoison(itemNumber, bite, Vector3i(0.0f, -100.0f, speed << 2), Vector3(0.0f, 1.0f, 0.0f));
|
{
|
||||||
|
auto colorStart = Color(0.0f, Random::GenerateFloat(0.25f, 0.5f), 0.1f);
|
||||||
ThrowPoison(itemNumber, bite, Vector3i(0.0f, -100.0f, speed << 1), Vector3(0.0f, 1.0f, 0.0f));
|
auto colorEnd = Color(0.0f, Random::GenerateFloat(0.1f, 0.2f), 0.1f);
|
||||||
|
ThrowPoison(item, bite, velVector, colorStart, colorEnd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LizardControl(short itemNumber)
|
void LizardControl(short itemNumber)
|
||||||
|
@ -319,9 +322,13 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
creature.Flags += 2;
|
creature.Flags += 2;
|
||||||
|
|
||||||
if (creature.Flags < 24)
|
if (creature.Flags < 24)
|
||||||
SpawnLizardGas(itemNumber, LizardGasBite, creature.Flags);
|
{
|
||||||
|
SpawnLizardGas(item, LizardGasBite, creature.Flags);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SpawnLizardGas(itemNumber, LizardGasBite, (GetRandomControl() & 15) + 8);
|
{
|
||||||
|
SpawnLizardGas(item, LizardGasBite, (GetRandomControl() & 15) + 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TestAnimFrame(item, 28))
|
if (TestAnimFrame(item, 28))
|
||||||
|
|
450
TombEngine/Objects/TR3/Entity/Raptor.cpp
Normal file
450
TombEngine/Objects/TR3/Entity/Raptor.cpp
Normal file
|
@ -0,0 +1,450 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "Objects/TR3/Entity/Raptor.h"
|
||||||
|
|
||||||
|
#include "Game/collision/Point.h"
|
||||||
|
#include "Game/control/box.h"
|
||||||
|
#include "Game/control/control.h"
|
||||||
|
#include "Game/control/lot.h"
|
||||||
|
#include "Game/effects/effects.h"
|
||||||
|
#include "Game/items.h"
|
||||||
|
#include "Game/itemdata/creature_info.h"
|
||||||
|
#include "Game/Lara/lara.h"
|
||||||
|
#include "Game/misc.h"
|
||||||
|
#include "Game/Setup.h"
|
||||||
|
#include "Math/Math.h"
|
||||||
|
#include "Specific/level.h"
|
||||||
|
|
||||||
|
using namespace TEN::Collision::Point;
|
||||||
|
using namespace TEN::Math;
|
||||||
|
|
||||||
|
namespace TEN::Entities::Creatures::TR3
|
||||||
|
{
|
||||||
|
constexpr auto RAPTOR_ATTACK_DAMAGE = 100;
|
||||||
|
|
||||||
|
constexpr auto RAPTOR_BITE_ATTACK_RANGE = SQUARE(BLOCK(0.6f));
|
||||||
|
constexpr auto RAPTOR_JUMP_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
||||||
|
constexpr auto RAPTOR_RUN_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
||||||
|
|
||||||
|
constexpr auto RAPTOR_ROAR_CHANCE = 1.0f / 256;
|
||||||
|
constexpr auto RAPTOR_SWITCH_TARGET_CHANCE = 1.0f / 128;
|
||||||
|
|
||||||
|
constexpr auto RAPTOR_WALK_TURN_RATE_MAX = ANGLE(2.0f);
|
||||||
|
constexpr auto RAPTOR_RUN_TURN_RATE_MAX = ANGLE(4.0f);
|
||||||
|
constexpr auto RAPTOR_ATTACK_TURN_RATE_MAX = ANGLE(2.0f);
|
||||||
|
|
||||||
|
const auto RaptorBite = CreatureBiteInfo(Vector3(0, 66, 318), 22);
|
||||||
|
const auto RaptorAttackJoints = std::vector<unsigned int>{ 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23 };
|
||||||
|
|
||||||
|
enum RaptorState
|
||||||
|
{
|
||||||
|
RAPTOR_STATE_DEATH = 0,
|
||||||
|
RAPTOR_STATE_IDLE = 1,
|
||||||
|
RAPTOR_STATE_WALK_FORWARD = 2,
|
||||||
|
RAPTOR_STATE_RUN_FORWARD = 3,
|
||||||
|
RAPTOR_STATE_JUMP_ATTACK = 4,
|
||||||
|
RAPTOR_STATE_NONE = 5,
|
||||||
|
RAPTOR_STATE_ROAR = 6,
|
||||||
|
RAPTOR_STATE_RUN_BITE_ATTACK = 7,
|
||||||
|
RAPTOR_STATE_BITE_ATTACK = 8,
|
||||||
|
RAPTOR_STATE_JUMP_START = 9,
|
||||||
|
RAPTOR_STATE_JUMP_2_BLOCKS = 10,
|
||||||
|
RAPTOR_STATE_JUMP_1_BLOCK = 11,
|
||||||
|
RAPTOR_STATE_CLIMB = 12
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RaptorAnim
|
||||||
|
{
|
||||||
|
RAPTOR_ANIM_IDLE = 0,
|
||||||
|
RAPTOR_ANIM_RUN_FORWARD = 1,
|
||||||
|
RAPTOR_ANIM_RUN_FORWARD_TO_IDLE = 2,
|
||||||
|
RAPTOR_ANIM_IDLE_TO_RUN_FORWARD = 3,
|
||||||
|
RAPTOR_ANIM_ROAR = 4,
|
||||||
|
RAPTOR_ANIM_WALK_FORWARD = 5,
|
||||||
|
RAPTOR_ANIM_WALK_FORWARD_TO_IDLE = 6,
|
||||||
|
RAPTOR_ANIM_IDLE_TO_WALK_FORWARD = 7,
|
||||||
|
RAPTOR_ANIM_RUN_BITE_ATTACK = 8,
|
||||||
|
RAPTOR_ANIM_DEATH_1 = 9,
|
||||||
|
RAPTOR_ANIM_DEATH_2 = 10,
|
||||||
|
RAPTOR_ANIM_JUMP_ATTACK_START = 11,
|
||||||
|
RAPTOR_ANIM_JUMP_ATTACK_END = 12,
|
||||||
|
RAPTOR_ANIM_BITE_ATTACK = 13,
|
||||||
|
RAPTOR_ANIM_JUMP_START = 14,
|
||||||
|
RAPTOR_ANIM_JUMP_2_BLOCKS = 15,
|
||||||
|
RAPTOR_ANIM_JUMP_END = 16,
|
||||||
|
RAPTOR_ANIM_JUMP_1_BLOCK = 17,
|
||||||
|
RAPTOR_ANIM_VAULT_2_STEPS = 18,
|
||||||
|
RAPTOR_ANIM_VAULT_3_STEPS = 19,
|
||||||
|
RAPTOR_ANIM_VAULT_4_STEPS = 20,
|
||||||
|
RAPTOR_ANIM_VAULT_DROP_2_STEPS = 21,
|
||||||
|
RAPTOR_ANIM_VAULT_DROP_3_STEPS = 22,
|
||||||
|
RAPTOR_ANIM_VAULT_DROP_4_STEPS = 23
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RaptorFlags
|
||||||
|
{
|
||||||
|
OCB_NORMAL_BEHAVIOUR = 0,
|
||||||
|
OCB_ENABLE_JUMP = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array RaptorDeathAnims = { RAPTOR_ANIM_DEATH_1, RAPTOR_ANIM_DEATH_2, };
|
||||||
|
const std::vector<GAME_OBJECT_ID> RaptorIgnoredObjectIds = { ID_RAPTOR, ID_COMPSOGNATHUS };
|
||||||
|
|
||||||
|
void RaptorControl(short itemNumber)
|
||||||
|
{
|
||||||
|
if (!CreatureActive(itemNumber))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
auto& creature = *GetCreatureInfo(&item);
|
||||||
|
|
||||||
|
short headingAngle = 0;
|
||||||
|
short tiltAngle = 0;
|
||||||
|
short headYOrient = 0;
|
||||||
|
short neckYOrient = 0;
|
||||||
|
|
||||||
|
bool canJump = item.TestOcb(OCB_ENABLE_JUMP);
|
||||||
|
if (!canJump)
|
||||||
|
{
|
||||||
|
creature.LOT.Step = CLICK(1);
|
||||||
|
creature.LOT.Drop = -CLICK(2);
|
||||||
|
creature.LOT.Zone = ZoneType::Basic;
|
||||||
|
creature.LOT.CanJump = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canJump1block = (canJump && CanCreatureJump(item, JumpDistance::Block1));
|
||||||
|
bool canJump2blocks = (canJump && !canJump1block && CanCreatureJump(item, JumpDistance::Block2));
|
||||||
|
|
||||||
|
// Require Idle state.
|
||||||
|
if (item.HitPoints <= 0 && item.Animation.ActiveState == RAPTOR_STATE_IDLE)
|
||||||
|
{
|
||||||
|
if (item.Animation.ActiveState != RAPTOR_STATE_DEATH)
|
||||||
|
SetAnimation(item, RaptorDeathAnims[Random::GenerateInt(0, (int)RaptorDeathAnims.size() - 1)]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NOTE: Ignores other small dinosaurs.
|
||||||
|
TargetNearestEntity(&item, &creature, RaptorIgnoredObjectIds);
|
||||||
|
|
||||||
|
AI_INFO ai;
|
||||||
|
if (item.AIBits)
|
||||||
|
GetAITarget(&creature);
|
||||||
|
CreatureAIInfo(&item, &ai);
|
||||||
|
|
||||||
|
GetCreatureMood(&item, &ai, true);
|
||||||
|
CreatureMood(&item, &ai, true);
|
||||||
|
if (creature.Mood == MoodType::Bored)
|
||||||
|
creature.MaxTurn /= 2;
|
||||||
|
|
||||||
|
headingAngle = CreatureTurn(&item, creature.MaxTurn);
|
||||||
|
if (ai.ahead)
|
||||||
|
{
|
||||||
|
headYOrient = ai.angle;
|
||||||
|
neckYOrient = -headingAngle * 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item.Animation.ActiveState)
|
||||||
|
{
|
||||||
|
case RAPTOR_STATE_IDLE:
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.LOT.IsJumping = false;
|
||||||
|
creature.Flags &= ~1;
|
||||||
|
|
||||||
|
if (canJump1block || canJump2blocks)
|
||||||
|
{
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.LOT.IsJumping = true;
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_JUMP_START);
|
||||||
|
|
||||||
|
if (canJump1block)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_1_BLOCK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_2_BLOCKS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item.Animation.RequiredState != NO_VALUE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = item.Animation.RequiredState;
|
||||||
|
}
|
||||||
|
else if (creature.Flags & 2)
|
||||||
|
{
|
||||||
|
creature.Flags &= ~2;
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_ROAR;
|
||||||
|
}
|
||||||
|
else if (item.TouchBits.Test(RaptorAttackJoints) ||
|
||||||
|
(ai.distance < RAPTOR_BITE_ATTACK_RANGE && ai.bite))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_BITE_ATTACK;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < RAPTOR_JUMP_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_ATTACK;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Escape &&
|
||||||
|
Lara.TargetEntity != &item && ai.ahead && !item.HitStatus)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Bored)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_WALK_FORWARD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_RUN_FORWARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RAPTOR_STATE_WALK_FORWARD:
|
||||||
|
creature.MaxTurn = RAPTOR_WALK_TURN_RATE_MAX;
|
||||||
|
creature.LOT.IsJumping = false;
|
||||||
|
creature.Flags &= ~1;
|
||||||
|
|
||||||
|
if (item.HitPoints <= 0)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (canJump1block || canJump2blocks)
|
||||||
|
{
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.LOT.IsJumping = true;
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_JUMP_START);
|
||||||
|
|
||||||
|
if (canJump1block)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_1_BLOCK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_2_BLOCKS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (creature.Mood != MoodType::Bored)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (ai.ahead && Random::TestProbability(RAPTOR_ROAR_CHANCE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
item.Animation.RequiredState = RAPTOR_STATE_ROAR;
|
||||||
|
creature.Flags &= ~2;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RAPTOR_STATE_RUN_FORWARD:
|
||||||
|
creature.MaxTurn = RAPTOR_RUN_TURN_RATE_MAX;
|
||||||
|
creature.LOT.IsJumping = false;
|
||||||
|
creature.Flags &= ~1;
|
||||||
|
tiltAngle = headingAngle;
|
||||||
|
|
||||||
|
if (item.HitPoints <= 0)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (canJump1block || canJump2blocks)
|
||||||
|
{
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.LOT.IsJumping = true;
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_JUMP_START);
|
||||||
|
|
||||||
|
if (canJump1block)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_1_BLOCK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_JUMP_2_BLOCKS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item.TouchBits.Test(RaptorAttackJoints))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (creature.Flags & 2)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
item.Animation.RequiredState = RAPTOR_STATE_ROAR;
|
||||||
|
creature.Flags &= ~2;
|
||||||
|
}
|
||||||
|
else if (ai.bite && ai.distance < RAPTOR_RUN_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
if (Random::TestProbability(1 / 4.0f))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_RUN_BITE_ATTACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ai.ahead && creature.Mood != MoodType::Escape &&
|
||||||
|
Random::TestProbability(RAPTOR_ROAR_CHANCE))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
item.Animation.RequiredState = RAPTOR_STATE_ROAR;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Bored ||
|
||||||
|
(creature.Mood == MoodType::Escape && Lara.TargetEntity != &item && ai.ahead))
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RAPTOR_STATE_JUMP_ATTACK:
|
||||||
|
creature.MaxTurn = RAPTOR_ATTACK_TURN_RATE_MAX;
|
||||||
|
tiltAngle = headingAngle;
|
||||||
|
|
||||||
|
if (creature.Enemy != nullptr)
|
||||||
|
{
|
||||||
|
if (creature.Enemy->IsLara() && !(creature.Flags & 1) &&
|
||||||
|
item.TouchBits.Test(RaptorAttackJoints))
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, RAPTOR_ATTACK_DAMAGE);
|
||||||
|
CreatureEffect(&item, RaptorBite, DoBloodSplat);
|
||||||
|
creature.Flags |= 1;
|
||||||
|
|
||||||
|
if (LaraItem->HitPoints <= 0)
|
||||||
|
creature.Flags |= 2;
|
||||||
|
|
||||||
|
item.Animation.RequiredState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (!(creature.Flags & 1))
|
||||||
|
{
|
||||||
|
if (Vector3i::Distance(item.Pose.Position, creature.Enemy->Pose.Position) <= BLOCK(0.5f))
|
||||||
|
{
|
||||||
|
if (creature.Enemy->HitPoints <= 0)
|
||||||
|
creature.Flags |= 2;
|
||||||
|
|
||||||
|
DoDamage(creature.Enemy, 25);
|
||||||
|
CreatureEffect(&item, RaptorBite, DoBloodSplat);
|
||||||
|
creature.Flags |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RAPTOR_STATE_BITE_ATTACK:
|
||||||
|
creature.MaxTurn = RAPTOR_ATTACK_TURN_RATE_MAX;
|
||||||
|
tiltAngle = headingAngle;
|
||||||
|
|
||||||
|
if (creature.Enemy != nullptr)
|
||||||
|
{
|
||||||
|
if (creature.Enemy->IsLara() && !(creature.Flags & 1) &&
|
||||||
|
item.TouchBits.Test(RaptorAttackJoints))
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, RAPTOR_ATTACK_DAMAGE);
|
||||||
|
CreatureEffect(&item, RaptorBite, DoBloodSplat);
|
||||||
|
creature.Flags |= 1;
|
||||||
|
|
||||||
|
if (LaraItem->HitPoints <= 0)
|
||||||
|
creature.Flags |= 2;
|
||||||
|
|
||||||
|
item.Animation.RequiredState = RAPTOR_STATE_IDLE;
|
||||||
|
}
|
||||||
|
else if (!(creature.Flags & 1))
|
||||||
|
{
|
||||||
|
if (Vector3i::Distance(item.Pose.Position, creature.Enemy->Pose.Position) <= BLOCK(0.5f))
|
||||||
|
{
|
||||||
|
if (creature.Enemy->HitPoints <= 0)
|
||||||
|
creature.Flags |= 2;
|
||||||
|
|
||||||
|
DoDamage(creature.Enemy, 25);
|
||||||
|
CreatureEffect(&item, RaptorBite, DoBloodSplat);
|
||||||
|
creature.Flags |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RAPTOR_STATE_RUN_BITE_ATTACK:
|
||||||
|
creature.MaxTurn = RAPTOR_ATTACK_TURN_RATE_MAX;
|
||||||
|
tiltAngle = headingAngle;
|
||||||
|
|
||||||
|
if (creature.Enemy != nullptr)
|
||||||
|
{
|
||||||
|
if (creature.Enemy->IsLara() && !(creature.Flags & 1) &&
|
||||||
|
item.TouchBits.Test(RaptorAttackJoints))
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, RAPTOR_ATTACK_DAMAGE);
|
||||||
|
CreatureEffect(&item, RaptorBite, DoBloodSplat);
|
||||||
|
item.Animation.RequiredState = RAPTOR_STATE_RUN_FORWARD;
|
||||||
|
creature.Flags |= 1;
|
||||||
|
|
||||||
|
if (LaraItem->HitPoints <= 0)
|
||||||
|
creature.Flags |= 2;
|
||||||
|
}
|
||||||
|
else if (!(creature.Flags & 1))
|
||||||
|
{
|
||||||
|
if (Vector3i::Distance(item.Pose.Position, creature.Enemy->Pose.Position) <= BLOCK(0.5f))
|
||||||
|
{
|
||||||
|
if (creature.Enemy->HitPoints <= 0)
|
||||||
|
creature.Flags |= 2;
|
||||||
|
|
||||||
|
DoDamage(creature.Enemy, 25);
|
||||||
|
CreatureEffect(&item, RaptorBite, DoBloodSplat);
|
||||||
|
creature.Flags |= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureTilt(&item, tiltAngle);
|
||||||
|
CreatureJoint(&item, 0, headYOrient / 2);
|
||||||
|
CreatureJoint(&item, 1, headYOrient / 2);
|
||||||
|
CreatureJoint(&item, 2, neckYOrient);
|
||||||
|
CreatureJoint(&item, 3, neckYOrient);
|
||||||
|
|
||||||
|
if (item.Animation.ActiveState != RAPTOR_STATE_JUMP_2_BLOCKS &&
|
||||||
|
item.Animation.ActiveState != RAPTOR_STATE_JUMP_1_BLOCK &&
|
||||||
|
item.Animation.ActiveState != RAPTOR_STATE_CLIMB &&
|
||||||
|
item.Animation.ActiveState != RAPTOR_STATE_JUMP_START)
|
||||||
|
{
|
||||||
|
switch (CreatureVault(itemNumber, headingAngle, 2, CLICK(2.5f)))
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_VAULT_2_STEPS);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_VAULT_3_STEPS);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_VAULT_4_STEPS);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -2:
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_VAULT_DROP_2_STEPS);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -3:
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_VAULT_DROP_3_STEPS);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -4:
|
||||||
|
SetAnimation(item, RAPTOR_ANIM_VAULT_DROP_4_STEPS);
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreatureAnimation(itemNumber, headingAngle, tiltAngle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
332
TombEngine/Objects/TR3/Entity/SealMutant.cpp
Normal file
332
TombEngine/Objects/TR3/Entity/SealMutant.cpp
Normal file
|
@ -0,0 +1,332 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "Objects/TR3/Entity/SealMutant.h"
|
||||||
|
|
||||||
|
#include "Game/animation.h"
|
||||||
|
#include "Game/control/box.h"
|
||||||
|
#include "Game/effects/effects.h"
|
||||||
|
#include "Game/effects/tomb4fx.h"
|
||||||
|
#include "Game/Lara/lara.h"
|
||||||
|
#include "Game/Lara/lara_helpers.h"
|
||||||
|
#include "Game/misc.h"
|
||||||
|
#include "Game/people.h"
|
||||||
|
#include "Game/Setup.h"
|
||||||
|
#include "Math/Math.h"
|
||||||
|
#include "Objects/Effects/enemy_missile.h"
|
||||||
|
|
||||||
|
using namespace TEN::Math;
|
||||||
|
|
||||||
|
// NOTES:
|
||||||
|
// ItemFlags[0]: Sprite ID for poison effect.
|
||||||
|
|
||||||
|
namespace TEN::Entities::Creatures::TR3
|
||||||
|
{
|
||||||
|
constexpr auto SEAL_MUTANT_ATTACK_DAMAGE = 1;
|
||||||
|
|
||||||
|
constexpr auto SEAL_MUTANT_ALERT_RANGE = SQUARE(BLOCK(1));
|
||||||
|
constexpr auto SEAL_MUTANT_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
||||||
|
|
||||||
|
constexpr auto SEAL_MUTANT_WALK_TURN_RATE = ANGLE(3.0f);
|
||||||
|
|
||||||
|
constexpr auto SEAL_MUTANT_FLAME_LIGHT_Y_OFFSET = CLICK(2);
|
||||||
|
constexpr auto SEAL_MUTANT_BURN_END_TIME = 16;
|
||||||
|
|
||||||
|
const auto SealMutantGasBite = CreatureBiteInfo(Vector3(0.0f, 48.0f, 140.0f), 10);
|
||||||
|
const auto SealMutantAttackTargetObjectIds = { ID_LARA, ID_FLAMETHROWER_BADDY, ID_WORKER_FLAMETHROWER };
|
||||||
|
|
||||||
|
enum SealMutantState
|
||||||
|
{
|
||||||
|
SEAL_MUTANT_STATE_IDLE = 0,
|
||||||
|
SEAL_MUTANT_STATE_WALK = 1,
|
||||||
|
SEAL_MUTANT_STATE_ATTACK = 2,
|
||||||
|
SEAL_MUTANT_STATE_DEATH = 3,
|
||||||
|
SEAL_MUTANT_STATE_TRAP = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SealMutantAnim
|
||||||
|
{
|
||||||
|
SEAL_MUTANT_ANIM_IDLE = 0,
|
||||||
|
SEAL_MUTANT_ANIM_IDLE_TO_WALK = 1,
|
||||||
|
SEAL_MUTANT_ANIM_WALK = 2,
|
||||||
|
SEAL_MUTANT_ANIM_WALK_TO_IDLE = 3,
|
||||||
|
SEAL_MUTANT_ANIM_ATTACK = 4,
|
||||||
|
SEAL_MUTANT_ANIM_DEATH = 5,
|
||||||
|
SEAL_MUTANT_ANIM_TRAP = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SealMutantItemFlags
|
||||||
|
{
|
||||||
|
IF_SEAL_MUTANT_FLAME_TIMER = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SealMutantOcb
|
||||||
|
{
|
||||||
|
OCB_NORMAL_BEHAVIOUR = 0,
|
||||||
|
OCB_TRAP = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
static void SpawnSealMutantPoisonGas(ItemInfo& item, float vel)
|
||||||
|
{
|
||||||
|
constexpr auto GAS_COUNT = 2;
|
||||||
|
constexpr auto VEL_MULT = 5.0f;
|
||||||
|
constexpr auto PLAYER_CROUCH_GRAVITY = 32.0f;
|
||||||
|
|
||||||
|
auto& creature = *GetCreatureInfo(&item);
|
||||||
|
|
||||||
|
// HACK.
|
||||||
|
float gravity = 0.0f;
|
||||||
|
if (creature.Enemy != nullptr)
|
||||||
|
{
|
||||||
|
if (creature.Enemy->IsLara())
|
||||||
|
{
|
||||||
|
const auto& player = GetLaraInfo(*creature.Enemy);
|
||||||
|
if (player.Control.IsLow)
|
||||||
|
gravity = PLAYER_CROUCH_GRAVITY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DoDamage(creature.Enemy, SEAL_MUTANT_ATTACK_DAMAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto velVector = Vector3(0.0f, gravity, vel * VEL_MULT);
|
||||||
|
auto colorStart = Color(Random::GenerateFloat(0.25f, 0.5f), Random::GenerateFloat(0.25f, 0.5f), 0.1f);
|
||||||
|
auto colorEnd = Color(Random::GenerateFloat(0.05f, 0.1f), Random::GenerateFloat(0.05f, 0.1f), 0.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < GAS_COUNT; i++)
|
||||||
|
ThrowPoison(item, SealMutantGasBite, velVector, colorStart, colorEnd, item.ItemFlags[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeSealMutant(short itemNumber)
|
||||||
|
{
|
||||||
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
|
||||||
|
item.ItemFlags[0] = 0;
|
||||||
|
InitializeCreature(itemNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSealMutant(short itemNumber)
|
||||||
|
{
|
||||||
|
if (!CreatureActive(itemNumber))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& item = g_Level.Items[itemNumber];
|
||||||
|
auto& creature = *GetCreatureInfo(&item);
|
||||||
|
|
||||||
|
short headingAngle = 0;
|
||||||
|
auto headOrient = EulerAngles::Identity;
|
||||||
|
auto torsoOrient = EulerAngles::Identity;
|
||||||
|
|
||||||
|
float gasVel = 0.0f;
|
||||||
|
|
||||||
|
if (item.TestOcb(OCB_TRAP))
|
||||||
|
{
|
||||||
|
if (item.Animation.ActiveState != SEAL_MUTANT_STATE_TRAP)
|
||||||
|
{
|
||||||
|
SetAnimation(item, SEAL_MUTANT_ANIM_TRAP);
|
||||||
|
}
|
||||||
|
else if (TestAnimFrameRange(item, 1, 124))
|
||||||
|
{
|
||||||
|
const auto& anim = GetAnimData(item.Animation.AnimNumber);
|
||||||
|
|
||||||
|
gasVel = item.Animation.FrameNumber - (anim.frameBase + 1);
|
||||||
|
if (gasVel > 24.0f)
|
||||||
|
{
|
||||||
|
gasVel = item.Animation.FrameNumber - (anim.frameEnd - 8);
|
||||||
|
if (gasVel <= 0.0f)
|
||||||
|
gasVel = 1.0f;
|
||||||
|
|
||||||
|
if (gasVel > 24.0f)
|
||||||
|
gasVel = Random::GenerateFloat(8.0f, 24.0f);
|
||||||
|
|
||||||
|
SpawnSealMutantPoisonGas(item, gasVel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureAnimation(itemNumber, 0, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.GetFlagField(IF_SEAL_MUTANT_FLAME_TIMER) > 80)
|
||||||
|
item.HitPoints = 0;
|
||||||
|
|
||||||
|
if (item.HitPoints <= 0)
|
||||||
|
{
|
||||||
|
const auto& anim = GetAnimData(item.Animation.AnimNumber);
|
||||||
|
|
||||||
|
if (item.Animation.ActiveState != SEAL_MUTANT_STATE_DEATH)
|
||||||
|
{
|
||||||
|
SetAnimation(item, SEAL_MUTANT_ANIM_DEATH);
|
||||||
|
}
|
||||||
|
else if (item.GetFlagField(IF_SEAL_MUTANT_FLAME_TIMER) > 80)
|
||||||
|
{
|
||||||
|
for (int boneID = 9; boneID < 17; boneID++)
|
||||||
|
{
|
||||||
|
auto pos = GetJointPosition(item, boneID);
|
||||||
|
TriggerFireFlame(pos.x, pos.y, pos.z, FlameType::Medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
int burnTimer = item.Animation.FrameNumber - anim.frameBase;
|
||||||
|
if (burnTimer > SEAL_MUTANT_BURN_END_TIME)
|
||||||
|
{
|
||||||
|
burnTimer = item.Animation.FrameNumber - anim.frameEnd;
|
||||||
|
if (burnTimer > SEAL_MUTANT_BURN_END_TIME)
|
||||||
|
burnTimer = SEAL_MUTANT_BURN_END_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (burnTimer != SEAL_MUTANT_BURN_END_TIME)
|
||||||
|
{
|
||||||
|
auto pos = GetJointPosition(item, SealMutantGasBite.BoneID, Vector3(0.0f, -SEAL_MUTANT_FLAME_LIGHT_Y_OFFSET, 0.0f));
|
||||||
|
auto color = Color(Random::GenerateFloat(0.75f, 1.0f), Random::GenerateFloat(0.4f, 0.5f), Random::GenerateFloat(0.0f, 0.25f));
|
||||||
|
float falloff = Random::GenerateFloat(0.03f, 0.04f);
|
||||||
|
TriggerDynamicLight(pos.ToVector3(), color, falloff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (TestAnimFrameRange(item, 1, 124))
|
||||||
|
{
|
||||||
|
gasVel = item.Animation.FrameNumber - (anim.frameBase + 1);
|
||||||
|
if (gasVel > 24.0f)
|
||||||
|
{
|
||||||
|
gasVel = item.Animation.FrameNumber - (anim.frameEnd - 8);
|
||||||
|
if (gasVel <= 0.0f)
|
||||||
|
gasVel = 1.0f;
|
||||||
|
|
||||||
|
if (gasVel > 24.0f)
|
||||||
|
gasVel = Random::GenerateFloat(16.0f, 24.0f);
|
||||||
|
|
||||||
|
SpawnSealMutantPoisonGas(item, gasVel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (item.AIBits)
|
||||||
|
{
|
||||||
|
GetAITarget(&creature);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TargetNearestEntity(&item, &creature, SealMutantAttackTargetObjectIds, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
AI_INFO ai;
|
||||||
|
CreatureAIInfo(&item, &ai);
|
||||||
|
|
||||||
|
GetCreatureMood(&item, &ai, ai.zoneNumber == ai.enemyZone);
|
||||||
|
if (creature.Enemy != nullptr && creature.Enemy->IsLara())
|
||||||
|
{
|
||||||
|
const auto& player = GetLaraInfo(*creature.Enemy);
|
||||||
|
if (player.Status.Poison >= LARA_POISON_MAX)
|
||||||
|
creature.Mood = MoodType::Escape;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureMood(&item, &ai, ai.zoneNumber == ai.enemyZone);
|
||||||
|
headingAngle = CreatureTurn(&item, creature.MaxTurn);
|
||||||
|
|
||||||
|
auto* target = creature.Enemy;
|
||||||
|
creature.Enemy = LaraItem;
|
||||||
|
if (ai.distance < SEAL_MUTANT_ALERT_RANGE || item.HitStatus || TargetVisible(&item, &ai))
|
||||||
|
AlertAllGuards(itemNumber);
|
||||||
|
|
||||||
|
creature.Enemy = target;
|
||||||
|
|
||||||
|
switch (item.Animation.ActiveState)
|
||||||
|
{
|
||||||
|
case SEAL_MUTANT_STATE_IDLE:
|
||||||
|
creature.MaxTurn = 0;
|
||||||
|
creature.Flags = 0;
|
||||||
|
headOrient.x = -ai.xAngle;
|
||||||
|
headOrient.y = ai.angle;
|
||||||
|
torsoOrient.x = 0;
|
||||||
|
torsoOrient.z = 0;
|
||||||
|
|
||||||
|
if (item.AIBits & GUARD)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_IDLE;
|
||||||
|
headOrient.x = 0;
|
||||||
|
headOrient.y = AIGuard(&creature);
|
||||||
|
}
|
||||||
|
else if (item.AIBits & PATROL1)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_WALK;
|
||||||
|
headOrient.x = 0;
|
||||||
|
headOrient.y = 0;
|
||||||
|
}
|
||||||
|
else if (creature.Mood == MoodType::Escape)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_WALK;
|
||||||
|
}
|
||||||
|
else if (Targetable(&item, &ai) && ai.distance < SEAL_MUTANT_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_ATTACK;
|
||||||
|
}
|
||||||
|
else if (item.Animation.RequiredState != NO_VALUE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = item.Animation.RequiredState;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_WALK;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEAL_MUTANT_STATE_WALK:
|
||||||
|
creature.MaxTurn = SEAL_MUTANT_WALK_TURN_RATE;
|
||||||
|
|
||||||
|
if (ai.ahead)
|
||||||
|
{
|
||||||
|
headOrient.x = -ai.xAngle;
|
||||||
|
headOrient.y = ai.angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.AIBits & PATROL1)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_WALK;
|
||||||
|
headOrient.y = 0;
|
||||||
|
}
|
||||||
|
else if (Targetable(&item, &ai) && ai.distance < SEAL_MUTANT_ATTACK_RANGE)
|
||||||
|
{
|
||||||
|
item.Animation.TargetState = SEAL_MUTANT_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEAL_MUTANT_STATE_ATTACK:
|
||||||
|
if (ai.ahead)
|
||||||
|
{
|
||||||
|
headOrient.x = -ai.xAngle;
|
||||||
|
headOrient.y = ai.angle;
|
||||||
|
torsoOrient.x = -ai.xAngle / 2;
|
||||||
|
torsoOrient.z = ai.angle / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TestAnimFrameRange(item, 35, 58))
|
||||||
|
{
|
||||||
|
if (creature.Flags < 24)
|
||||||
|
creature.Flags += 3;
|
||||||
|
|
||||||
|
gasVel = 0.0f;
|
||||||
|
if (creature.Flags < 24.0f)
|
||||||
|
{
|
||||||
|
gasVel = creature.Flags;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gasVel = Random::GenerateFloat(16.0f, 24.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnSealMutantPoisonGas(item, gasVel);
|
||||||
|
if (creature.Enemy != nullptr && !creature.Enemy->IsLara())
|
||||||
|
creature.Enemy->HitStatus = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureJoint(&item, 0, torsoOrient.z);
|
||||||
|
CreatureJoint(&item, 1, torsoOrient.x);
|
||||||
|
CreatureJoint(&item, 2, headOrient.y);
|
||||||
|
CreatureAnimation(itemNumber, headingAngle, 0);
|
||||||
|
}
|
||||||
|
}
|
7
TombEngine/Objects/TR3/Entity/SealMutant.h
Normal file
7
TombEngine/Objects/TR3/Entity/SealMutant.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace TEN::Entities::Creatures::TR3
|
||||||
|
{
|
||||||
|
void InitializeSealMutant(short itemNumber);
|
||||||
|
void ControlSealMutant(short itemNumber);
|
||||||
|
}
|
|
@ -21,8 +21,8 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
constexpr auto TWIN_AUTO_GUN_SHOT_DAMAGE = 5;
|
constexpr auto TWIN_AUTO_GUN_SHOT_DAMAGE = 5;
|
||||||
constexpr auto TWIN_AUTO_GUN_HIT_POINTS_MAX = 28;
|
constexpr auto TWIN_AUTO_GUN_HIT_POINTS_MAX = 28;
|
||||||
|
|
||||||
const auto TwinAutoGunLeftBite = CreatureBiteInfo(110, -30, 530, 2);
|
const auto TwinAutoGunLeftBite = CreatureBiteInfo(Vector3(110.0f, -30.0f, 530.0f), 2);
|
||||||
const auto TwinAutoGunRightBite = CreatureBiteInfo(-110, -30, 530, 2);
|
const auto TwinAutoGunRightBite = CreatureBiteInfo(Vector3(-110.0f, -30.0f, 530.0f), 2);
|
||||||
|
|
||||||
enum TwinAutoGunAnim
|
enum TwinAutoGunAnim
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
constexpr auto FLAMETHROWER_WALK_TURN_RATE_MAX = ANGLE(5.0f);
|
constexpr auto FLAMETHROWER_WALK_TURN_RATE_MAX = ANGLE(5.0f);
|
||||||
|
|
||||||
const auto FlamethrowerBite = CreatureBiteInfo(Vector3(0, 340, 64), 7);
|
const auto FlamethrowerBite = CreatureBiteInfo(Vector3(0, 340, 64), 7);
|
||||||
|
const auto FlamethrowerTargetIds = { ID_LARA, ID_SEAL_MUTANT };
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
enum FlamethrowerState
|
enum FlamethrowerState
|
||||||
|
@ -94,30 +95,7 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
creature->Enemy = nullptr;
|
TargetNearestEntity(item, creature, FlamethrowerTargetIds, false);
|
||||||
|
|
||||||
ItemInfo* target = nullptr;
|
|
||||||
int minDistance = INT_MAX;
|
|
||||||
|
|
||||||
for (auto& currentCreature : ActiveCreatures)
|
|
||||||
{
|
|
||||||
if (currentCreature->ItemNumber == NO_VALUE || currentCreature->ItemNumber == itemNumber)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
target = &g_Level.Items[currentCreature->ItemNumber];
|
|
||||||
if (target->ObjectNumber == ID_LARA || target->HitPoints <= 0 || target->ObjectNumber == ID_FLAMETHROWER_BADDY)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int x = target->Pose.Position.x - item->Pose.Position.x;
|
|
||||||
int z = target->Pose.Position.z - item->Pose.Position.z;
|
|
||||||
|
|
||||||
int distance = SQUARE(z) + SQUARE(x);
|
|
||||||
if (distance < minDistance)
|
|
||||||
{
|
|
||||||
creature->Enemy = target;
|
|
||||||
minDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AI_INFO AI;
|
AI_INFO AI;
|
||||||
|
@ -311,10 +289,8 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ThrowFire(itemNumber, FlamethrowerBite, Vector3i(0, (Random::GenerateInt() & 63) + 12, 0));
|
ThrowFire(itemNumber, FlamethrowerBite, Vector3i(0, (Random::GenerateInt() & 63) + 12, 0));
|
||||||
if (realEnemy)
|
if (realEnemy && realEnemy->ObjectNumber == ID_SEAL_MUTANT)
|
||||||
{
|
realEnemy->ItemFlags[0]++;
|
||||||
/*code*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_FLAME_EMITTER, &item->Pose);
|
SoundEffect(SFX_TR4_FLAME_EMITTER, &item->Pose);
|
||||||
|
@ -345,10 +321,8 @@ namespace TEN::Entities::Creatures::TR3
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ThrowFire(itemNumber, FlamethrowerBite, Vector3i(0, (GetRandomControl() & 63) + 12, 0));
|
ThrowFire(itemNumber, FlamethrowerBite, Vector3i(0, (GetRandomControl() & 63) + 12, 0));
|
||||||
if (realEnemy)
|
if (realEnemy && realEnemy->ObjectNumber == ID_SEAL_MUTANT)
|
||||||
{
|
realEnemy->ItemFlags[0]++;
|
||||||
/*code*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundEffect(SFX_TR4_FLAME_EMITTER, &item->Pose);
|
SoundEffect(SFX_TR4_FLAME_EMITTER, &item->Pose);
|
||||||
|
|
|
@ -1,348 +0,0 @@
|
||||||
#include "framework.h"
|
|
||||||
#include "Objects/TR3/Entity/tr3_raptor.h"
|
|
||||||
|
|
||||||
#include "Game/control/box.h"
|
|
||||||
#include "Game/control/control.h"
|
|
||||||
#include "Game/control/lot.h"
|
|
||||||
#include "Game/effects/effects.h"
|
|
||||||
#include "Game/items.h"
|
|
||||||
#include "Game/itemdata/creature_info.h"
|
|
||||||
#include "Game/Lara/lara.h"
|
|
||||||
#include "Game/misc.h"
|
|
||||||
#include "Game/Setup.h"
|
|
||||||
#include "Math/Math.h"
|
|
||||||
#include "Specific/level.h"
|
|
||||||
|
|
||||||
using namespace TEN::Math;
|
|
||||||
|
|
||||||
namespace TEN::Entities::Creatures::TR3
|
|
||||||
{
|
|
||||||
constexpr auto RAPTOR_ATTACK_DAMAGE = 100;
|
|
||||||
|
|
||||||
constexpr auto RAPTOR_BITE_ATTACK_RANGE = SQUARE(585);
|
|
||||||
constexpr auto RAPTOR_JUMP_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
|
||||||
constexpr auto RAPTOR_RUN_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
|
||||||
|
|
||||||
constexpr auto RAPTOR_ROAR_CHANCE = 1.0f / 256;
|
|
||||||
constexpr auto RAPTOR_SWITCH_TARGET_CHANCE = 1.0f / 128;
|
|
||||||
|
|
||||||
constexpr auto RAPTOR_WALK_TURN_RATE_MAX = ANGLE(2.0f);
|
|
||||||
constexpr auto RAPTOR_RUN_TURN_RATE_MAX = ANGLE(2.0f);
|
|
||||||
constexpr auto RAPTOR_ATTACK_TURN_RATE_MAX = ANGLE(2.0f);
|
|
||||||
|
|
||||||
const auto RaptorBite = CreatureBiteInfo(Vector3(0, 66, 318), 22);
|
|
||||||
const auto RaptorAttackJoints = std::vector<unsigned int>{ 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23 };
|
|
||||||
|
|
||||||
enum RaptorState
|
|
||||||
{
|
|
||||||
RAPTOR_STATE_DEATH = 0,
|
|
||||||
RAPTOR_STATE_IDLE = 1,
|
|
||||||
RAPTOR_STATE_WALK_FORWARD = 2,
|
|
||||||
RAPTOR_STATE_RUN_FORWARD = 3,
|
|
||||||
RAPTOR_STATE_JUMP_ATTACK = 4,
|
|
||||||
RAPTOR_STATE_NONE = 5,
|
|
||||||
RAPTOR_STATE_ROAR = 6,
|
|
||||||
RAPTOR_STATE_RUN_BITE_ATTACK = 7,
|
|
||||||
RAPTOR_STATE_BITE_ATTACK = 8
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RaptorAnim
|
|
||||||
{
|
|
||||||
RAPTOR_ANIM_IDLE = 0,
|
|
||||||
RAPTOR_ANIM_RUN_FORWARD = 1,
|
|
||||||
RAPTOR_ANIM_RUN_FORWARD_TO_IDLE = 2,
|
|
||||||
RAPTOR_ANIM_IDLE_TO_RUN_FORWARD = 3,
|
|
||||||
RAPTOR_ANIM_ROAR = 4,
|
|
||||||
RAPTOR_ANIM_WALK_FORWARD = 5,
|
|
||||||
RAPTOR_ANIM_WALK_FORWARD_TO_IDLE = 6,
|
|
||||||
RAPTOR_ANIM_IDLE_TO_WALK_FORWARD = 7,
|
|
||||||
RAPTOR_ANIM_RUN_BITE_ATTACK = 8,
|
|
||||||
RAPTOR_ANIM_DEATH_1 = 9,
|
|
||||||
RAPTOR_ANIM_DEATH_2 = 10,
|
|
||||||
RAPTOR_ANIM_JUMP_ATTACK_START = 11,
|
|
||||||
RAPTOR_ANIM_JUMP_ATTACK_END = 12,
|
|
||||||
RAPTOR_ANIM_BITE_ATTACK = 13
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
enum RaptorFlags
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::array RaptorDeathAnims = { RAPTOR_ANIM_DEATH_1, RAPTOR_ANIM_DEATH_2, };
|
|
||||||
|
|
||||||
void RaptorControl(short itemNumber)
|
|
||||||
{
|
|
||||||
if (!CreatureActive(itemNumber))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
|
||||||
auto* creature = GetCreatureInfo(item);
|
|
||||||
|
|
||||||
short angle = 0;
|
|
||||||
short tilt = 0;
|
|
||||||
short head = 0;
|
|
||||||
short neck = 0;
|
|
||||||
|
|
||||||
if (item->HitPoints <= 0)
|
|
||||||
{
|
|
||||||
if (item->Animation.ActiveState != RAPTOR_STATE_DEATH)
|
|
||||||
SetAnimation(item, RaptorDeathAnims[Random::GenerateInt(0, (int)RaptorDeathAnims.size() - 1)]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (creature->Enemy == nullptr || Random::TestProbability(RAPTOR_SWITCH_TARGET_CHANCE))
|
|
||||||
{
|
|
||||||
ItemInfo* nearestItem = nullptr;
|
|
||||||
float minDistance = INFINITY;
|
|
||||||
|
|
||||||
for (auto& currentCreature : ActiveCreatures)
|
|
||||||
{
|
|
||||||
if (currentCreature->ItemNumber == NO_VALUE || currentCreature->ItemNumber == itemNumber)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto* targetItem = &g_Level.Items[currentCreature->ItemNumber];
|
|
||||||
|
|
||||||
int distance = Vector3i::Distance(item->Pose.Position, targetItem->Pose.Position);
|
|
||||||
if (distance < minDistance && item->HitPoints > 0)
|
|
||||||
{
|
|
||||||
nearestItem = targetItem;
|
|
||||||
minDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nearestItem != nullptr &&
|
|
||||||
(nearestItem->ObjectNumber != ID_RAPTOR ||
|
|
||||||
(Random::TestProbability(1 / 30.0f) && minDistance < SQUARE(BLOCK(2)))))
|
|
||||||
{
|
|
||||||
creature->Enemy = nearestItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
int distance = Vector3i::Distance(item->Pose.Position, LaraItem->Pose.Position);
|
|
||||||
if (distance <= minDistance)
|
|
||||||
creature->Enemy = LaraItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->AIBits)
|
|
||||||
GetAITarget(creature);
|
|
||||||
|
|
||||||
AI_INFO AI;
|
|
||||||
CreatureAIInfo(item, &AI);
|
|
||||||
|
|
||||||
if (AI.ahead)
|
|
||||||
head = AI.angle;
|
|
||||||
|
|
||||||
GetCreatureMood(item, &AI, true);
|
|
||||||
CreatureMood(item, &AI, true);
|
|
||||||
|
|
||||||
if (creature->Mood == MoodType::Bored)
|
|
||||||
creature->MaxTurn /= 2;
|
|
||||||
|
|
||||||
angle = CreatureTurn(item, creature->MaxTurn);
|
|
||||||
neck = -angle * 6;
|
|
||||||
|
|
||||||
switch (item->Animation.ActiveState)
|
|
||||||
{
|
|
||||||
case RAPTOR_STATE_IDLE:
|
|
||||||
creature->MaxTurn = 0;
|
|
||||||
creature->Flags &= ~1;
|
|
||||||
|
|
||||||
if (item->Animation.RequiredState != NO_VALUE)
|
|
||||||
item->Animation.TargetState = item->Animation.RequiredState;
|
|
||||||
else if (creature->Flags & 2)
|
|
||||||
{
|
|
||||||
creature->Flags &= ~2;
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_ROAR;
|
|
||||||
}
|
|
||||||
else if (item->TouchBits.Test(RaptorAttackJoints) ||
|
|
||||||
(AI.distance < RAPTOR_BITE_ATTACK_RANGE && AI.bite))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_BITE_ATTACK;
|
|
||||||
}
|
|
||||||
else if (AI.bite && AI.distance < RAPTOR_JUMP_ATTACK_RANGE)
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_JUMP_ATTACK;
|
|
||||||
else if (creature->Mood == MoodType::Escape &&
|
|
||||||
Lara.TargetEntity != item && AI.ahead && !item->HitStatus)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Bored)
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_WALK_FORWARD;
|
|
||||||
else
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_RUN_FORWARD;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RAPTOR_STATE_WALK_FORWARD:
|
|
||||||
creature->MaxTurn = RAPTOR_WALK_TURN_RATE_MAX;
|
|
||||||
creature->Flags &= ~1;
|
|
||||||
|
|
||||||
if (creature->Mood != MoodType::Bored)
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
else if (AI.ahead && Random::TestProbability(RAPTOR_ROAR_CHANCE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
item->Animation.RequiredState = RAPTOR_STATE_ROAR;
|
|
||||||
creature->Flags &= ~2;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RAPTOR_STATE_RUN_FORWARD:
|
|
||||||
creature->MaxTurn = RAPTOR_RUN_TURN_RATE_MAX;
|
|
||||||
creature->Flags &= ~1;
|
|
||||||
tilt = angle;
|
|
||||||
|
|
||||||
if (item->TouchBits.Test(RaptorAttackJoints))
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
else if (creature->Flags & 2)
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
item->Animation.RequiredState = RAPTOR_STATE_ROAR;
|
|
||||||
creature->Flags &= ~2;
|
|
||||||
}
|
|
||||||
else if (AI.bite && AI.distance < RAPTOR_RUN_ATTACK_RANGE)
|
|
||||||
{
|
|
||||||
if (item->Animation.TargetState == RAPTOR_STATE_RUN_FORWARD)
|
|
||||||
{
|
|
||||||
if (Random::TestProbability(0.25f))
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
else
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_RUN_BITE_ATTACK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (AI.ahead && creature->Mood != MoodType::Escape &&
|
|
||||||
Random::TestProbability(RAPTOR_ROAR_CHANCE))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
item->Animation.RequiredState = RAPTOR_STATE_ROAR;
|
|
||||||
}
|
|
||||||
else if (creature->Mood == MoodType::Bored ||
|
|
||||||
(creature->Mood == MoodType::Escape && Lara.TargetEntity != item && AI.ahead))
|
|
||||||
{
|
|
||||||
item->Animation.TargetState = RAPTOR_STATE_IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RAPTOR_STATE_JUMP_ATTACK:
|
|
||||||
creature->MaxTurn = RAPTOR_ATTACK_TURN_RATE_MAX;
|
|
||||||
tilt = angle;
|
|
||||||
|
|
||||||
if (creature->Enemy->IsLara())
|
|
||||||
{
|
|
||||||
if (!(creature->Flags & 1) &&
|
|
||||||
item->TouchBits.Test(RaptorAttackJoints))
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, RAPTOR_ATTACK_DAMAGE);
|
|
||||||
CreatureEffect(item, RaptorBite, DoBloodSplat);
|
|
||||||
creature->Flags |= 1;
|
|
||||||
|
|
||||||
if (LaraItem->HitPoints <= 0)
|
|
||||||
creature->Flags |= 2;
|
|
||||||
|
|
||||||
item->Animation.RequiredState = RAPTOR_STATE_IDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(creature->Flags & 1) && creature->Enemy != nullptr)
|
|
||||||
{
|
|
||||||
if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= BLOCK(0.5f))
|
|
||||||
{
|
|
||||||
if (creature->Enemy->HitPoints <= 0)
|
|
||||||
creature->Flags |= 2;
|
|
||||||
|
|
||||||
DoDamage(creature->Enemy, 25);
|
|
||||||
CreatureEffect(item, RaptorBite, DoBloodSplat);
|
|
||||||
creature->Flags |= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RAPTOR_STATE_BITE_ATTACK:
|
|
||||||
creature->MaxTurn = RAPTOR_ATTACK_TURN_RATE_MAX;
|
|
||||||
tilt = angle;
|
|
||||||
|
|
||||||
if (creature->Enemy->IsLara())
|
|
||||||
{
|
|
||||||
if (!(creature->Flags & 1) &&
|
|
||||||
item->TouchBits.Test(RaptorAttackJoints))
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, RAPTOR_ATTACK_DAMAGE);
|
|
||||||
CreatureEffect(item, RaptorBite, DoBloodSplat);
|
|
||||||
creature->Flags |= 1;
|
|
||||||
|
|
||||||
if (LaraItem->HitPoints <= 0)
|
|
||||||
creature->Flags |= 2;
|
|
||||||
|
|
||||||
item->Animation.RequiredState = RAPTOR_STATE_IDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(creature->Flags & 1) && creature->Enemy != nullptr)
|
|
||||||
{
|
|
||||||
if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= BLOCK(0.5f))
|
|
||||||
{
|
|
||||||
if (creature->Enemy->HitPoints <= 0)
|
|
||||||
creature->Flags |= 2;
|
|
||||||
|
|
||||||
DoDamage(creature->Enemy, 25);
|
|
||||||
CreatureEffect(item, RaptorBite, DoBloodSplat);
|
|
||||||
creature->Flags |= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RAPTOR_STATE_RUN_BITE_ATTACK:
|
|
||||||
creature->MaxTurn = RAPTOR_ATTACK_TURN_RATE_MAX;
|
|
||||||
tilt = angle;
|
|
||||||
|
|
||||||
if (creature->Enemy->IsLara())
|
|
||||||
{
|
|
||||||
if (!(creature->Flags & 1) &&
|
|
||||||
item->TouchBits.Test(RaptorAttackJoints))
|
|
||||||
{
|
|
||||||
DoDamage(creature->Enemy, RAPTOR_ATTACK_DAMAGE);
|
|
||||||
CreatureEffect(item, RaptorBite, DoBloodSplat);
|
|
||||||
item->Animation.RequiredState = RAPTOR_STATE_RUN_FORWARD;
|
|
||||||
creature->Flags |= 1;
|
|
||||||
|
|
||||||
if (LaraItem->HitPoints <= 0)
|
|
||||||
creature->Flags |= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(creature->Flags & 1) && creature->Enemy != nullptr)
|
|
||||||
{
|
|
||||||
if (Vector3i::Distance(item->Pose.Position, creature->Enemy->Pose.Position) <= BLOCK(0.5f))
|
|
||||||
{
|
|
||||||
if (creature->Enemy->HitPoints <= 0)
|
|
||||||
creature->Flags |= 2;
|
|
||||||
|
|
||||||
DoDamage(creature->Enemy, 25);
|
|
||||||
CreatureEffect(item, RaptorBite, DoBloodSplat);
|
|
||||||
creature->Flags |= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CreatureTilt(item, tilt);
|
|
||||||
CreatureJoint(item, 0, head / 2);
|
|
||||||
CreatureJoint(item, 1, head / 2);
|
|
||||||
CreatureJoint(item, 2, neck);
|
|
||||||
CreatureJoint(item, 3, neck);
|
|
||||||
CreatureAnimation(itemNumber, angle, tilt);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -998,7 +998,7 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
void KayakToItemCollision(ItemInfo* kayakItem, ItemInfo* laraItem)
|
void KayakToItemCollision(ItemInfo* kayakItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
for (auto i : g_Level.Rooms[kayakItem->RoomNumber].neighbors)
|
for (auto i : g_Level.Rooms[kayakItem->RoomNumber].NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
if (!g_Level.Rooms[i].Active())
|
if (!g_Level.Rooms[i].Active())
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -281,7 +281,7 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
static void MinecartToEntityCollision(ItemInfo* minecartItem, ItemInfo* laraItem)
|
static void MinecartToEntityCollision(ItemInfo* minecartItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
for (auto i : g_Level.Rooms[minecartItem->RoomNumber].neighbors)
|
for (auto i : g_Level.Rooms[minecartItem->RoomNumber].NeighborRoomNumbers)
|
||||||
{
|
{
|
||||||
if (!g_Level.Rooms[i].Active())
|
if (!g_Level.Rooms[i].Active())
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -8,28 +8,29 @@
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
|
|
||||||
// Creatures
|
// Creatures
|
||||||
#include "Objects/TR3/Entity/Compsognathus.h" // OK
|
#include "Objects/TR3/Entity/Compsognathus.h"
|
||||||
#include "Objects/TR3/Entity/Lizard.h" // OK
|
#include "Objects/TR3/Entity/Lizard.h"
|
||||||
#include "Objects/TR3/Entity/PunaBoss.h" // OK
|
#include "Objects/TR3/Entity/PunaBoss.h"
|
||||||
#include "Objects/TR3/Entity/Shiva.h" // OK
|
#include "Objects/TR3/Entity/SealMutant.h"
|
||||||
#include "Objects/TR3/Entity/SophiaLeigh.h" // OK
|
#include "Objects/TR3/Entity/Shiva.h"
|
||||||
|
#include "Objects/TR3/Entity/SophiaLeigh.h"
|
||||||
|
#include "Objects/TR3/Entity/Raptor.h"
|
||||||
#include "Objects/TR3/Entity/TwinAutoGun.h"
|
#include "Objects/TR3/Entity/TwinAutoGun.h"
|
||||||
#include "Objects/TR3/Entity/WaspMutant.h" // OK
|
#include "Objects/TR3/Entity/WaspMutant.h"
|
||||||
#include "Objects/TR3/Entity/Winston.h" // OK
|
#include "Objects/TR3/Entity/Winston.h"
|
||||||
#include "Objects/TR3/Entity/tr3_tony.h" // OK
|
#include "Objects/TR3/Entity/tr3_tony.h"
|
||||||
#include "Objects/TR3/Entity/tr3_civvy.h" // OK
|
#include "Objects/TR3/Entity/tr3_civvy.h"
|
||||||
#include "Objects/TR3/Entity/tr3_claw_mutant.h" // OK
|
#include "Objects/TR3/Entity/tr3_claw_mutant.h"
|
||||||
#include "Objects/TR3/Entity/tr3_cobra.h" // OK
|
#include "Objects/TR3/Entity/tr3_cobra.h"
|
||||||
#include "Objects/TR3/Entity/FishSwarm.h" // OK
|
#include "Objects/TR3/Entity/FishSwarm.h"
|
||||||
#include "Objects/TR3/Entity/tr3_flamethrower.h" // OK
|
#include "Objects/TR3/Entity/tr3_flamethrower.h"
|
||||||
#include "Objects/TR3/Entity/tr3_monkey.h" // OK
|
#include "Objects/TR3/Entity/tr3_monkey.h"
|
||||||
#include "Objects/TR3/Entity/tr3_mp_gun.h" // OK
|
#include "Objects/TR3/Entity/tr3_mp_gun.h"
|
||||||
#include "Objects/TR3/Entity/tr3_mp_stick.h" // OK
|
#include "Objects/TR3/Entity/tr3_mp_stick.h"
|
||||||
#include "Objects/TR3/Entity/tr3_raptor.h" // OK
|
#include "Objects/TR3/Entity/tr3_scuba_diver.h"
|
||||||
#include "Objects/TR3/Entity/tr3_scuba_diver.h" // OK
|
#include "Objects/TR3/Entity/tr3_tiger.h"
|
||||||
#include "Objects/TR3/Entity/tr3_tiger.h" // OK
|
#include "Objects/TR3/Entity/tr3_trex.h"
|
||||||
#include "Objects/TR3/Entity/tr3_trex.h" // OK
|
#include "Objects/TR3/Entity/tr3_tribesman.h"
|
||||||
#include "Objects/TR3/Entity/tr3_tribesman.h" // OK
|
|
||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
#include "Objects/Effects/Boss.h"
|
#include "Objects/Effects/Boss.h"
|
||||||
|
@ -117,6 +118,7 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
obj->radius = 341;
|
obj->radius = 341;
|
||||||
obj->pivotLength = 600;
|
obj->pivotLength = 600;
|
||||||
obj->intelligent = true;
|
obj->intelligent = true;
|
||||||
|
obj->LotType = LotType::HumanPlusJump;
|
||||||
obj->SetBoneRotationFlags(20, ROT_Y);
|
obj->SetBoneRotationFlags(20, ROT_Y);
|
||||||
obj->SetBoneRotationFlags(21, ROT_Y);
|
obj->SetBoneRotationFlags(21, ROT_Y);
|
||||||
obj->SetBoneRotationFlags(23, ROT_Y);
|
obj->SetBoneRotationFlags(23, ROT_Y);
|
||||||
|
@ -365,7 +367,7 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
obj->SetBoneRotationFlags(7, ROT_X | ROT_Y); // Head.
|
obj->SetBoneRotationFlags(7, ROT_X | ROT_Y); // Head.
|
||||||
obj->SetHitEffect();
|
obj->SetHitEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = &Objects[ID_WASP_MUTANT];
|
obj = &Objects[ID_WASP_MUTANT];
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
|
@ -380,7 +382,7 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
obj->LotType = LotType::Flyer;
|
obj->LotType = LotType::Flyer;
|
||||||
obj->SetHitEffect();
|
obj->SetHitEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = &Objects[ID_COMPSOGNATHUS];
|
obj = &Objects[ID_COMPSOGNATHUS];
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
|
@ -412,6 +414,22 @@ static void StartEntity(ObjectInfo* obj)
|
||||||
obj->SetHitEffect();
|
obj->SetHitEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj = &Objects[ID_SEAL_MUTANT];
|
||||||
|
if (obj->loaded)
|
||||||
|
{
|
||||||
|
obj->Initialize = InitializeSealMutant;
|
||||||
|
obj->collision = CreatureCollision;
|
||||||
|
obj->control = ControlSealMutant;
|
||||||
|
obj->shadowType = ShadowMode::All;
|
||||||
|
obj->HitPoints = 50;
|
||||||
|
obj->radius = 204;
|
||||||
|
obj->pivotLength = 0;
|
||||||
|
obj->intelligent = true;
|
||||||
|
obj->SetBoneRotationFlags(8, ROT_X | ROT_Z); // Torso X/Z
|
||||||
|
obj->SetBoneRotationFlags(9, ROT_Y); // Head
|
||||||
|
obj->SetHitEffect();
|
||||||
|
}
|
||||||
|
|
||||||
obj = &Objects[ID_WINSTON];
|
obj = &Objects[ID_WINSTON];
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
|
|
|
@ -229,13 +229,13 @@ namespace TEN::Entities::TR4
|
||||||
{
|
{
|
||||||
const auto& room = g_Level.Rooms[LaraItem->RoomNumber];
|
const auto& room = g_Level.Rooms[LaraItem->RoomNumber];
|
||||||
|
|
||||||
x = room.x + room.xSize * BLOCK(1) / 2 - item.Pose.Position.x;
|
x = room.Position.x + room.XSize * BLOCK(1) / 2 - item.Pose.Position.x;
|
||||||
z = room.z + room.zSize * BLOCK(1) / 2 - item.Pose.Position.z;
|
z = room.Position.z + room.ZSize * BLOCK(1) / 2 - item.Pose.Position.z;
|
||||||
|
|
||||||
distance = SQUARE(x) + SQUARE(z);
|
distance = SQUARE(x) + SQUARE(z);
|
||||||
dy = abs((distance / MAX_VISIBILITY_DISTANCE) - CLICK(1));
|
dy = abs((distance / MAX_VISIBILITY_DISTANCE) - CLICK(1));
|
||||||
//Prevent Wraiths to go below floor level
|
//Prevent Wraiths to go below floor level
|
||||||
y = room.y + ((room.maxceiling - room.minfloor) / 4);
|
y = room.Position.y + ((room.TopHeight - room.BottomHeight) / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
dy = y - item.Pose.Position.y - dy - CLICK(0.5f);
|
dy = y - item.Pose.Position.y - dy - CLICK(0.5f);
|
||||||
|
|
|
@ -186,7 +186,7 @@ namespace TEN::Entities::TR4
|
||||||
auto pos = GetJointPosition(item, LM_LINARM);
|
auto pos = GetJointPosition(item, LM_LINARM);
|
||||||
|
|
||||||
auto& room = g_Level.Rooms[item->RoomNumber];
|
auto& room = g_Level.Rooms[item->RoomNumber];
|
||||||
auto& currentFloor = room.floor[(pos.z - room.z) / BLOCK(1) + (pos.x - room.x) / BLOCK(1) * room.zSize];
|
auto& currentFloor = room.Sectors[(pos.z - room.Position.z) / BLOCK(1) + (pos.x - room.Position.x) / BLOCK(1) * room.ZSize];
|
||||||
|
|
||||||
if (currentFloor.Stopper)
|
if (currentFloor.Stopper)
|
||||||
{
|
{
|
||||||
|
|
|
@ -266,7 +266,7 @@ void UpdateRats()
|
||||||
|
|
||||||
if (TestEnvironment(ENV_FLAG_WATER, room))
|
if (TestEnvironment(ENV_FLAG_WATER, room))
|
||||||
{
|
{
|
||||||
rat->Pose.Position.y = room->maxceiling + 50;
|
rat->Pose.Position.y = room->TopHeight + 50;
|
||||||
rat->Velocity = 16;
|
rat->Velocity = 16;
|
||||||
rat->VerticalVelocity = 0;
|
rat->VerticalVelocity = 0;
|
||||||
|
|
||||||
|
@ -274,16 +274,16 @@ void UpdateRats()
|
||||||
{
|
{
|
||||||
if (!(GetRandomControl() & 0xF))
|
if (!(GetRandomControl() & 0xF))
|
||||||
SpawnRipple(
|
SpawnRipple(
|
||||||
Vector3(rat->Pose.Position.x, room->maxceiling, rat->Pose.Position.z),
|
Vector3(rat->Pose.Position.x, room->TopHeight, rat->Pose.Position.z),
|
||||||
rat->RoomNumber,
|
rat->RoomNumber,
|
||||||
Random::GenerateFloat(48.0f, 52.0f),
|
Random::GenerateFloat(48.0f, 52.0f),
|
||||||
(int)RippleFlags::SlowFade);
|
(int)RippleFlags::SlowFade);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddWaterSparks(rat->Pose.Position.x, room->maxceiling, rat->Pose.Position.z, 16);
|
AddWaterSparks(rat->Pose.Position.x, room->TopHeight, rat->Pose.Position.z, 16);
|
||||||
SpawnRipple(
|
SpawnRipple(
|
||||||
Vector3(rat->Pose.Position.x, room->maxceiling, rat->Pose.Position.z),
|
Vector3(rat->Pose.Position.x, room->TopHeight, rat->Pose.Position.z),
|
||||||
rat->RoomNumber,
|
rat->RoomNumber,
|
||||||
Random::GenerateFloat(48.0f, 52.0f),
|
Random::GenerateFloat(48.0f, 52.0f),
|
||||||
(int)RippleFlags::SlowFade);
|
(int)RippleFlags::SlowFade);
|
||||||
|
|
|
@ -232,9 +232,9 @@ void UpdateSpiders()
|
||||||
spider->VerticalVelocity = 0;
|
spider->VerticalVelocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spider->Pose.Position.y < g_Level.Rooms[spider->RoomNumber].maxceiling + 50)
|
if (spider->Pose.Position.y < g_Level.Rooms[spider->RoomNumber].TopHeight + 50)
|
||||||
{
|
{
|
||||||
spider->Pose.Position.y = g_Level.Rooms[spider->RoomNumber].maxceiling + 50;
|
spider->Pose.Position.y = g_Level.Rooms[spider->RoomNumber].TopHeight + 50;
|
||||||
spider->Pose.Orientation.y += -ANGLE(180.0f);
|
spider->Pose.Orientation.y += -ANGLE(180.0f);
|
||||||
spider->VerticalVelocity = 1;
|
spider->VerticalVelocity = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,7 +337,7 @@ namespace TEN::Entities::Creatures::TR5
|
||||||
|
|
||||||
auto pos = GetJointPosition(item, 16);
|
auto pos = GetJointPosition(item, 16);
|
||||||
|
|
||||||
auto* floor = GetSector(room, pos.x - room->x, pos.z - room->z);
|
auto* floor = GetSector(room, pos.x - room->Position.x, pos.z - room->Position.z);
|
||||||
if (floor->Stopper)
|
if (floor->Stopper)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < room->mesh.size(); i++)
|
for (int i = 0; i < room->mesh.size(); i++)
|
||||||
|
|
|
@ -363,9 +363,9 @@ namespace TEN::Entities::Creatures::TR5
|
||||||
|
|
||||||
auto* room = &g_Level.Rooms[roomNumber];
|
auto* room = &g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
int x = room->x + (creature->Tosspad / 256 & 0xFF) * BLOCK(1) + 512;
|
int x = room->Position.x + (creature->Tosspad / 256 & 0xFF) * BLOCK(1) + 512;
|
||||||
int y = room->minfloor + floorHeight;
|
int y = room->BottomHeight + floorHeight;
|
||||||
int z = room->z + (creature->Tosspad & 0xFF) * BLOCK(1) + 512;
|
int z = room->Position.z + (creature->Tosspad & 0xFF) * BLOCK(1) + 512;
|
||||||
|
|
||||||
TestTriggers(x, y, z, roomNumber, true);
|
TestTriggers(x, y, z, roomNumber, true);
|
||||||
|
|
||||||
|
|
|
@ -543,7 +543,7 @@ namespace TEN::Entities::Creatures::TR5
|
||||||
pos = GetJointPosition(item, 16);
|
pos = GetJointPosition(item, 16);
|
||||||
|
|
||||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||||
FloorInfo* floor = GetSector(room, pos.x - room->x, pos.z - room->z);
|
FloorInfo* floor = GetSector(room, pos.x - room->Position.x, pos.z - room->Position.z);
|
||||||
|
|
||||||
// If floor is stopped, then try to find static meshes and shatter them, activating heavy triggers below
|
// If floor is stopped, then try to find static meshes and shatter them, activating heavy triggers below
|
||||||
if (floor->Stopper)
|
if (floor->Stopper)
|
||||||
|
@ -823,9 +823,9 @@ namespace TEN::Entities::Creatures::TR5
|
||||||
short floorHeight = item->ItemFlags[2] & 0xFF00;
|
short floorHeight = item->ItemFlags[2] & 0xFF00;
|
||||||
auto* room = &g_Level.Rooms[roomNumber];
|
auto* room = &g_Level.Rooms[roomNumber];
|
||||||
|
|
||||||
int x = room->x + (creature->Tosspad / 256 & 0xFF) * BLOCK(1) + 512;
|
int x = room->Position.x + (creature->Tosspad / 256 & 0xFF) * BLOCK(1) + 512;
|
||||||
int y = room->minfloor + floorHeight;
|
int y = room->BottomHeight + floorHeight;
|
||||||
int z = room->z + (creature->Tosspad & 0xFF) * BLOCK(1) + 512;
|
int z = room->Position.z + (creature->Tosspad & 0xFF) * BLOCK(1) + 512;
|
||||||
|
|
||||||
TestTriggers(x, y, z, roomNumber, true);
|
TestTriggers(x, y, z, roomNumber, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ namespace TEN::Entities::Generic
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int distToPortal = *&g_Level.Rooms[item->RoomNumber].maxceiling - item->Pose.Position.y;
|
int distToPortal = *&g_Level.Rooms[item->RoomNumber].TopHeight - item->Pose.Position.y;
|
||||||
if (distToPortal <= speed)
|
if (distToPortal <= speed)
|
||||||
UpdateBridgeItem(*item);
|
UpdateBridgeItem(*item);
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,10 @@ void InitializeSmashObject(short itemNumber)
|
||||||
item->Flags = 0;
|
item->Flags = 0;
|
||||||
item->MeshBits = 1;
|
item->MeshBits = 1;
|
||||||
|
|
||||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
auto& room = g_Level.Rooms[item->RoomNumber];
|
||||||
|
|
||||||
// NOTE: Avoids crash when attempting to access Boxes[] array while box is equal to NO_VALUE. -- TokyoSU 2022.12.20
|
// NOTE: Avoids crash when attempting to access Boxes[] array while box is equal to NO_VALUE. -- TokyoSU 2022.12.20
|
||||||
FloorInfo* floor = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z);
|
FloorInfo* floor = GetSector(&room, item->Pose.Position.x - room.Position.x, item->Pose.Position.z - room.Position.z);
|
||||||
if (floor->PathfindingBoxID == NO_VALUE)
|
if (floor->PathfindingBoxID == NO_VALUE)
|
||||||
{
|
{
|
||||||
TENLog("Smash object with ID " + std::to_string(itemNumber) + " may be inside a wall." , LogLevel::Warning);
|
TENLog("Smash object with ID " + std::to_string(itemNumber) + " may be inside a wall." , LogLevel::Warning);
|
||||||
|
@ -34,9 +34,9 @@ void SmashObject(short itemNumber)
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
auto* item = &g_Level.Items[itemNumber];
|
||||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||||
|
|
||||||
int sector = ((item->Pose.Position.z - room->z) / 1024) + room->zSize * ((item->Pose.Position.x - room->x) / 1024);
|
int sector = ((item->Pose.Position.z - room->Position.z) / 1024) + room->ZSize * ((item->Pose.Position.x - room->Position.z) / 1024);
|
||||||
|
|
||||||
auto* box = &g_Level.PathfindingBoxes[room->floor[sector].PathfindingBoxID];
|
auto* box = &g_Level.PathfindingBoxes[room->Sectors[sector].PathfindingBoxID];
|
||||||
if (box->flags & 0x8000)
|
if (box->flags & 0x8000)
|
||||||
box->flags &= ~BOX_BLOCKED;
|
box->flags &= ~BOX_BLOCKED;
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,7 @@ enum GAME_OBJECT_ID : short
|
||||||
ID_GIANT_MUTANT = 225,
|
ID_GIANT_MUTANT = 225,
|
||||||
// 226
|
// 226
|
||||||
ID_PROJ_SHARD = 227,
|
ID_PROJ_SHARD = 227,
|
||||||
ID_PROJ_BOMB,
|
ID_PROJ_BOMB,
|
||||||
ID_YETI,
|
ID_YETI,
|
||||||
ID_BIRDMONSTER,
|
ID_BIRDMONSTER,
|
||||||
ID_MARCO_BARTOLI,
|
ID_MARCO_BARTOLI,
|
||||||
|
@ -232,10 +232,10 @@ enum GAME_OBJECT_ID : short
|
||||||
ID_CLAW_MUTANT,
|
ID_CLAW_MUTANT,
|
||||||
ID_WASP_MUTANT,
|
ID_WASP_MUTANT,
|
||||||
ID_TWIN_AUTO_GUN,
|
ID_TWIN_AUTO_GUN,
|
||||||
ID_SKATEBOARD = 296,
|
ID_SKATEBOARD,
|
||||||
ID_SKATEBOARD_KID,
|
ID_SKATEBOARD_KID,
|
||||||
ID_WINSTON,
|
ID_WINSTON,
|
||||||
//299
|
ID_SEAL_MUTANT,
|
||||||
|
|
||||||
ID_SPRINGBOARD = 320,
|
ID_SPRINGBOARD = 320,
|
||||||
ID_ROLLING_SPINDLE,
|
ID_ROLLING_SPINDLE,
|
||||||
|
|
|
@ -212,14 +212,14 @@ namespace TEN::Renderer
|
||||||
r->ItemsToDraw.reserve(MAX_ITEMS_DRAW);
|
r->ItemsToDraw.reserve(MAX_ITEMS_DRAW);
|
||||||
r->EffectsToDraw.reserve(MAX_ITEMS_DRAW);
|
r->EffectsToDraw.reserve(MAX_ITEMS_DRAW);
|
||||||
|
|
||||||
Vector3 boxMin = Vector3(room.x + BLOCK(1), room.maxceiling - CLICK(1), room.z + BLOCK(1));
|
Vector3 boxMin = Vector3(room.Position.x + BLOCK(1), room.TopHeight - CLICK(1), room.Position.z + BLOCK(1));
|
||||||
Vector3 boxMax = Vector3(room.x + (room.xSize - 1) * BLOCK(1), room.minfloor + CLICK(1), room.z + (room.zSize - 1) * BLOCK(1));
|
Vector3 boxMax = Vector3(room.Position.x + (room.XSize - 1) * BLOCK(1), room.BottomHeight + CLICK(1), room.Position.z + (room.ZSize - 1) * BLOCK(1));
|
||||||
Vector3 center = (boxMin + boxMax) / 2.0f;
|
Vector3 center = (boxMin + boxMax) / 2.0f;
|
||||||
Vector3 extents = boxMax - center;
|
Vector3 extents = boxMax - center;
|
||||||
r->BoundingBox = BoundingBox(center, extents);
|
r->BoundingBox = BoundingBox(center, extents);
|
||||||
|
|
||||||
r->Neighbors.clear();
|
r->Neighbors.clear();
|
||||||
for (int j : room.neighbors)
|
for (int j : room.NeighborRoomNumbers)
|
||||||
if (g_Level.Rooms[j].Active())
|
if (g_Level.Rooms[j].Active())
|
||||||
r->Neighbors.push_back(j);
|
r->Neighbors.push_back(j);
|
||||||
|
|
||||||
|
@ -238,9 +238,9 @@ namespace TEN::Renderer
|
||||||
for (int k = 0; k < 4; k++)
|
for (int k = 0; k < 4; k++)
|
||||||
{
|
{
|
||||||
door->AbsoluteVertices[k] = Vector4(
|
door->AbsoluteVertices[k] = Vector4(
|
||||||
room.x + oldDoor->vertices[k].x,
|
room.Position.x + oldDoor->vertices[k].x,
|
||||||
room.y + oldDoor->vertices[k].y,
|
room.Position.y + oldDoor->vertices[k].y,
|
||||||
room.z + oldDoor->vertices[k].z,
|
room.Position.z + oldDoor->vertices[k].z,
|
||||||
1.0f);
|
1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,9 +312,9 @@ namespace TEN::Renderer
|
||||||
Vertex* vertex = &_roomsVertices[lastVertex];
|
Vertex* vertex = &_roomsVertices[lastVertex];
|
||||||
int index = poly.indices[k];
|
int index = poly.indices[k];
|
||||||
|
|
||||||
vertex->Position.x = room.x + room.positions[index].x;
|
vertex->Position.x = room.Position.x + room.positions[index].x;
|
||||||
vertex->Position.y = room.y + room.positions[index].y;
|
vertex->Position.y = room.Position.y + room.positions[index].y;
|
||||||
vertex->Position.z = room.z + room.positions[index].z;
|
vertex->Position.z = room.Position.z + room.positions[index].z;
|
||||||
|
|
||||||
bucket.Centre += vertex->Position;
|
bucket.Centre += vertex->Position;
|
||||||
|
|
||||||
|
|
|
@ -1725,7 +1725,7 @@ namespace TEN::Renderer
|
||||||
//RenderSimpleSceneToParaboloid(&_roomAmbientMapsCache[ambientMapCacheIndex].Back, LaraItem->Pose.Position.ToVector3(), -1);
|
//RenderSimpleSceneToParaboloid(&_roomAmbientMapsCache[ambientMapCacheIndex].Back, LaraItem->Pose.Position.ToVector3(), -1);
|
||||||
|
|
||||||
// Bind and clear render target.
|
// Bind and clear render target.
|
||||||
_context->ClearRenderTargetView(_renderTarget.RenderTargetView.Get(), _debugPage == RendererDebugPage::WireframeMode ? Colors::White : Colors::Black);
|
_context->ClearRenderTargetView(_renderTarget.RenderTargetView.Get(), _debugPage == RendererDebugPage::WireframeMode ? Colors::DimGray : Colors::Black);
|
||||||
_context->ClearDepthStencilView(_renderTarget.DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
_context->ClearDepthStencilView(_renderTarget.DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
||||||
|
|
||||||
// Reset viewport and scissor
|
// Reset viewport and scissor
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace TEN::Renderer
|
||||||
constexpr auto MenuVerticalLineSpacing = 30;
|
constexpr auto MenuVerticalLineSpacing = 30;
|
||||||
constexpr auto MenuVerticalNarrowLineSpacing = 24;
|
constexpr auto MenuVerticalNarrowLineSpacing = 24;
|
||||||
constexpr auto MenuVerticalBlockSpacing = 50;
|
constexpr auto MenuVerticalBlockSpacing = 50;
|
||||||
|
|
||||||
// Vertical menu positioning templates
|
// Vertical menu positioning templates
|
||||||
constexpr auto MenuVerticalControls = 30;
|
constexpr auto MenuVerticalControls = 30;
|
||||||
constexpr auto MenuVerticalDisplaySettings = 160;
|
constexpr auto MenuVerticalDisplaySettings = 160;
|
||||||
|
@ -65,10 +65,25 @@ namespace TEN::Renderer
|
||||||
// Helper functions to construct string flags
|
// Helper functions to construct string flags
|
||||||
inline int SF(bool selected = false) { return (int)PrintStringFlags::Outline | (selected ? (int)PrintStringFlags::Blink : 0); }
|
inline int SF(bool selected = false) { return (int)PrintStringFlags::Outline | (selected ? (int)PrintStringFlags::Blink : 0); }
|
||||||
inline int SF_Center(bool selected = false) { return (int)PrintStringFlags::Outline | (int)PrintStringFlags::Center | (selected ? (int)PrintStringFlags::Blink : 0); }
|
inline int SF_Center(bool selected = false) { return (int)PrintStringFlags::Outline | (int)PrintStringFlags::Center | (selected ? (int)PrintStringFlags::Blink : 0); }
|
||||||
|
|
||||||
// Helper functions to get specific generic strings
|
// Helper functions to get specific generic strings
|
||||||
inline const char* Str_Enabled(bool enabled = false) { return g_GameFlow->GetString(enabled ? STRING_ENABLED : STRING_DISABLED); }
|
inline const std::string Str_Enabled(bool enabled = false) { return g_GameFlow->GetString(enabled ? STRING_ENABLED : STRING_DISABLED); }
|
||||||
inline const char* Str_LoadSave(bool save = false) { return g_GameFlow->GetString(save ? STRING_SAVE_GAME : STRING_LOAD_GAME); }
|
inline const std::string Str_LoadSave(bool save = false) { return g_GameFlow->GetString(save ? STRING_SAVE_GAME : STRING_LOAD_GAME); }
|
||||||
|
inline const std::string Str_MenuOptionLoopingMode(MenuOptionLoopingMode loopingMode)
|
||||||
|
{
|
||||||
|
switch (loopingMode)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case MenuOptionLoopingMode::AllMenus:
|
||||||
|
return g_GameFlow->GetString(STRING_MENU_OPT_LOOP_ALL_MENUS);
|
||||||
|
|
||||||
|
case MenuOptionLoopingMode::SaveLoadOnly:
|
||||||
|
return g_GameFlow->GetString(STRING_MENU_OPT_LOOP_SAVE_LOAD_ONLY);
|
||||||
|
|
||||||
|
case MenuOptionLoopingMode::Disabled:
|
||||||
|
return g_GameFlow->GetString(STRING_MENU_OPT_LOOP_DISABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// These bars are only used in menus.
|
// These bars are only used in menus.
|
||||||
TEN::Renderer::RendererHudBar* g_MusicVolumeBar = nullptr;
|
TEN::Renderer::RendererHudBar* g_MusicVolumeBar = nullptr;
|
||||||
|
@ -235,7 +250,7 @@ namespace TEN::Renderer
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_MONKEY_SWING_JUMP), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 4));
|
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_MONKEY_SWING_JUMP), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 4));
|
||||||
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableAutoMonkeySwingJump), PRINTSTRING_COLOR_WHITE, SF(titleOption == 4));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableAutoMonkeySwingJump), PRINTSTRING_COLOR_WHITE, SF(titleOption == 4));
|
||||||
GetNextLinePosition(&y);
|
GetNextLinePosition(&y);
|
||||||
|
|
||||||
// Auto targeting
|
// Auto targeting
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_TARGETING), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 5));
|
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_TARGETING), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 5));
|
||||||
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableAutoTargeting), PRINTSTRING_COLOR_WHITE, SF(titleOption == 5));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableAutoTargeting), PRINTSTRING_COLOR_WHITE, SF(titleOption == 5));
|
||||||
|
@ -245,7 +260,7 @@ namespace TEN::Renderer
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_TARGET_HIGHLIGHTER), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 6));
|
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_TARGET_HIGHLIGHTER), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 6));
|
||||||
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableTargetHighlighter), PRINTSTRING_COLOR_WHITE, SF(titleOption == 6));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableTargetHighlighter), PRINTSTRING_COLOR_WHITE, SF(titleOption == 6));
|
||||||
GetNextLinePosition(&y);
|
GetNextLinePosition(&y);
|
||||||
|
|
||||||
// Vibration
|
// Vibration
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 7));
|
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 7));
|
||||||
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(titleOption == 7));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(titleOption == 7));
|
||||||
|
@ -261,9 +276,9 @@ namespace TEN::Renderer
|
||||||
AddString(MenuRightSideEntry, y, std::to_string(g_Gui.GetCurrentSettings().Configuration.MouseSensitivity).c_str(), PRINTSTRING_COLOR_WHITE, SF(titleOption == 9));
|
AddString(MenuRightSideEntry, y, std::to_string(g_Gui.GetCurrentSettings().Configuration.MouseSensitivity).c_str(), PRINTSTRING_COLOR_WHITE, SF(titleOption == 9));
|
||||||
GetNextLinePosition(&y);
|
GetNextLinePosition(&y);
|
||||||
|
|
||||||
// Mouse smoothing
|
// Menu option looping
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_MOUSE_SMOOTHING), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 10));
|
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_MENU_OPT_LOOP), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 10));
|
||||||
AddString(MenuRightSideEntry, y, std::to_string(g_Gui.GetCurrentSettings().Configuration.MouseSmoothing).c_str(), PRINTSTRING_COLOR_WHITE, SF(titleOption == 10));
|
AddString(MenuRightSideEntry, y, Str_MenuOptionLoopingMode(g_Gui.GetCurrentSettings().Configuration.MenuOptionLoopingMode), PRINTSTRING_COLOR_WHITE, SF(titleOption == 10));
|
||||||
GetNextBlockPosition(&y);
|
GetNextBlockPosition(&y);
|
||||||
|
|
||||||
// Apply
|
// Apply
|
||||||
|
@ -493,6 +508,14 @@ namespace TEN::Renderer
|
||||||
GetNextLinePosition(&y);
|
GetNextLinePosition(&y);
|
||||||
selectedOption++;
|
selectedOption++;
|
||||||
|
|
||||||
|
// Home Level
|
||||||
|
if (g_GameFlow->IsHomeLevelEnabled())
|
||||||
|
{
|
||||||
|
AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_HOME_LEVEL), PRINTSTRING_COLOR_WHITE, SF_Center(titleOption == selectedOption));
|
||||||
|
GetNextLinePosition(&y);
|
||||||
|
selectedOption++;
|
||||||
|
}
|
||||||
|
|
||||||
// Load game
|
// Load game
|
||||||
if (g_GameFlow->IsLoadSaveEnabled())
|
if (g_GameFlow->IsLoadSaveEnabled())
|
||||||
{
|
{
|
||||||
|
@ -523,13 +546,15 @@ namespace TEN::Renderer
|
||||||
AddString(MenuCenterEntry, 26, g_GameFlow->GetString(STRING_SELECT_LEVEL), PRINTSTRING_COLOR_ORANGE, SF_Center());
|
AddString(MenuCenterEntry, 26, g_GameFlow->GetString(STRING_SELECT_LEVEL), PRINTSTRING_COLOR_ORANGE, SF_Center());
|
||||||
GetNextBlockPosition(&y);
|
GetNextBlockPosition(&y);
|
||||||
|
|
||||||
// Level listing (starts with 1 because 0 is always title)
|
// Level 0 is always Title Level and level 1 might be Home Level.
|
||||||
for (int i = 1; i < g_GameFlow->GetNumLevels(); i++, selectedOption++)
|
for (int i = (g_GameFlow->IsHomeLevelEnabled() ? 2 : 1); i < g_GameFlow->GetNumLevels(); i++, selectedOption++)
|
||||||
{
|
{
|
||||||
AddString(MenuCenterEntry, y, g_GameFlow->GetString(g_GameFlow->GetLevel(i)->NameStringKey.c_str()),
|
AddString(
|
||||||
|
MenuCenterEntry, y, g_GameFlow->GetString(g_GameFlow->GetLevel(i)->NameStringKey.c_str()),
|
||||||
PRINTSTRING_COLOR_WHITE, SF_Center(titleOption == selectedOption));
|
PRINTSTRING_COLOR_WHITE, SF_Center(titleOption == selectedOption));
|
||||||
GetNextNarrowLinePosition(&y);
|
GetNextNarrowLinePosition(&y);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Menu::Options:
|
case Menu::Options:
|
||||||
|
@ -605,7 +630,7 @@ namespace TEN::Renderer
|
||||||
char stringBuffer[255];
|
char stringBuffer[255];
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
AddString(MenuCenterEntry, MenuVerticalNarrowLineSpacing, Str_LoadSave(g_Gui.GetInventoryMode() == InventoryMode::Save),
|
AddString(MenuCenterEntry, MenuVerticalNarrowLineSpacing, Str_LoadSave(g_Gui.GetInventoryMode() == InventoryMode::Save),
|
||||||
PRINTSTRING_COLOR_ORANGE, SF_Center());
|
PRINTSTRING_COLOR_ORANGE, SF_Center());
|
||||||
GetNextBlockPosition(&y);
|
GetNextBlockPosition(&y);
|
||||||
|
|
||||||
|
@ -798,7 +823,7 @@ namespace TEN::Renderer
|
||||||
{
|
{
|
||||||
if (meshBits && !(meshBits & (1 << n)))
|
if (meshBits && !(meshBits & (1 << n)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto* mesh = (*moveableObject).ObjectMeshes[n];
|
auto* mesh = (*moveableObject).ObjectMeshes[n];
|
||||||
|
|
||||||
// HACK: Rotate compass needle.
|
// HACK: Rotate compass needle.
|
||||||
|
@ -823,7 +848,7 @@ namespace TEN::Renderer
|
||||||
_cbItem.UpdateData(_stItem, _context.Get());
|
_cbItem.UpdateData(_stItem, _context.Get());
|
||||||
BindConstantBufferVS(ConstantBufferRegister::Item, _cbItem.get());
|
BindConstantBufferVS(ConstantBufferRegister::Item, _cbItem.get());
|
||||||
BindConstantBufferPS(ConstantBufferRegister::Item, _cbItem.get());
|
BindConstantBufferPS(ConstantBufferRegister::Item, _cbItem.get());
|
||||||
|
|
||||||
for (const auto& bucket : mesh->Buckets)
|
for (const auto& bucket : mesh->Buckets)
|
||||||
{
|
{
|
||||||
if (bucket.NumVertices == 0)
|
if (bucket.NumVertices == 0)
|
||||||
|
@ -835,10 +860,10 @@ namespace TEN::Renderer
|
||||||
|
|
||||||
BindTexture(TextureRegister::ColorMap, &std::get<0>(_moveablesTextures[bucket.Texture]), SamplerStateRegister::AnisotropicClamp);
|
BindTexture(TextureRegister::ColorMap, &std::get<0>(_moveablesTextures[bucket.Texture]), SamplerStateRegister::AnisotropicClamp);
|
||||||
BindTexture(TextureRegister::NormalMap, &std::get<1>(_moveablesTextures[bucket.Texture]), SamplerStateRegister::AnisotropicClamp);
|
BindTexture(TextureRegister::NormalMap, &std::get<1>(_moveablesTextures[bucket.Texture]), SamplerStateRegister::AnisotropicClamp);
|
||||||
|
|
||||||
if (bucket.BlendMode != BlendMode::Opaque)
|
if (bucket.BlendMode != BlendMode::Opaque)
|
||||||
Renderer::SetBlendMode(bucket.BlendMode, true);
|
Renderer::SetBlendMode(bucket.BlendMode, true);
|
||||||
|
|
||||||
SetAlphaTest(
|
SetAlphaTest(
|
||||||
(bucket.BlendMode == BlendMode::AlphaTest) ? AlphaTestMode::GreatherThan : AlphaTestMode::None,
|
(bucket.BlendMode == BlendMode::AlphaTest) ? AlphaTestMode::GreatherThan : AlphaTestMode::None,
|
||||||
ALPHA_TEST_THRESHOLD);
|
ALPHA_TEST_THRESHOLD);
|
||||||
|
@ -1104,9 +1129,9 @@ namespace TEN::Renderer
|
||||||
{
|
{
|
||||||
_context->ClearDepthStencilView(_backBuffer.DepthStencilView.Get(), D3D11_CLEAR_STENCIL | D3D11_CLEAR_DEPTH, 1.0f, 0);
|
_context->ClearDepthStencilView(_backBuffer.DepthStencilView.Get(), D3D11_CLEAR_STENCIL | D3D11_CLEAR_DEPTH, 1.0f, 0);
|
||||||
_context->ClearRenderTargetView(_backBuffer.RenderTargetView.Get(), Colors::Black);
|
_context->ClearRenderTargetView(_backBuffer.RenderTargetView.Get(), Colors::Black);
|
||||||
|
|
||||||
RenderInventoryScene(&_backBuffer, &_dumpScreenRenderTarget, 0.5f);
|
RenderInventoryScene(&_backBuffer, &_dumpScreenRenderTarget, 0.5f);
|
||||||
|
|
||||||
_swapChain->Present(0, 0);
|
_swapChain->Present(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1171,14 +1196,14 @@ namespace TEN::Renderer
|
||||||
PrintDebugMessage(" CheckPortal() calls: %d", _numCheckPortalCalls);
|
PrintDebugMessage(" CheckPortal() calls: %d", _numCheckPortalCalls);
|
||||||
PrintDebugMessage(" GetVisibleRooms() calls: %d", _numGetVisibleRoomsCalls);
|
PrintDebugMessage(" GetVisibleRooms() calls: %d", _numGetVisibleRoomsCalls);
|
||||||
PrintDebugMessage(" Dot products: %d", _numDotProducts);
|
PrintDebugMessage(" Dot products: %d", _numDotProducts);
|
||||||
|
|
||||||
_spriteBatch->Begin(SpriteSortMode_Deferred, _renderStates->Opaque());
|
_spriteBatch->Begin(SpriteSortMode_Deferred, _renderStates->Opaque());
|
||||||
|
|
||||||
rect.left = _screenWidth - thumbWidth;
|
rect.left = _screenWidth - thumbWidth;
|
||||||
rect.top = thumbY;
|
rect.top = thumbY;
|
||||||
rect.right = rect.left+ thumbWidth;
|
rect.right = rect.left+ thumbWidth;
|
||||||
rect.bottom = rect.top+thumbWidth / aspectRatio;
|
rect.bottom = rect.top+thumbWidth / aspectRatio;
|
||||||
|
|
||||||
_spriteBatch->Draw(_normalsRenderTarget.ShaderResourceView.Get(), rect);
|
_spriteBatch->Draw(_normalsRenderTarget.ShaderResourceView.Get(), rect);
|
||||||
thumbY += thumbWidth / aspectRatio;
|
thumbY += thumbWidth / aspectRatio;
|
||||||
|
|
||||||
|
@ -1194,7 +1219,7 @@ namespace TEN::Renderer
|
||||||
|
|
||||||
_spriteBatch->Draw(_SSAOBlurredRenderTarget.ShaderResourceView.Get(), rect);
|
_spriteBatch->Draw(_SSAOBlurredRenderTarget.ShaderResourceView.Get(), rect);
|
||||||
thumbY += thumbWidth / aspectRatio;
|
thumbY += thumbWidth / aspectRatio;
|
||||||
|
|
||||||
if (g_Configuration.AntialiasingMode > AntialiasingMode::Low)
|
if (g_Configuration.AntialiasingMode > AntialiasingMode::Low)
|
||||||
{
|
{
|
||||||
rect.left = _screenWidth - thumbWidth;
|
rect.left = _screenWidth - thumbWidth;
|
||||||
|
@ -1225,8 +1250,8 @@ namespace TEN::Renderer
|
||||||
PrintDebugMessage("RoomNumber: %d", LaraItem->RoomNumber);
|
PrintDebugMessage("RoomNumber: %d", LaraItem->RoomNumber);
|
||||||
PrintDebugMessage("PathfindingBoxID: %d", LaraItem->BoxNumber);
|
PrintDebugMessage("PathfindingBoxID: %d", LaraItem->BoxNumber);
|
||||||
PrintDebugMessage("WaterSurfaceDist: %d", Lara.Context.WaterSurfaceDist);
|
PrintDebugMessage("WaterSurfaceDist: %d", Lara.Context.WaterSurfaceDist);
|
||||||
PrintDebugMessage("Room Position: %d, %d, %d, %d", room.x, room.z, room.x + BLOCK(room.xSize), room.z + BLOCK(room.zSize));
|
PrintDebugMessage("Room Position: %d, %d, %d, %d", room.Position.z, room.Position.z, room.Position.z + BLOCK(room.XSize), room.Position.z + BLOCK(room.ZSize));
|
||||||
PrintDebugMessage("Room.y, minFloor, maxCeiling: %d, %d, %d ", room.y, room.minfloor, room.maxceiling);
|
PrintDebugMessage("Room.y, minFloor, maxCeiling: %d, %d, %d ", room.Position.y, room.BottomHeight, room.TopHeight);
|
||||||
PrintDebugMessage("Camera Position: %d, %d, %d", Camera.pos.x, Camera.pos.y, Camera.pos.z);
|
PrintDebugMessage("Camera Position: %d, %d, %d", Camera.pos.x, Camera.pos.y, Camera.pos.z);
|
||||||
PrintDebugMessage("Camera LookAt: %d, %d, %d", Camera.target.x, Camera.target.y, Camera.target.z);
|
PrintDebugMessage("Camera LookAt: %d, %d, %d", Camera.target.x, Camera.target.y, Camera.target.z);
|
||||||
PrintDebugMessage("Camera RoomNumber: %d", Camera.pos.RoomNumber);
|
PrintDebugMessage("Camera RoomNumber: %d", Camera.pos.RoomNumber);
|
||||||
|
@ -1265,7 +1290,7 @@ namespace TEN::Renderer
|
||||||
if (action.IsReleased())
|
if (action.IsReleased())
|
||||||
releasedActions.Set((int)action.GetID());
|
releasedActions.Set((int)action.GetID());
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintDebugMessage("INPUT STATS");
|
PrintDebugMessage("INPUT STATS");
|
||||||
PrintDebugMessage(("Clicked actions: " + clickedActions.ToString()).c_str());
|
PrintDebugMessage(("Clicked actions: " + clickedActions.ToString()).c_str());
|
||||||
PrintDebugMessage(("Held actions: " + heldActions.ToString()).c_str());
|
PrintDebugMessage(("Held actions: " + heldActions.ToString()).c_str());
|
||||||
|
@ -1288,12 +1313,12 @@ namespace TEN::Renderer
|
||||||
PrintDebugMessage("Front left ceil: %d", LaraCollision.FrontLeft.Ceiling);
|
PrintDebugMessage("Front left ceil: %d", LaraCollision.FrontLeft.Ceiling);
|
||||||
PrintDebugMessage("Front right ceil: %d", LaraCollision.FrontRight.Ceiling);
|
PrintDebugMessage("Front right ceil: %d", LaraCollision.FrontRight.Ceiling);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RendererDebugPage::PathfindingStats:
|
case RendererDebugPage::PathfindingStats:
|
||||||
PrintDebugMessage("PATHFINDING STATS");
|
PrintDebugMessage("PATHFINDING STATS");
|
||||||
PrintDebugMessage("BoxNumber: %d", LaraItem->BoxNumber);
|
PrintDebugMessage("BoxNumber: %d", LaraItem->BoxNumber);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RendererDebugPage::WireframeMode:
|
case RendererDebugPage::WireframeMode:
|
||||||
PrintDebugMessage("WIREFRAME MODE");
|
PrintDebugMessage("WIREFRAME MODE");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
virtual bool IsMassPickupEnabled() const = 0;
|
virtual bool IsMassPickupEnabled() const = 0;
|
||||||
virtual bool IsPointFilterEnabled() const = 0;
|
virtual bool IsPointFilterEnabled() const = 0;
|
||||||
virtual bool IsLaraInTitleEnabled() const = 0;
|
virtual bool IsLaraInTitleEnabled() const = 0;
|
||||||
|
virtual bool IsHomeLevelEnabled() const = 0;
|
||||||
virtual bool IsLoadSaveEnabled() const = 0;
|
virtual bool IsLoadSaveEnabled() const = 0;
|
||||||
virtual bool HasCrawlExtended() const = 0;
|
virtual bool HasCrawlExtended() const = 0;
|
||||||
virtual bool HasCrouchRoll() const = 0;
|
virtual bool HasCrouchRoll() const = 0;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// std::string ID macros
|
// std::string ID macros
|
||||||
#define STRING_WINDOW_TITLE "window_title"
|
#define STRING_WINDOW_TITLE "window_title"
|
||||||
#define STRING_PASSPORT "passport"
|
#define STRING_PASSPORT "passport"
|
||||||
#define STRING_LARA_HOME "lara_home"
|
#define STRING_HOME_LEVEL "home_level"
|
||||||
#define STRING_CONTROLS "controls"
|
#define STRING_CONTROLS "controls"
|
||||||
#define STRING_DISPLAY "display"
|
#define STRING_DISPLAY "display"
|
||||||
#define STRING_OTHER_SETTINGS "other_settings"
|
#define STRING_OTHER_SETTINGS "other_settings"
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
#define STRING_LOAD_GAME "load_game"
|
#define STRING_LOAD_GAME "load_game"
|
||||||
#define STRING_SAVE_GAME "save_game"
|
#define STRING_SAVE_GAME "save_game"
|
||||||
#define STRING_EXIT_GAME "exit_game"
|
#define STRING_EXIT_GAME "exit_game"
|
||||||
#define STRING_EXIT_TO_TITLE "exit_to_title"
|
#define STRING_EXIT_TO_TITLE "exit_to_title"
|
||||||
#define STRING_OPTIONS "options"
|
#define STRING_OPTIONS "options"
|
||||||
#define STRING_UZIS "uzis"
|
#define STRING_UZIS "uzis"
|
||||||
#define STRING_PISTOLS "pistols"
|
#define STRING_PISTOLS "pistols"
|
||||||
|
@ -86,8 +86,11 @@
|
||||||
#define STRING_RUMBLE "rumble"
|
#define STRING_RUMBLE "rumble"
|
||||||
#define STRING_THUMBSTICK_CAMERA "thumbstick_camera"
|
#define STRING_THUMBSTICK_CAMERA "thumbstick_camera"
|
||||||
#define STRING_SUBTITLES "subtitles"
|
#define STRING_SUBTITLES "subtitles"
|
||||||
|
#define STRING_MENU_OPT_LOOP "menu_option_looping"
|
||||||
|
#define STRING_MENU_OPT_LOOP_ALL_MENUS "menu_option_looping_all_menus"
|
||||||
|
#define STRING_MENU_OPT_LOOP_DISABLED "menu_option_looping_disabled"
|
||||||
|
#define STRING_MENU_OPT_LOOP_SAVE_LOAD_ONLY "menu_option_looping_save_load_only"
|
||||||
#define STRING_MOUSE_SENSITIVITY "mouse_sensitivity"
|
#define STRING_MOUSE_SENSITIVITY "mouse_sensitivity"
|
||||||
#define STRING_MOUSE_SMOOTHING "mouse_smoothing"
|
|
||||||
#define STRING_ACTIONS_FORWARD "actions_forward"
|
#define STRING_ACTIONS_FORWARD "actions_forward"
|
||||||
#define STRING_ACTIONS_BACKWARD "actions_backward"
|
#define STRING_ACTIONS_BACKWARD "actions_backward"
|
||||||
#define STRING_ACTIONS_LEFT "actions_left"
|
#define STRING_ACTIONS_LEFT "actions_left"
|
||||||
|
|
|
@ -223,6 +223,7 @@ static constexpr char ScriptReserved_EnableFlyCheat[] = "EnableFlyCheat";
|
||||||
static constexpr char ScriptReserved_EnableMassPickup[] = "EnableMassPickup";
|
static constexpr char ScriptReserved_EnableMassPickup[] = "EnableMassPickup";
|
||||||
static constexpr char ScriptReserved_EnableLaraInTitle[] = "EnableLaraInTitle";
|
static constexpr char ScriptReserved_EnableLaraInTitle[] = "EnableLaraInTitle";
|
||||||
static constexpr char ScriptReserved_EnableLevelSelect[] = "EnableLevelSelect";
|
static constexpr char ScriptReserved_EnableLevelSelect[] = "EnableLevelSelect";
|
||||||
|
static constexpr char ScriptReserved_EnableHomeLevel[] = "EnableHomeLevel";
|
||||||
static constexpr char ScriptReserved_EnableLoadSave[] = "EnableLoadSave";
|
static constexpr char ScriptReserved_EnableLoadSave[] = "EnableLoadSave";
|
||||||
static constexpr char ScriptReserved_EnablePointFilter[] = "EnablePointFilter";
|
static constexpr char ScriptReserved_EnablePointFilter[] = "EnablePointFilter";
|
||||||
|
|
||||||
|
|
|
@ -77,21 +77,23 @@ Must be true or false
|
||||||
*/
|
*/
|
||||||
tableFlow.set_function(ScriptReserved_EnableLevelSelect, &FlowHandler::EnableLevelSelect, this);
|
tableFlow.set_function(ScriptReserved_EnableLevelSelect, &FlowHandler::EnableLevelSelect, this);
|
||||||
|
|
||||||
/*** Enable or disable saving and loading of savegames.
|
/// Enable or disable Home Level entry in the main menu.
|
||||||
@function EnableLoadSave
|
// @function EnableHomeLevel()
|
||||||
@tparam bool enabled true or false.
|
// @tparam bool enabled True or false.
|
||||||
*/
|
tableFlow.set_function(ScriptReserved_EnableHomeLevel, &FlowHandler::EnableHomeLevel, this);
|
||||||
|
|
||||||
|
/// Enable or disable saving and loading of savegames.
|
||||||
|
// @function EnableLoadSave()
|
||||||
|
// @tparam bool enabled True or false.
|
||||||
tableFlow.set_function(ScriptReserved_EnableLoadSave, &FlowHandler::EnableLoadSave, this);
|
tableFlow.set_function(ScriptReserved_EnableLoadSave, &FlowHandler::EnableLoadSave, this);
|
||||||
|
|
||||||
/*** gameflow.lua or level scripts.
|
/*** gameflow.lua or level scripts.
|
||||||
@section FlowluaOrScripts
|
@section FlowluaOrScripts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*** Enable or disable DOZY mode (fly cheat).
|
/// Enable or disable the fly cheat.
|
||||||
Must be true or false
|
// @function EnableFlyCheat()
|
||||||
@function EnableFlyCheat
|
// @tparam bool enabled True or false.
|
||||||
@tparam bool enabled true or false
|
|
||||||
*/
|
|
||||||
tableFlow.set_function(ScriptReserved_EnableFlyCheat, &FlowHandler::EnableFlyCheat, this);
|
tableFlow.set_function(ScriptReserved_EnableFlyCheat, &FlowHandler::EnableFlyCheat, this);
|
||||||
|
|
||||||
/*** Enable or disable point texture filter.
|
/*** Enable or disable point texture filter.
|
||||||
|
@ -537,9 +539,9 @@ bool FlowHandler::IsFlyCheatEnabled() const
|
||||||
return FlyCheat;
|
return FlyCheat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::EnableFlyCheat(bool flyCheat)
|
void FlowHandler::EnableFlyCheat(bool enable)
|
||||||
{
|
{
|
||||||
FlyCheat = flyCheat;
|
FlyCheat = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlowHandler::IsPointFilterEnabled() const
|
bool FlowHandler::IsPointFilterEnabled() const
|
||||||
|
@ -547,9 +549,9 @@ bool FlowHandler::IsPointFilterEnabled() const
|
||||||
return PointFilter;
|
return PointFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::EnablePointFilter(bool pointFilter)
|
void FlowHandler::EnablePointFilter(bool enable)
|
||||||
{
|
{
|
||||||
PointFilter = pointFilter;
|
PointFilter = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlowHandler::IsMassPickupEnabled() const
|
bool FlowHandler::IsMassPickupEnabled() const
|
||||||
|
@ -557,9 +559,9 @@ bool FlowHandler::IsMassPickupEnabled() const
|
||||||
return MassPickup;
|
return MassPickup;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::EnableMassPickup(bool massPickup)
|
void FlowHandler::EnableMassPickup(bool enable)
|
||||||
{
|
{
|
||||||
MassPickup = massPickup;
|
MassPickup = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlowHandler::IsLaraInTitleEnabled() const
|
bool FlowHandler::IsLaraInTitleEnabled() const
|
||||||
|
@ -567,14 +569,24 @@ bool FlowHandler::IsLaraInTitleEnabled() const
|
||||||
return LaraInTitle;
|
return LaraInTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::EnableLaraInTitle(bool laraInTitle)
|
void FlowHandler::EnableLaraInTitle(bool enable)
|
||||||
{
|
{
|
||||||
LaraInTitle = laraInTitle;
|
LaraInTitle = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::EnableLevelSelect(bool levelSelect)
|
void FlowHandler::EnableLevelSelect(bool enable)
|
||||||
{
|
{
|
||||||
LevelSelect = levelSelect;
|
LevelSelect = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlowHandler::IsHomeLevelEnabled() const
|
||||||
|
{
|
||||||
|
return HomeLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowHandler::EnableHomeLevel(bool enable)
|
||||||
|
{
|
||||||
|
HomeLevel = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlowHandler::IsLoadSaveEnabled() const
|
bool FlowHandler::IsLoadSaveEnabled() const
|
||||||
|
@ -582,9 +594,9 @@ bool FlowHandler::IsLoadSaveEnabled() const
|
||||||
return LoadSave;
|
return LoadSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::EnableLoadSave(bool loadSave)
|
void FlowHandler::EnableLoadSave(bool enable)
|
||||||
{
|
{
|
||||||
LoadSave = loadSave;
|
LoadSave = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowHandler::PrepareInventoryObjects()
|
void FlowHandler::PrepareInventoryObjects()
|
||||||
|
@ -674,12 +686,20 @@ bool FlowHandler::DoFlow()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GameStatus::NewGame:
|
case GameStatus::NewGame:
|
||||||
CurrentLevel = (SelectedLevelForNewGame != 0 ? SelectedLevelForNewGame : 1);
|
// NOTE: 0 reserved for title level and 1 reserved for home level.
|
||||||
|
CurrentLevel = (SelectedLevelForNewGame != 0) ? SelectedLevelForNewGame : (IsHomeLevelEnabled() ? 2 : 1);
|
||||||
|
|
||||||
RequiredStartPos = 0;
|
RequiredStartPos = 0;
|
||||||
SelectedLevelForNewGame = 0;
|
SelectedLevelForNewGame = 0;
|
||||||
InitializeGame = true;
|
InitializeGame = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GameStatus::HomeLevel:
|
||||||
|
CurrentLevel = 1;
|
||||||
|
RequiredStartPos = 0;
|
||||||
|
InitializeGame = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case GameStatus::LoadGame:
|
case GameStatus::LoadGame:
|
||||||
// Load header of savegame to get level to load.
|
// Load header of savegame to get level to load.
|
||||||
SaveGame::LoadHeader(SelectedSaveGame, &header);
|
SaveGame::LoadHeader(SelectedSaveGame, &header);
|
||||||
|
|
|
@ -30,10 +30,11 @@ public:
|
||||||
int FogOutDistance = 0;
|
int FogOutDistance = 0;
|
||||||
|
|
||||||
bool LevelSelect = true;
|
bool LevelSelect = true;
|
||||||
|
bool HomeLevel = false;
|
||||||
bool LoadSave = true;
|
bool LoadSave = true;
|
||||||
bool FlyCheat = true;
|
bool FlyCheat = true;
|
||||||
bool PointFilter = false;
|
bool PointFilter = false;
|
||||||
bool MassPickup = true;
|
bool MassPickup = true;
|
||||||
bool LaraInTitle = false;
|
bool LaraInTitle = false;
|
||||||
bool DebugMode = false;
|
bool DebugMode = false;
|
||||||
|
|
||||||
|
@ -74,17 +75,19 @@ public:
|
||||||
void SetTitleScreenImagePath(const std::string& path);
|
void SetTitleScreenImagePath(const std::string& path);
|
||||||
void SetTotalSecretCount(int secretsNumber);
|
void SetTotalSecretCount(int secretsNumber);
|
||||||
bool IsFlyCheatEnabled() const;
|
bool IsFlyCheatEnabled() const;
|
||||||
void EnableFlyCheat(bool flyCheat);
|
void EnableFlyCheat(bool enable);
|
||||||
bool IsPointFilterEnabled() const;
|
bool IsPointFilterEnabled() const;
|
||||||
void EnablePointFilter(bool pointFilter);
|
void EnablePointFilter(bool enable);
|
||||||
bool IsMassPickupEnabled() const;
|
bool IsMassPickupEnabled() const;
|
||||||
void EnableMassPickup(bool massPickup);
|
void EnableMassPickup(bool enable);
|
||||||
bool IsLaraInTitleEnabled() const;
|
bool IsLaraInTitleEnabled() const;
|
||||||
void EnableLaraInTitle(bool laraInTitle);
|
void EnableLaraInTitle(bool enable);
|
||||||
bool IsLevelSelectEnabled() const;
|
bool IsLevelSelectEnabled() const;
|
||||||
void EnableLevelSelect(bool laraInTitle);
|
void EnableLevelSelect(bool enable);
|
||||||
|
bool IsHomeLevelEnabled() const;
|
||||||
|
void EnableHomeLevel(bool enable);
|
||||||
bool IsLoadSaveEnabled() const;
|
bool IsLoadSaveEnabled() const;
|
||||||
void EnableLoadSave(bool loadSave);
|
void EnableLoadSave(bool enable);
|
||||||
|
|
||||||
bool HasCrawlExtended() const override { return Anims.HasCrawlExtended; }
|
bool HasCrawlExtended() const override { return Anims.HasCrawlExtended; }
|
||||||
bool HasCrouchRoll() const override { return Anims.HasCrouchRoll; }
|
bool HasCrouchRoll() const override { return Anims.HasCrouchRoll; }
|
||||||
|
|
|
@ -239,7 +239,7 @@ The following constants are inside ObjID.
|
||||||
SKATEBOARD
|
SKATEBOARD
|
||||||
SKATEBOARD_KID
|
SKATEBOARD_KID
|
||||||
WINSTON
|
WINSTON
|
||||||
ARMY_WINSTON
|
SEAL_MUTANT
|
||||||
SPRINGBOARD
|
SPRINGBOARD
|
||||||
ROLLING_SPINDLE
|
ROLLING_SPINDLE
|
||||||
DISK_SHOOTER
|
DISK_SHOOTER
|
||||||
|
@ -825,6 +825,7 @@ The following constants are inside ObjID.
|
||||||
MESHSWAP_ROMAN_GOD2
|
MESHSWAP_ROMAN_GOD2
|
||||||
MESHSWAP_MONKEY_MEDIPACK
|
MESHSWAP_MONKEY_MEDIPACK
|
||||||
MESHSWAP_MONKEY_KEY
|
MESHSWAP_MONKEY_KEY
|
||||||
|
MESHSWAP_WINSTON_ARMY_OUTFIT
|
||||||
ANIMATING1
|
ANIMATING1
|
||||||
ANIMATING2
|
ANIMATING2
|
||||||
ANIMATING3
|
ANIMATING3
|
||||||
|
@ -1415,6 +1416,7 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> kObjIDs {
|
||||||
{ "SKATEBOARD", ID_SKATEBOARD },
|
{ "SKATEBOARD", ID_SKATEBOARD },
|
||||||
{ "SKATEBOARD_KID", ID_SKATEBOARD_KID },
|
{ "SKATEBOARD_KID", ID_SKATEBOARD_KID },
|
||||||
{ "WINSTON", ID_WINSTON },
|
{ "WINSTON", ID_WINSTON },
|
||||||
|
{ "SEAL_MUTANT", ID_SEAL_MUTANT },
|
||||||
{ "SPRINGBOARD", ID_SPRINGBOARD },
|
{ "SPRINGBOARD", ID_SPRINGBOARD },
|
||||||
{ "ROLLING_SPINDLE", ID_ROLLING_SPINDLE },
|
{ "ROLLING_SPINDLE", ID_ROLLING_SPINDLE },
|
||||||
{ "DISK_SHOOTER", ID_DISK_SHOOTER },
|
{ "DISK_SHOOTER", ID_DISK_SHOOTER },
|
||||||
|
|
|
@ -111,7 +111,7 @@ private:
|
||||||
|
|
||||||
auto room = std::get<std::reference_wrapper<ROOM_INFO>>(val).get();
|
auto room = std::get<std::reference_wrapper<ROOM_INFO>>(val).get();
|
||||||
|
|
||||||
if (std::any_of(room.tags.begin(), room.tags.end(),
|
if (std::any_of(room.Tags.begin(), room.Tags.end(),
|
||||||
[&tag](const std::string& value) { return value == tag; }))
|
[&tag](const std::string& value) { return value == tag; }))
|
||||||
{
|
{
|
||||||
rooms.push_back(GetByName<Room, ScriptReserved_Room>(key));
|
rooms.push_back(GetByName<Room, ScriptReserved_Room>(key));
|
||||||
|
|
|
@ -104,7 +104,7 @@ void Room::SetReverbType(ReverbType reverb)
|
||||||
|
|
||||||
std::string Room::GetName() const
|
std::string Room::GetName() const
|
||||||
{
|
{
|
||||||
return m_room.name;
|
return m_room.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Room::SetName(const std::string& name)
|
void Room::SetName(const std::string& name)
|
||||||
|
@ -115,8 +115,8 @@ void Room::SetName(const std::string& name)
|
||||||
// Remove old name if it already exists.
|
// Remove old name if it already exists.
|
||||||
if (s_callbackSetName(name, m_room))
|
if (s_callbackSetName(name, m_room))
|
||||||
{
|
{
|
||||||
s_callbackRemoveName(m_room.name);
|
s_callbackRemoveName(m_room.Name);
|
||||||
m_room.name = name;
|
m_room.Name = name;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -144,10 +144,10 @@ void Room::SetFlag(RoomEnvFlags flag, bool value)
|
||||||
|
|
||||||
bool Room::IsTagPresent(const std::string& tag) const
|
bool Room::IsTagPresent(const std::string& tag) const
|
||||||
{
|
{
|
||||||
if (m_room.tags.empty())
|
if (m_room.Tags.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return std::any_of(
|
return std::any_of(
|
||||||
m_room.tags.begin(), m_room.tags.end(),
|
m_room.Tags.begin(), m_room.Tags.end(),
|
||||||
[&tag](const std::string& value) { return (value == tag); });
|
[&tag](const std::string& value) { return (value == tag); });
|
||||||
}
|
}
|
||||||
|
|
|
@ -463,10 +463,9 @@ namespace TEN::Input
|
||||||
(((rawAxes.x - -DISPLAY_SPACE_RES.x) * 2) / (DISPLAY_SPACE_RES.x - -DISPLAY_SPACE_RES.x)) - 1.0f,
|
(((rawAxes.x - -DISPLAY_SPACE_RES.x) * 2) / (DISPLAY_SPACE_RES.x - -DISPLAY_SPACE_RES.x)) - 1.0f,
|
||||||
(((rawAxes.y - -DISPLAY_SPACE_RES.y) * 2) / (DISPLAY_SPACE_RES.y - -DISPLAY_SPACE_RES.y)) - 1.0f);
|
(((rawAxes.y - -DISPLAY_SPACE_RES.y) * 2) / (DISPLAY_SPACE_RES.y - -DISPLAY_SPACE_RES.y)) - 1.0f);
|
||||||
|
|
||||||
// Apply sensitivity and smoothing.
|
// Apply sensitivity.
|
||||||
float sensitivity = (g_Configuration.MouseSensitivity * 0.1f) + 0.4f;
|
float sensitivity = (g_Configuration.MouseSensitivity * 0.1f) + 0.4f;
|
||||||
float smoothing = 1.0f - (g_Configuration.MouseSmoothing * 0.1f);
|
normAxes *= sensitivity;
|
||||||
normAxes *= sensitivity * smoothing;
|
|
||||||
|
|
||||||
// Set mouse axis values.
|
// Set mouse axis values.
|
||||||
AxisMap[(int)InputAxis::Mouse] = normAxes;
|
AxisMap[(int)InputAxis::Mouse] = normAxes;
|
||||||
|
|
|
@ -257,7 +257,7 @@ bool SaveConfiguration()
|
||||||
|
|
||||||
// Set Input keys.
|
// Set Input keys.
|
||||||
if (SetDWORDRegKey(inputKey, REGKEY_MOUSE_SENSITIVITY, g_Configuration.MouseSensitivity) != ERROR_SUCCESS ||
|
if (SetDWORDRegKey(inputKey, REGKEY_MOUSE_SENSITIVITY, g_Configuration.MouseSensitivity) != ERROR_SUCCESS ||
|
||||||
SetDWORDRegKey(inputKey, REGKEY_MOUSE_SMOOTHING, g_Configuration.MouseSmoothing) != ERROR_SUCCESS)
|
SetDWORDRegKey(inputKey, REGKEY_ENABLE_MENU_OPTION_LOOPING, (int)g_Configuration.MenuOptionLoopingMode) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
RegCloseKey(rootKey);
|
RegCloseKey(rootKey);
|
||||||
RegCloseKey(graphicsKey);
|
RegCloseKey(graphicsKey);
|
||||||
|
@ -330,7 +330,7 @@ void InitDefaultConfiguration()
|
||||||
g_Configuration.EnableThumbstickCamera = false;
|
g_Configuration.EnableThumbstickCamera = false;
|
||||||
|
|
||||||
g_Configuration.MouseSensitivity = GameConfiguration::DEFAULT_MOUSE_SENSITIVITY;
|
g_Configuration.MouseSensitivity = GameConfiguration::DEFAULT_MOUSE_SENSITIVITY;
|
||||||
g_Configuration.MouseSmoothing = GameConfiguration::DEFAULT_MOUSE_SMOOTHING;
|
g_Configuration.MenuOptionLoopingMode = MenuOptionLoopingMode::SaveLoadOnly;
|
||||||
|
|
||||||
g_Configuration.SupportedScreenResolutions = GetAllSupportedScreenResolutions();
|
g_Configuration.SupportedScreenResolutions = GetAllSupportedScreenResolutions();
|
||||||
g_Configuration.AdapterName = g_Renderer.GetDefaultAdapterName();
|
g_Configuration.AdapterName = g_Renderer.GetDefaultAdapterName();
|
||||||
|
@ -444,14 +444,14 @@ bool LoadConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD mouseSensitivity = GameConfiguration::DEFAULT_MOUSE_SENSITIVITY;
|
DWORD mouseSensitivity = GameConfiguration::DEFAULT_MOUSE_SENSITIVITY;
|
||||||
DWORD mouseSmoothing = GameConfiguration::DEFAULT_MOUSE_SMOOTHING;
|
DWORD menuOptionLoopingMode = (DWORD)MenuOptionLoopingMode::SaveLoadOnly;
|
||||||
|
|
||||||
// Load Input keys.
|
// Load Input keys.
|
||||||
HKEY inputKey = NULL;
|
HKEY inputKey = NULL;
|
||||||
if (RegOpenKeyExA(rootKey, REGKEY_INPUT, 0, KEY_READ, &inputKey) == ERROR_SUCCESS)
|
if (RegOpenKeyExA(rootKey, REGKEY_INPUT, 0, KEY_READ, &inputKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (GetDWORDRegKey(inputKey, REGKEY_MOUSE_SENSITIVITY, &mouseSensitivity, GameConfiguration::DEFAULT_MOUSE_SENSITIVITY) != ERROR_SUCCESS ||
|
if (GetDWORDRegKey(inputKey, REGKEY_MOUSE_SENSITIVITY, &mouseSensitivity, GameConfiguration::DEFAULT_MOUSE_SENSITIVITY) != ERROR_SUCCESS ||
|
||||||
GetDWORDRegKey(inputKey, REGKEY_MOUSE_SMOOTHING, &mouseSmoothing, GameConfiguration::DEFAULT_MOUSE_SMOOTHING) != ERROR_SUCCESS)
|
GetDWORDRegKey(inputKey, REGKEY_ENABLE_MENU_OPTION_LOOPING, &menuOptionLoopingMode, (DWORD)MenuOptionLoopingMode::SaveLoadOnly) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
RegCloseKey(rootKey);
|
RegCloseKey(rootKey);
|
||||||
RegCloseKey(graphicsKey);
|
RegCloseKey(graphicsKey);
|
||||||
|
@ -519,7 +519,7 @@ bool LoadConfiguration()
|
||||||
g_Configuration.EnableThumbstickCamera = enableThumbstickCamera;
|
g_Configuration.EnableThumbstickCamera = enableThumbstickCamera;
|
||||||
|
|
||||||
g_Configuration.MouseSensitivity = mouseSensitivity;
|
g_Configuration.MouseSensitivity = mouseSensitivity;
|
||||||
g_Configuration.MouseSmoothing = mouseSmoothing;
|
g_Configuration.MenuOptionLoopingMode = (MenuOptionLoopingMode)menuOptionLoopingMode;
|
||||||
|
|
||||||
// Set legacy variables.
|
// Set legacy variables.
|
||||||
SetVolumeTracks(musicVolume);
|
SetVolumeTracks(musicVolume);
|
||||||
|
@ -558,10 +558,10 @@ LONG GetDWORDRegKey(HKEY hKey, LPCSTR strValueName, DWORD* nValue, DWORD nDefaul
|
||||||
NULL,
|
NULL,
|
||||||
reinterpret_cast<LPBYTE>(&nResult),
|
reinterpret_cast<LPBYTE>(&nResult),
|
||||||
&dwBufferSize);
|
&dwBufferSize);
|
||||||
|
|
||||||
if (ERROR_SUCCESS == nError)
|
if (ERROR_SUCCESS == nError)
|
||||||
*nValue = nResult;
|
*nValue = nResult;
|
||||||
|
|
||||||
return nError;
|
return nError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,10 +570,10 @@ LONG GetBoolRegKey(HKEY hKey, LPCSTR strValueName, bool* bValue, bool bDefaultVa
|
||||||
DWORD nDefValue((bDefaultValue) ? 1 : 0);
|
DWORD nDefValue((bDefaultValue) ? 1 : 0);
|
||||||
DWORD nResult(nDefValue);
|
DWORD nResult(nDefValue);
|
||||||
LONG nError = GetDWORDRegKey(hKey, strValueName, &nResult, nDefValue);
|
LONG nError = GetDWORDRegKey(hKey, strValueName, &nResult, nDefValue);
|
||||||
|
|
||||||
if (ERROR_SUCCESS == nError)
|
if (ERROR_SUCCESS == nError)
|
||||||
*bValue = (nResult != 0);
|
*bValue = (nResult != 0);
|
||||||
|
|
||||||
return nError;
|
return nError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ using namespace TEN::Input;
|
||||||
using namespace TEN::Math;
|
using namespace TEN::Math;
|
||||||
|
|
||||||
// Directories
|
// Directories
|
||||||
|
|
||||||
constexpr auto REGKEY_ROOT = "Software\\TombEngine\\1.1.0";
|
constexpr auto REGKEY_ROOT = "Software\\TombEngine\\1.1.0";
|
||||||
constexpr auto REGKEY_GRAPHICS = "Graphics";
|
constexpr auto REGKEY_GRAPHICS = "Graphics";
|
||||||
constexpr auto REGKEY_SOUND = "Sound";
|
constexpr auto REGKEY_SOUND = "Sound";
|
||||||
|
@ -14,6 +15,7 @@ constexpr auto REGKEY_GAMEPLAY = "Gameplay";
|
||||||
constexpr auto REGKEY_INPUT = "Input";
|
constexpr auto REGKEY_INPUT = "Input";
|
||||||
|
|
||||||
// Graphics keys
|
// Graphics keys
|
||||||
|
|
||||||
constexpr auto REGKEY_SCREEN_WIDTH = "ScreenWidth";
|
constexpr auto REGKEY_SCREEN_WIDTH = "ScreenWidth";
|
||||||
constexpr auto REGKEY_SCREEN_HEIGHT = "ScreenHeight";
|
constexpr auto REGKEY_SCREEN_HEIGHT = "ScreenHeight";
|
||||||
constexpr auto REGKEY_ENABLE_WINDOWED_MODE = "EnableWindowedMode";
|
constexpr auto REGKEY_ENABLE_WINDOWED_MODE = "EnableWindowedMode";
|
||||||
|
@ -25,6 +27,7 @@ constexpr auto REGKEY_ANTIALIASING_MODE = "AntialiasingMode";
|
||||||
constexpr auto REGKEY_AMBIENT_OCCLUSION = "AmbientOcclusion";
|
constexpr auto REGKEY_AMBIENT_OCCLUSION = "AmbientOcclusion";
|
||||||
|
|
||||||
// Sound keys
|
// Sound keys
|
||||||
|
|
||||||
constexpr auto REGKEY_SOUND_DEVICE = "SoundDevice";
|
constexpr auto REGKEY_SOUND_DEVICE = "SoundDevice";
|
||||||
constexpr auto REGKEY_ENABLE_SOUND = "EnableSound";
|
constexpr auto REGKEY_ENABLE_SOUND = "EnableSound";
|
||||||
constexpr auto REGKEY_ENABLE_REVERB = "EnableReverb";
|
constexpr auto REGKEY_ENABLE_REVERB = "EnableReverb";
|
||||||
|
@ -32,6 +35,7 @@ constexpr auto REGKEY_MUSIC_VOLUME = "MusicVolume";
|
||||||
constexpr auto REGKEY_SFX_VOLUME = "SfxVolume";
|
constexpr auto REGKEY_SFX_VOLUME = "SfxVolume";
|
||||||
|
|
||||||
// Gameplay keys
|
// Gameplay keys
|
||||||
|
|
||||||
constexpr auto REGKEY_ENABLE_SUBTITLES = "EnableSubtitles";
|
constexpr auto REGKEY_ENABLE_SUBTITLES = "EnableSubtitles";
|
||||||
constexpr auto REGKEY_ENABLE_AUTO_MONKEY_JUMP = "EnableAutoMonkeySwingJump";
|
constexpr auto REGKEY_ENABLE_AUTO_MONKEY_JUMP = "EnableAutoMonkeySwingJump";
|
||||||
constexpr auto REGKEY_ENABLE_AUTO_TARGETING = "EnableAutoTargeting";
|
constexpr auto REGKEY_ENABLE_AUTO_TARGETING = "EnableAutoTargeting";
|
||||||
|
@ -40,17 +44,25 @@ constexpr auto REGKEY_ENABLE_RUMBLE = "EnableRumble";
|
||||||
constexpr auto REGKEY_ENABLE_THUMBSTICK_CAMERA = "EnableThumbstickCamera";
|
constexpr auto REGKEY_ENABLE_THUMBSTICK_CAMERA = "EnableThumbstickCamera";
|
||||||
|
|
||||||
// Input keys
|
// Input keys
|
||||||
constexpr auto REGKEY_MOUSE_SENSITIVITY = "MouseSensitivity";
|
|
||||||
constexpr auto REGKEY_MOUSE_SMOOTHING = "MouseSmoothing";
|
|
||||||
|
|
||||||
struct GameConfiguration
|
constexpr auto REGKEY_MOUSE_SENSITIVITY = "MouseSensitivity";
|
||||||
|
constexpr auto REGKEY_ENABLE_MENU_OPTION_LOOPING = "EnableMenuOptionLooping";
|
||||||
|
|
||||||
|
enum class MenuOptionLoopingMode
|
||||||
|
{
|
||||||
|
AllMenus,
|
||||||
|
SaveLoadOnly,
|
||||||
|
Disabled
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GameConfiguration
|
||||||
{
|
{
|
||||||
static constexpr auto DEFAULT_SHADOW_MAP_SIZE = 1024;
|
static constexpr auto DEFAULT_SHADOW_MAP_SIZE = 1024;
|
||||||
static constexpr auto DEFAULT_SHADOW_BLOBS_MAX = 16;
|
static constexpr auto DEFAULT_SHADOW_BLOBS_MAX = 16;
|
||||||
static constexpr auto DEFAULT_MOUSE_SENSITIVITY = 6;
|
static constexpr auto DEFAULT_MOUSE_SENSITIVITY = 6;
|
||||||
static constexpr auto DEFAULT_MOUSE_SMOOTHING = 1;
|
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
|
|
||||||
int ScreenWidth = 0;
|
int ScreenWidth = 0;
|
||||||
int ScreenHeight = 0;
|
int ScreenHeight = 0;
|
||||||
bool EnableWindowedMode = false;
|
bool EnableWindowedMode = false;
|
||||||
|
@ -62,6 +74,7 @@ struct GameConfiguration
|
||||||
AntialiasingMode AntialiasingMode = AntialiasingMode::None;
|
AntialiasingMode AntialiasingMode = AntialiasingMode::None;
|
||||||
|
|
||||||
// Sound
|
// Sound
|
||||||
|
|
||||||
int SoundDevice = 0;
|
int SoundDevice = 0;
|
||||||
bool EnableSound = false;
|
bool EnableSound = false;
|
||||||
bool EnableReverb = false;
|
bool EnableReverb = false;
|
||||||
|
@ -69,17 +82,19 @@ struct GameConfiguration
|
||||||
int SfxVolume = 0;
|
int SfxVolume = 0;
|
||||||
|
|
||||||
// Gameplay
|
// Gameplay
|
||||||
bool EnableSubtitles = false;
|
|
||||||
bool EnableAutoMonkeySwingJump = false;
|
bool EnableSubtitles = false;
|
||||||
bool EnableAutoTargeting = false;
|
bool EnableAutoMonkeySwingJump = false;
|
||||||
bool EnableTargetHighlighter = false;
|
bool EnableAutoTargeting = false;
|
||||||
bool EnableRumble = false;
|
bool EnableTargetHighlighter = false;
|
||||||
bool EnableThumbstickCamera = false;
|
bool EnableRumble = false;
|
||||||
|
bool EnableThumbstickCamera = false;
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
int MouseSensitivity = DEFAULT_MOUSE_SENSITIVITY;
|
|
||||||
int MouseSmoothing = DEFAULT_MOUSE_SMOOTHING;
|
int MouseSensitivity = DEFAULT_MOUSE_SENSITIVITY;
|
||||||
std::vector<int> Bindings = {};
|
MenuOptionLoopingMode MenuOptionLoopingMode = MenuOptionLoopingMode::SaveLoadOnly;
|
||||||
|
std::vector<int> Bindings = {};
|
||||||
|
|
||||||
std::vector<Vector2i> SupportedScreenResolutions = {};
|
std::vector<Vector2i> SupportedScreenResolutions = {};
|
||||||
std::string AdapterName = {};
|
std::string AdapterName = {};
|
||||||
|
|
|
@ -687,17 +687,17 @@ void ReadRooms()
|
||||||
{
|
{
|
||||||
auto& room = g_Level.Rooms.emplace_back();
|
auto& room = g_Level.Rooms.emplace_back();
|
||||||
|
|
||||||
room.name = ReadString();
|
room.Name = ReadString();
|
||||||
|
|
||||||
int tagCount = ReadInt32();
|
int tagCount = ReadInt32();
|
||||||
for (int j = 0; j < tagCount; j++)
|
for (int j = 0; j < tagCount; j++)
|
||||||
room.tags.push_back(ReadString());
|
room.Tags.push_back(ReadString());
|
||||||
|
|
||||||
room.x = ReadInt32();
|
room.Position.x = ReadInt32();
|
||||||
room.y = 0;
|
room.Position.y = 0;
|
||||||
room.z = ReadInt32();
|
room.Position.z = ReadInt32();
|
||||||
room.minfloor = ReadInt32();
|
room.BottomHeight = ReadInt32();
|
||||||
room.maxceiling = ReadInt32();
|
room.TopHeight = ReadInt32();
|
||||||
|
|
||||||
int vertexCount = ReadInt32();
|
int vertexCount = ReadInt32();
|
||||||
|
|
||||||
|
@ -769,14 +769,14 @@ void ReadRooms()
|
||||||
for (int j = 0; j < portalCount; j++)
|
for (int j = 0; j < portalCount; j++)
|
||||||
LoadPortal(room);
|
LoadPortal(room);
|
||||||
|
|
||||||
room.zSize = ReadInt32();
|
room.ZSize = ReadInt32();
|
||||||
room.xSize = ReadInt32();
|
room.XSize = ReadInt32();
|
||||||
auto roomPos = Vector2i(room.x, room.z);
|
auto roomPos = Vector2i(room.Position.x, room.Position.z);
|
||||||
|
|
||||||
room.floor.reserve(room.zSize * room.xSize);
|
room.Sectors.reserve(room.XSize * room.ZSize);
|
||||||
for (int x = 0; x < room.xSize; x++)
|
for (int x = 0; x < room.XSize; x++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < room.zSize; z++)
|
for (int z = 0; z < room.ZSize; z++)
|
||||||
{
|
{
|
||||||
auto sector = FloorInfo{};
|
auto sector = FloorInfo{};
|
||||||
|
|
||||||
|
@ -820,17 +820,17 @@ void ReadRooms()
|
||||||
sector.Flags.MarkTriggererActive = 0; // TODO: Needs to be written to and read from savegames.
|
sector.Flags.MarkTriggererActive = 0; // TODO: Needs to be written to and read from savegames.
|
||||||
sector.Flags.MarkBeetle = ReadBool();
|
sector.Flags.MarkBeetle = ReadBool();
|
||||||
|
|
||||||
room.floor.push_back(sector);
|
room.Sectors.push_back(sector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
room.ambient = ReadVector3();
|
room.ambient = ReadVector3();
|
||||||
|
|
||||||
int numLights = ReadInt32();
|
int lightCount = ReadInt32();
|
||||||
room.lights.reserve(numLights);
|
room.lights.reserve(lightCount);
|
||||||
for (int j = 0; j < numLights; j++)
|
for (int j = 0; j < lightCount; j++)
|
||||||
{
|
{
|
||||||
ROOM_LIGHT light;
|
auto light = ROOM_LIGHT{};
|
||||||
|
|
||||||
light.x = ReadInt32();
|
light.x = ReadInt32();
|
||||||
light.y = ReadInt32();
|
light.y = ReadInt32();
|
||||||
|
@ -852,9 +852,9 @@ void ReadRooms()
|
||||||
room.lights.push_back(light);
|
room.lights.push_back(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
int numStatics = ReadInt32();
|
int staticCount = ReadInt32();
|
||||||
room.mesh.reserve(numStatics);
|
room.mesh.reserve(staticCount);
|
||||||
for (int j = 0; j < numStatics; j++)
|
for (int j = 0; j < staticCount; j++)
|
||||||
{
|
{
|
||||||
auto& mesh = room.mesh.emplace_back();
|
auto& mesh = room.mesh.emplace_back();
|
||||||
|
|
||||||
|
@ -875,21 +875,17 @@ void ReadRooms()
|
||||||
g_GameScriptEntities->AddName(mesh.Name, mesh);
|
g_GameScriptEntities->AddName(mesh.Name, mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
int numTriggerVolumes = ReadInt32();
|
int triggerVolumeCount = ReadInt32();
|
||||||
|
room.TriggerVolumes.reserve(triggerVolumeCount);
|
||||||
// Reserve in advance so the vector doesn't resize itself and leave anything
|
for (int j = 0; j < triggerVolumeCount; j++)
|
||||||
// in the script name-to-reference map obsolete.
|
|
||||||
room.triggerVolumes.reserve(numTriggerVolumes);
|
|
||||||
for (int j = 0; j < numTriggerVolumes; j++)
|
|
||||||
{
|
{
|
||||||
auto& volume = room.triggerVolumes.emplace_back();
|
auto& volume = room.TriggerVolumes.emplace_back();
|
||||||
|
|
||||||
volume.Type = (VolumeType)ReadInt32();
|
volume.Type = (VolumeType)ReadInt32();
|
||||||
|
|
||||||
// NOTE: Braces are necessary to ensure correct value init order.
|
auto pos = ReadVector3();
|
||||||
auto pos = Vector3{ ReadFloat(), ReadFloat(), ReadFloat() };
|
auto orient = ReadVector4();
|
||||||
auto orient = Quaternion{ ReadFloat(), ReadFloat(), ReadFloat(), ReadFloat() };
|
auto scale = ReadVector3();
|
||||||
auto scale = Vector3{ ReadFloat(), ReadFloat(), ReadFloat() };
|
|
||||||
|
|
||||||
volume.Enabled = ReadBool();
|
volume.Enabled = ReadBool();
|
||||||
volume.DetectInAdjacentRooms = ReadBool();
|
volume.DetectInAdjacentRooms = ReadBool();
|
||||||
|
@ -897,7 +893,7 @@ void ReadRooms()
|
||||||
volume.Name = ReadString();
|
volume.Name = ReadString();
|
||||||
volume.EventSetIndex = ReadInt32();
|
volume.EventSetIndex = ReadInt32();
|
||||||
|
|
||||||
volume.Box = BoundingOrientedBox(pos, scale, orient);
|
volume.Box = BoundingOrientedBox(pos, scale, orient);
|
||||||
volume.Sphere = BoundingSphere(pos, scale.x);
|
volume.Sphere = BoundingSphere(pos, scale.x);
|
||||||
|
|
||||||
volume.StateQueue.reserve(VOLUME_STATE_QUEUE_SIZE);
|
volume.StateQueue.reserve(VOLUME_STATE_QUEUE_SIZE);
|
||||||
|
@ -913,9 +909,9 @@ void ReadRooms()
|
||||||
|
|
||||||
room.itemNumber = NO_VALUE;
|
room.itemNumber = NO_VALUE;
|
||||||
room.fxNumber = NO_VALUE;
|
room.fxNumber = NO_VALUE;
|
||||||
room.index = i;
|
room.RoomNumber = i;
|
||||||
|
|
||||||
g_GameScriptEntities->AddName(room.name, room);
|
g_GameScriptEntities->AddName(room.Name, room);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1543,17 +1539,17 @@ void BuildOutsideRoomsTable()
|
||||||
{
|
{
|
||||||
auto* room = &g_Level.Rooms[i];
|
auto* room = &g_Level.Rooms[i];
|
||||||
|
|
||||||
int rx = (room->x / BLOCK(1));
|
int rx = (room->Position.x / BLOCK(1));
|
||||||
int rz = (room->z / BLOCK(1));
|
int rz = (room->Position.z / BLOCK(1));
|
||||||
|
|
||||||
for (int x = 0; x < OUTSIDE_SIZE; x++)
|
for (int x = 0; x < OUTSIDE_SIZE; x++)
|
||||||
{
|
{
|
||||||
if (x < (rx + 1) || x > (rx + room->xSize - 2))
|
if (x < (rx + 1) || x > (rx + room->XSize - 2))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int z = 0; z < OUTSIDE_SIZE; z++)
|
for (int z = 0; z < OUTSIDE_SIZE; z++)
|
||||||
{
|
{
|
||||||
if (z < (rz + 1) || z > (rz + room->zSize - 2))
|
if (z < (rz + 1) || z > (rz + room->ZSize - 2))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
OutsideRoomTable[x][z].push_back(i);
|
OutsideRoomTable[x][z].push_back(i);
|
||||||
|
|
|
@ -483,18 +483,18 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
||||||
<ClInclude Include="Objects\Generic\generic_objects.h" />
|
<ClInclude Include="Objects\Generic\generic_objects.h" />
|
||||||
<ClInclude Include="Objects\Generic\puzzles_keys.h" />
|
<ClInclude Include="Objects\Generic\puzzles_keys.h" />
|
||||||
<ClInclude Include="Objects\Sink.h" />
|
<ClInclude Include="Objects\Sink.h" />
|
||||||
|
<ClInclude Include="Objects\TR1\Entity\Centaur.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\Cowboy.h" />
|
<ClInclude Include="Objects\TR1\Entity\Cowboy.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\Kold.h" />
|
<ClInclude Include="Objects\TR1\Entity\Kold.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_ape.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_ape.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_bear.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_bear.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_big_rat.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_big_rat.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_centaur.h" />
|
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_doppelganger.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_doppelganger.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_giant_mutant.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_giant_mutant.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_natla.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_natla.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\SkateboardKid.h" />
|
<ClInclude Include="Objects\TR1\Entity\SkateboardKid.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_winged_mutant.h" />
|
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_wolf.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_wolf.h" />
|
||||||
|
<ClInclude Include="Objects\TR1\Entity\WingedMutant.h" />
|
||||||
<ClInclude Include="Objects\TR1\Trap\DamoclesSword.h" />
|
<ClInclude Include="Objects\TR1\Trap\DamoclesSword.h" />
|
||||||
<ClInclude Include="Objects\TR1\Trap\SlammingDoors.h" />
|
<ClInclude Include="Objects\TR1\Trap\SlammingDoors.h" />
|
||||||
<ClInclude Include="Objects\TR1\tr1_objects.h" />
|
<ClInclude Include="Objects\TR1\tr1_objects.h" />
|
||||||
|
@ -530,7 +530,9 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
||||||
<ClInclude Include="Objects\TR3\Entity\Compsognathus.h" />
|
<ClInclude Include="Objects\TR3\Entity\Compsognathus.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\FishSwarm.h" />
|
<ClInclude Include="Objects\TR3\Entity\FishSwarm.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\Lizard.h" />
|
<ClInclude Include="Objects\TR3\Entity\Lizard.h" />
|
||||||
|
<ClInclude Include="Objects\TR3\Entity\SealMutant.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\PunaBoss.h" />
|
<ClInclude Include="Objects\TR3\Entity\PunaBoss.h" />
|
||||||
|
<ClInclude Include="Objects\TR3\Entity\Raptor.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\Shiva.h" />
|
<ClInclude Include="Objects\TR3\Entity\Shiva.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\SophiaLeigh.h" />
|
<ClInclude Include="Objects\TR3\Entity\SophiaLeigh.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_claw_mutant.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_claw_mutant.h" />
|
||||||
|
@ -542,7 +544,6 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_monkey.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_monkey.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_mp_gun.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_mp_gun.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_mp_stick.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_mp_stick.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_raptor.h" />
|
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_scuba_diver.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_scuba_diver.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_tiger.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_tiger.h" />
|
||||||
<ClInclude Include="Objects\TR3\Entity\tr3_tony.h" />
|
<ClInclude Include="Objects\TR3\Entity\tr3_tony.h" />
|
||||||
|
@ -991,18 +992,18 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
||||||
<ClCompile Include="Objects\Generic\Traps\CrumblingPlatform.cpp" />
|
<ClCompile Include="Objects\Generic\Traps\CrumblingPlatform.cpp" />
|
||||||
<ClCompile Include="Objects\Generic\Traps\dart_emitter.cpp" />
|
<ClCompile Include="Objects\Generic\Traps\dart_emitter.cpp" />
|
||||||
<ClCompile Include="Objects\Generic\Traps\falling_block.cpp" />
|
<ClCompile Include="Objects\Generic\Traps\falling_block.cpp" />
|
||||||
|
<ClCompile Include="Objects\TR1\Entity\Centaur.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\Cowboy.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\Cowboy.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\Kold.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\Kold.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_ape.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_ape.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_bear.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_bear.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_big_rat.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_big_rat.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_centaur.cpp" />
|
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_doppelganger.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_doppelganger.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_giant_mutant.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_giant_mutant.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_natla.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_natla.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\SkateboardKid.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\SkateboardKid.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_winged_mutant.cpp" />
|
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_wolf.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_wolf.cpp" />
|
||||||
|
<ClCompile Include="Objects\TR1\Entity\WingedMutant.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\tr1_objects.cpp" />
|
<ClCompile Include="Objects\TR1\tr1_objects.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Trap\DamoclesSword.cpp" />
|
<ClCompile Include="Objects\TR1\Trap\DamoclesSword.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Trap\SlammingDoors.cpp" />
|
<ClCompile Include="Objects\TR1\Trap\SlammingDoors.cpp" />
|
||||||
|
@ -1036,7 +1037,9 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
||||||
<ClCompile Include="Objects\TR3\Entity\Compsognathus.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\Compsognathus.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\FishSwarm.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\FishSwarm.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\Lizard.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\Lizard.cpp" />
|
||||||
|
<ClCompile Include="Objects\TR3\Entity\SealMutant.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\PunaBoss.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\PunaBoss.cpp" />
|
||||||
|
<ClCompile Include="Objects\TR3\Entity\Raptor.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\Shiva.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\Shiva.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\SophiaLeigh.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\SophiaLeigh.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_civvy.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_civvy.cpp" />
|
||||||
|
@ -1046,7 +1049,6 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_monkey.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_monkey.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_mp_gun.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_mp_gun.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_mp_stick.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_mp_stick.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_raptor.cpp" />
|
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_scuba_diver.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_scuba_diver.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_tiger.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_tiger.cpp" />
|
||||||
<ClCompile Include="Objects\TR3\Entity\tr3_tony.cpp" />
|
<ClCompile Include="Objects\TR3\Entity\tr3_tony.cpp" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue