mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-01 09:18:00 +03:00
Merge branch 'master' into states_tier_3
This commit is contained in:
commit
aaa8213b34
282 changed files with 4887 additions and 3710 deletions
|
@ -1,6 +1,9 @@
|
|||
Version 1.0.2
|
||||
=============
|
||||
|
||||
* Removing Pistols with TakeItem and SetItemCount now works correctly.
|
||||
* Vec3s can now be saved and loaded in LevelVars and GameVars.
|
||||
* Support volume triggers made with node editor.
|
||||
* Adjust max turn rate of idle state.
|
||||
* Align Lara on slopes when crouching, crawling, and dying.
|
||||
* Better slope alignment for large, flat enemies (i.e. big scorpion and crocodile).
|
||||
|
@ -19,7 +22,17 @@ Version 1.0.2
|
|||
* Fix incorrect viewport size in windowed mode.
|
||||
* Fix late landing animation dispatch in rare cases.
|
||||
* Fix Lara's subway train death so that she no longer slides slowly after the animation has finished.
|
||||
* Fix horseman's axe attack using his left foot as the damaging joint.
|
||||
* Fix stargate blades needlessly pushing the player around while hardly doing any damage.
|
||||
|
||||
Lua API changes:
|
||||
|
||||
* Timer.lua, EventSequence.lua and Util.lua have been moved to a subfolder, Engine.
|
||||
* LevelFuncs can now contain tables as well as functions. These tables can contain functions and other tables, and so forth.
|
||||
* Moveable functions SetOnHit, SetOnKilled, SetOnCollidedWithObject and SetOnCollidedWithRoom no longer take strings, and instead take function objects themselves.
|
||||
* EventSequence and Timer no longer require you to call Timer.UpdateAll in OnControlPhase.
|
||||
* TEN.Logic.AddCallback and TEN.Logic.RemoveCallback have been added.
|
||||
* GiveItem, TakeItem, and SetItemCount have been reworked (e.g. SetItemCount with a value of -1 can give infinite ammo/consumables).
|
||||
|
||||
Version 1.0.1
|
||||
=============
|
||||
|
|
|
@ -12,7 +12,7 @@ new_type("luautil", "5 Lua utility modules", true)
|
|||
|
||||
not_luadoc = true
|
||||
|
||||
local version = "1.0.1"
|
||||
local version = "1.0.2"
|
||||
project = "TombEngine"
|
||||
title = "TombEngine " .. version .. " Lua API"
|
||||
description = "TombEngine " .. version .. " scripting interface"
|
||||
|
@ -24,7 +24,7 @@ Other than the "special tables" (GameVars, LevelVars and LevelFuncs), every modu
|
|||
For example, to call GetMoveableByName, you would have to do:
|
||||
local door = TEN.Objects.GetMoveableByName("door_type4_14")
|
||||
To save on typing, you can put the following at the start of a Lua file:
|
||||
local Util = require("Util")
|
||||
local Util = require("Engine.Util")
|
||||
Util.ShortenTENCalls()
|
||||
This will put the modules and classes in the global table. In other words, it means you can do the following:
|
||||
local door = GetMoveableByName("door_type4_14")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -511,7 +511,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -102,6 +102,14 @@
|
|||
<td class="summary">Add a level to the Flow.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetLevel">GetLevel(id)</a></td>
|
||||
<td class="summary">GetLevel.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetCurrentLevel">GetCurrentLevel()</a></td>
|
||||
<td class="summary">GetCurrentLevel.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#SetIntroImagePath">SetIntroImagePath(path)</a></td>
|
||||
<td class="summary">Image to show when loading the game.</td>
|
||||
</tr>
|
||||
|
@ -173,6 +181,55 @@ ambient tracks.
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "GetLevel"></a>
|
||||
<strong>GetLevel(id)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
GetLevel.
|
||||
Returns the level indicated by the parameter id.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">id</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
of the level
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">Level</span></span>
|
||||
the level indicated by the id
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "GetCurrentLevel"></a>
|
||||
<strong>GetCurrentLevel()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
GetCurrentLevel.
|
||||
Returns the level that the game control is running in that moment.
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">Level</span></span>
|
||||
the current level
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "SetIntroImagePath"></a>
|
||||
|
@ -353,7 +410,7 @@ Specify which translations in the strings table correspond to which languages.
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -96,17 +96,21 @@
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#GiveItem">GiveItem(item, count)</a></td>
|
||||
<td class="name" ><a href="#GiveItem">GiveItem(item[, count])</a></td>
|
||||
<td class="summary">Add x of an item to the inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetItemCount">GetItemCount(item)</a></td>
|
||||
<td class="summary">Get the amount the player holds of an item.</td>
|
||||
<td class="name" ><a href="#TakeItem">TakeItem(item[, count])</a></td>
|
||||
<td class="summary">Remove x of a certain item from the inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#SetItemCount">SetItemCount(item, count)</a></td>
|
||||
<td class="summary">Set the amount of a certain item the player has in the inventory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#GetItemCount">GetItemCount(item)</a></td>
|
||||
<td class="summary">Get the amount the player holds of an item.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
@ -118,14 +122,15 @@
|
|||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "GiveItem"></a>
|
||||
<strong>GiveItem(item, count)</strong>
|
||||
<strong>GiveItem(item[, count])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Add x of an item to the inventory.
|
||||
A count of 0 will add the "default" amount of that item
|
||||
Omitting the second argument will give the "default" amount of the item
|
||||
(i.e. the amount the player would get from a pickup of that type).
|
||||
For example, giving "zero" crossbow ammo would give the player
|
||||
10 instead, whereas giving "zero" medkits would give the player 1 medkit.
|
||||
For example, giving crossbow ammo without specifying the number would give the player
|
||||
10 instead.
|
||||
Has no effect if the player has an infinite number of that item.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
|
@ -136,7 +141,62 @@ For example, giving "zero" crossbow ammo would give the player
|
|||
</li>
|
||||
<li><span class="parameter">count</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the number of items to add (default: 0)
|
||||
the number of items to add (default: the amount you would get from a pickup)
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "TakeItem"></a>
|
||||
<strong>TakeItem(item[, count])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Remove x of a certain item from the inventory.
|
||||
As in <a href="../1 modules/Inventory.html#GiveItem">GiveItem</a>, omitting the count will remove the "default" amount of that item.
|
||||
Has no effect if the player has an infinite number of the item.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">item</span>
|
||||
<span class="types"><span class="type">InvID</span></span>
|
||||
the item to be removed
|
||||
</li>
|
||||
<li><span class="parameter">count</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the number of items to remove (default: the amount you would get from a pickup)
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "SetItemCount"></a>
|
||||
<strong>SetItemCount(item, count)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the amount of a certain item the player has in the inventory.
|
||||
Similar to <a href="../1 modules/Inventory.html#GiveItem">GiveItem</a> but replaces with the new amount instead of adding it.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">item</span>
|
||||
<span class="types"><span class="type">InvID</span></span>
|
||||
the ID of the item to be set.
|
||||
</li>
|
||||
<li><span class="parameter">count</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the number of items the player will have. A value of -1 will give an infinite amount of that item.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -165,37 +225,12 @@ For example, giving "zero" crossbow ammo would give the player
|
|||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the amount of the item the player has in the inventory
|
||||
the amount of the item the player has in the inventory. -1 indicates an infinite amount of that item.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "SetItemCount"></a>
|
||||
<strong>SetItemCount(item, count)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the amount of a certain item the player has in the inventory.
|
||||
Similar to <a href="../1 modules/Inventory.html#GiveItem">GiveItem</a> but replaces with the new amount instead of adding it.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">item</span>
|
||||
the ID of the item to be set
|
||||
</li>
|
||||
<li><span class="parameter">count</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the number of items the player will have
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
@ -204,7 +239,7 @@ Similar to <a href="../1 modules/Inventory.html#GiveItem">GiveItem</a> but repla
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -32,6 +32,7 @@
|
|||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
<li><a href="#Special_objects">Special objects </a></li>
|
||||
<li><a href="#Special_tables">Special tables </a></li>
|
||||
</ul>
|
||||
|
@ -94,6 +95,17 @@
|
|||
</p>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#AddCallback">AddCallback(CallbackPoint, func)</a></td>
|
||||
<td class="summary">Register a function as a callback.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#RemoveCallback">RemoveCallback(CallbackPoint, LevelFunc)</a></td>
|
||||
<td class="summary">Deregister a function as a callback.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a href="#Special_objects">Special objects </a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
|
@ -113,7 +125,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#LevelFuncs">LevelFuncs</a></td>
|
||||
<td class="summary">A table with level-specific functions.</td>
|
||||
<td class="summary">A table nested table system for level-specific functions.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -121,6 +133,79 @@
|
|||
<br/>
|
||||
|
||||
|
||||
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "AddCallback"></a>
|
||||
<strong>AddCallback(CallbackPoint, func)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Register a function as a callback.
|
||||
Possible values for CallbackPoint:</p>
|
||||
<pre><code>PRECONTROLPHASE -- will be called immediately before OnControlPhase
|
||||
POSTCONTROLPHASE -- will be called immediately after OnControlPhase
|
||||
</code></pre>
|
||||
|
||||
<p>The order in which two functions with the same CallbackPoint are called is undefined.
|
||||
i.e. if you register <code>MyFunc</code> and <code>MyFunc2</code> with <code>PRECONTROLPHASE</code>, both will be called before <code>OnControlPhase</code>, but there is no guarantee whether <code>MyFunc</code> will be called before <code>MyFunc2</code>, or vice-versa.</p>
|
||||
|
||||
<p>Any returned value will be discarded.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">CallbackPoint</span>
|
||||
<span class="types"><span class="type">point</span></span>
|
||||
When should the callback be called?
|
||||
</li>
|
||||
<li><span class="parameter">func</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
The function to be called (must be in the LevelFuncs hierarchy). Will receive, as an argument, the time in seconds since the last frame.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">LevelFuncs.MyFunc = <span class="keyword">function</span>(dt) <span class="global">print</span>(dt) <span class="keyword">end</span>
|
||||
TEN.Logic.AddCallback(TEN.Logic.CallbackPoint.PRECONTROLPHASE, LevelFuncs.MyFunc)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "RemoveCallback"></a>
|
||||
<strong>RemoveCallback(CallbackPoint, LevelFunc)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Deregister a function as a callback.
|
||||
Will have no effect if the function was not registered as a callback
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">CallbackPoint</span>
|
||||
<span class="types"><span class="type">point</span></span>
|
||||
The callback point the function was registered with. See <a href="../1 modules/Logic.html#AddCallback">AddCallback</a>
|
||||
</li>
|
||||
<li><span class="parameter">LevelFunc</span>
|
||||
<span class="types"><span class="type">func</span></span>
|
||||
the function to remove; must be in the LevelFuncs hierarchy.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">TEN.Logic.RemoveCallback(TEN.Logic.CallbackPoint.PRECONTROLPHASE, <span class="string">"MyFunc"</span>)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h2 class="section-header "><a name="Special_objects"></a>Special objects </h2>
|
||||
|
||||
<dl class="function">
|
||||
|
@ -165,7 +250,9 @@ some time later, the values <code>3</code> will be put back into <code>LevelVars
|
|||
|
||||
<p><strong>This table is emptied when a level is finished.</strong> If the player needs to be able
|
||||
to return to the level (like in the Karnak and Alexandria levels in <em>The Last Revelation</em>),
|
||||
you will need to use the <a href="../1 modules/Logic.html#GameVars">GameVars</a> table, below.
|
||||
you will need to use the <a href="../1 modules/Logic.html#GameVars">GameVars</a> table, below.</p>
|
||||
|
||||
<p><strong>LevelVars.Engine is a reserved table used internally by TombEngine's libs. Do not modify, overwrite, or add to it.</strong>
|
||||
|
||||
|
||||
|
||||
|
@ -197,7 +284,9 @@ write:</p>
|
|||
end
|
||||
</code></pre>
|
||||
|
||||
<p>Unlike <a href="../1 modules/Logic.html#LevelVars">LevelVars</a>, this table will remain intact for the entirety of the game.
|
||||
<p>Unlike <a href="../1 modules/Logic.html#LevelVars">LevelVars</a>, this table will remain intact for the entirety of the game.</p>
|
||||
|
||||
<p><strong>GameVars.Engine is a reserved table used internally by TombEngine's libs. Do not modify, overwrite, or add to it.</strong>
|
||||
|
||||
|
||||
|
||||
|
@ -212,9 +301,9 @@ end
|
|||
</dt>
|
||||
<dd>
|
||||
|
||||
<p>A table with level-specific functions. </p>
|
||||
<p>A table nested table system for level-specific functions. </p>
|
||||
|
||||
<p>This serves two purposes: it holds the level callbacks (listed below) as well as
|
||||
<p>This serves a few purposes: it holds the level callbacks (listed below) as well as
|
||||
any trigger functions you might have specified. For example, if you give a trigger
|
||||
a Lua name of "my_trigger" in Tomb Editor, you will have to implement it as a member
|
||||
of this table:</p>
|
||||
|
@ -224,6 +313,25 @@ of this table:</p>
|
|||
end
|
||||
</code></pre>
|
||||
|
||||
<p>You can organise functions into tables within the hierarchy:</p>
|
||||
|
||||
<pre><code>LevelFuncs.enemyFuncs = {}
|
||||
|
||||
LevelFuncs.enemyFuncs.makeBaddyRunAway = function()
|
||||
-- implementation goes here
|
||||
end
|
||||
|
||||
LevelFuncs.enemyFuncs.makeBaddyUseMedkit = function()
|
||||
-- implementation goes here
|
||||
end
|
||||
</code></pre>
|
||||
|
||||
<p>There are two special subtables which you should <strong>not</strong> overwrite:</p>
|
||||
|
||||
<pre><code>LevelFuncs.Engine -- this is for 'first-party' functions, i.e. ones that come with TombEngine.
|
||||
LevelFuncs.External -- this is for 'third-party' functions. If you write a library providing LevelFuncs functions for other builders to use in their levels, put those functions in LevelFuncs.External.YourLibraryNameHere
|
||||
</code></pre>
|
||||
|
||||
<p>The following are the level callbacks. They are optional; if your level has no special
|
||||
behaviour for a particular scenario, you do not need to implement the function. For
|
||||
example, if your level does not need any special initialisation when it is loaded,
|
||||
|
@ -279,7 +387,7 @@ and provides the delta time (a float representing game time since last call) via
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -124,6 +124,10 @@
|
|||
<td class="summary">Set and play an ambient track</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#PlaySound">PlaySound(sound[, position])</a></td>
|
||||
<td class="summary">Play sound effect</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#CalculateDistance">CalculateDistance(posA, posB)</a></td>
|
||||
<td class="summary">Calculate the distance between two positions.</td>
|
||||
</tr>
|
||||
|
@ -144,10 +148,6 @@
|
|||
<td class="summary">Vibrate gamepad, if possible.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#PlaySound">PlaySound(sound, position)</a></td>
|
||||
<td class="summary">Play sound effect</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#KeyIsHeld">KeyIsHeld(action)</a></td>
|
||||
<td class="summary">Check if particular action key is held</td>
|
||||
</tr>
|
||||
|
@ -355,6 +355,32 @@ eyes of the creatures would be.
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "PlaySound"></a>
|
||||
<strong>PlaySound(sound[, position])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Play sound effect
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">sound</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
ID to play. Corresponds to the value in the sound XML file or Tomb Editor's "Sound Infos" window.
|
||||
</li>
|
||||
<li><span class="parameter">position</span>
|
||||
<span class="types"><span class="type">Vec3</span></span>
|
||||
The 3D position of the sound, i.e. where the sound "comes from". If not given, the sound will not be positional.
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "CalculateDistance"></a>
|
||||
|
@ -451,6 +477,17 @@ To be used with <a href="../2 classes/Strings.DisplayString.html#DisplayString:S
|
|||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> halfwayX, halfwayY = PercentToScreen(<span class="number">50</span>, <span class="number">50</span>)
|
||||
<span class="keyword">local</span> baddy
|
||||
<span class="keyword">local</span> spawnLocationNullmesh = GetMoveableByName(<span class="string">"position_behind_left_pillar"</span>)
|
||||
<span class="keyword">local</span> str1 = DisplayString(<span class="string">"You spawned a baddy!"</span>, halfwayX, halfwayY, Color(<span class="number">255</span>, <span class="number">100</span>, <span class="number">100</span>), <span class="keyword">false</span>, {DisplayStringOption.SHADOW, DisplayStringOption.CENTER})
|
||||
|
||||
LevelFuncs.triggerOne = <span class="keyword">function</span>(obj)
|
||||
ShowString(str1, <span class="number">4</span>)
|
||||
<span class="keyword">end</span></pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
|
@ -514,33 +551,6 @@ To be used with <a href="../2 classes/Strings.DisplayString.html#DisplayString:G
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "PlaySound"></a>
|
||||
<strong>PlaySound(sound, position)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Play sound effect
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">sound</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
ID to play
|
||||
</li>
|
||||
<li><span class="parameter">position</span>
|
||||
<span class="types"><span class="type">Vec3</span></span>
|
||||
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "KeyIsHeld"></a>
|
||||
|
@ -633,7 +643,7 @@ To be used with <a href="../2 classes/Strings.DisplayString.html#DisplayString:G
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-08 19:16:14 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -297,7 +297,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -169,7 +169,7 @@ with a call to <a href="../1 modules/Strings.html#ShowString">ShowString</a>, or
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -100,7 +100,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -112,7 +112,7 @@
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#Fog.new">Fog.new(color, Min, Max)</a></td>
|
||||
<td class="name" ><a href="#Fog">Fog(color, Min, Max)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
|
@ -185,8 +185,8 @@
|
|||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Fog.new"></a>
|
||||
<strong>Fog.new(color, Min, Max)</strong>
|
||||
<a name = "Fog"></a>
|
||||
<strong>Fog(color, Min, Max)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
@ -227,7 +227,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -182,7 +182,7 @@ EXAMINE
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -120,8 +120,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#layer2">layer2</a></td>
|
||||
<td class="summary">(<a href="../2 classes/Flow.SkyLayer.html#">Flow.SkyLayer</a>) Secondary sky layer
|
||||
<strong>(not yet implemented)</strong></td>
|
||||
<td class="summary">(<a href="../2 classes/Flow.SkyLayer.html#">Flow.SkyLayer</a>) Secondary sky layer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#fog">fog</a></td>
|
||||
|
@ -132,10 +131,6 @@
|
|||
<td class="summary">(bool) Draw sky layer?</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#colAddHorizon">colAddHorizon</a></td>
|
||||
<td class="summary">(bool) Enable smooth transition from horizon graphic to sky layer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#storm">storm</a></td>
|
||||
<td class="summary">(bool) Enable flickering lightning in the sky.</td>
|
||||
</tr>
|
||||
|
@ -175,7 +170,7 @@
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#Level.new">Level.new()</a></td>
|
||||
<td class="name" ><a href="#Level">Level()</a></td>
|
||||
<td class="summary">Make a new Level object.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -282,7 +277,6 @@
|
|||
</dt>
|
||||
<dd>
|
||||
(<a href="../2 classes/Flow.SkyLayer.html#">Flow.SkyLayer</a>) Secondary sky layer
|
||||
<strong>(not yet implemented)</strong>
|
||||
|
||||
|
||||
|
||||
|
@ -320,23 +314,6 @@
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "colAddHorizon"></a>
|
||||
<strong>colAddHorizon</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
(bool) Enable smooth transition from horizon graphic to sky layer.
|
||||
If set to false, there will be a black band between the two.</p>
|
||||
|
||||
<p> <strong>(not yet implemented)</strong>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "storm"></a>
|
||||
|
@ -494,8 +471,8 @@ Must be at least 4.</p>
|
|||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Level.new"></a>
|
||||
<strong>Level.new()</strong>
|
||||
<a name = "Level"></a>
|
||||
<strong>Level()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Make a new Level object.
|
||||
|
@ -519,7 +496,7 @@ Must be at least 4.</p>
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -100,7 +100,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -115,19 +115,19 @@
|
|||
<dd>
|
||||
How should the application respond to script errors?
|
||||
Must be one of the following:
|
||||
<code>ErrorMode.TERMINATE</code> - print to the log file and terminate the application when any script error is hit.
|
||||
<code>ErrorMode.TERMINATE</code> - print to the log file and return to the title level when any script error is hit.
|
||||
This is the one you will want to go for if you want to know IMMEDIATELY if something has gone wrong.</p>
|
||||
|
||||
<p><code>ErrorMode.WARN</code> - print to the log file and continue running the application when a recoverable script error is hit.
|
||||
Choose this one if terminating the application is too much for you. Note that unrecoverable errors will still terminate
|
||||
the application.</p>
|
||||
Choose this one if booting to the title level is too much for you.</p>
|
||||
|
||||
<p><code>ErrorMode.SILENT</code> - do nothing when a recoverable script error is hit.
|
||||
Think <strong>very</strong> carefully before using this setting. These error modes are here to help you to keep your scripts
|
||||
working properly, but if you opt to ignore errors, you won't be alerted if you've misused a function or passed
|
||||
an invalid argument.</p>
|
||||
|
||||
<p>As with <code>ErrorMode.WARN</code>, unrecoverable errors will still terminate the application.
|
||||
<p>In all of these modes, an <em>unrecoverable</em> error will boot you to the title level. If the title level itself
|
||||
has an unrecoverable error, the game will close.
|
||||
|
||||
|
||||
|
||||
|
@ -143,7 +143,7 @@ an invalid argument.</p>
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -106,7 +106,7 @@
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#SkyLayer.new">SkyLayer.new(color, speed)</a></td>
|
||||
<td class="name" ><a href="#SkyLayer">SkyLayer(color, speed)</a></td>
|
||||
<td class="summary">
|
||||
|
||||
</td>
|
||||
|
@ -161,8 +161,8 @@ Less is more. City of The Dead, for example, uses a speed value of 16.
|
|||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "SkyLayer.new"></a>
|
||||
<strong>SkyLayer.new(color, speed)</strong>
|
||||
<a name = "SkyLayer"></a>
|
||||
<strong>SkyLayer(color, speed)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
|
@ -199,7 +199,7 @@ Less is more. City of The Dead, for example, uses a speed value of 16.
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -372,7 +372,7 @@ aiObj:SetObjectID(TEN.Objects.ObjID.AI_PATROL1)</pre>
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -260,7 +260,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -95,7 +95,7 @@ pickups, and Lara herself.</p>
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable">Moveable(object, name, position, rotation, room, animNumber, frameNumber, hp, OCB, AIBits)</a></td>
|
||||
<td class="name" ><a href="#Moveable">Moveable(object, name, position[, rotation[, room[, animNumber=0[, frameNumber=0[, hp=10[, OCB=0[, AIBits]]]]]]])</a></td>
|
||||
<td class="summary">For more information on each parameter, see the
|
||||
associated getters and setters.</td>
|
||||
</tr>
|
||||
|
@ -124,39 +124,6 @@ associated getters and setters.</td>
|
|||
<td class="summary">Get the status of object.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnHit">Moveable:SetOnHit(name)</a></td>
|
||||
<td class="summary">Set the name of the function to be called when the moveable is shot by Lara
|
||||
Note that this will be triggered twice when shot with both pistols at once.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetOnHit">Moveable:GetOnHit()</a></td>
|
||||
<td class="summary">Get the name of the function called when this moveable is shot</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnCollidedWithObject">Moveable:SetOnCollidedWithObject(name)</a></td>
|
||||
<td class="summary">Set the name of the function called when this moveable collides with another moveable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetOnCollidedWithObject">Moveable:GetOnCollidedWithObject()</a></td>
|
||||
<td class="summary">Get the name of the function called when this moveable collides with another moveable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnCollidedWithRoom">Moveable:SetOnCollidedWithRoom(name)</a></td>
|
||||
<td class="summary">Set the name of the function called when this moveable collides with room geometry (e.g.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetOnCollidedWithRoom">Moveable:GetOnCollidedWithRoom()</a></td>
|
||||
<td class="summary">Get the name of the function called when this moveable collides with room geometry (e.g.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnKilled">Moveable:SetOnKilled(callback)</a></td>
|
||||
<td class="summary">Set the name of the function to be called when the moveable is destroyed/killed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetOnKilled">Moveable:GetOnKilled()</a></td>
|
||||
<td class="summary">Get the name of the function called when this moveable is killed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetObjectID">Moveable:GetObjectID()</a></td>
|
||||
<td class="summary">Retrieve the object ID</td>
|
||||
</tr>
|
||||
|
@ -197,6 +164,10 @@ associated getters and setters.</td>
|
|||
<td class="summary">Set current HP (hit points/health points)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetSlotHP">Moveable:GetSlotHP(ID)</a></td>
|
||||
<td class="summary">Get HP definded for that object type (hit points/health points) (Read Only).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetOCB">Moveable:GetOCB()</a></td>
|
||||
<td class="summary">Get OCB (object code bit) of the moveable</td>
|
||||
</tr>
|
||||
|
@ -205,6 +176,14 @@ associated getters and setters.</td>
|
|||
<td class="summary">Set OCB (object code bit) of the moveable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetItemFlags">Moveable:GetItemFlags()</a></td>
|
||||
<td class="summary">Get the value stored in ItemFlags[x] (x is the value of the parameter)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetItemFlags">Moveable:SetItemFlags(value)</a></td>
|
||||
<td class="summary">Stores the value of the first parameter in the ItemFlags[x] (x is the value of the second parameter)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetColor">Moveable:GetColor()</a></td>
|
||||
<td class="summary">Get the moveable's color</td>
|
||||
</tr>
|
||||
|
@ -270,27 +249,8 @@ associated getters and setters.</td>
|
|||
<td class="summary">Determine whether the moveable is active or not</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetRoom">Moveable:GetRoom()</a></td>
|
||||
<td class="summary">Get the current room of the object</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetRoom">Moveable:SetRoom(ID)</a></td>
|
||||
<td class="summary">Set room of object
|
||||
This is used in conjunction with SetPosition to teleport an item to a new room.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetPosition">Moveable:GetPosition()</a></td>
|
||||
<td class="summary">Get the object's position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetJointPosition">Moveable:GetJointPosition()</a></td>
|
||||
<td class="summary">Get the object's joint position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetPosition">Moveable:SetPosition(position)</a></td>
|
||||
<td class="summary">Set the moveable's position
|
||||
If you are moving a moveable whose behaviour involves knowledge of room geometry,
|
||||
(e.g.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetRotation">Moveable:GetRotation()</a></td>
|
||||
|
@ -318,6 +278,44 @@ associated getters and setters.</td>
|
|||
<td class="name" ><a href="#Moveable:Destroy">Moveable:Destroy()</a></td>
|
||||
<td class="summary">Destroy the moveable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnHit">Moveable:SetOnHit(callback)</a></td>
|
||||
<td class="summary">Set the name of the function to be called when the moveable is shot by Lara
|
||||
Note that this will be triggered twice when shot with both pistols at once.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnKilled">Moveable:SetOnKilled(callback)</a></td>
|
||||
<td class="summary">Set the name of the function to be called when the moveable is destroyed/killed
|
||||
Note that enemy death often occurs at the end of an animation, and not at the exact moment
|
||||
the enemy's HP becomes zero.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnCollidedWithObject">Moveable:SetOnCollidedWithObject(func)</a></td>
|
||||
<td class="summary">Set the function to be called called when this moveable collides with another moveable</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetOnCollidedWithRoom">Moveable:SetOnCollidedWithRoom(func)</a></td>
|
||||
<td class="summary">Set the function called when this moveable collides with room geometry (e.g.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetPosition">Moveable:GetPosition()</a></td>
|
||||
<td class="summary">Get the object's position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetPosition">Moveable:SetPosition(position[, updateRoom])</a></td>
|
||||
<td class="summary">Set the moveable's position
|
||||
If you are moving a moveable whose behaviour involves knowledge of room geometry,
|
||||
(e.g.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:GetRoom">Moveable:GetRoom()</a></td>
|
||||
<td class="summary">Get the current room of the object</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable:SetRoom">Moveable:SetRoom(ID)</a></td>
|
||||
<td class="summary">Set room of object
|
||||
Use this if you are not using SetPosition's automatic room update - for example, when dealing with overlapping rooms.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
|
@ -329,7 +327,7 @@ associated getters and setters.</td>
|
|||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Moveable"></a>
|
||||
<strong>Moveable(object, name, position, rotation, room, animNumber, frameNumber, hp, OCB, AIBits)</strong>
|
||||
<strong>Moveable(object, name, position[, rotation[, room[, animNumber=0[, frameNumber=0[, hp=10[, OCB=0[, AIBits]]]]]]])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
For more information on each parameter, see the
|
||||
|
@ -354,30 +352,37 @@ most can just be ignored (see usage).
|
|||
<li><span class="parameter">rotation</span>
|
||||
<span class="types"><span class="type">Rotation</span></span>
|
||||
rotation about x, y, and z axes (default Rotation(0, 0, 0))
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
<li><span class="parameter">room</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
room ID item is in
|
||||
room ID item is in (default: calculated automatically)
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
<li><span class="parameter">animNumber</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
anim number (default 0)
|
||||
anim number
|
||||
(<em>default</em> 0)
|
||||
</li>
|
||||
<li><span class="parameter">frameNumber</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
frame number (default 0)
|
||||
frame number
|
||||
(<em>default</em> 0)
|
||||
</li>
|
||||
<li><span class="parameter">hp</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
HP of item (default 10)
|
||||
HP of item
|
||||
(<em>default</em> 10)
|
||||
</li>
|
||||
<li><span class="parameter">OCB</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
ocb of item (default 0)
|
||||
(<em>default</em> 0)
|
||||
</li>
|
||||
<li><span class="parameter">AIBits</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
|
||||
table with AI bits (default {0,0,0,0,0,0})
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -394,10 +399,8 @@ most can just be ignored (see usage).
|
|||
<pre class="example"><span class="keyword">local</span> item = Moveable(
|
||||
TEN.ObjID.PISTOLS_ITEM, <span class="comment">-- object id
|
||||
</span> <span class="string">"test"</span>, <span class="comment">-- name
|
||||
</span> Vec3(<span class="number">18907</span>, <span class="number">0</span>, <span class="number">21201</span>),
|
||||
Rotation(<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>),
|
||||
<span class="number">0</span>, <span class="comment">-- room
|
||||
</span> )</pre>
|
||||
</span> Vec3(<span class="number">18907</span>, <span class="number">0</span>, <span class="number">21201</span>)
|
||||
)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
|
@ -495,176 +498,6 @@ most can just be ignored (see usage).
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnHit"></a>
|
||||
<strong>Moveable:SetOnHit(name)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the name of the function to be called when the moveable is shot by Lara
|
||||
Note that this will be triggered twice when shot with both pistols at once.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">name</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
of callback function to be called
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetOnHit"></a>
|
||||
<strong>Moveable:GetOnHit()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the name of the function called when this moveable is shot
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
name of the function
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnCollidedWithObject"></a>
|
||||
<strong>Moveable:SetOnCollidedWithObject(name)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the name of the function called when this moveable collides with another moveable
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">name</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
of callback function to be called
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetOnCollidedWithObject"></a>
|
||||
<strong>Moveable:GetOnCollidedWithObject()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the name of the function called when this moveable collides with another moveable
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
name of the function
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnCollidedWithRoom"></a>
|
||||
<strong>Moveable:SetOnCollidedWithRoom(name)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the name of the function called when this moveable collides with room geometry (e.g. a wall or floor)
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">name</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
of callback function to be called
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetOnCollidedWithRoom"></a>
|
||||
<strong>Moveable:GetOnCollidedWithRoom()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the name of the function called when this moveable collides with room geometry (e.g. a wall or floor)
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
name of the function
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnKilled"></a>
|
||||
<strong>Moveable:SetOnKilled(callback)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the name of the function to be called when the moveable is destroyed/killed
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">callback</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
name of function to be called
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">LevelFuncs.baddyKilled = <span class="keyword">function</span>(theBaddy) <span class="global">print</span>(<span class="string">"You killed a baddy!"</span>) <span class="keyword">end</span>
|
||||
baddy:SetOnKilled(<span class="string">"baddyKilled"</span>)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetOnKilled"></a>
|
||||
<strong>Moveable:GetOnKilled()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the name of the function called when this moveable is killed
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
name of the function
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetObjectID"></a>
|
||||
|
@ -886,6 +719,27 @@ shiva:SetObjectID(TEN.Objects.ObjID.BIGMEDI_ITEM)</pre>
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetSlotHP"></a>
|
||||
<strong>Moveable:GetSlotHP(ID)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get HP definded for that object type (hit points/health points) (Read Only).
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">ID</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
of the moveable slot type.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetOCB"></a>
|
||||
|
@ -927,6 +781,47 @@ shiva:SetObjectID(TEN.Objects.ObjID.BIGMEDI_ITEM)</pre>
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetItemFlags"></a>
|
||||
<strong>Moveable:GetItemFlags()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the value stored in ItemFlags[x] (x is the value of the parameter)
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">short</span></span>
|
||||
id of the ItemFlags array
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetItemFlags"></a>
|
||||
<strong>Moveable:SetItemFlags(value)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Stores the value of the first parameter in the ItemFlags[x] (x is the value of the second parameter)
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">value</span>
|
||||
<span class="types"><span class="type">short</span></span>
|
||||
to store in the moveable's ItemFlags[x], short id of ItemFlags array to store the value.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetColor"></a>
|
||||
|
@ -1242,74 +1137,6 @@ sas:SetAIBits({<span class="number">1</span>, <span class="number">0</span>, <sp
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetRoom"></a>
|
||||
<strong>Moveable:GetRoom()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the current room of the object
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
number representing the current room of the object
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetRoom"></a>
|
||||
<strong>Moveable:SetRoom(ID)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set room of object
|
||||
This is used in conjunction with SetPosition to teleport an item to a new room.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">ID</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the ID of the new room
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> sas = TEN.Objects.GetMoveableByName(<span class="string">"sas_enemy"</span>)
|
||||
sas:SetRoom(destinationRoom)
|
||||
sas:SetPosition(destinationPosition)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetPosition"></a>
|
||||
<strong>Moveable:GetPosition()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the object's position
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">Vec3</span></span>
|
||||
a copy of the moveable's position
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetJointPosition"></a>
|
||||
|
@ -1330,30 +1157,6 @@ sas:SetPosition(destinationPosition)</pre>
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetPosition"></a>
|
||||
<strong>Moveable:SetPosition(position)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the moveable's position
|
||||
If you are moving a moveable whose behaviour involves knowledge of room geometry,
|
||||
(e.g. a BADDY1, which uses it for pathfinding), then you <em>must</em> use this in conjunction
|
||||
with <a href="../2 classes/Objects.Moveable.html#Moveable:SetRoom">Moveable:SetRoom</a>. Otherwise, said moveable will not behave correctly.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">position</span>
|
||||
<span class="types"><span class="type">Vec3</span></span>
|
||||
the new position of the moveable
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetRotation"></a>
|
||||
|
@ -1480,6 +1283,195 @@ sas:SetPosition(destinationPosition)</pre>
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnHit"></a>
|
||||
<strong>Moveable:SetOnHit(callback)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the name of the function to be called when the moveable is shot by Lara
|
||||
Note that this will be triggered twice when shot with both pistols at once.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">callback</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
function in LevelFuncs hierarchy to call when moveable is shot
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnKilled"></a>
|
||||
<strong>Moveable:SetOnKilled(callback)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the name of the function to be called when the moveable is destroyed/killed
|
||||
Note that enemy death often occurs at the end of an animation, and not at the exact moment
|
||||
the enemy's HP becomes zero.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">callback</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
function in LevelFuncs hierarchy to call when enemy is killed
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">LevelFuncs.baddyKilled = <span class="keyword">function</span>(theBaddy) <span class="global">print</span>(<span class="string">"You killed a baddy!"</span>) <span class="keyword">end</span>
|
||||
baddy:SetOnKilled(LevelFuncs.baddyKilled)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnCollidedWithObject"></a>
|
||||
<strong>Moveable:SetOnCollidedWithObject(func)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the function to be called called when this moveable collides with another moveable
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">func</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
callback function to be called (must be in LevelFuncs hierarchy)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetOnCollidedWithRoom"></a>
|
||||
<strong>Moveable:SetOnCollidedWithRoom(func)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the function called when this moveable collides with room geometry (e.g. a wall or floor)
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">func</span>
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
callback function to be called (must be in LevelFuncs hierarchy)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetPosition"></a>
|
||||
<strong>Moveable:GetPosition()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the object's position
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">Vec3</span></span>
|
||||
a copy of the moveable's position
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetPosition"></a>
|
||||
<strong>Moveable:SetPosition(position[, updateRoom])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the moveable's position
|
||||
If you are moving a moveable whose behaviour involves knowledge of room geometry,
|
||||
(e.g. a BADDY1, which uses it for pathfinding), then the second argument should
|
||||
be true (or omitted, as true is the default). Otherwise, said moveable will not behave correctly.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">position</span>
|
||||
<span class="types"><span class="type">Vec3</span></span>
|
||||
the new position of the moveable
|
||||
</li>
|
||||
<li><span class="parameter">updateRoom</span>
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
Will room changes be automatically detected? Set to false if you are using overlapping rooms (default: true)
|
||||
(<em>optional</em>)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:GetRoom"></a>
|
||||
<strong>Moveable:GetRoom()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the current room of the object
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
number representing the current room of the object
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Moveable:SetRoom"></a>
|
||||
<strong>Moveable:SetRoom(ID)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set room of object
|
||||
Use this if you are not using SetPosition's automatic room update - for example, when dealing with overlapping rooms.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">ID</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
the ID of the new room
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> sas = TEN.Objects.GetMoveableByName(<span class="string">"sas_enemy"</span>)
|
||||
sas:SetRoom(destinationRoom)
|
||||
sas:SetPosition(destinationPosition, <span class="keyword">false</span>)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
@ -1488,7 +1480,7 @@ sas:SetPosition(destinationPosition)</pre>
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -262,7 +262,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -260,7 +260,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -112,6 +112,14 @@
|
|||
<td class="summary">Set the static's rotation</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Static:GetScale">Static:GetScale()</a></td>
|
||||
<td class="summary">Get the static's scale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Static:SetScale">Static:SetScale(scale)</a></td>
|
||||
<td class="summary">Set the static's scale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Static:GetName">Static:GetName()</a></td>
|
||||
<td class="summary">Get the static's unique string identifier</td>
|
||||
</tr>
|
||||
|
@ -226,6 +234,47 @@
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Static:GetScale"></a>
|
||||
<strong>Static:GetScale()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the static's scale
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">float</span></span>
|
||||
current static scale
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Static:SetScale"></a>
|
||||
<strong>Static:SetScale(scale)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the static's scale
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">scale</span>
|
||||
<span class="types"><span class="type">Scale</span></span>
|
||||
the static's new scale
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Static:GetName"></a>
|
||||
|
@ -358,7 +407,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -307,7 +307,7 @@ TEN.Strings.DisplayStringOption.SHADOW -- will give the text a small shadow
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -312,7 +312,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -250,7 +250,7 @@ All values will be clamped to [-32768, 32767].</p>
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -277,7 +277,7 @@ However, this function would return it as (0, 1, 1).
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -149,7 +149,7 @@ ALPHABLEND
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -358,7 +358,7 @@ EXAMINE_ITEM8_COMBO2
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -1096,7 +1096,7 @@ PANEL_MIDDLE_CORNER
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -90,10 +90,13 @@
|
|||
<p>Event sequence - a chain of functions to call at specified times, modeled after TRNG's organizers.</p>
|
||||
<p>
|
||||
|
||||
|
||||
<p> Works atop the Timer, and so is updated automatically pre-OnControlPhase, and saved automatically when the game is saved.</p>
|
||||
|
||||
<p> Example usage:</p>
|
||||
|
||||
<pre>
|
||||
<span class="keyword">local</span> EventSequence = <span class="global">require</span>(<span class="string">"EventSequence"</span>)
|
||||
<span class="keyword">local</span> EventSequence = <span class="global">require</span>(<span class="string">"Engine.EventSequence"</span>)
|
||||
|
||||
<span class="comment">-- These will be called by the sequence
|
||||
</span>LevelFuncs.HealLara = <span class="keyword">function</span>()
|
||||
|
@ -115,22 +118,17 @@ LevelFuncs.SpawnBaddy = <span class="keyword">function</span>(baddy, name, pos)
|
|||
<span class="keyword">false</span>, <span class="comment">-- does not loop
|
||||
</span> {seconds = <span class="keyword">true</span>, deciseconds = <span class="keyword">true</span>}, <span class="comment">-- timer format, see Timer for details
|
||||
</span> <span class="number">6</span>, <span class="comment">-- seconds until call the function specified in next arg
|
||||
</span> <span class="string">"HealLara"</span>, <span class="comment">-- first function to call. If we don't need to pass any arguments, we can just give the func name as a string
|
||||
</span> LevelFuncs.HealLara, <span class="comment">-- first function to call. If we don't need to pass any arguments, we can just pass the function
|
||||
</span> <span class="number">2.1</span>, <span class="comment">-- seconds until the next function, after the previous one has been called
|
||||
</span> {<span class="string">"SpawnBaddy"</span>, TEN.Objects.ObjID.BADDY1, <span class="string">"steve"</span>, posSteve}, <span class="comment">-- if we DO want to pass arguments to the function to be called, we give a table with the name of the function ("SpawnBaddy" in this case) followed by the args to pass to it
|
||||
</span> {LevelFuncs.SpawnBaddy, TEN.Objects.ObjID.BADDY1, <span class="string">"steve"</span>, posSteve}, <span class="comment">-- if we DO want to pass arguments to the function to be called, we give a table with the function (LevelFuncs.SpawnBaddy in this case) followed by the args to pass to it
|
||||
</span> <span class="number">0.5</span>,
|
||||
{<span class="string">"SpawnBaddy"</span>, TEN.Objects.ObjID.SAS_CAIRO, <span class="string">"chris"</span>, posChris},
|
||||
{LevelFuncs.SpawnBaddy, TEN.Objects.ObjID.SAS_CAIRO, <span class="string">"chris"</span>, posChris},
|
||||
<span class="number">1</span>,
|
||||
<span class="string">"HealLara"</span>)
|
||||
LevelFuncs.HealLara)
|
||||
|
||||
<span class="comment">-- event sequences are inactive to begin with and so need to be started
|
||||
</span> mySeq:Start()
|
||||
<span class="keyword">end</span>
|
||||
|
||||
<span class="comment">-- EventSequence runs on Timer, so this call is required
|
||||
</span>LevelFuncs.OnControlPhase = <span class="keyword">function</span>(dt)
|
||||
Timer.UpdateAll(dt)
|
||||
<span class="keyword">end</span>
|
||||
</pre>
|
||||
|
||||
</p>
|
||||
|
@ -333,7 +331,7 @@ LevelFuncs.SpawnBaddy = <span class="keyword">function</span>(baddy, name, pos)
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -90,10 +90,13 @@
|
|||
<p>Basic timer - after a specified number of seconds, the specified thing happens.</p>
|
||||
<p>
|
||||
|
||||
|
||||
<p> Timers are updated automatically every frame before OnControlPhase.</p>
|
||||
|
||||
<p> Example usage:</p>
|
||||
|
||||
<pre>
|
||||
<span class="keyword">local</span> Timer = <span class="global">require</span>(<span class="string">"Timer"</span>)
|
||||
<span class="keyword">local</span> Timer = <span class="global">require</span>(<span class="string">"Engine.Timer"</span>)
|
||||
|
||||
<span class="comment">-- This will be called when the timer runs out
|
||||
</span>LevelFuncs.FinishTimer = <span class="keyword">function</span>(healthWhenStarted, victoryMessage)
|
||||
|
@ -107,15 +110,11 @@
|
|||
<span class="number">5.0</span>,
|
||||
<span class="keyword">false</span>,
|
||||
{minutes = <span class="keyword">false</span>, seconds = <span class="keyword">true</span>, deciseconds = <span class="keyword">true</span>},
|
||||
<span class="string">"FinishTimer"</span>,
|
||||
LevelFuncs.FinishTimer,
|
||||
Lara:GetHP(),
|
||||
<span class="string">"Well done!"</span>)
|
||||
myTimer:Start()
|
||||
<span class="keyword">end</span>
|
||||
|
||||
LevelFuncs.OnControlPhase = <span class="keyword">function</span>(dt)
|
||||
Timer.UpdateAll(dt)
|
||||
<span class="keyword">end</span>
|
||||
</pre>
|
||||
|
||||
</p>
|
||||
|
@ -124,7 +123,7 @@ LevelFuncs.OnControlPhase = <span class="keyword">function</span>(dt)
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#Create">Create(name, totalTime, loop, timerFormat, func[, ...])</a></td>
|
||||
<td class="name" ><a href="#func">func(name, totalTime, loop, timerFormat[, ...])</a></td>
|
||||
<td class="summary">Create (but do not start) a new timer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -132,10 +131,6 @@ LevelFuncs.OnControlPhase = <span class="keyword">function</span>(dt)
|
|||
<td class="summary">Get a timer by its name.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#UpdateAll">UpdateAll(dt)</a></td>
|
||||
<td class="summary">Update all active timers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#myTimer:SetFunction">myTimer:SetFunction(func[, ...])</a></td>
|
||||
<td class="summary">Give the timer a new function and args</td>
|
||||
</tr>
|
||||
|
@ -189,8 +184,8 @@ LevelFuncs.OnControlPhase = <span class="keyword">function</span>(dt)
|
|||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Create"></a>
|
||||
<strong>Create(name, totalTime, loop, timerFormat, func[, ...])</strong>
|
||||
<a name = "func"></a>
|
||||
<strong>func(name, totalTime, loop, timerFormat[, ...])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Create (but do not start) a new timer. </p>
|
||||
|
@ -214,7 +209,10 @@ local myTimeFormat4 = {seconds = true}
|
|||
|
||||
<p><strong>At any given time, only one timer can show its countdown</strong>.</p>
|
||||
|
||||
<p><strong>Do not give your timers a name beginning with __TEN, as this is reserved for timers used by other internal libaries</strong>.</p>
|
||||
|
||||
<p>Use this sparingly; in the classics, timed challenges did not have visible countdowns. For shorter timers, the gameplay benefit from showing the remaining time might not be necessary, and could interfere with the atmosphere of the level.
|
||||
The LevelFunc function to call when the time is up
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
|
@ -235,10 +233,6 @@ local myTimeFormat4 = {seconds = true}
|
|||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">bool</span></span>
|
||||
If a table is given, the remaining time will be shown as a string, formatted according to the values in the table. If true, the remaining seconds, rounded up, will show at the bottom of the screen. If false, the remaining time will not be shown on screen.
|
||||
</li>
|
||||
<li><span class="parameter">func</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
The name of the LevelFunc member to call when the time is upssss
|
||||
</li>
|
||||
<li><span class="parameter">...</span>
|
||||
a variable number of arguments with which the above function will be called
|
||||
(<em>optional</em>)
|
||||
|
@ -280,28 +274,6 @@ local myTimeFormat4 = {seconds = true}
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "UpdateAll"></a>
|
||||
<strong>UpdateAll(dt)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Update all active timers.
|
||||
Should be called in LevelFuncs.OnControlPhase
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">dt</span>
|
||||
<span class="types"><span class="type">number</span></span>
|
||||
The time in seconds since the last frame
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "myTimer:SetFunction"></a>
|
||||
|
@ -314,8 +286,8 @@ local myTimeFormat4 = {seconds = true}
|
|||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">func</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
|
||||
The name of the LevelFunc member to call when the time is up
|
||||
<span class="types"><span class="type">function</span></span>
|
||||
The LevelFunc member to call when the time is up
|
||||
</li>
|
||||
<li><span class="parameter">...</span>
|
||||
a variable number of arguments with which the above function will be called
|
||||
|
@ -524,7 +496,7 @@ local myTimeFormat4 = {seconds = true}
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="../ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -138,7 +138,7 @@
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-11 22:43:52 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>TombEngine 1.0.1 Lua API</title>
|
||||
<title>TombEngine 1.0.2 Lua API</title>
|
||||
<link rel="stylesheet" href="ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -80,7 +80,7 @@
|
|||
<div id="content">
|
||||
|
||||
|
||||
<h2>TombEngine 1.0.1 scripting interface</h2>
|
||||
<h2>TombEngine 1.0.2 scripting interface</h2>
|
||||
<p>Welcome to the TombEngine scripting API. This is a work in progress and some information might be wrong or outdated. Please also note that this is primarily a reference document, not a tutorial, so expect descriptions to be fairly sparse.</p>
|
||||
|
||||
<p>At the time of writing, there is a tutorial describing the basics of Lua, as well as a number of example scripts, on the wiki <a href="https://github.com/Stranger1992/Tomb-Engine-Demo-Levels/wiki">here</a>.</p>
|
||||
|
@ -90,7 +90,7 @@ For example, to call GetMoveableByName, you would have to do:</p>
|
|||
<pre><code>local door = TEN.Objects.GetMoveableByName("door_type4_14")
|
||||
</code></pre>
|
||||
<p>To save on typing, you can put the following at the start of a Lua file:</p>
|
||||
<pre><code>local Util = require("Util")
|
||||
<pre><code>local Util = require("Engine.Util")
|
||||
Util.ShortenTENCalls()
|
||||
</code></pre>
|
||||
<p>This will put the modules and classes in the global table. In other words, it means you can do the following:</p>
|
||||
|
@ -248,7 +248,7 @@ Util.ShortenTENCalls()
|
|||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||
<i style="float:right;">Last updated 2022-08-14 20:33:42 </i>
|
||||
<i style="float:right;">Last updated 2022-09-07 20:56:06 </i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
-----
|
||||
--- Event sequence - a chain of functions to call at specified times, modeled after TRNG's organizers.
|
||||
--
|
||||
-- Works atop the Timer, and so is updated automatically pre-OnControlPhase, and saved automatically when the game is saved.
|
||||
--
|
||||
-- Example usage:
|
||||
-- local EventSequence = require("EventSequence")
|
||||
-- local EventSequence = require("Engine.EventSequence")
|
||||
--
|
||||
-- -- These will be called by the sequence
|
||||
-- LevelFuncs.HealLara = function()
|
||||
|
@ -23,34 +26,30 @@
|
|||
-- false, -- does not loop
|
||||
-- {seconds = true, deciseconds = true}, -- timer format, see Timer for details
|
||||
-- 6, -- seconds until call the function specified in next arg
|
||||
-- "HealLara", -- first function to call. If we don't need to pass any arguments, we can just give the func name as a string
|
||||
-- LevelFuncs.HealLara, -- first function to call. If we don't need to pass any arguments, we can just pass the function
|
||||
-- 2.1, -- seconds until the next function, after the previous one has been called
|
||||
-- {"SpawnBaddy", TEN.Objects.ObjID.BADDY1, "steve", posSteve}, -- if we DO want to pass arguments to the function to be called, we give a table with the name of the function ("SpawnBaddy" in this case) followed by the args to pass to it
|
||||
-- {LevelFuncs.SpawnBaddy, TEN.Objects.ObjID.BADDY1, "steve", posSteve}, -- if we DO want to pass arguments to the function to be called, we give a table with the function (LevelFuncs.SpawnBaddy in this case) followed by the args to pass to it
|
||||
-- 0.5,
|
||||
-- {"SpawnBaddy", TEN.Objects.ObjID.SAS_CAIRO, "chris", posChris},
|
||||
-- {LevelFuncs.SpawnBaddy, TEN.Objects.ObjID.SAS_CAIRO, "chris", posChris},
|
||||
-- 1,
|
||||
-- "HealLara")
|
||||
-- LevelFuncs.HealLara)
|
||||
--
|
||||
-- -- event sequences are inactive to begin with and so need to be started
|
||||
-- mySeq:Start()
|
||||
-- end
|
||||
--
|
||||
-- -- EventSequence runs on Timer, so this call is required
|
||||
-- LevelFuncs.OnControlPhase = function(dt)
|
||||
-- Timer.UpdateAll(dt)
|
||||
-- end
|
||||
--
|
||||
-- @luautil EventSequence
|
||||
|
||||
local Timer = require("Timer")
|
||||
|
||||
local EventSequence
|
||||
|
||||
LevelVars.__TEN_eventSequence = {sequences = {}}
|
||||
LevelFuncs.Engine.EventSequence = {}
|
||||
LevelVars.Engine.EventSequence = {sequences = {}}
|
||||
|
||||
LevelFuncs.__TEN_eventSequence_callNext = function(sequenceName, nextTimerName, func, ...)
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[sequenceName]
|
||||
LevelFuncs[func](...)
|
||||
LevelFuncs.Engine.EventSequence.CallNext = function(sequenceName, nextTimerName, func, ...)
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[sequenceName]
|
||||
func(...)
|
||||
|
||||
thisES.currentTimer = thisES.currentTimer + 1
|
||||
if thisES.currentTimer <= #thisES.timers then
|
||||
|
@ -82,9 +81,8 @@ EventSequence = {
|
|||
setmetatable(obj, mt)
|
||||
|
||||
obj.name = name
|
||||
|
||||
LevelVars.__TEN_eventSequence.sequences[name] = {}
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[name]
|
||||
LevelVars.Engine.EventSequence.sequences[name] = {}
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[name]
|
||||
thisES.name = name
|
||||
thisES.timesFuncsAndArgs = {...}
|
||||
thisES.loop = loop
|
||||
|
@ -99,7 +97,6 @@ EventSequence = {
|
|||
local nextTimer = i + 2
|
||||
local timerIndex = #thisES.timers + 1
|
||||
|
||||
local funcName = "__TEN_eventSequence_" .. name .. "_func" .. timerIndex
|
||||
local timerName = "__TEN_eventSequence_" .. name .. "_timer" .. timerIndex
|
||||
local nextTimerName = "__TEN_eventSequence_" .. name .. "_timer" .. timerIndex + 1
|
||||
|
||||
|
@ -110,7 +107,7 @@ EventSequence = {
|
|||
thisES.firstTimerName = timerName
|
||||
end
|
||||
|
||||
if type(funcAndArgs) == "string" then
|
||||
if type(funcAndArgs) == "userdata" then
|
||||
-- we only have a function
|
||||
func = funcAndArgs
|
||||
funcAndArgs = {}
|
||||
|
@ -123,7 +120,7 @@ EventSequence = {
|
|||
tfa[i], -- time
|
||||
false,
|
||||
timerFormat,
|
||||
"__TEN_eventSequence_callNext",
|
||||
LevelFuncs.Engine.EventSequence.CallNext,
|
||||
name,
|
||||
nextTimerName,
|
||||
func,
|
||||
|
@ -140,7 +137,7 @@ EventSequence = {
|
|||
-- @string name The label that was given to the sequence when it was created
|
||||
-- @return The sequence
|
||||
Get = function(name)
|
||||
if LevelVars.__TEN_eventSequence.sequences[name] then
|
||||
if LevelVars.Engine.EventSequence.sequences[name] then
|
||||
local obj = {}
|
||||
local mt = {}
|
||||
mt.__index = EventSequence
|
||||
|
@ -155,7 +152,7 @@ EventSequence = {
|
|||
-- @function mySequence:SetPaused
|
||||
-- @bool p if true, the sequence will be paused; if false, it will be unpaused
|
||||
SetPaused = function(t, p)
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[t.name]
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[t.name]
|
||||
Timer.Get(thisES.timers[thisES.currentTimer]):SetPaused(p)
|
||||
end;
|
||||
|
||||
|
@ -163,21 +160,21 @@ EventSequence = {
|
|||
-- @function mySequence:IsPaused
|
||||
-- @return true if the timer is paused, false if otherwise
|
||||
IsPaused = function(t)
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[t.name]
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[t.name]
|
||||
return Timer.Get(thisES.timers[thisES.currentTimer]):IsPaused()
|
||||
end;
|
||||
|
||||
--- Begin or unpause a sequence. If showing the remaining time on-screen, its color will be set to white.
|
||||
-- @function mySequence:Start
|
||||
Start = function(t)
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[t.name]
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[t.name]
|
||||
Timer.Get(thisES.timers[thisES.currentTimer]):Start()
|
||||
end;
|
||||
|
||||
--- Stop the sequence.
|
||||
--@function mySequence:Stop
|
||||
Stop = function(t)
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[t.name]
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[t.name]
|
||||
Timer.Get(thisES.timers[thisES.currentTimer]):Stop()
|
||||
end;
|
||||
|
||||
|
@ -185,7 +182,7 @@ EventSequence = {
|
|||
-- @function mySequence:IsActive
|
||||
-- @return true if the sequence is active, false if otherwise
|
||||
IsActive = function(t)
|
||||
local thisES = LevelVars.__TEN_eventSequence.sequences[t.name]
|
||||
local thisES = LevelVars.Engine.EventSequence.sequences[t.name]
|
||||
return Timer.Get(thisES.timers[thisES.currentTimer]):IsActive()
|
||||
end;
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
-----
|
||||
--- Basic timer - after a specified number of seconds, the specified thing happens.
|
||||
--
|
||||
-- Timers are updated automatically every frame before OnControlPhase.
|
||||
--
|
||||
-- Example usage:
|
||||
-- local Timer = require("Timer")
|
||||
-- local Timer = require("Engine.Timer")
|
||||
--
|
||||
-- -- This will be called when the timer runs out
|
||||
-- LevelFuncs.FinishTimer = function(healthWhenStarted, victoryMessage)
|
||||
|
@ -15,19 +18,16 @@
|
|||
-- 5.0,
|
||||
-- false,
|
||||
-- {minutes = false, seconds = true, deciseconds = true},
|
||||
-- "FinishTimer",
|
||||
-- LevelFuncs.FinishTimer,
|
||||
-- Lara:GetHP(),
|
||||
-- "Well done!")
|
||||
-- myTimer:Start()
|
||||
-- end
|
||||
--
|
||||
-- LevelFuncs.OnControlPhase = function(dt)
|
||||
-- Timer.UpdateAll(dt)
|
||||
-- end
|
||||
--
|
||||
-- @luautil Timer
|
||||
|
||||
LevelVars.__TEN_timer = {timers = {}}
|
||||
LevelFuncs.Engine.Timer = {}
|
||||
LevelVars.Engine.Timer = {timers = {}}
|
||||
|
||||
local Timer
|
||||
|
||||
|
@ -35,6 +35,7 @@ local unpausedColor = TEN.Color(255, 255, 255)
|
|||
local pausedColor = TEN.Color(255, 255, 0)
|
||||
local str = TEN.Strings.DisplayString("TIMER", 0, 0, unpausedColor, false, {TEN.Strings.DisplayStringOption.CENTER, TEN.Strings.DisplayStringOption.SHADOW} )
|
||||
|
||||
|
||||
Timer = {
|
||||
--- Create (but do not start) a new timer.
|
||||
--
|
||||
|
@ -56,13 +57,15 @@ Timer = {
|
|||
--
|
||||
--__At any given time, only one timer can show its countdown__.
|
||||
--
|
||||
--__Do not give your timers a name beginning with __TEN, as this is reserved for timers used by other internal libaries__.
|
||||
--
|
||||
--Use this sparingly; in the classics, timed challenges did not have visible countdowns. For shorter timers, the gameplay benefit from showing the remaining time might not be necessary, and could interfere with the atmosphere of the level.
|
||||
--
|
||||
-- @string name A label to give this timer; used to retrieve the timer later
|
||||
-- @number totalTime The duration of the timer, in seconds
|
||||
-- @bool loop if true, the timer will start again immediately after the time has elapsed
|
||||
-- @tparam ?table|bool timerFormat If a table is given, the remaining time will be shown as a string, formatted according to the values in the table. If true, the remaining seconds, rounded up, will show at the bottom of the screen. If false, the remaining time will not be shown on screen.
|
||||
-- @string func The name of the LevelFunc member to call when the time is upssss
|
||||
-- @function func The LevelFunc function to call when the time is up
|
||||
-- @param[opt] ... a variable number of arguments with which the above function will be called
|
||||
-- @return The timer in its paused state
|
||||
--
|
||||
|
@ -73,8 +76,13 @@ Timer = {
|
|||
setmetatable(obj, mt)
|
||||
|
||||
obj.name = name
|
||||
LevelVars.__TEN_timer.timers[name] ={}
|
||||
local thisTimer = LevelVars.__TEN_timer.timers[name]
|
||||
|
||||
if LevelVars.Engine.Timer.timers[name] then
|
||||
print("Warning: a timer with name " .. name .. " already exists.")
|
||||
end
|
||||
|
||||
LevelVars.Engine.Timer.timers[name] ={}
|
||||
local thisTimer = LevelVars.Engine.Timer.timers[name]
|
||||
thisTimer.name = name
|
||||
thisTimer.totalTime = totalTime
|
||||
thisTimer.remainingTime = totalTime
|
||||
|
@ -95,7 +103,7 @@ Timer = {
|
|||
-- @string name The label that was given to the timer when it was created
|
||||
-- @return The timer
|
||||
Get = function(name)
|
||||
if LevelVars.__TEN_timer.timers[name] then
|
||||
if LevelVars.Engine.Timer.timers[name] then
|
||||
local obj = {}
|
||||
local mt = {}
|
||||
mt.__index = Timer
|
||||
|
@ -112,8 +120,7 @@ Timer = {
|
|||
t.remainingTime = t.remainingTime - dt
|
||||
|
||||
if t.remainingTime <= 0 then
|
||||
LevelFuncs[t.func](table.unpack(t.funcArgs))
|
||||
|
||||
t.func(table.unpack(t.funcArgs))
|
||||
if not t.loop then
|
||||
t.active = false
|
||||
else
|
||||
|
@ -190,21 +197,16 @@ Timer = {
|
|||
end
|
||||
end;
|
||||
|
||||
--- Update all active timers.
|
||||
-- Should be called in LevelFuncs.OnControlPhase
|
||||
-- @number dt The time in seconds since the last frame
|
||||
UpdateAll = function(dt)
|
||||
for _, t in pairs(LevelVars.__TEN_timer.timers) do
|
||||
Timer.Update(t, dt)
|
||||
end
|
||||
print("Timer.UpdateAll is deprecated; timers and event sequences now get updated automatically pre-control phase.")
|
||||
end;
|
||||
|
||||
--- Give the timer a new function and args
|
||||
-- @function myTimer:SetFunction
|
||||
-- @string func The name of the LevelFunc member to call when the time is up
|
||||
-- @tparam function func The LevelFunc member to call when the time is up
|
||||
-- @param[opt] ... a variable number of arguments with which the above function will be called
|
||||
SetFunction = function(t, func, ...)
|
||||
local thisTimer = LevelVars.__TEN_timer.timers[t.name]
|
||||
local thisTimer = LevelVars.Engine.Timer.timers[t.name]
|
||||
thisTimer.func = func
|
||||
thisTimer.funcArgs = {...}
|
||||
end;
|
||||
|
@ -212,7 +214,7 @@ Timer = {
|
|||
--- Begin or unpause a timer. If showing the remaining time on-screen, its color will be set to white.
|
||||
-- @function myTimer:Start
|
||||
Start = function(t)
|
||||
local thisTimer = LevelVars.__TEN_timer.timers[t.name]
|
||||
local thisTimer = LevelVars.Engine.Timer.timers[t.name]
|
||||
if not thisTimer.active then
|
||||
thisTimer.active = true
|
||||
end
|
||||
|
@ -227,21 +229,21 @@ Timer = {
|
|||
--- Stop the timer.
|
||||
-- @function myTimer:Stop
|
||||
Stop = function(t)
|
||||
LevelVars.__TEN_timer.timers[t.name].active = false
|
||||
LevelVars.Engine.Timer.timers[t.name].active = false
|
||||
end;
|
||||
|
||||
--- Get whether or not the timer is active
|
||||
-- @function myTimer:IsActive
|
||||
-- @return true if the timer is active, false if otherwise
|
||||
IsActive = function(t)
|
||||
return LevelVars.__TEN_timer.timers[t.name].active
|
||||
return LevelVars.Engine.Timer.timers[t.name].active
|
||||
end;
|
||||
|
||||
--- Pause or unpause the timer. If showing the remaining time on-screen, its color will be set to yellow (paused) or white (unpaused).
|
||||
-- @function myTimer:SetPaused
|
||||
-- @bool p if true, the timer will be paused; if false, it would be unpaused
|
||||
SetPaused = function(t, p)
|
||||
local thisTimer = LevelVars.__TEN_timer.timers[t.name]
|
||||
local thisTimer = LevelVars.Engine.Timer.timers[t.name]
|
||||
thisTimer.paused = p
|
||||
if thisTimer.timerFormat then
|
||||
if p then
|
||||
|
@ -256,21 +258,21 @@ Timer = {
|
|||
-- @function myTimer:IsPaused
|
||||
-- @return true if the timer is paused, false if otherwise
|
||||
IsPaused = function(t)
|
||||
return LevelVars.__TEN_timer.timers[t.name].paused
|
||||
return LevelVars.Engine.Timer.timers[t.name].paused
|
||||
end;
|
||||
|
||||
--- Get the remaining time for a timer.
|
||||
-- @function myTimer:GetRemainingTime
|
||||
-- @return the time in seconds remaining on the clock
|
||||
GetRemainingTime = function(t)
|
||||
return LevelVars.__TEN_timer.timers[t.name].remainingTime
|
||||
return LevelVars.Engine.Timer.timers[t.name].remainingTime
|
||||
end;
|
||||
|
||||
--- Set the remaining time for a timer
|
||||
-- @function myTimer:SetRemainingTime
|
||||
-- @number remainingTime the new time remaining for the timer
|
||||
SetRemainingTime = function(t, remainingTime)
|
||||
LevelVars.__TEN_timer.timers[t.name].remainingTime = remainingTime
|
||||
LevelVars.Engine.Timer.timers[t.name].remainingTime = remainingTime
|
||||
end;
|
||||
|
||||
--- Get the total time for a timer.
|
||||
|
@ -278,23 +280,31 @@ Timer = {
|
|||
-- @function myTimer:GetRemainingTime
|
||||
-- @return the timer's total time
|
||||
GetTotalTime = function(t)
|
||||
return LevelVars.__TEN_timer.timers[t.name].totalTime
|
||||
return LevelVars.Engine.Timer.timers[t.name].totalTime
|
||||
end;
|
||||
|
||||
--- Set the total time for a timer
|
||||
-- @function myTimer:SetTotalTime
|
||||
-- @number totalTime timer's new total time
|
||||
SetTotalTime = function(t, totalTime)
|
||||
LevelVars.__TEN_timer.timers[t.name].totalTime = totalTime
|
||||
LevelVars.Engine.Timer.timers[t.name].totalTime = totalTime
|
||||
end;
|
||||
|
||||
--- Set whether or not the timer loops
|
||||
-- @function myTimer:SetLooping
|
||||
-- @bool looping whether or not the timer loops
|
||||
SetLooping = function(t, looping)
|
||||
LevelVars.__TEN_timer.timers[t.name].loop = looping
|
||||
LevelVars.Engine.Timer.timers[t.name].loop = looping
|
||||
end;
|
||||
}
|
||||
|
||||
LevelFuncs.Engine.Timer.UpdateAll = function(dt)
|
||||
for _, t in pairs(LevelVars.Engine.Timer.timers) do
|
||||
Timer.Update(t, dt)
|
||||
end
|
||||
end
|
||||
|
||||
TEN.Logic.AddCallback(TEN.Logic.CallbackPoint.PRECONTROLPHASE, LevelFuncs.Engine.Timer.UpdateAll)
|
||||
|
||||
return Timer
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
-- New level script file.
|
||||
-- To include other script files, you can use require("filename") command.
|
||||
|
||||
local Util = require("Util")
|
||||
local Util = require("Engine.Util")
|
||||
Util.ShortenTENCalls()
|
||||
|
||||
-- Called when entering a level, either after leveljump, new game or loading game
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
-- Title script file
|
||||
|
||||
local Util = require("Util")
|
||||
local Util = require("Engine.Util")
|
||||
Util.ShortenTENCalls()
|
||||
|
||||
LevelFuncs.OnLoad = function() end
|
||||
LevelFuncs.OnSave = function() end
|
||||
LevelFuncs.OnEnd = function() end
|
||||
|
||||
LevelFuncs.OnControlPhase = function() end
|
||||
LevelFuncs.OnStart = function() end
|
||||
LevelFuncs.OnControlPhase = function(dt) end
|
||||
|
|
|
@ -570,7 +570,9 @@ void LaraGun(ItemInfo* laraItem)
|
|||
{
|
||||
if (!GetAmmo(laraItem, lara->Control.Weapon.GunType))
|
||||
{
|
||||
lara->Control.Weapon.RequestGunType = Objects[ID_PISTOLS_ITEM].loaded ? LaraWeaponType::Pistol : LaraWeaponType::None;
|
||||
bool hasPistols = lara->Weapons[(int)LaraWeaponType::Pistol].Present && Objects[ID_PISTOLS_ITEM].loaded;
|
||||
|
||||
lara->Control.Weapon.RequestGunType = hasPistols ? LaraWeaponType::Pistol : LaraWeaponType::None;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1186,7 +1188,7 @@ HolsterSlot HolsterSlotForWeapon(LaraWeaponType weaponType)
|
|||
return HolsterSlot::Harpoon;
|
||||
|
||||
case LaraWeaponType::Crossbow:
|
||||
return HolsterSlot::Crowssbow;
|
||||
return HolsterSlot::Crossbow;
|
||||
|
||||
case LaraWeaponType::GrenadeLauncher:
|
||||
return HolsterSlot::GrenadeLauncher;
|
||||
|
|
|
@ -436,8 +436,12 @@ void UndrawShotgunMeshes(ItemInfo* laraItem, LaraWeaponType weaponType)
|
|||
{
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
lara->Control.Weapon.HolsterInfo.BackHolster = HolsterSlotForWeapon(weaponType);
|
||||
lara->MeshPtrs[LM_RHAND] = Objects[ID_LARA_SKIN].meshIndex + LM_RHAND;
|
||||
|
||||
if (lara->Weapons[(int)weaponType].Present)
|
||||
lara->Control.Weapon.HolsterInfo.BackHolster = HolsterSlotForWeapon(weaponType);
|
||||
else
|
||||
lara->Control.Weapon.HolsterInfo.BackHolster = HolsterSlot::Empty;
|
||||
}
|
||||
|
||||
void FireHarpoon(ItemInfo* laraItem)
|
||||
|
@ -621,10 +625,6 @@ void HarpoonBoltControl(short itemNumber)
|
|||
auto pos = PHD_3DPOS(currentMesh->pos.Position.x, currentMesh->pos.Position.y - 128, currentMesh->pos.Position.z, 0, currentMesh->pos.Orientation.y, 0);
|
||||
TriggerShockwave(&pos, 40, 176, 64, 0, 96, 128, 16, 0, 0);
|
||||
ShatterObject(nullptr, currentMesh, -128, item->RoomNumber, 0);
|
||||
SmashedMeshRoom[SmashedMeshCount] = item->RoomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = currentMesh;
|
||||
SmashedMeshCount++;
|
||||
currentMesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1009,10 +1009,6 @@ void GrenadeControl(short itemNumber)
|
|||
auto pos = PHD_3DPOS(currentMesh->pos.Position.x, currentMesh->pos.Position.y - 128, currentMesh->pos.Position.z, 0, currentMesh->pos.Orientation.y, 0);
|
||||
TriggerShockwave(&pos, 40, 176, 64, 0, 96, 128, 16, 0, 0);
|
||||
ShatterObject(nullptr, currentMesh, -128, item->RoomNumber, 0);
|
||||
SmashedMeshRoom[SmashedMeshCount] = item->RoomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = currentMesh;
|
||||
SmashedMeshCount++;
|
||||
currentMesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1316,10 +1312,6 @@ void RocketControl(short itemNumber)
|
|||
auto pose = PHD_3DPOS(currentMesh->pos.Position.x, currentMesh->pos.Position.y - 128, currentMesh->pos.Position.z, 0, currentMesh->pos.Orientation.y, 0);
|
||||
TriggerShockwave(&pose, 40, 176, 64, 0, 96, 128, 16, 0, 0);
|
||||
ShatterObject(nullptr, currentMesh, -128, item->RoomNumber, 0);
|
||||
SmashedMeshRoom[SmashedMeshCount] = item->RoomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = currentMesh;
|
||||
SmashedMeshCount++;
|
||||
currentMesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1598,13 +1590,7 @@ void CrossbowBoltControl(short itemNumber)
|
|||
{
|
||||
currentMesh->HitPoints -= Weapons[(int)LaraWeaponType::Crossbow].Damage;
|
||||
if (currentMesh->HitPoints <= 0)
|
||||
{
|
||||
ShatterObject(nullptr, currentMesh, -128, item->RoomNumber, 0);
|
||||
SmashedMeshRoom[SmashedMeshCount] = item->RoomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = currentMesh;
|
||||
SmashedMeshCount++;
|
||||
currentMesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
k++;
|
||||
|
|
|
@ -891,7 +891,7 @@ enum class HolsterSlot
|
|||
Shotgun = ID_SHOTGUN_ANIM,
|
||||
HK = ID_HK_ANIM,
|
||||
Harpoon = ID_HARPOON_ANIM,
|
||||
Crowssbow = ID_CROSSBOW_ANIM,
|
||||
Crossbow = ID_CROSSBOW_ANIM,
|
||||
GrenadeLauncher = ID_GRENADE_ANIM,
|
||||
RocketLauncher = ID_ROCKET_ANIM
|
||||
};
|
||||
|
|
|
@ -490,7 +490,10 @@ void UndrawPistolMeshRight(ItemInfo* laraItem, LaraWeaponType weaponType)
|
|||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
lara->MeshPtrs[LM_RHAND] = Objects[ID_LARA_SKIN].meshIndex + LM_RHAND;
|
||||
if (lara->Weapons[(int)weaponType].Present)
|
||||
lara->Control.Weapon.HolsterInfo.RightHolster = HolsterSlotForWeapon(weaponType);
|
||||
else
|
||||
lara->Control.Weapon.HolsterInfo.RightHolster = HolsterSlot::Empty;
|
||||
}
|
||||
|
||||
void UndrawPistolMeshLeft(ItemInfo* laraItem, LaraWeaponType weaponType)
|
||||
|
@ -500,6 +503,10 @@ void UndrawPistolMeshLeft(ItemInfo* laraItem, LaraWeaponType weaponType)
|
|||
if (weaponType != LaraWeaponType::Revolver)
|
||||
{
|
||||
lara->MeshPtrs[LM_LHAND] = Objects[ID_LARA_SKIN].meshIndex + LM_LHAND;
|
||||
|
||||
if (lara->Weapons[(int)weaponType].Present)
|
||||
lara->Control.Weapon.HolsterInfo.LeftHolster = HolsterSlotForWeapon(weaponType);
|
||||
else
|
||||
lara->Control.Weapon.HolsterInfo.LeftHolster = HolsterSlot::Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -476,8 +476,10 @@ BOUNDING_BOX* GetBoundsAccurate(ItemInfo* item)
|
|||
InterpolatedBounds.Y2 = framePtr[0]->boundingBox.Y2 + (framePtr[1]->boundingBox.Y2 - framePtr[0]->boundingBox.Y2) * frac / rate;
|
||||
InterpolatedBounds.Z1 = framePtr[0]->boundingBox.Z1 + (framePtr[1]->boundingBox.Z1 - framePtr[0]->boundingBox.Z1) * frac / rate;
|
||||
InterpolatedBounds.Z2 = framePtr[0]->boundingBox.Z2 + (framePtr[1]->boundingBox.Z2 - framePtr[0]->boundingBox.Z2) * frac / rate;
|
||||
{
|
||||
return &InterpolatedBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ANIM_FRAME* GetBestFrame(ItemInfo* item)
|
||||
|
|
|
@ -271,10 +271,10 @@ bool TestWithGlobalCollisionBounds(ItemInfo* item, ItemInfo* laraItem, Collision
|
|||
{
|
||||
auto* framePtr = GetBestFrame(laraItem);
|
||||
|
||||
if (item->Pose.Position.y + GlobalCollisionBounds.Y2 <= laraItem->Pose.Position.y + framePtr->boundingBox.Y1)
|
||||
if ((item->Pose.Position.y + GlobalCollisionBounds.Y2) <= (laraItem->Pose.Position.y + framePtr->boundingBox.Y1))
|
||||
return false;
|
||||
|
||||
if (item->Pose.Position.y + GlobalCollisionBounds.Y1 >= framePtr->boundingBox.Y2)
|
||||
if ((item->Pose.Position.y + GlobalCollisionBounds.Y1) >= framePtr->boundingBox.Y2)
|
||||
return false;
|
||||
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
|
@ -286,10 +286,10 @@ bool TestWithGlobalCollisionBounds(ItemInfo* item, ItemInfo* laraItem, Collision
|
|||
int x = (dx * cosY) - (dz * sinY);
|
||||
int z = (dz * cosY) + (dx * sinY);
|
||||
|
||||
if (x < GlobalCollisionBounds.X1 - coll->Setup.Radius ||
|
||||
x > GlobalCollisionBounds.X2 + coll->Setup.Radius ||
|
||||
z < GlobalCollisionBounds.Z1 - coll->Setup.Radius ||
|
||||
z > GlobalCollisionBounds.Z2 + coll->Setup.Radius)
|
||||
if (x < (GlobalCollisionBounds.X1 - coll->Setup.Radius) ||
|
||||
x > (GlobalCollisionBounds.X2 + coll->Setup.Radius) ||
|
||||
z < (GlobalCollisionBounds.Z1 - coll->Setup.Radius) ||
|
||||
z > (GlobalCollisionBounds.Z2 + coll->Setup.Radius))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (phd_Distance(&item->Pose, &item2->Pose) < COLLISION_CHECK_DISTANCE)
|
||||
if (Vector3Int::Distance(item->Pose.Position, item2->Pose.Position) < COLLISION_CHECK_DISTANCE)
|
||||
{
|
||||
auto box = TO_DX_BBOX(item2->Pose, GetBoundsAccurate(item2));
|
||||
float distance;
|
||||
|
@ -346,16 +346,14 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
|
|||
itemNumber = item2->NextItem;
|
||||
}
|
||||
|
||||
for (int j = 0; j < g_Level.Rooms[i].mesh.size(); j++)
|
||||
for (auto& mesh : g_Level.Rooms[i].mesh)
|
||||
{
|
||||
auto* mesh = &g_Level.Rooms[i].mesh[j];
|
||||
|
||||
if (!(mesh->flags & StaticMeshFlags::SM_VISIBLE))
|
||||
if (!(mesh.flags & StaticMeshFlags::SM_VISIBLE))
|
||||
continue;
|
||||
|
||||
if (phd_Distance(&item->Pose, &mesh->pos) < COLLISION_CHECK_DISTANCE)
|
||||
if (phd_Distance(&item->Pose, &mesh.pos) < COLLISION_CHECK_DISTANCE)
|
||||
{
|
||||
auto box = TO_DX_BBOX(mesh->pos, GetBoundsAccurate(mesh, false));
|
||||
auto box = TO_DX_BBOX(mesh.pos, GetBoundsAccurate(&mesh, false));
|
||||
float distance;
|
||||
|
||||
if (box.Intersects(origin, direction, distance) && distance < coll->Setup.Radius * 2)
|
||||
|
@ -453,7 +451,7 @@ bool MoveLaraPosition(Vector3Int* offset, ItemInfo* item, ItemInfo* laraItem)
|
|||
{
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
Matrix matrix = Matrix::CreateFromYawPitchRoll(
|
||||
auto matrix = Matrix::CreateFromYawPitchRoll(
|
||||
TO_RAD(item->Pose.Orientation.y),
|
||||
TO_RAD(item->Pose.Orientation.x),
|
||||
TO_RAD(item->Pose.Orientation.z)
|
||||
|
@ -491,12 +489,12 @@ static bool ItemInRange(int x, int z, int radius)
|
|||
return ((SQUARE(x) + SQUARE(z)) <= SQUARE(radius));
|
||||
}
|
||||
|
||||
bool ItemNearLara(PHD_3DPOS* pos, int radius)
|
||||
bool ItemNearLara(Vector3Int* origin, int radius)
|
||||
{
|
||||
auto target = GameVector(
|
||||
pos->Position.x - LaraItem->Pose.Position.x,
|
||||
pos->Position.y - LaraItem->Pose.Position.y,
|
||||
pos->Position.z - LaraItem->Pose.Position.z
|
||||
origin->x - LaraItem->Pose.Position.x,
|
||||
origin->y - LaraItem->Pose.Position.y,
|
||||
origin->z - LaraItem->Pose.Position.z
|
||||
);
|
||||
|
||||
if (!ItemCollide(target.y, ITEM_RADIUS_YMAX))
|
||||
|
@ -515,9 +513,9 @@ bool ItemNearLara(PHD_3DPOS* pos, int radius)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ItemNearTarget(PHD_3DPOS* origin, ItemInfo* target, int radius)
|
||||
bool ItemNearTarget(Vector3Int* origin, ItemInfo* targetEntity, int radius)
|
||||
{
|
||||
auto pos = origin->Position - target->Pose.Position;
|
||||
auto pos = *origin - targetEntity->Pose.Position;
|
||||
|
||||
if (!ItemCollide(pos.y, ITEM_RADIUS_YMAX))
|
||||
return false;
|
||||
|
@ -528,31 +526,31 @@ bool ItemNearTarget(PHD_3DPOS* origin, ItemInfo* target, int radius)
|
|||
if (!ItemInRange(pos.x, pos.z, radius))
|
||||
return false;
|
||||
|
||||
auto* bounds = GetBoundsAccurate(target);
|
||||
auto* bounds = GetBoundsAccurate(targetEntity);
|
||||
if (pos.y >= bounds->Y1 && pos.y <= bounds->Y2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Move3DPosTo3DPos(PHD_3DPOS* origin, PHD_3DPOS* target, int velocity, short angleAdd)
|
||||
bool Move3DPosTo3DPos(PHD_3DPOS* fromPose, PHD_3DPOS* toPose, int velocity, short angleAdd)
|
||||
{
|
||||
auto direction = target->Position - origin->Position;
|
||||
int distance = sqrt(SQUARE(direction.x) + SQUARE(direction.y) + SQUARE(direction.z));
|
||||
auto direction = toPose->Position - fromPose->Position;
|
||||
float distance = Vector3Int::Distance(fromPose->Position, toPose->Position);
|
||||
|
||||
if (velocity < distance)
|
||||
origin->Position += direction * velocity / distance;
|
||||
fromPose->Position += direction * (velocity / distance);
|
||||
else
|
||||
origin->Position = target->Position;
|
||||
fromPose->Position = toPose->Position;
|
||||
|
||||
if (!Lara.Control.IsMoving)
|
||||
{
|
||||
bool shouldAnimate = (distance - velocity) > (velocity * ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD);
|
||||
bool shouldAnimate = ((distance - velocity) > (velocity * ANIMATED_ALIGNMENT_FRAME_COUNT_THRESHOLD));
|
||||
|
||||
if (shouldAnimate && Lara.Control.WaterStatus != WaterStatus::Underwater)
|
||||
{
|
||||
int angle = mGetAngle(target->Position.x, target->Position.z, origin->Position.x, origin->Position.z);
|
||||
int direction = (GetQuadrant(angle) - GetQuadrant(target->Orientation.y)) & 3;
|
||||
int angle = mGetAngle(toPose->Position.x, toPose->Position.z, fromPose->Position.x, fromPose->Position.z);
|
||||
int direction = (GetQuadrant(angle) - GetQuadrant(toPose->Orientation.y)) & 3;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
|
@ -583,31 +581,31 @@ bool Move3DPosTo3DPos(PHD_3DPOS* origin, PHD_3DPOS* target, int velocity, short
|
|||
Lara.Control.Count.PositionAdjust = 0;
|
||||
}
|
||||
|
||||
short deltaAngle = target->Orientation.x - origin->Orientation.x;
|
||||
short deltaAngle = toPose->Orientation.x - fromPose->Orientation.x;
|
||||
if (deltaAngle > angleAdd)
|
||||
origin->Orientation.x += angleAdd;
|
||||
fromPose->Orientation.x += angleAdd;
|
||||
else if (deltaAngle < -angleAdd)
|
||||
origin->Orientation.x -= angleAdd;
|
||||
fromPose->Orientation.x -= angleAdd;
|
||||
else
|
||||
origin->Orientation.x = target->Orientation.x;
|
||||
fromPose->Orientation.x = toPose->Orientation.x;
|
||||
|
||||
deltaAngle = target->Orientation.y - origin->Orientation.y;
|
||||
deltaAngle = toPose->Orientation.y - fromPose->Orientation.y;
|
||||
if (deltaAngle > angleAdd)
|
||||
origin->Orientation.y += angleAdd;
|
||||
fromPose->Orientation.y += angleAdd;
|
||||
else if (deltaAngle < -angleAdd)
|
||||
origin->Orientation.y -= angleAdd;
|
||||
fromPose->Orientation.y -= angleAdd;
|
||||
else
|
||||
origin->Orientation.y = target->Orientation.y;
|
||||
fromPose->Orientation.y = toPose->Orientation.y;
|
||||
|
||||
deltaAngle = target->Orientation.z - origin->Orientation.z;
|
||||
deltaAngle = toPose->Orientation.z - fromPose->Orientation.z;
|
||||
if (deltaAngle > angleAdd)
|
||||
origin->Orientation.z += angleAdd;
|
||||
fromPose->Orientation.z += angleAdd;
|
||||
else if (deltaAngle < -angleAdd)
|
||||
origin->Orientation.z -= angleAdd;
|
||||
fromPose->Orientation.z -= angleAdd;
|
||||
else
|
||||
origin->Orientation.z = target->Orientation.z;
|
||||
fromPose->Orientation.z = toPose->Orientation.z;
|
||||
|
||||
return (origin->Position == target->Position && origin->Orientation == target->Orientation);
|
||||
return (fromPose->Position == toPose->Position && fromPose->Orientation == toPose->Orientation);
|
||||
}
|
||||
|
||||
bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius)
|
||||
|
@ -626,13 +624,13 @@ bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius)
|
|||
|
||||
int x = laraItem->Pose.Position.x - item->Pose.Position.x;
|
||||
int z = laraItem->Pose.Position.z - item->Pose.Position.z;
|
||||
int dx = (cosY * x) - (sinY * z);
|
||||
int dz = (cosY * z) + (sinY * x);
|
||||
int dx = (x * cosY) - (z * sinY);
|
||||
int dz = (z * cosY) + (x * sinY);
|
||||
|
||||
if (dx >= bounds->X1 - radius &&
|
||||
dx <= radius + bounds->X2 &&
|
||||
dz >= bounds->Z1 - radius &&
|
||||
dz <= radius + bounds->Z2)
|
||||
if (dx >= (bounds->X1 - radius) &&
|
||||
dx <= (radius + bounds->X2) &&
|
||||
dz >= (bounds->Z1 - radius) &&
|
||||
dz <= (radius + bounds->Z2))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -688,11 +686,7 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa
|
|||
int rx = (dx * cosY) - (dz * sinY);
|
||||
int rz = (dz * cosY) + (dx * sinY);
|
||||
|
||||
BOUNDING_BOX* bounds;
|
||||
if (bigPush & 2)
|
||||
bounds = &GlobalCollisionBounds;
|
||||
else
|
||||
bounds = (BOUNDING_BOX*)GetBestFrame(item);
|
||||
auto* bounds = (bigPush & 2) ? &GlobalCollisionBounds : (BOUNDING_BOX*)GetBestFrame(item);
|
||||
|
||||
int minX = bounds->X1;
|
||||
int maxX = bounds->X2;
|
||||
|
@ -729,8 +723,8 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa
|
|||
else
|
||||
rz -= bottom;
|
||||
|
||||
item2->Pose.Position.x = item->Pose.Position.x + cosY * rx + sinY * rz;
|
||||
item2->Pose.Position.z = item->Pose.Position.z + cosY * rz - sinY * rx;
|
||||
item2->Pose.Position.x = item->Pose.Position.x + (rx * cosY) + (rz * sinY);
|
||||
item2->Pose.Position.z = item->Pose.Position.z + (rz * cosY) - (rx * sinY);
|
||||
|
||||
auto* lara = item2->IsLara() ? GetLaraInfo(item2) : nullptr;
|
||||
|
||||
|
@ -755,12 +749,12 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa
|
|||
coll->Setup.LowerCeilingBound = 0;
|
||||
coll->Setup.UpperCeilingBound = MAX_HEIGHT;
|
||||
|
||||
auto facing = coll->Setup.ForwardAngle;
|
||||
auto headingAngle = coll->Setup.ForwardAngle;
|
||||
coll->Setup.ForwardAngle = phd_atan(item2->Pose.Position.z - coll->Setup.OldPosition.z, item2->Pose.Position.x - coll->Setup.OldPosition.x);
|
||||
|
||||
GetCollisionInfo(coll, item2);
|
||||
|
||||
coll->Setup.ForwardAngle = facing;
|
||||
coll->Setup.ForwardAngle = headingAngle;
|
||||
|
||||
if (coll->CollisionType == CT_NONE)
|
||||
{
|
||||
|
@ -778,8 +772,8 @@ bool ItemPushItem(ItemInfo* item, ItemInfo* item2, CollisionInfo* coll, bool spa
|
|||
// If Lara is in the process of aligning to an object, cancel it.
|
||||
if (lara != nullptr && lara->Control.Count.PositionAdjust > (LARA_POSITION_ADJUST_MAX_TIME / 6))
|
||||
{
|
||||
Lara.Control.IsMoving = false;
|
||||
Lara.Control.HandStatus = HandStatus::Free;
|
||||
lara->Control.IsMoving = false;
|
||||
lara->Control.HandStatus = HandStatus::Free;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -868,7 +862,7 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
|
|||
{
|
||||
auto* mesh = &g_Level.Rooms[i].mesh[j];
|
||||
|
||||
// Only process meshes which are visible and solid
|
||||
// Only process meshes which are visible and solid.
|
||||
if ((mesh->flags & StaticMeshFlags::SM_VISIBLE) && (mesh->flags & StaticMeshFlags::SM_SOLID))
|
||||
{
|
||||
if (phd_Distance(&item->Pose, &mesh->pos) < COLLISION_CHECK_DISTANCE)
|
||||
|
@ -882,39 +876,39 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
}
|
||||
|
||||
bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, CollisionInfo* coll)
|
||||
bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pose, CollisionInfo* coll)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Get DX static bounds in global coords
|
||||
auto staticBounds = TO_DX_BBOX(pos, box);
|
||||
// Get DX static bounds in global coordinates.
|
||||
auto staticBounds = TO_DX_BBOX(pose, box);
|
||||
|
||||
// Get local TR bounds and DX item bounds in global coords
|
||||
// Get local TR bounds and DX item bounds in global coordinates.
|
||||
auto itemBBox = GetBoundsAccurate(item);
|
||||
auto itemBounds = TO_DX_BBOX(item->Pose, itemBBox);
|
||||
|
||||
// Extend bounds a bit for visual testing
|
||||
itemBounds.Extents = itemBounds.Extents + Vector3(WALL_SIZE);
|
||||
// Extend bounds a bit for visual testing.
|
||||
itemBounds.Extents = itemBounds.Extents + Vector3(SECTOR(1));
|
||||
|
||||
// Filter out any further checks if static isn't nearby
|
||||
// Filter out any further checks if static isn't nearby.
|
||||
if (!staticBounds.Intersects(itemBounds))
|
||||
return false;
|
||||
|
||||
// Bring back extents
|
||||
itemBounds.Extents = itemBounds.Extents - Vector3(WALL_SIZE);
|
||||
// Bring back extents.
|
||||
itemBounds.Extents = itemBounds.Extents - Vector3(SECTOR(1));
|
||||
|
||||
// Draw static bounds
|
||||
// Draw static bounds.
|
||||
g_Renderer.AddDebugBox(staticBounds, Vector4(1, 0.3f, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
|
||||
|
||||
// Calculate horizontal item coll bounds according to radius
|
||||
// Calculate horizontal item collision bounds according to radius.
|
||||
BOUNDING_BOX collBox;
|
||||
collBox.X1 = -coll->Setup.Radius;
|
||||
collBox.X2 = coll->Setup.Radius;
|
||||
collBox.Z1 = -coll->Setup.Radius;
|
||||
collBox.Z2 = coll->Setup.Radius;
|
||||
|
||||
// Calculate vertical item coll bounds according to either height (land mode) or precise bounds (water mode).
|
||||
// Water mode needs special processing because height calc in original engines is inconsistent in such cases.
|
||||
// Calculate vertical item collision bounds according to either height (land mode) or precise bounds (water mode).
|
||||
// Water mode needs special processing because height calculation in original engines is inconsistent in such cases.
|
||||
if (TestEnvironment(ENV_FLAG_WATER, item))
|
||||
{
|
||||
collBox.Y1 = itemBBox->Y1;
|
||||
|
@ -926,18 +920,18 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
collBox.Y2 = 0;
|
||||
}
|
||||
|
||||
// Get and test DX item coll bounds
|
||||
// Get and test DX item collision bounds.
|
||||
auto collBounds = TO_DX_BBOX(PHD_3DPOS(item->Pose.Position), &collBox);
|
||||
bool intersects = staticBounds.Intersects(collBounds);
|
||||
|
||||
// Check if previous item horizontal position intersects bounds
|
||||
// Check if previous item horizontal position intersects bounds.
|
||||
auto oldCollBounds = TO_DX_BBOX(PHD_3DPOS(coll->Setup.OldPosition.x, item->Pose.Position.y, coll->Setup.OldPosition.z), &collBox);
|
||||
bool oldHorIntersects = staticBounds.Intersects(oldCollBounds);
|
||||
|
||||
// Draw item coll bounds
|
||||
// Draw item coll bounds.
|
||||
g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
|
||||
|
||||
// Decompose static bounds into top/bottom plane vertices
|
||||
// Decompose static bounds into top/bottom plane vertices.
|
||||
Vector3 corners[8];
|
||||
staticBounds.GetCorners(corners);
|
||||
Vector3 planeVertices[4][3] =
|
||||
|
@ -948,7 +942,7 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
{ corners[3], corners[6], corners[2] }
|
||||
};
|
||||
|
||||
// Determine collision box vertical dimensions
|
||||
// Determine collision box vertical dimensions.
|
||||
auto height = collBox.Height();
|
||||
auto center = item->Pose.Position.y - height / 2;
|
||||
|
||||
|
@ -960,24 +954,23 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Calculate ray direction
|
||||
// Calculate ray direction.
|
||||
auto mxR = Matrix::CreateFromYawPitchRoll(TO_RAD(item->Pose.Orientation.y), TO_RAD(item->Pose.Orientation.x + (ANGLE(90 * i))), 0);
|
||||
auto mxT = Matrix::CreateTranslation(Vector3::UnitY);
|
||||
auto direction = (mxT * mxR).Translation();
|
||||
|
||||
// Make a ray and do ray tests against all decomposed planes
|
||||
// Make a ray and do ray tests against all decomposed planes.
|
||||
auto ray = Ray(collBounds.Center, direction);
|
||||
|
||||
// Determine if top/bottom planes are closest ones or not
|
||||
// Determine if top/bottom planes are closest ones or not.
|
||||
for (int p = 0; p < 4; p++)
|
||||
{
|
||||
// No plane intersection, quickly discard
|
||||
// No plane intersection, quickly discard.
|
||||
float d = 0.0f;
|
||||
if (!ray.Intersects(planeVertices[p][0], planeVertices[p][1], planeVertices[p][2], d))
|
||||
continue;
|
||||
|
||||
// Process plane intersection only if distance is smaller
|
||||
// than already found minimum
|
||||
// Process plane intersection only if distance is smaller than already found minimum.
|
||||
if (d < minDistance)
|
||||
{
|
||||
closestRay = ray;
|
||||
|
@ -987,24 +980,25 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
}
|
||||
}
|
||||
|
||||
if (closestPlane != -1) // Top/bottom plane found
|
||||
// Top/bottom plane found.
|
||||
if (closestPlane != -1)
|
||||
{
|
||||
auto bottom = closestPlane >= 2;
|
||||
auto yPoint = abs((closestRay.direction * minDistance).y);
|
||||
auto distanceToVerticalPlane = height / 2 - yPoint;
|
||||
|
||||
// Correct position according to top/bottom bounds, if collided and plane is nearby
|
||||
// Correct position according to top/bottom bounds, if collided and plane is nearby.
|
||||
if (intersects && oldHorIntersects && minDistance < height)
|
||||
{
|
||||
if (bottom)
|
||||
{
|
||||
// HACK: additionally subtract 2 from bottom plane, or else false positives may occur.
|
||||
// HACK: Additionally subtract 2 from bottom plane, otherwise false positives may occur.
|
||||
item->Pose.Position.y += distanceToVerticalPlane + 2;
|
||||
coll->CollisionType = CT_TOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set collision type only if dry room (in water rooms it causes stucking)
|
||||
// Set collision type only if dry room (in water rooms the player can get stuck).
|
||||
item->Pose.Position.y -= distanceToVerticalPlane;
|
||||
coll->CollisionType = (g_Level.Rooms[item->RoomNumber].flags & 1) ? coll->CollisionType : CT_CLAMP;
|
||||
}
|
||||
|
@ -1020,29 +1014,29 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
if (!intersects)
|
||||
return false;
|
||||
|
||||
// Check if bounds still collide after top/bottom position correction
|
||||
// Check if bounds still collide after top/bottom position correction.
|
||||
if (!staticBounds.Intersects(TO_DX_BBOX(PHD_3DPOS(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z), &collBox)))
|
||||
return result;
|
||||
|
||||
// Determine identity rotation/distance
|
||||
auto distance = Vector3(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z);
|
||||
auto sinY = phd_sin(pos.Orientation.y);
|
||||
auto cosY = phd_cos(pos.Orientation.y);
|
||||
// Determine identity orientation/distance.
|
||||
auto distance = (item->Pose.Position - pose.Position).ToVector3();
|
||||
auto sinY = phd_sin(pose.Orientation.y);
|
||||
auto cosY = phd_cos(pose.Orientation.y);
|
||||
|
||||
// Rotate item to collision bounds identity
|
||||
auto x = round(distance.x * cosY - distance.z * sinY) + pos.Position.x;
|
||||
// Rotate item to collision bounds identity.
|
||||
auto x = round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x;
|
||||
auto y = item->Pose.Position.y;
|
||||
auto z = round(distance.x * sinY + distance.z * cosY) + pos.Position.z;
|
||||
auto z = round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z;
|
||||
|
||||
// Determine identity static collision bounds
|
||||
auto XMin = pos.Position.x + box->X1;
|
||||
auto XMax = pos.Position.x + box->X2;
|
||||
auto YMin = pos.Position.y + box->Y1;
|
||||
auto YMax = pos.Position.y + box->Y2;
|
||||
auto ZMin = pos.Position.z + box->Z1;
|
||||
auto ZMax = pos.Position.z + box->Z2;
|
||||
// Determine identity static collision bounds.
|
||||
auto XMin = pose.Position.x + box->X1;
|
||||
auto XMax = pose.Position.x + box->X2;
|
||||
auto YMin = pose.Position.y + box->Y1;
|
||||
auto YMax = pose.Position.y + box->Y2;
|
||||
auto ZMin = pose.Position.z + box->Z1;
|
||||
auto ZMax = pose.Position.z + box->Z2;
|
||||
|
||||
// Determine item collision bounds
|
||||
// Determine item collision bounds.
|
||||
auto inXMin = x + collBox.X1;
|
||||
auto inXMax = x + collBox.X2;
|
||||
auto inYMin = y + collBox.Y1;
|
||||
|
@ -1050,15 +1044,15 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
auto inZMin = z + collBox.Z1;
|
||||
auto inZMax = z + collBox.Z2;
|
||||
|
||||
// Don't calculate shifts if not in bounds
|
||||
// Don't calculate shifts if not in bounds.
|
||||
if (inXMax <= XMin || inXMin >= XMax ||
|
||||
inYMax <= YMin || inYMin >= YMax ||
|
||||
inZMax <= ZMin || inZMin >= ZMax)
|
||||
return result;
|
||||
|
||||
// Calculate shifts
|
||||
// Calculate shifts.
|
||||
|
||||
Vector3Int rawShift = {};
|
||||
auto rawShift = Vector3Int::Zero;
|
||||
|
||||
auto shiftLeft = inXMax - XMin;
|
||||
auto shiftRight = XMax - inXMin;
|
||||
|
@ -1076,13 +1070,13 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
else
|
||||
rawShift.z = shiftRight;
|
||||
|
||||
// Rotate previous collision position to identity
|
||||
distance = Vector3(coll->Setup.OldPosition.x, coll->Setup.OldPosition.y, coll->Setup.OldPosition.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z);
|
||||
auto ox = round(distance.x * cosY - distance.z * sinY) + pos.Position.x;
|
||||
auto oz = round(distance.x * sinY + distance.z * cosY) + pos.Position.z;
|
||||
// Rotate previous collision position to identity.
|
||||
distance = (coll->Setup.OldPosition - pose.Position).ToVector3();
|
||||
auto ox = round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x;
|
||||
auto oz = round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z;
|
||||
|
||||
// Calculate collisison type based on identity rotation
|
||||
switch (GetQuadrant(coll->Setup.ForwardAngle - pos.Orientation.y))
|
||||
// Calculate collisison type based on identity orientation.
|
||||
switch (GetQuadrant(coll->Setup.ForwardAngle - pose.Orientation.y))
|
||||
{
|
||||
case NORTH:
|
||||
if (rawShift.x > coll->Setup.Radius || rawShift.x < -coll->Setup.Radius)
|
||||
|
@ -1173,19 +1167,19 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, Collis
|
|||
break;
|
||||
}
|
||||
|
||||
// Determine final shifts rotation/distance
|
||||
distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - Vector3(pos.Position.x, pos.Position.y, pos.Position.z);
|
||||
sinY = phd_sin(-pos.Orientation.y);
|
||||
cosY = phd_cos(-pos.Orientation.y);
|
||||
// Determine final shifts orientation/distance.
|
||||
distance = Vector3(x + coll->Shift.x, y, z + coll->Shift.z) - pose.Position.ToVector3();
|
||||
sinY = phd_sin(-pose.Orientation.y);
|
||||
cosY = phd_cos(-pose.Orientation.y);
|
||||
|
||||
// Calculate final shifts rotation/distance
|
||||
coll->Shift.x = (round(distance.x * cosY - distance.z * sinY) + pos.Position.x) - item->Pose.Position.x;
|
||||
coll->Shift.z = (round(distance.x * sinY + distance.z * cosY) + pos.Position.z) - item->Pose.Position.z;
|
||||
// Calculate final shifts orientation/distance.
|
||||
coll->Shift.x = (round((distance.x * cosY) - (distance.z * sinY)) + pose.Position.x) - item->Pose.Position.x;
|
||||
coll->Shift.z = (round((distance.x * sinY) + (distance.z * cosY)) + pose.Position.z) - item->Pose.Position.z;
|
||||
|
||||
if (coll->Shift.x == 0 && coll->Shift.z == 0)
|
||||
coll->CollisionType = CT_NONE; // Paranoid
|
||||
coll->CollisionType = CT_NONE; // Paranoid.
|
||||
|
||||
// Set splat state flag if item is Lara and bounds are taller than Lara's headroom
|
||||
// Set splat state flag if item is Lara and bounds are taller than Lara's headroom.
|
||||
if (item == LaraItem && coll->CollisionType == CT_FRONT)
|
||||
coll->HitTallObject = (YMin <= inYMin + LARA_HEADROOM);
|
||||
|
||||
|
@ -1197,39 +1191,39 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
|
||||
auto prevCollResult = GetCollision(x, y, z, item->RoomNumber);
|
||||
auto collResult = GetCollision(item);
|
||||
auto prevPointProbe = GetCollision(x, y, z, item->RoomNumber);
|
||||
auto pointProbe = GetCollision(item);
|
||||
|
||||
auto* bounds = GetBoundsAccurate(item);
|
||||
int radius = bounds->Height();
|
||||
|
||||
item->Pose.Position.y += radius;
|
||||
|
||||
if (item->Pose.Position.y >= collResult.Position.Floor)
|
||||
if (item->Pose.Position.y >= pointProbe.Position.Floor)
|
||||
{
|
||||
int bs = 0;
|
||||
|
||||
if (collResult.Position.FloorSlope && prevCollResult.Position.Floor < collResult.Position.Floor)
|
||||
if (pointProbe.Position.FloorSlope && prevPointProbe.Position.Floor < pointProbe.Position.Floor)
|
||||
{
|
||||
int yAngle = (long)((unsigned short)item->Pose.Orientation.y);
|
||||
|
||||
if (collResult.FloorTilt.x < 0)
|
||||
if (pointProbe.FloorTilt.x < 0)
|
||||
{
|
||||
if (yAngle >= ANGLE(180.0f))
|
||||
bs = 1;
|
||||
}
|
||||
else if (collResult.FloorTilt.x > 0)
|
||||
else if (pointProbe.FloorTilt.x > 0)
|
||||
{
|
||||
if (yAngle <= ANGLE(180.0f))
|
||||
bs = 1;
|
||||
}
|
||||
|
||||
if (collResult.FloorTilt.y < 0)
|
||||
if (pointProbe.FloorTilt.y < 0)
|
||||
{
|
||||
if (yAngle >= ANGLE(90.0f) && yAngle <= ANGLE(270.0f))
|
||||
bs = 1;
|
||||
}
|
||||
else if (collResult.FloorTilt.y > 0)
|
||||
else if (pointProbe.FloorTilt.y > 0)
|
||||
{
|
||||
if (yAngle <= ANGLE(90.0f) || yAngle >= ANGLE(270.0f))
|
||||
bs = 1;
|
||||
|
@ -1238,7 +1232,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
|
||||
// If last position of item was also below this floor height, we've hit a wall, else we've hit a floor.
|
||||
|
||||
if (y > (collResult.Position.Floor + 32) && bs == 0 &&
|
||||
if (y > (pointProbe.Position.Floor + 32) && bs == 0 &&
|
||||
(((x / SECTOR(1)) != (item->Pose.Position.x / SECTOR(1))) ||
|
||||
((z / SECTOR(1)) != (item->Pose.Position.z / SECTOR(1)))))
|
||||
{
|
||||
|
@ -1246,8 +1240,8 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
|
||||
long xs;
|
||||
|
||||
if ((x & (~(WALL_SIZE - 1))) != (item->Pose.Position.x & (~(WALL_SIZE - 1))) && // X crossed boundary?
|
||||
(z & (~(WALL_SIZE - 1))) != (item->Pose.Position.z & (~(WALL_SIZE - 1)))) // Z crossed boundary as well?
|
||||
if ((x & (~WALL_MASK)) != (item->Pose.Position.x & (~WALL_MASK)) && // X crossed boundary?
|
||||
(z & (~WALL_MASK)) != (item->Pose.Position.z & (~WALL_MASK))) // Z crossed boundary as well?
|
||||
{
|
||||
if (abs(x - item->Pose.Position.x) < abs(z - item->Pose.Position.z))
|
||||
xs = 1; // X has travelled the shortest, so (maybe) hit first. (Seems to work ok).
|
||||
|
@ -1257,7 +1251,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
else
|
||||
xs = 1;
|
||||
|
||||
if ((x & (~(WALL_SIZE - 1))) != (item->Pose.Position.x & (~(WALL_SIZE - 1))) && xs) // X crossed boundary?
|
||||
if ((x & (~WALL_MASK)) != (item->Pose.Position.x & (~WALL_MASK)) && xs) // X crossed boundary?
|
||||
{
|
||||
// Hit angle = ANGLE(270.0f).
|
||||
if (xv <= 0)
|
||||
|
@ -1278,14 +1272,14 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
item->Pose.Position.z = z;
|
||||
}
|
||||
// Hit a steep slope?
|
||||
else if (collResult.Position.FloorSlope)
|
||||
else if (pointProbe.Position.FloorSlope)
|
||||
{
|
||||
// Need to know which direction the slope is.
|
||||
|
||||
item->Animation.Velocity.z -= (item->Animation.Velocity.z / 4);
|
||||
|
||||
// Hit angle = ANGLE(90.0f)
|
||||
if (collResult.FloorTilt.x < 0 && ((abs(collResult.FloorTilt.x)) - (abs(collResult.FloorTilt.y)) >= 2))
|
||||
if (pointProbe.FloorTilt.x < 0 && ((abs(pointProbe.FloorTilt.x)) - (abs(pointProbe.FloorTilt.y)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1297,7 +1291,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z -= collResult.FloorTilt.x * 2;
|
||||
item->Animation.Velocity.z -= pointProbe.FloorTilt.x * 2;
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(90.0f) && (unsigned short)item->Pose.Orientation.y < ANGLE(270.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1319,7 +1313,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(270.0f)
|
||||
else if (collResult.FloorTilt.x > 0 && ((abs(collResult.FloorTilt.x)) - (abs(collResult.FloorTilt.y)) >= 2))
|
||||
else if (pointProbe.FloorTilt.x > 0 && ((abs(pointProbe.FloorTilt.x)) - (abs(pointProbe.FloorTilt.y)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) < ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1331,7 +1325,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += collResult.FloorTilt.x * 2;
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.x * 2;
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(270.0f) || (unsigned short)item->Pose.Orientation.y < ANGLE(90.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1353,7 +1347,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = 0
|
||||
else if (collResult.FloorTilt.y < 0 && ((abs(collResult.FloorTilt.y)) - (abs(collResult.FloorTilt.x)) >= 2))
|
||||
else if (pointProbe.FloorTilt.y < 0 && ((abs(pointProbe.FloorTilt.y)) - (abs(pointProbe.FloorTilt.x)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(90.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(270.0f))
|
||||
{
|
||||
|
@ -1365,7 +1359,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z -= collResult.FloorTilt.y * 2;
|
||||
item->Animation.Velocity.z -= pointProbe.FloorTilt.y * 2;
|
||||
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1388,7 +1382,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(180.0f)
|
||||
else if (collResult.FloorTilt.y > 0 && ((abs(collResult.FloorTilt.y)) - (abs(collResult.FloorTilt.x)) >= 2))
|
||||
else if (pointProbe.FloorTilt.y > 0 && ((abs(pointProbe.FloorTilt.y)) - (abs(pointProbe.FloorTilt.x)) >= 2))
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(270.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(90.0f))
|
||||
{
|
||||
|
@ -1400,7 +1394,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += collResult.FloorTilt.y * 2;
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.y * 2;
|
||||
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(180.0f))
|
||||
{
|
||||
|
@ -1422,7 +1416,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
item->Animation.Velocity.y = 0;
|
||||
}
|
||||
}
|
||||
else if (collResult.FloorTilt.x < 0 && collResult.FloorTilt.y < 0) // Hit angle = 0x2000
|
||||
else if (pointProbe.FloorTilt.x < 0 && pointProbe.FloorTilt.y < 0) // Hit angle = 0x2000
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(135.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(315.0f))
|
||||
{
|
||||
|
@ -1434,7 +1428,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += -collResult.FloorTilt.x + -collResult.FloorTilt.y;
|
||||
item->Animation.Velocity.z += -pointProbe.FloorTilt.x + -pointProbe.FloorTilt.y;
|
||||
if ((unsigned short)item->Pose.Orientation.y > ANGLE(45.0f) && (unsigned short)item->Pose.Orientation.y < ANGLE(225.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1456,7 +1450,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(135.0f)
|
||||
else if (collResult.FloorTilt.x < 0 && collResult.FloorTilt.y > 0)
|
||||
else if (pointProbe.FloorTilt.x < 0 && pointProbe.FloorTilt.y > 0)
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(225.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(45.0f))
|
||||
{
|
||||
|
@ -1468,7 +1462,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += (-collResult.FloorTilt.x) + collResult.FloorTilt.y;
|
||||
item->Animation.Velocity.z += (-pointProbe.FloorTilt.x) + pointProbe.FloorTilt.y;
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(315.0f) && (unsigned short)item->Pose.Orientation.y > ANGLE(135.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1490,7 +1484,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(225.5f)
|
||||
else if (collResult.FloorTilt.x > 0 && collResult.FloorTilt.y > 0)
|
||||
else if (pointProbe.FloorTilt.x > 0 && pointProbe.FloorTilt.y > 0)
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(315.0f) || ((unsigned short)item->Pose.Orientation.y) < ANGLE(135.0f))
|
||||
{
|
||||
|
@ -1502,7 +1496,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += collResult.FloorTilt.x + collResult.FloorTilt.y;
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.x + pointProbe.FloorTilt.y;
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(45.0f) || (unsigned short)item->Pose.Orientation.y > ANGLE(225.5f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1524,7 +1518,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
// Hit angle = ANGLE(315.0f)
|
||||
else if (collResult.FloorTilt.x > 0 && collResult.FloorTilt.y < 0)
|
||||
else if (pointProbe.FloorTilt.x > 0 && pointProbe.FloorTilt.y < 0)
|
||||
{
|
||||
if (((unsigned short)item->Pose.Orientation.y) > ANGLE(45.0f) && ((unsigned short)item->Pose.Orientation.y) < ANGLE(225.5f))
|
||||
{
|
||||
|
@ -1536,7 +1530,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (item->Animation.Velocity.z < 32)
|
||||
{
|
||||
item->Animation.Velocity.z += collResult.FloorTilt.x + (-collResult.FloorTilt.y);
|
||||
item->Animation.Velocity.z += pointProbe.FloorTilt.x + (-pointProbe.FloorTilt.y);
|
||||
if ((unsigned short)item->Pose.Orientation.y < ANGLE(135.0f) || (unsigned short)item->Pose.Orientation.y > ANGLE(315.0f))
|
||||
{
|
||||
item->Pose.Orientation.y -= ANGLE(22.5f);
|
||||
|
@ -1558,7 +1552,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
// Put item back in its last position.
|
||||
// Move item back to its previous position.
|
||||
item->Pose.Position.x = x;
|
||||
item->Pose.Position.y = y;
|
||||
item->Pose.Position.z = z;
|
||||
|
@ -1597,7 +1591,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
item->Pose.Position.y = collResult.Position.Floor;
|
||||
item->Pose.Position.y = pointProbe.Position.Floor;
|
||||
}
|
||||
}
|
||||
// Check for on top of object.
|
||||
|
@ -1605,8 +1599,8 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
{
|
||||
if (yv >= 0)
|
||||
{
|
||||
prevCollResult = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber);
|
||||
collResult = GetCollision(item);
|
||||
prevPointProbe = GetCollision(item->Pose.Position.x, y, item->Pose.Position.z, item->RoomNumber);
|
||||
pointProbe = GetCollision(item);
|
||||
|
||||
// Bounce off floor.
|
||||
|
||||
|
@ -1614,7 +1608,7 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
// was always set to 0 by GetHeight() function which was called before the check.
|
||||
// Possibly a mistake or unfinished feature by Core? -- Lwmte, 27.08.21
|
||||
|
||||
if (item->Pose.Position.y >= prevCollResult.Position.Floor)
|
||||
if (item->Pose.Position.y >= prevPointProbe.Position.Floor)
|
||||
{
|
||||
// Hit the floor; bounce and slow down.
|
||||
if (item->Animation.Velocity.y > 0)
|
||||
|
@ -1648,17 +1642,17 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
item->Pose.Position.y = prevCollResult.Position.Floor;
|
||||
item->Pose.Position.y = prevPointProbe.Position.Floor;
|
||||
}
|
||||
}
|
||||
// else
|
||||
{
|
||||
// Bounce off ceiling.
|
||||
collResult = GetCollision(item);
|
||||
pointProbe = GetCollision(item);
|
||||
|
||||
if (item->Pose.Position.y < collResult.Position.Ceiling)
|
||||
if (item->Pose.Position.y < pointProbe.Position.Ceiling)
|
||||
{
|
||||
if (y < collResult.Position.Ceiling &&
|
||||
if (y < pointProbe.Position.Ceiling &&
|
||||
(((x / SECTOR(1)) != (item->Pose.Position.x / SECTOR(1))) ||
|
||||
((z / SECTOR(1)) != (item->Pose.Position.z / SECTOR(1)))))
|
||||
{
|
||||
|
@ -1681,13 +1675,13 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
else
|
||||
item->Animation.Velocity.z /= 2;
|
||||
|
||||
// Put item back in its last position.
|
||||
// Move item back to its previous position.
|
||||
item->Pose.Position.x = x;
|
||||
item->Pose.Position.y = y;
|
||||
item->Pose.Position.z = z;
|
||||
}
|
||||
else
|
||||
item->Pose.Position.y = collResult.Position.Ceiling;
|
||||
item->Pose.Position.y = pointProbe.Position.Ceiling;
|
||||
|
||||
if (item->Animation.Velocity.y < 0)
|
||||
item->Animation.Velocity.y = -item->Animation.Velocity.y;
|
||||
|
@ -1695,14 +1689,14 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
|||
}
|
||||
}
|
||||
|
||||
collResult = GetCollision(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber);
|
||||
pointProbe = GetCollision(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber);
|
||||
|
||||
if (collResult.RoomNumber != item->RoomNumber)
|
||||
if (pointProbe.RoomNumber != item->RoomNumber)
|
||||
{
|
||||
if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, collResult.RoomNumber))
|
||||
if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, pointProbe.RoomNumber))
|
||||
Splash(item);
|
||||
|
||||
ItemNewRoom(itemNumber, collResult.RoomNumber);
|
||||
ItemNewRoom(itemNumber, pointProbe.RoomNumber);
|
||||
}
|
||||
|
||||
item->Pose.Position.y -= radius;
|
||||
|
@ -1791,8 +1785,8 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
else
|
||||
{
|
||||
DoDamage(item, INT_MAX);
|
||||
|
||||
DoLotsOfBlood(item->Pose.Position.x,
|
||||
DoLotsOfBlood(
|
||||
item->Pose.Position.x,
|
||||
laraItem->Pose.Position.y - CLICK(1),
|
||||
item->Pose.Position.z,
|
||||
laraItem->Animation.Velocity.z,
|
||||
|
@ -1832,10 +1826,6 @@ void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
|||
{
|
||||
SoundEffect(GetShatterSound(mesh->staticNumber), (PHD_3DPOS*)mesh);
|
||||
ShatterObject(nullptr, mesh, -128, laraItem->RoomNumber, 0);
|
||||
SmashedMeshRoom[SmashedMeshCount] = laraItem->RoomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = mesh;
|
||||
SmashedMeshCount++;
|
||||
mesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
}
|
||||
else if (coll->Setup.EnableObjectPush)
|
||||
ItemPushStatic(laraItem, mesh, coll);
|
||||
|
@ -1901,7 +1891,7 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll
|
|||
int rx = (frame->boundingBox.X1 + frame->boundingBox.X2) / 2;
|
||||
int rz = (frame->boundingBox.X2 + frame->boundingBox.Z2) / 2;
|
||||
|
||||
if (frame->boundingBox.Height() > STEP_SIZE)
|
||||
if (frame->boundingBox.Height() > CLICK(1))
|
||||
{
|
||||
auto* lara = GetLaraInfo(laraItem);
|
||||
|
||||
|
@ -1909,7 +1899,7 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll
|
|||
|
||||
lara->HitDirection = (short)angle;
|
||||
|
||||
// TODO: check if a second Lara.hitFrame++; is required there !
|
||||
// TODO: Check if a second Lara.hitFrame++ is required. -- TokyoSU
|
||||
lara->HitFrame++;
|
||||
if (lara->HitFrame > 30)
|
||||
lara->HitFrame = 30;
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
#include "Specific/phd_global.h"
|
||||
#include "Specific/trmath.h"
|
||||
|
||||
struct ItemInfo;
|
||||
struct CollisionInfo;
|
||||
class FloorInfo;
|
||||
struct CollisionInfo;
|
||||
struct ItemInfo;
|
||||
struct MESH_INFO;
|
||||
|
||||
constexpr auto MAX_COLLIDED_OBJECTS = 1024;
|
||||
constexpr auto ITEM_RADIUS_YMAX = SECTOR(3);
|
||||
|
||||
constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30;
|
||||
constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30.0f;
|
||||
|
||||
extern BOUNDING_BOX GlobalCollisionBounds;
|
||||
extern ItemInfo* CollidedItems[MAX_COLLIDED_OBJECTS];
|
||||
|
@ -36,17 +36,17 @@ bool TestLaraPosition(OBJECT_COLLISION_BOUNDS* bounds, ItemInfo* item, ItemInfo*
|
|||
bool AlignLaraPosition(Vector3Int* offset, ItemInfo* item, ItemInfo* laraItem);
|
||||
bool MoveLaraPosition(Vector3Int* pos, ItemInfo* item, ItemInfo* laraItem);
|
||||
|
||||
bool ItemNearLara(PHD_3DPOS* pos, int radius);
|
||||
bool ItemNearTarget(PHD_3DPOS* origin, ItemInfo* target, int radius);
|
||||
bool ItemNearLara(Vector3Int* origin, int radius);
|
||||
bool ItemNearTarget(Vector3Int* origin, ItemInfo* targetEntity, int radius);
|
||||
|
||||
bool Move3DPosTo3DPos(PHD_3DPOS* origin, PHD_3DPOS* target, int velocity, short angleAdd);
|
||||
bool Move3DPosTo3DPos(PHD_3DPOS* fromPose, PHD_3DPOS* toPose, int velocity, short angleAdd);
|
||||
|
||||
bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius);
|
||||
bool TestBoundsCollideStatic(ItemInfo* item, MESH_INFO* mesh, int radius);
|
||||
bool ItemPushItem(ItemInfo* item, ItemInfo* laraItem, CollisionInfo* coll, bool spasmEnabled, char bigPush);
|
||||
bool ItemPushStatic(ItemInfo* laraItem, MESH_INFO* mesh, CollisionInfo* coll);
|
||||
|
||||
bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pos, CollisionInfo* coll);
|
||||
bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX* box, PHD_3DPOS pose, CollisionInfo* coll);
|
||||
void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll);
|
||||
|
||||
void AIPickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
|
|
|
@ -78,7 +78,7 @@ int TestCollision(ItemInfo* item, ItemInfo* laraItem)
|
|||
int dz = z1 - z2;
|
||||
int r = r1 + r2;
|
||||
|
||||
if ((pow(dx, 2) + pow(dy, 2) + pow(dz, 2)) < pow(r, 2))
|
||||
if ((SQUARE(dx) + SQUARE(dy) + SQUARE(dz)) < SQUARE(r))
|
||||
{
|
||||
item->SetBits(JointBitType::Touch, i);
|
||||
laraItem->SetBits(JointBitType::Touch, j);
|
||||
|
|
|
@ -92,7 +92,7 @@ void DrawNearbyPathfinding(int boxIndex)
|
|||
|
||||
void DropEntityPickups(ItemInfo* item)
|
||||
{
|
||||
ItemInfo* pickup = NULL;
|
||||
ItemInfo* pickup = nullptr;
|
||||
|
||||
for (short pickupNumber = item->CarriedItem; pickupNumber != NO_ITEM; pickupNumber = pickup->CarriedItem)
|
||||
{
|
||||
|
@ -157,7 +157,7 @@ void CreatureYRot2(PHD_3DPOS* srcPos, short angle, short angleAdd)
|
|||
|
||||
bool SameZone(CreatureInfo* creature, ItemInfo* target)
|
||||
{
|
||||
int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data();
|
||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data();
|
||||
auto* item = &g_Level.Items[creature->ItemNumber];
|
||||
|
||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||
|
@ -449,12 +449,13 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
short top;
|
||||
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
if (!item->Data)
|
||||
|
||||
if (!item->IsCreature())
|
||||
return false;
|
||||
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
auto* LOT = &creature->LOT;
|
||||
int* zone = g_Level.Zones[LOT->Zone][FlipStatus].data();
|
||||
int* zone = g_Level.Zones[(int)LOT->Zone][FlipStatus].data();
|
||||
|
||||
int boxHeight;
|
||||
if (item->BoxNumber != NO_BOX)
|
||||
|
@ -462,7 +463,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
else
|
||||
boxHeight = item->Floor;
|
||||
|
||||
auto oldPos = item->Pose.Position;
|
||||
auto prevPos = item->Pose.Position;
|
||||
|
||||
AnimateItem(item);
|
||||
|
||||
|
@ -477,7 +478,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
int y = item->Pose.Position.y + bounds->Y1;
|
||||
|
||||
short roomNumber = item->RoomNumber;
|
||||
GetFloor(oldPos.x, y, oldPos.z, &roomNumber);
|
||||
GetFloor(prevPos.x, y, prevPos.z, &roomNumber);
|
||||
FloorInfo* floor = GetFloor(item->Pose.Position.x, y, item->Pose.Position.z, &roomNumber);
|
||||
|
||||
// TODO: Check why some blocks have box = -1 assigned to them -- Lwmte, 10.11.21
|
||||
|
@ -506,18 +507,18 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
{
|
||||
xPos = item->Pose.Position.x / SECTOR(1);
|
||||
zPos = item->Pose.Position.z / SECTOR(1);
|
||||
shiftX = oldPos.x / SECTOR(1);
|
||||
shiftZ = oldPos.z / SECTOR(1);
|
||||
shiftX = prevPos.x / SECTOR(1);
|
||||
shiftZ = prevPos.z / SECTOR(1);
|
||||
|
||||
if (xPos < shiftX)
|
||||
item->Pose.Position.x = oldPos.x & (~(SECTOR(1) - 1));
|
||||
item->Pose.Position.x = prevPos.x & (~WALL_MASK);
|
||||
else if (xPos > shiftX)
|
||||
item->Pose.Position.x = oldPos.x | (SECTOR(1) - 1);
|
||||
item->Pose.Position.x = prevPos.x | WALL_MASK;
|
||||
|
||||
if (zPos < shiftZ)
|
||||
item->Pose.Position.z = oldPos.z & (~(SECTOR(1) - 1));
|
||||
item->Pose.Position.z = prevPos.z & (~WALL_MASK);
|
||||
else if (zPos > shiftZ)
|
||||
item->Pose.Position.z = oldPos.z | (SECTOR(1) - 1);
|
||||
item->Pose.Position.z = prevPos.z | (WALL_MASK);
|
||||
|
||||
floor = GetFloor(item->Pose.Position.x, y, item->Pose.Position.z, &roomNumber);
|
||||
height = g_Level.Boxes[floor->Box].height;
|
||||
|
@ -538,8 +539,8 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
|
||||
int x = item->Pose.Position.x;
|
||||
int z = item->Pose.Position.z;
|
||||
xPos = x & (SECTOR(1) - 1);
|
||||
zPos = z & (SECTOR(1) - 1);
|
||||
xPos = x & WALL_MASK;
|
||||
zPos = z & WALL_MASK;
|
||||
short radius = Objects[item->ObjectNumber].radius;
|
||||
shiftX = 0;
|
||||
shiftZ = 0;
|
||||
|
@ -669,8 +670,8 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
{
|
||||
if (item->Pose.Position.y + top < ceiling)
|
||||
{
|
||||
item->Pose.Position.x = oldPos.x;
|
||||
item->Pose.Position.z = oldPos.z;
|
||||
item->Pose.Position.x = prevPos.x;
|
||||
item->Pose.Position.z = prevPos.z;
|
||||
dy = LOT->Fly;
|
||||
}
|
||||
else
|
||||
|
@ -689,13 +690,13 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
}
|
||||
else if (item->Pose.Position.y <= height)
|
||||
{
|
||||
dy = 0;
|
||||
item->Pose.Position.y = height;
|
||||
dy = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Pose.Position.x = oldPos.x;
|
||||
item->Pose.Position.z = oldPos.z;
|
||||
item->Pose.Position.x = prevPos.x;
|
||||
item->Pose.Position.z = prevPos.z;
|
||||
dy = -LOT->Fly;
|
||||
}
|
||||
|
||||
|
@ -732,7 +733,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
if (item->Pose.Position.y > item->Floor)
|
||||
{
|
||||
if (item->Pose.Position.y > (item->Floor + CLICK(1)))
|
||||
item->Pose.Position = oldPos;
|
||||
item->Pose.Position = prevPos;
|
||||
else
|
||||
item->Pose.Position.y = item->Floor;
|
||||
}
|
||||
|
@ -749,7 +750,7 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
top = bounds->Y1; // TODO: check if Y1 or Y2
|
||||
|
||||
if (item->Pose.Position.y + top < ceiling)
|
||||
item->Pose.Position = oldPos;
|
||||
item->Pose.Position = prevPos;
|
||||
|
||||
floor = GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &roomNumber);
|
||||
item->Floor = GetFloorHeight(floor, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z);
|
||||
|
@ -765,7 +766,6 @@ int CreatureAnimation(short itemNumber, short angle, short tilt)
|
|||
}
|
||||
|
||||
CreatureSwitchRoom(itemNumber);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -884,7 +884,7 @@ int ValidBox(ItemInfo* item, short zoneNumber, short boxNumber)
|
|||
return false;
|
||||
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data();
|
||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data();
|
||||
if (creature->LOT.Fly == NO_FLYING && zone[boxNumber] != zoneNumber)
|
||||
return false;
|
||||
|
||||
|
@ -970,7 +970,7 @@ int UpdateLOT(LOTInfo* LOT, int depth)
|
|||
|
||||
int SearchLOT(LOTInfo* LOT, int depth)
|
||||
{
|
||||
int* zone = g_Level.Zones[LOT->Zone][FlipStatus].data();
|
||||
int* zone = g_Level.Zones[(int)LOT->Zone][FlipStatus].data();
|
||||
int searchZone = zone[LOT->Head];
|
||||
|
||||
if (depth <= 0)
|
||||
|
@ -1084,7 +1084,7 @@ int CreatureActive(short itemNumber)
|
|||
if (item->Flags & IFLAG_KILLED)
|
||||
return false; // Object is already dead
|
||||
|
||||
if (item->Status == ITEM_INVISIBLE || !item->Data.is<CreatureInfo>())
|
||||
if (item->Status == ITEM_INVISIBLE || !item->IsCreature())
|
||||
{
|
||||
if (!EnableEntityAI(itemNumber, 0))
|
||||
return false; // AI couldn't be activated
|
||||
|
@ -1162,7 +1162,7 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
|
|||
vault = 0;
|
||||
else if (item->Floor > y + CHECK_CLICK(7))
|
||||
vault = -4;
|
||||
// FIXME: edit assets adding climb down animations for Von Croy and baddys?
|
||||
// FIXME: edit assets adding climb down animations for Von Croy and baddies?
|
||||
else if (item->Floor > y + CHECK_CLICK(5) &&
|
||||
item->ObjectNumber != ID_VON_CROY &&
|
||||
item->ObjectNumber != ID_BADDY1 &&
|
||||
|
@ -1367,7 +1367,7 @@ void FindAITargetObject(CreatureInfo* creature, short objectNumber)
|
|||
|
||||
if (g_Level.AIObjects.size() > 0)
|
||||
{
|
||||
AI_OBJECT* foundObject = NULL;
|
||||
AI_OBJECT* foundObject = nullptr;
|
||||
|
||||
for (int i = 0; i < g_Level.AIObjects.size(); i++)
|
||||
{
|
||||
|
@ -1375,7 +1375,7 @@ void FindAITargetObject(CreatureInfo* creature, short objectNumber)
|
|||
|
||||
if (aiObject->objectNumber == objectNumber && aiObject->triggerFlags == item->ItemFlags[3] && aiObject->roomNumber != NO_ROOM)
|
||||
{
|
||||
int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data();
|
||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data();
|
||||
|
||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->Box;
|
||||
|
@ -1394,7 +1394,7 @@ void FindAITargetObject(CreatureInfo* creature, short objectNumber)
|
|||
}
|
||||
}
|
||||
|
||||
if (foundObject != NULL)
|
||||
if (foundObject != nullptr)
|
||||
{
|
||||
auto* aiItem = creature->AITarget;
|
||||
|
||||
|
@ -1435,7 +1435,7 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI)
|
|||
creature->Enemy = LaraItem;
|
||||
}
|
||||
|
||||
int* zone = g_Level.Zones[creature->LOT.Zone][FlipStatus].data();
|
||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][FlipStatus].data();
|
||||
|
||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||
item->BoxNumber = NO_BOX;
|
||||
|
@ -1457,8 +1457,8 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI)
|
|||
// This prevents enemies from running to Lara and attacking nothing when she is hanging or shimmying. -- Lwmte, 27.06.22
|
||||
|
||||
bool reachable = false;
|
||||
if (object->zoneType == ZoneType::ZONE_FLYER ||
|
||||
(object->zoneType == ZoneType::ZONE_WATER && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item->RoomNumber)))
|
||||
if (object->ZoneType == ZoneType::Flyer ||
|
||||
(object->ZoneType == ZoneType::Water && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item->RoomNumber)))
|
||||
{
|
||||
reachable = true; // If NPC is flying or swimming in water, always reach Lara
|
||||
}
|
||||
|
|
|
@ -444,9 +444,8 @@ GameStatus DoTitle(int index, std::string const& ambient)
|
|||
g_Gui.SetMenuToDisplay(Menu::Title);
|
||||
g_Gui.SetSelectedOption(0);
|
||||
|
||||
// Initialise ponytails
|
||||
InitialiseHair();
|
||||
|
||||
InitialiseNodeScripts();
|
||||
InitialiseItemBoxData();
|
||||
|
||||
g_GameScript->OnStart();
|
||||
|
@ -570,9 +569,8 @@ GameStatus DoLevel(int index, std::string const& ambient, bool loadFromSavegame)
|
|||
// Initialise flyby cameras
|
||||
InitSpotCamSequences();
|
||||
|
||||
// Initialise ponytails
|
||||
InitialiseHair();
|
||||
|
||||
InitialiseNodeScripts();
|
||||
InitialiseItemBoxData();
|
||||
|
||||
if (loadFromSavegame)
|
||||
|
|
|
@ -121,10 +121,6 @@ bool GetTargetOnLOS(GameVector* origin, GameVector* target, bool drawTarget, boo
|
|||
ShatterImpactData.impactDirection = direction;
|
||||
ShatterImpactData.impactLocation = Vector3(mesh->pos.Position.x, mesh->pos.Position.y, mesh->pos.Position.z);
|
||||
ShatterObject(nullptr, mesh, 128, target2.roomNumber, 0);
|
||||
SmashedMeshRoom[SmashedMeshCount] = target2.roomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = mesh;
|
||||
++SmashedMeshCount;
|
||||
mesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
SoundEffect(GetShatterSound(mesh->staticNumber), (PHD_3DPOS*)mesh);
|
||||
}
|
||||
|
||||
|
|
|
@ -112,15 +112,15 @@ void DisableEntityAI(short itemNumber)
|
|||
item->Data = nullptr;
|
||||
}
|
||||
|
||||
void InitialiseSlot(short itemNum, short slot, bool makeTarget)
|
||||
void InitialiseSlot(short itemNumber, short slot, bool makeTarget)
|
||||
{
|
||||
auto* item = &g_Level.Items[itemNum];
|
||||
auto* obj = &Objects[item->ObjectNumber];
|
||||
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
auto* object = &Objects[item->ObjectNumber];
|
||||
item->Data = CreatureInfo();
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
InitialiseLOTarray(itemNum);
|
||||
creature->ItemNumber = itemNum;
|
||||
|
||||
InitialiseLOTarray(itemNumber);
|
||||
creature->ItemNumber = itemNumber;
|
||||
creature->Mood = MoodType::Bored;
|
||||
creature->JointRotation[0] = 0;
|
||||
creature->JointRotation[1] = 0;
|
||||
|
@ -136,12 +136,12 @@ void InitialiseSlot(short itemNum, short slot, bool makeTarget)
|
|||
creature->MonkeySwingAhead = false;
|
||||
creature->LOT.CanJump = false;
|
||||
creature->LOT.CanMonkey = false;
|
||||
creature->LOT.IsAmphibious = false; // only the crocodile can go water and land. (default: true)
|
||||
creature->LOT.IsAmphibious = false; // True for crocodile by default as the only the crocodile that can move in water and on land.
|
||||
creature->LOT.IsJumping = false;
|
||||
creature->LOT.IsMonkeying = false;
|
||||
creature->MaxTurn = ANGLE(1);
|
||||
creature->Flags = 0;
|
||||
creature->Enemy = NULL;
|
||||
creature->Enemy = nullptr;
|
||||
creature->LOT.Fly = NO_FLYING;
|
||||
creature->LOT.BlockMask = BLOCKED;
|
||||
|
||||
|
@ -155,117 +155,116 @@ void InitialiseSlot(short itemNum, short slot, bool makeTarget)
|
|||
else
|
||||
creature->AITarget = nullptr;
|
||||
|
||||
switch (obj->zoneType)
|
||||
switch (object->ZoneType)
|
||||
{
|
||||
default:
|
||||
case ZONE_NULL:
|
||||
case ZoneType::None:
|
||||
creature->LOT.Step = CLICK(1);
|
||||
creature->LOT.Drop = -CLICK(1);
|
||||
obj->zoneType = ZONE_BASIC; // only entity that use CreatureActive() will reach InitialiseSlot() !
|
||||
object->ZoneType = ZoneType::Basic; // Only entities that use CreatureActive() will reach InitialiseSlot().
|
||||
break;
|
||||
|
||||
case ZONE_SKELLY:
|
||||
// Can jump
|
||||
// Can jump.
|
||||
case ZoneType::Skeleton:
|
||||
creature->LOT.Step = CLICK(1);
|
||||
creature->LOT.Drop = -CLICK(1);
|
||||
creature->LOT.CanJump = true;
|
||||
creature->LOT.Zone = ZONE_SKELLY;
|
||||
creature->LOT.Zone = ZoneType::Skeleton;
|
||||
break;
|
||||
|
||||
case ZONE_BASIC:
|
||||
case ZoneType::Basic:
|
||||
creature->LOT.Step = CLICK(1);
|
||||
creature->LOT.Drop = -CLICK(1);
|
||||
creature->LOT.Zone = ZONE_BASIC;
|
||||
creature->LOT.Zone = ZoneType::Basic;
|
||||
break;
|
||||
|
||||
case ZONE_FLYER:
|
||||
// Can fly
|
||||
// Can fly.
|
||||
case ZoneType::Flyer:
|
||||
creature->LOT.Step = SECTOR(20);
|
||||
creature->LOT.Drop = -SECTOR(20);
|
||||
creature->LOT.Fly = DEFAULT_FLY_UPDOWN_SPEED;
|
||||
creature->LOT.Zone = ZONE_FLYER;
|
||||
creature->LOT.Zone = ZoneType::Flyer;
|
||||
break;
|
||||
|
||||
case ZONE_WATER:
|
||||
// Can swim
|
||||
// Can swim.
|
||||
case ZoneType::Water:
|
||||
creature->LOT.Step = SECTOR(20);
|
||||
creature->LOT.Drop = -SECTOR(20);
|
||||
creature->LOT.Zone = ZONE_WATER;
|
||||
creature->LOT.Zone = ZoneType::Water;
|
||||
|
||||
if (item->ObjectNumber == ID_CROCODILE)
|
||||
{
|
||||
creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED / 2; // is more slow than the other underwater entity
|
||||
creature->LOT.IsAmphibious = true; // crocodile can walk and swim.
|
||||
creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED / 2; // Slower than the other underwater creatures.
|
||||
creature->LOT.IsAmphibious = true; // Can walk and swim.
|
||||
}
|
||||
else if (item->ObjectNumber == ID_BIG_RAT)
|
||||
{
|
||||
creature->LOT.Fly = NO_FLYING; // dont want the bigrat to be able to go in water (just the surface !)
|
||||
creature->LOT.IsAmphibious = true; // bigrat can walk and swim.
|
||||
creature->LOT.Fly = NO_FLYING; // Can't swim underwater, only on the surface.
|
||||
creature->LOT.IsAmphibious = true; // Can walk and swim.
|
||||
}
|
||||
else
|
||||
{
|
||||
creature->LOT.Fly = DEFAULT_SWIM_UPDOWN_SPEED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ZONE_HUMAN_CLASSIC:
|
||||
// Can climb
|
||||
// Can climb.
|
||||
case ZoneType::HumanClassic:
|
||||
creature->LOT.Step = SECTOR(1);
|
||||
creature->LOT.Drop = -SECTOR(1);
|
||||
creature->LOT.Zone = ZONE_HUMAN_CLASSIC;
|
||||
creature->LOT.Zone = ZoneType::HumanClassic;
|
||||
break;
|
||||
|
||||
case ZONE_HUMAN_JUMP:
|
||||
// Can climb and jump
|
||||
// Can climb and jump.
|
||||
case ZoneType::HumanJump:
|
||||
creature->LOT.Step = SECTOR(1);
|
||||
creature->LOT.Drop = -SECTOR(1);
|
||||
creature->LOT.CanJump = true;
|
||||
creature->LOT.Zone = ZONE_HUMAN_CLASSIC;
|
||||
creature->LOT.Zone = ZoneType::HumanClassic;
|
||||
break;
|
||||
|
||||
case ZONE_HUMAN_JUMP_AND_MONKEY:
|
||||
// Can climb, jump, monkey
|
||||
// Can climb, jump, monkeyswing.
|
||||
case ZoneType::HumanJumpAndMonkey:
|
||||
creature->LOT.Step = SECTOR(1);
|
||||
creature->LOT.Drop = -SECTOR(1);
|
||||
creature->LOT.CanJump = true;
|
||||
creature->LOT.CanMonkey = true;
|
||||
creature->LOT.Zone = ZONE_HUMAN_CLASSIC;
|
||||
creature->LOT.Zone = ZoneType::HumanClassic;
|
||||
break;
|
||||
|
||||
case ZONE_HUMAN_LONGJUMP_AND_MONKEY:
|
||||
// Can climb, jump, monkey, long jump
|
||||
// Can climb, jump, monkey swing, long jump.
|
||||
case ZoneType::HumanLongJumpAndMonkey:
|
||||
creature->LOT.Step = SECTOR(1) + CLICK(3);
|
||||
creature->LOT.Drop = -(SECTOR(1) + CLICK(3));
|
||||
creature->LOT.CanJump = true;
|
||||
creature->LOT.CanMonkey = true;
|
||||
creature->LOT.Zone = ZONE_VON_CROY;
|
||||
creature->LOT.Zone = ZoneType::VonCroy;
|
||||
break;
|
||||
|
||||
case ZONE_SPIDER:
|
||||
case ZoneType::Spider:
|
||||
creature->LOT.Step = SECTOR(1) - CLICK(2);
|
||||
creature->LOT.Drop = -(SECTOR(1) - CLICK(2));
|
||||
creature->LOT.Zone = ZONE_HUMAN_CLASSIC;
|
||||
creature->LOT.Zone = ZoneType::HumanClassic;
|
||||
break;
|
||||
|
||||
case ZONE_BLOCKABLE:
|
||||
case ZoneType::Blockable:
|
||||
creature->LOT.BlockMask = BLOCKABLE;
|
||||
creature->LOT.Zone = ZONE_BASIC;
|
||||
creature->LOT.Zone = ZoneType::Basic;
|
||||
break;
|
||||
|
||||
case ZONE_APE:
|
||||
case ZoneType::Ape:
|
||||
creature->LOT.Step = CLICK(2);
|
||||
creature->LOT.Drop = -SECTOR(1);
|
||||
break;
|
||||
|
||||
case ZONE_SOPHIALEE:
|
||||
case ZoneType::SophiaLee:
|
||||
creature->LOT.Step = SECTOR(1);
|
||||
creature->LOT.Drop = -CLICK(3);
|
||||
creature->LOT.Zone = ZONE_HUMAN_CLASSIC;
|
||||
creature->LOT.Zone = ZoneType::HumanClassic;
|
||||
break;
|
||||
}
|
||||
|
||||
ClearLOT(&creature->LOT);
|
||||
if (itemNum != Lara.ItemNumber)
|
||||
if (itemNumber != Lara.ItemNumber)
|
||||
CreateZone(item);
|
||||
|
||||
SlotsUsed++;
|
||||
|
@ -304,16 +303,16 @@ void ClearLOT(LOTInfo* LOT)
|
|||
void CreateZone(ItemInfo* item)
|
||||
{
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
auto* r = &g_Level.Rooms[item->RoomNumber];
|
||||
auto* room = &g_Level.Rooms[item->RoomNumber];
|
||||
|
||||
item->BoxNumber = GetSector(r, item->Pose.Position.x - r->x, item->Pose.Position.z - r->z)->Box;
|
||||
item->BoxNumber = GetSector(room, item->Pose.Position.x - room->x, item->Pose.Position.z - room->z)->Box;
|
||||
|
||||
if (creature->LOT.Fly)
|
||||
{
|
||||
BOX_NODE* node = creature->LOT.Node.data();
|
||||
auto* node = creature->LOT.Node.data();
|
||||
creature->LOT.ZoneCount = 0;
|
||||
|
||||
for (int i = 0; i < g_Level.Boxes.size(); i++)
|
||||
for (size_t i = 0; i < g_Level.Boxes.size(); i++)
|
||||
{
|
||||
node->boxNumber = i;
|
||||
node++;
|
||||
|
@ -322,8 +321,8 @@ void CreateZone(ItemInfo* item)
|
|||
}
|
||||
else
|
||||
{
|
||||
int* zone = g_Level.Zones[creature->LOT.Zone][0].data();
|
||||
int* flippedZone = g_Level.Zones[creature->LOT.Zone][1].data();
|
||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][0].data();
|
||||
int* flippedZone = g_Level.Zones[(int)creature->LOT.Zone][1].data();
|
||||
|
||||
int zoneNumber = zone[item->BoxNumber];
|
||||
int flippedZoneNumber = flippedZone[item->BoxNumber];
|
||||
|
@ -331,7 +330,7 @@ void CreateZone(ItemInfo* item)
|
|||
auto* node = creature->LOT.Node.data();
|
||||
creature->LOT.ZoneCount = 0;
|
||||
|
||||
for (int i = 0; i < g_Level.Boxes.size(); i++)
|
||||
for (size_t i = 0; i < g_Level.Boxes.size(); i++)
|
||||
{
|
||||
if (*zone == zoneNumber || *flippedZone == flippedZoneNumber)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@ int TriggerActive(ItemInfo* item)
|
|||
flag = !flag;
|
||||
}
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "framework.h"
|
||||
#include "Game/control/volume.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include "Game/animation.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
|
@ -79,7 +80,7 @@ namespace TEN::Control::Volumes
|
|||
volume->Status = TriggerStatus::Entering;
|
||||
if (!set->OnEnter.Function.empty() && set->OnEnter.CallCounter != 0)
|
||||
{
|
||||
g_GameScript->ExecuteFunction(set->OnEnter.Function, triggerer, set->OnEnter.Argument);
|
||||
g_GameScript->ExecuteFunction(set->OnEnter.Function, triggerer, set->OnEnter.Data);
|
||||
if (set->OnEnter.CallCounter != NO_CALL_COUNTER)
|
||||
set->OnEnter.CallCounter--;
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ namespace TEN::Control::Volumes
|
|||
volume->Status = TriggerStatus::Inside;
|
||||
if (!set->OnInside.Function.empty() && set->OnInside.CallCounter != 0)
|
||||
{
|
||||
g_GameScript->ExecuteFunction(set->OnInside.Function, triggerer, set->OnInside.Argument);
|
||||
g_GameScript->ExecuteFunction(set->OnInside.Function, triggerer, set->OnInside.Data);
|
||||
if (set->OnInside.CallCounter != NO_CALL_COUNTER)
|
||||
set->OnInside.CallCounter--;
|
||||
}
|
||||
|
@ -108,7 +109,7 @@ namespace TEN::Control::Volumes
|
|||
volume->Status = TriggerStatus::Leaving;
|
||||
if (!set->OnLeave.Function.empty() && set->OnLeave.CallCounter != 0)
|
||||
{
|
||||
g_GameScript->ExecuteFunction(set->OnLeave.Function, triggerer, set->OnLeave.Argument);
|
||||
g_GameScript->ExecuteFunction(set->OnLeave.Function, triggerer, set->OnLeave.Data);
|
||||
if (set->OnLeave.CallCounter != NO_CALL_COUNTER)
|
||||
set->OnLeave.CallCounter--;
|
||||
}
|
||||
|
@ -155,4 +156,53 @@ namespace TEN::Control::Volumes
|
|||
else
|
||||
TestVolumes(item->RoomNumber, bbox, TriggerVolumeActivators::Movable, itemNumber);
|
||||
}
|
||||
|
||||
void InitialiseNodeScripts()
|
||||
{
|
||||
static const std::string nodeScriptPath = "Scripts/Engine/NodeCatalogs/";
|
||||
|
||||
if (!std::filesystem::exists(nodeScriptPath))
|
||||
return;
|
||||
|
||||
std::vector<std::string> nodeCatalogs;
|
||||
for (auto& path : std::filesystem::recursive_directory_iterator(nodeScriptPath))
|
||||
if (path.path().extension() == ".lua")
|
||||
nodeCatalogs.push_back(path.path().filename().string());
|
||||
|
||||
if (nodeCatalogs.size() == 0)
|
||||
return;
|
||||
|
||||
TENLog("Loading node scripts...", LogLevel::Info);
|
||||
|
||||
std::sort(nodeCatalogs.rbegin(), nodeCatalogs.rend());
|
||||
for (auto& file : nodeCatalogs)
|
||||
g_GameScript->ExecuteScriptFile(nodeScriptPath + file);
|
||||
|
||||
TENLog(std::to_string(nodeCatalogs.size()) + " node catalogs were found and loaded.", LogLevel::Info);
|
||||
|
||||
int nodeCount = 0;
|
||||
for (auto& set : g_Level.EventSets)
|
||||
{
|
||||
if ((set.OnEnter.Mode == VolumeEventMode::Nodes) && (set.OnEnter.Data.size() > 0))
|
||||
{
|
||||
g_GameScript->ExecuteString(set.OnEnter.Data);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
if ((set.OnInside.Mode == VolumeEventMode::Nodes) && (set.OnInside.Data.size() > 0))
|
||||
{
|
||||
g_GameScript->ExecuteString(set.OnInside.Data);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
if ((set.OnLeave.Mode == VolumeEventMode::Nodes) && (set.OnLeave.Data.size() > 0))
|
||||
{
|
||||
g_GameScript->ExecuteString(set.OnLeave.Data);
|
||||
nodeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeCount != 0)
|
||||
TENLog(std::to_string(nodeCount) + " node scripts were found and loaded.", LogLevel::Info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,4 +61,6 @@ namespace TEN::Control::Volumes
|
|||
void TestVolumes(short itemNum);
|
||||
void TestVolumes(short roomNumber, MESH_INFO* mesh);
|
||||
void TestVolumes(CAMERA_INFO* camera);
|
||||
|
||||
void InitialiseNodeScripts();
|
||||
}
|
||||
|
|
|
@ -15,14 +15,14 @@ namespace TEN::Control::Volumes
|
|||
enum class VolumeEventMode
|
||||
{
|
||||
LevelScript,
|
||||
Constructor
|
||||
Nodes
|
||||
};
|
||||
|
||||
struct VolumeEvent
|
||||
{
|
||||
VolumeEventMode Mode;
|
||||
std::string Function;
|
||||
std::string Argument;
|
||||
std::string Data;
|
||||
|
||||
int CallCounter;
|
||||
};
|
||||
|
|
|
@ -69,11 +69,19 @@ void ShatterObject(SHATTER_ITEM* item, MESH_INFO* mesh, int num, short roomNumbe
|
|||
|
||||
if (mesh)
|
||||
{
|
||||
if (!(mesh->flags & StaticMeshFlags::SM_VISIBLE))
|
||||
return;
|
||||
|
||||
isStatic = true;
|
||||
meshIndex = StaticObjects[mesh->staticNumber].meshNumber;
|
||||
yRot = mesh->pos.Orientation.y;
|
||||
pos = Vector3(mesh->pos.Position.x, mesh->pos.Position.y, mesh->pos.Position.z);
|
||||
scale = mesh->scale;
|
||||
|
||||
mesh->flags &= ~StaticMeshFlags::SM_VISIBLE;
|
||||
SmashedMeshRoom[SmashedMeshCount] = roomNumber;
|
||||
SmashedMesh[SmashedMeshCount] = mesh;
|
||||
SmashedMeshCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1495,7 +1495,7 @@ void GuiController::SetupAmmoSelector()
|
|||
{
|
||||
num++;
|
||||
ammo_object_list[0].invitem = INV_OBJECT_PISTOLS_AMMO;
|
||||
ammo_object_list[0].amount = -1;
|
||||
ammo_object_list[0].amount = AmountPistolsAmmo;
|
||||
num_ammo_slots = num;
|
||||
current_ammo_type = &CurrentPistolsAmmoType;
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ void AddDisplayPickup(GAME_OBJECT_ID objectNumber)
|
|||
}
|
||||
|
||||
// No free slot found; pickup the object without displaying it.
|
||||
PickedUpObject(objectNumber, 0);
|
||||
PickedUpObject(objectNumber);
|
||||
}
|
||||
|
||||
void InitialisePickupDisplay()
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "Specific/phd_global.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
struct ItemInfo;
|
||||
|
||||
struct BOX_NODE
|
||||
|
@ -12,34 +13,37 @@ struct BOX_NODE
|
|||
int boxNumber;
|
||||
};
|
||||
|
||||
enum ZoneType : char
|
||||
enum class ZoneType
|
||||
{
|
||||
ZONE_NULL = -1, // default zone
|
||||
ZONE_SKELLY = 0,
|
||||
ZONE_BASIC,
|
||||
ZONE_FLYER,
|
||||
ZONE_HUMAN_CLASSIC,
|
||||
ZONE_VON_CROY,
|
||||
ZONE_WATER,
|
||||
ZONE_MAX,
|
||||
/// custom zone (using zone above for LOT.zone):
|
||||
ZONE_HUMAN_JUMP_AND_MONKEY,
|
||||
ZONE_HUMAN_JUMP,
|
||||
ZONE_SPIDER,
|
||||
ZONE_BLOCKABLE, // for trex, shiva, etc..
|
||||
ZONE_SOPHIALEE, // dont want sophia to go down again !
|
||||
ZONE_APE, // only 2 click climb
|
||||
ZONE_HUMAN_LONGJUMP_AND_MONKEY,
|
||||
None = -1,
|
||||
Skeleton,
|
||||
Basic,
|
||||
Flyer,
|
||||
HumanClassic,
|
||||
VonCroy,
|
||||
Water,
|
||||
Max,
|
||||
|
||||
// Custom zones (above zones are used for LOT.zone):
|
||||
HumanJumpAndMonkey,
|
||||
HumanJump,
|
||||
Spider,
|
||||
Blockable, // For large creatures such as trex and shiva.
|
||||
SophiaLee, // Prevents Sophia from going to lower levels again.
|
||||
Ape, // Only 0.5 block climb.
|
||||
HumanLongJumpAndMonkey,
|
||||
};
|
||||
|
||||
struct LOTInfo
|
||||
{
|
||||
bool Initialised;
|
||||
|
||||
std::vector<BOX_NODE> Node;
|
||||
vector<BOX_NODE> Node;
|
||||
int Head;
|
||||
int Tail;
|
||||
|
||||
ZoneType Zone = ZoneType::None;
|
||||
Vector3Int Target = Vector3Int::Zero;
|
||||
int SearchNumber;
|
||||
int BlockMask;
|
||||
short Step;
|
||||
|
@ -49,18 +53,16 @@ struct LOTInfo
|
|||
int RequiredBox;
|
||||
short Fly;
|
||||
|
||||
bool CanJump;
|
||||
bool CanMonkey;
|
||||
bool IsJumping;
|
||||
bool IsMonkeying;
|
||||
bool IsAmphibious;
|
||||
|
||||
Vector3Int Target;
|
||||
ZoneType Zone;
|
||||
bool CanJump = false;
|
||||
bool CanMonkey = false;
|
||||
bool IsJumping = false;
|
||||
bool IsMonkeying = false;
|
||||
bool IsAmphibious = false;
|
||||
};
|
||||
|
||||
enum class MoodType
|
||||
{
|
||||
None,
|
||||
Bored,
|
||||
Attack,
|
||||
Escape,
|
||||
|
@ -70,45 +72,43 @@ enum class MoodType
|
|||
enum class CreatureAIPriority
|
||||
{
|
||||
None,
|
||||
High,
|
||||
Low,
|
||||
Medium,
|
||||
Low
|
||||
High
|
||||
};
|
||||
|
||||
struct CreatureInfo
|
||||
{
|
||||
short ItemNumber;
|
||||
short ItemNumber = -1;
|
||||
|
||||
short MaxTurn;
|
||||
short JointRotation[4];
|
||||
bool HeadLeft;
|
||||
bool HeadRight;
|
||||
LOTInfo LOT = {};
|
||||
MoodType Mood = MoodType::None;
|
||||
ItemInfo* Enemy = nullptr;
|
||||
ItemInfo* AITarget = nullptr;
|
||||
short AITargetNumber = -1;
|
||||
Vector3Int Target = Vector3Int::Zero;
|
||||
|
||||
bool Patrol; // Unused?
|
||||
bool Alerted;
|
||||
bool Friendly;
|
||||
bool HurtByLara;
|
||||
bool Poisoned;
|
||||
bool JumpAhead;
|
||||
bool MonkeySwingAhead;
|
||||
bool ReachedGoal;
|
||||
short MaxTurn = 0;
|
||||
short JointRotation[4] = {};
|
||||
bool HeadLeft = false;
|
||||
bool HeadRight = false;
|
||||
|
||||
bool Patrol = false; // Unused?
|
||||
bool Alerted = false;
|
||||
bool Friendly = false;
|
||||
bool HurtByLara = false;
|
||||
bool Poisoned = false;
|
||||
bool JumpAhead = false;
|
||||
bool MonkeySwingAhead = false;
|
||||
bool ReachedGoal = false;
|
||||
|
||||
short FiredWeapon;
|
||||
short Tosspad;
|
||||
short LocationAI;
|
||||
short FiredWeapon;
|
||||
|
||||
LOTInfo LOT;
|
||||
MoodType Mood;
|
||||
ItemInfo* Enemy;
|
||||
short AITargetNumber;
|
||||
ItemInfo* AITarget;
|
||||
short Pad; // Unused?
|
||||
Vector3Int Target;
|
||||
short Flags = 0;
|
||||
|
||||
#ifdef CREATURE_AI_PRIORITY_OPTIMIZATION
|
||||
CreatureAIPriority Priority;
|
||||
size_t FramesSinceLOTUpdate;
|
||||
CreatureAIPriority Priority = CreatureAIPriority::None;
|
||||
size_t FramesSinceLOTUpdate = 0;
|
||||
#endif
|
||||
|
||||
short Flags;
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ template<class... Ts> struct visitor : Ts... { using Ts::operator()...; };
|
|||
template<class... Ts> visitor(Ts...)->visitor<Ts...>; // line not needed in C++20...
|
||||
|
||||
using namespace TEN::Entities::TR4;
|
||||
using namespace TEN::Entities::TR5;
|
||||
using namespace TEN::Entities::Creatures::TR5;
|
||||
using namespace TEN::Entities::Vehicles;
|
||||
|
||||
struct ItemInfo;
|
||||
|
|
|
@ -570,14 +570,17 @@ short CreateItem()
|
|||
|
||||
void InitialiseItemArray(int totalItem)
|
||||
{
|
||||
auto* item = &g_Level.Items[g_Level.NumItems];
|
||||
g_Level.Items.clear();
|
||||
g_Level.Items.resize(totalItem);
|
||||
|
||||
NextItemActive = NO_ITEM;
|
||||
NextItemFree = g_Level.NumItems;
|
||||
for (int i = 0; i < totalItem; i++)
|
||||
g_Level.Items[i].Index = i;
|
||||
|
||||
auto* item = &g_Level.Items[g_Level.NumItems];
|
||||
|
||||
if (g_Level.NumItems + 1 < totalItem)
|
||||
{
|
||||
for(int i = g_Level.NumItems + 1; i < totalItem; i++, item++)
|
||||
for (int i = g_Level.NumItems + 1; i < totalItem; i++, item++)
|
||||
{
|
||||
item->NextItem = i;
|
||||
item->Active = false;
|
||||
|
@ -586,6 +589,8 @@ void InitialiseItemArray(int totalItem)
|
|||
}
|
||||
|
||||
item->NextItem = NO_ITEM;
|
||||
NextItemActive = NO_ITEM;
|
||||
NextItemFree = g_Level.NumItems;
|
||||
}
|
||||
|
||||
short SpawnItem(ItemInfo* item, GAME_OBJECT_ID objectNumber)
|
||||
|
@ -629,7 +634,6 @@ int GlobalItemReplace(short search, GAME_OBJECT_ID replace)
|
|||
}
|
||||
|
||||
// Offset values may be used to account for the quirk of room traversal only being able to occur at portals.
|
||||
// Note: may not work for dynamic items because of FindItem.
|
||||
void UpdateItemRoom(ItemInfo* item, int height, int xOffset, int zOffset)
|
||||
{
|
||||
float sinY = phd_sin(item->Pose.Orientation.y);
|
||||
|
@ -643,7 +647,7 @@ void UpdateItemRoom(ItemInfo* item, int height, int xOffset, int zOffset)
|
|||
item->Floor = GetFloorHeight(item->Location, x, z).value_or(NO_HEIGHT);
|
||||
|
||||
if (item->RoomNumber != item->Location.roomNumber)
|
||||
ItemNewRoom(FindItem(item), item->Location.roomNumber);
|
||||
ItemNewRoom(item->Index, item->Location.roomNumber);
|
||||
}
|
||||
|
||||
std::vector<int> FindAllItems(short objectNumber)
|
||||
|
|
|
@ -70,8 +70,11 @@ struct EntityAnimationData
|
|||
struct ItemInfo
|
||||
{
|
||||
GAME_OBJECT_ID ObjectNumber;
|
||||
|
||||
int Status; // ItemStatus enum.
|
||||
bool Active;
|
||||
|
||||
short Index;
|
||||
short NextItem;
|
||||
short NextActive;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ void ControlMissile(short fxNumber)
|
|||
fx->pos.Position.x += velocity * phd_sin(fx->pos.Orientation.y);
|
||||
|
||||
auto probe = GetCollision(fx->pos.Position.x, fx->pos.Position.y, fx->pos.Position.z, fx->roomNumber);
|
||||
auto hitLara = ItemNearLara(&fx->pos, 200);
|
||||
auto hitLara = ItemNearLara(&fx->pos.Position, 200);
|
||||
|
||||
// Check for hitting something.
|
||||
if (fx->pos.Position.y >= probe.Position.Floor ||
|
||||
|
|
|
@ -17,45 +17,45 @@ bool ShotLara(ItemInfo* item, AI_INFO* AI, BiteInfo gun, short extraRotation, in
|
|||
auto* creature = GetCreatureInfo(item);
|
||||
auto* enemy = creature->Enemy;
|
||||
|
||||
bool hit = false;
|
||||
bool targetable = false;
|
||||
bool hasHit = false;
|
||||
bool isTargetable = false;
|
||||
|
||||
if (AI->distance <= pow(MAX_VISIBILITY_DISTANCE, 2) && Targetable(item, AI))
|
||||
if (AI->distance <= SQUARE(MAX_VISIBILITY_DISTANCE) && Targetable(item, AI))
|
||||
{
|
||||
int distance = phd_sin(AI->enemyFacing) * enemy->Animation.Velocity.z * pow(MAX_VISIBILITY_DISTANCE, 2) / 300;
|
||||
distance = pow(distance, 2) + AI->distance;
|
||||
if (distance <= pow(MAX_VISIBILITY_DISTANCE, 2))
|
||||
distance = SQUARE(distance) + AI->distance;
|
||||
if (distance <= SQUARE(MAX_VISIBILITY_DISTANCE))
|
||||
{
|
||||
int random = (pow(MAX_VISIBILITY_DISTANCE, 2) - AI->distance) / (pow(MAX_VISIBILITY_DISTANCE, 2) / 0x5000) + 8192;
|
||||
hit = GetRandomControl() < random;
|
||||
int random = (SQUARE(MAX_VISIBILITY_DISTANCE) - AI->distance) / (SQUARE(MAX_VISIBILITY_DISTANCE) / 0x5000) + 8192;
|
||||
hasHit = GetRandomControl() < random;
|
||||
}
|
||||
else
|
||||
hit = false;
|
||||
hasHit = false;
|
||||
|
||||
targetable = true;
|
||||
isTargetable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hit = false;
|
||||
targetable = false;
|
||||
hasHit = false;
|
||||
isTargetable = false;
|
||||
}
|
||||
|
||||
if (damage)
|
||||
{
|
||||
if (enemy->IsLara())
|
||||
{
|
||||
if (hit)
|
||||
if (hasHit)
|
||||
{
|
||||
DoDamage(enemy, damage);
|
||||
CreatureEffect(item, gun, &GunHit);
|
||||
}
|
||||
else if (targetable)
|
||||
else if (isTargetable)
|
||||
CreatureEffect(item, gun, &GunMiss);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatureEffect(item, gun, &GunShot);
|
||||
if (hit)
|
||||
if (hasHit)
|
||||
{
|
||||
enemy->HitStatus = true;
|
||||
enemy->HitPoints += damage / -10;
|
||||
|
@ -74,7 +74,7 @@ bool ShotLara(ItemInfo* item, AI_INFO* AI, BiteInfo gun, short extraRotation, in
|
|||
|
||||
// TODO: smash objects
|
||||
|
||||
return targetable;
|
||||
return isTargetable;
|
||||
}
|
||||
|
||||
short GunMiss(int x, int y, int z, short velocity, short yRot, short roomNumber)
|
||||
|
@ -145,32 +145,32 @@ bool TargetVisible(ItemInfo* item, AI_INFO* AI, float maxAngle)
|
|||
return false;
|
||||
|
||||
// Check just in case.
|
||||
auto* creatureInfo = GetCreatureInfo(item);
|
||||
if (creatureInfo == nullptr)
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
if (creature == nullptr)
|
||||
return false;
|
||||
|
||||
auto* enemy = creatureInfo->Enemy;
|
||||
auto* enemy = creature->Enemy;
|
||||
if (enemy == nullptr || enemy->HitPoints == 0)
|
||||
return false;
|
||||
|
||||
short angle = AI->angle - creatureInfo->JointRotation[2];
|
||||
if (angle > -ANGLE(maxAngle) && angle < ANGLE(maxAngle))
|
||||
short angle = AI->angle - creature->JointRotation[2];
|
||||
if (angle > ANGLE(-maxAngle) && angle < ANGLE(maxAngle))
|
||||
{
|
||||
GameVector start;
|
||||
GameVector target;
|
||||
auto& bounds = GetBestFrame(enemy)->boundingBox;
|
||||
|
||||
start.x = item->Pose.Position.x;
|
||||
start.y = item->Pose.Position.y - CLICK(3);
|
||||
start.z = item->Pose.Position.z;
|
||||
start.roomNumber = item->RoomNumber;
|
||||
|
||||
target.x = enemy->Pose.Position.x;
|
||||
target.y = enemy->Pose.Position.y + ((((bounds.Y1 * 2) + bounds.Y1) + bounds.Y2) / 4);
|
||||
target.z = enemy->Pose.Position.z;
|
||||
target.roomNumber = enemy->RoomNumber; // TODO: Check why this line didn't exist before. -- TokyoSU, 10/8/2022
|
||||
|
||||
return LOS(&start, &target);
|
||||
auto origin = GameVector(
|
||||
item->Pose.Position.x,
|
||||
item->Pose.Position.y - CLICK(3),
|
||||
item->Pose.Position.z,
|
||||
item->RoomNumber
|
||||
);
|
||||
auto target = GameVector(
|
||||
enemy->Pose.Position.x,
|
||||
enemy->Pose.Position.y + ((((bounds.Y1 * 2) + bounds.Y1) + bounds.Y2) / 4),
|
||||
enemy->Pose.Position.z,
|
||||
enemy->RoomNumber // TODO: Check why this line didn't exist before. -- TokyoSU, 10/8/2022
|
||||
);
|
||||
return LOS(&origin, &target);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "framework.h"
|
||||
#include "Game/pickup/pickup.h"
|
||||
|
||||
#include "pickuputil.h"
|
||||
#include "Game/animation.h"
|
||||
#include "Game/camera.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
|
@ -127,10 +128,23 @@ short RPickups[16];
|
|||
short getThisItemPlease = NO_ITEM;
|
||||
Vector3Int OldPickupPos;
|
||||
|
||||
void PickedUpObject(GAME_OBJECT_ID objectID, int count)
|
||||
bool SetInventoryCount(GAME_OBJECT_ID objectID, int count)
|
||||
{
|
||||
if (!TryModifyWeapon(Lara, objectID, count, ModificationType::Set) &&
|
||||
!TryModifyingAmmo(Lara, objectID, count, ModificationType::Set) &&
|
||||
!TryModifyingKeyItem(Lara, objectID, count, ModificationType::Set) &&
|
||||
!TryModifyingConsumable(Lara, objectID, count, ModificationType::Set) &&
|
||||
!TryModifyMiscCount(Lara, objectID, count, ModificationType::Set))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PickedUpObject(GAME_OBJECT_ID objectID, std::optional<int> count)
|
||||
{
|
||||
// See if the items fit into one of these easy groups.
|
||||
if (!TryAddingWeapon(Lara, objectID, count) &&
|
||||
if (!TryAddingWeapon(Lara, objectID) &&
|
||||
!TryAddingAmmo(Lara, objectID, count) &&
|
||||
!TryAddingKeyItem(Lara, objectID, count) &&
|
||||
!TryAddingConsumable(Lara, objectID, count) &&
|
||||
|
@ -165,10 +179,10 @@ int GetInventoryCount(GAME_OBJECT_ID objectID)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void RemoveObjectFromInventory(GAME_OBJECT_ID objectID, int count)
|
||||
void RemoveObjectFromInventory(GAME_OBJECT_ID objectID, std::optional<int> count)
|
||||
{
|
||||
// See if the items fit into one of these easy groups.
|
||||
if (!TryRemovingWeapon(Lara, objectID, count) &&
|
||||
if (!TryRemovingWeapon(Lara, objectID) &&
|
||||
!TryRemovingAmmo(Lara, objectID, count) &&
|
||||
!TryRemovingKeyItem(Lara, objectID, count) &&
|
||||
!TryRemovingConsumable(Lara, objectID, count) &&
|
||||
|
|
|
@ -11,8 +11,9 @@ extern short RPickups[16];
|
|||
extern Vector3Int OldPickupPos;
|
||||
|
||||
void InitialisePickup(short itemNumber);
|
||||
void PickedUpObject(GAME_OBJECT_ID objectID, int count);
|
||||
void RemoveObjectFromInventory(GAME_OBJECT_ID objectID, int count);
|
||||
bool SetInventoryCount(GAME_OBJECT_ID objectID, int count);
|
||||
void PickedUpObject(GAME_OBJECT_ID objectID, std::optional<int> count = std::nullopt);
|
||||
void RemoveObjectFromInventory(GAME_OBJECT_ID objectID, std::optional<int> count = std::nullopt);
|
||||
int GetInventoryCount(GAME_OBJECT_ID objectID);
|
||||
void CollectCarriedItems(ItemInfo* item);
|
||||
void PickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
|
|
|
@ -20,8 +20,8 @@ static constexpr std::array<AmmoPickupInfo, 14> kAmmo
|
|||
{
|
||||
{ ID_PISTOLS_AMMO_ITEM, LaraWeaponType::Pistol, WeaponAmmoType::Ammo1, 0 },
|
||||
{ ID_UZI_AMMO_ITEM, LaraWeaponType::Uzi, WeaponAmmoType::Ammo1, 30 },
|
||||
{ ID_SHOTGUN_AMMO1_ITEM, LaraWeaponType::Shotgun, WeaponAmmoType::Ammo1, 36 },
|
||||
{ ID_SHOTGUN_AMMO2_ITEM, LaraWeaponType::Shotgun, WeaponAmmoType::Ammo2, 36 },
|
||||
{ ID_SHOTGUN_AMMO1_ITEM, LaraWeaponType::Shotgun, WeaponAmmoType::Ammo1, 6 },
|
||||
{ ID_SHOTGUN_AMMO2_ITEM, LaraWeaponType::Shotgun, WeaponAmmoType::Ammo2, 6 },
|
||||
{ ID_CROSSBOW_AMMO1_ITEM, LaraWeaponType::Crossbow, WeaponAmmoType::Ammo1, 10 },
|
||||
{ ID_CROSSBOW_AMMO2_ITEM, LaraWeaponType::Crossbow, WeaponAmmoType::Ammo2, 10 },
|
||||
{ ID_CROSSBOW_AMMO3_ITEM, LaraWeaponType::Crossbow, WeaponAmmoType::Ammo3, 10 },
|
||||
|
@ -35,7 +35,7 @@ static constexpr std::array<AmmoPickupInfo, 14> kAmmo
|
|||
}
|
||||
};
|
||||
|
||||
static bool TryModifyingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount, bool add)
|
||||
bool TryModifyingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType)
|
||||
{
|
||||
int arrayPos = GetArraySlot(kAmmo, objectID);
|
||||
if (-1 == arrayPos)
|
||||
|
@ -43,26 +43,40 @@ static bool TryModifyingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount
|
|||
|
||||
AmmoPickupInfo info = kAmmo[arrayPos];
|
||||
|
||||
auto currentAmmo = lara.Weapons[(int)info.LaraWeaponType].Ammo[(int)info.AmmoType];
|
||||
auto & currentWeapon = lara.Weapons[(int)info.LaraWeaponType];
|
||||
auto & currentAmmo = currentWeapon.Ammo[(int)info.AmmoType];
|
||||
|
||||
switch(modType)
|
||||
{
|
||||
case ModificationType::Set:
|
||||
currentAmmo = amount.value();
|
||||
currentAmmo.setInfinite(amount == -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!currentAmmo.hasInfinite())
|
||||
{
|
||||
int defaultModify = add ? info.Amount : -info.Amount;
|
||||
int newVal = int{ currentAmmo.getCount() } + (amount ? amount : defaultModify);
|
||||
lara.Weapons[(int)info.LaraWeaponType].Ammo[(int)info.AmmoType] = std::max(0, newVal);
|
||||
int defaultModify = modType == ModificationType::Add ? info.Amount : -info.Amount;
|
||||
int newVal = int{ currentAmmo.getCount() } + (amount.has_value() ? amount.value() : defaultModify);
|
||||
currentAmmo = std::max(0, newVal);
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// We need the extra bool because amount might be zero to signify the default amount.
|
||||
bool TryAddingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount)
|
||||
bool TryAddingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount)
|
||||
{
|
||||
return TryModifyingAmmo(lara, objectID, amount, true);
|
||||
return TryModifyingAmmo(lara, objectID, amount, ModificationType::Add);
|
||||
}
|
||||
|
||||
bool TryRemovingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount)
|
||||
bool TryRemovingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount)
|
||||
{
|
||||
return TryModifyingAmmo(lara, objectID, -amount, false);
|
||||
if (amount.has_value())
|
||||
return TryModifyingAmmo(lara, objectID, -amount.value(), ModificationType::Remove);
|
||||
else
|
||||
return TryModifyingAmmo(lara, objectID, amount, ModificationType::Remove);
|
||||
}
|
||||
|
||||
std::optional<int> GetAmmoCount(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
enum class ModificationType;
|
||||
enum GAME_OBJECT_ID : short;
|
||||
struct LaraInfo;
|
||||
|
||||
bool TryAddingAmmo(LaraInfo&, GAME_OBJECT_ID objectID, int amount = 0);
|
||||
bool TryRemovingAmmo(LaraInfo&, GAME_OBJECT_ID objectID, int amount = 0);
|
||||
bool TryAddingAmmo(LaraInfo&, GAME_OBJECT_ID objectID, std::optional<int> amount = std::nullopt);
|
||||
bool TryRemovingAmmo(LaraInfo&, GAME_OBJECT_ID objectID, std::optional<int> amount = std::nullopt);
|
||||
bool TryModifyingAmmo(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType);
|
||||
std::optional<int> GetAmmoCount(LaraInfo&, GAME_OBJECT_ID objectID);
|
||||
|
|
|
@ -26,32 +26,44 @@ static constexpr std::array<ConsumablePickupInfo, 3> kConsumables =
|
|||
}
|
||||
};
|
||||
|
||||
static bool TryModifyingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount, bool add)
|
||||
bool TryModifyingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType)
|
||||
{
|
||||
int arrayPos = GetArraySlot(kConsumables, objectID);
|
||||
if (-1 == arrayPos)
|
||||
return false;
|
||||
|
||||
ConsumablePickupInfo info = kConsumables[arrayPos];
|
||||
|
||||
if (lara.Inventory.*(info.Count) != -1)
|
||||
auto & currentAmt = lara.Inventory.*(info.Count);
|
||||
switch (modType)
|
||||
{
|
||||
int defaultModify = add ? info.Amount : -info.Amount;
|
||||
int newVal = lara.Inventory.*(info.Count) + (amount ? amount : defaultModify);
|
||||
lara.Inventory.*(info.Count) = std::max(0, newVal);
|
||||
case ModificationType::Set:
|
||||
currentAmt = amount.value();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (currentAmt != -1)
|
||||
{
|
||||
int defaultModify = ModificationType::Add == modType ? info.Amount : -info.Amount;
|
||||
int newVal = currentAmt + (amount.has_value() ? amount.value() : defaultModify);
|
||||
currentAmt = std::max(0, newVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryAddingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount)
|
||||
bool TryAddingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount)
|
||||
{
|
||||
return TryModifyingConsumable(lara, objectID, amount, true);
|
||||
return TryModifyingConsumable(lara, objectID, amount, ModificationType::Add);
|
||||
}
|
||||
|
||||
bool TryRemovingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount)
|
||||
bool TryRemovingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount)
|
||||
{
|
||||
return TryModifyingConsumable(lara, objectID, -amount, false);
|
||||
if (amount.has_value())
|
||||
return TryModifyingConsumable(lara, objectID, -amount.value(), ModificationType::Remove);
|
||||
else
|
||||
return TryModifyingConsumable(lara, objectID, amount, ModificationType::Remove);
|
||||
}
|
||||
|
||||
std::optional<int> GetConsumableCount(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
enum class ModificationType;
|
||||
enum GAME_OBJECT_ID : short;
|
||||
struct LaraInfo;
|
||||
|
||||
bool TryAddingConsumable(LaraInfo&, GAME_OBJECT_ID objectID, int amount = 0);
|
||||
bool TryRemovingConsumable(LaraInfo&, GAME_OBJECT_ID objectID, int amount = 0);
|
||||
bool TryAddingConsumable(LaraInfo&, GAME_OBJECT_ID objectID, std::optional<int> amount = 0);
|
||||
bool TryRemovingConsumable(LaraInfo&, GAME_OBJECT_ID objectID, std::optional<int> amount = 0);
|
||||
bool TryModifyingConsumable(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType);
|
||||
std::optional<int> GetConsumableCount(LaraInfo&, GAME_OBJECT_ID objectID);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "Game/pickup/pickup_key_items.h"
|
||||
|
||||
#include "Game/Lara/lara_struct.h"
|
||||
#include "Game/pickup/pickup_misc_items.h"
|
||||
#include "Game/pickup/pickuputil.h"
|
||||
#include "Objects/objectslist.h"
|
||||
|
||||
template <size_t N> struct KeyPickupInfo
|
||||
|
@ -64,29 +64,42 @@ template<> static std::pair<int*, size_t> GetArrayInternal<0>(LaraInfo& lara, GA
|
|||
return TestAgainstRange<0>(lara, objectID);
|
||||
}
|
||||
|
||||
static bool TryModifyingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount, bool add)
|
||||
bool TryModifyingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType)
|
||||
{
|
||||
// kick off the recursion starting at the last element
|
||||
auto result = GetArrayInternal<nInfos - 1>(lara, objectID);
|
||||
|
||||
if (result.first)
|
||||
{
|
||||
int defaultModify = add ? kDefaultPickupAmount : -kDefaultPickupAmount;
|
||||
int newVal = int{result.first[result.second]} + (amount ? amount : defaultModify);
|
||||
auto& amt = result.first[result.second];
|
||||
switch (modType)
|
||||
{
|
||||
case ModificationType::Set:
|
||||
// infinite key items not yet implemented
|
||||
amt = amount.value();
|
||||
break;
|
||||
default:
|
||||
int defaultModify = modType == ModificationType::Add ? kDefaultPickupAmount : -kDefaultPickupAmount;
|
||||
int newVal = int{ result.first[result.second] } + (amount.has_value() ? amount.value() : defaultModify);
|
||||
result.first[result.second] = std::max(0, newVal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryAddingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, int count)
|
||||
bool TryAddingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount)
|
||||
{
|
||||
return TryModifyingKeyItem(lara, objectID, count, true);
|
||||
return TryModifyingKeyItem(lara, objectID, amount, ModificationType::Add);
|
||||
}
|
||||
|
||||
bool TryRemovingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, int count)
|
||||
bool TryRemovingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount)
|
||||
{
|
||||
return TryModifyingKeyItem(lara, objectID, -count, false);
|
||||
if(amount.has_value())
|
||||
return TryModifyingKeyItem(lara, objectID, -amount.value(), ModificationType::Remove);
|
||||
else
|
||||
return TryModifyingKeyItem(lara, objectID, amount, ModificationType::Remove);
|
||||
}
|
||||
|
||||
std::optional<int> GetKeyItemCount(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
enum class ModificationType;
|
||||
enum GAME_OBJECT_ID : short;
|
||||
struct LaraInfo;
|
||||
|
||||
bool TryAddingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, int count);
|
||||
bool TryRemovingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, int count);
|
||||
bool TryAddingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount = std::nullopt);
|
||||
bool TryRemovingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount = std::nullopt);
|
||||
bool TryModifyingKeyItem(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType);
|
||||
std::optional<int> GetKeyItemCount(LaraInfo& lara, GAME_OBJECT_ID objectID);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include "framework.h"
|
||||
#include "Game/pickup/pickup_misc_items.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "Game/Lara/lara_struct.h"
|
||||
#include "Game/pickup/pickuputil.h"
|
||||
#include "Objects/objectslist.h"
|
||||
|
@ -34,11 +32,14 @@ auto LaserSightIsEquipped(LaraInfo& lara)
|
|||
return false;
|
||||
};
|
||||
|
||||
static bool TryModifyMiscCount(LaraInfo& lara, GAME_OBJECT_ID objectID, bool add)
|
||||
bool TryModifyMiscCount(LaraInfo & lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType)
|
||||
{
|
||||
// If adding, replace the small/large waterskin with one of the requested
|
||||
// capacity. If removing, only remove the waterskin if it contains the given
|
||||
// capacity.
|
||||
|
||||
bool add = ModificationType::Add == modType || ((ModificationType::Set == modType) && amount != 0);
|
||||
|
||||
auto modifyWaterSkinAmount = [&](byte& currentFlag, byte newFlag)
|
||||
{
|
||||
if (add)
|
||||
|
@ -141,12 +142,12 @@ static bool TryModifyMiscCount(LaraInfo& lara, GAME_OBJECT_ID objectID, bool add
|
|||
|
||||
bool TryAddMiscItem(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
{
|
||||
return TryModifyMiscCount(lara, objectID, true);
|
||||
return TryModifyMiscCount(lara, objectID, std::nullopt, ModificationType::Add);
|
||||
}
|
||||
|
||||
bool TryRemoveMiscItem(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
{
|
||||
return TryModifyMiscCount(lara, objectID, false);
|
||||
return TryModifyMiscCount(lara, objectID, std::nullopt, ModificationType::Remove);
|
||||
}
|
||||
|
||||
std::optional<bool> HasMiscItem(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
enum class ModificationType;
|
||||
enum GAME_OBJECT_ID : short;
|
||||
struct LaraInfo;
|
||||
|
||||
bool TryAddMiscItem(LaraInfo& lara, GAME_OBJECT_ID objectID);
|
||||
bool TryRemoveMiscItem(LaraInfo& lara, GAME_OBJECT_ID objectID);
|
||||
bool TryModifyMiscCount(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> amount, ModificationType modType);
|
||||
std::optional<bool> HasMiscItem(LaraInfo& lara, GAME_OBJECT_ID objectID);
|
||||
|
|
|
@ -3,30 +3,38 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
#include "lara_fire.h"
|
||||
#include "Game/Lara/lara_struct.h"
|
||||
#include "Game/pickup/pickuputil.h"
|
||||
#include "Game/pickup/pickup_ammo.h"
|
||||
#include "Objects/objectslist.h"
|
||||
|
||||
enum class HolsterType
|
||||
{
|
||||
Hips,
|
||||
Back
|
||||
};
|
||||
|
||||
struct WeaponPickupInfo
|
||||
{
|
||||
GAME_OBJECT_ID ObjectID;
|
||||
GAME_OBJECT_ID AmmoID; // When the player picks up a weapon, they get one clip's worth of this ammo.
|
||||
LaraWeaponType LaraWeaponType;
|
||||
HolsterType Holster;
|
||||
};
|
||||
|
||||
static constexpr std::array<WeaponPickupInfo, 9> kWeapons
|
||||
{
|
||||
{
|
||||
{ ID_PISTOLS_ITEM, ID_PISTOLS_AMMO_ITEM, LaraWeaponType::Pistol },
|
||||
{ ID_UZI_ITEM, ID_UZI_AMMO_ITEM, LaraWeaponType::Uzi },
|
||||
{ ID_SHOTGUN_ITEM, ID_SHOTGUN_AMMO1_ITEM, LaraWeaponType::Shotgun },
|
||||
{ ID_CROSSBOW_ITEM, ID_CROSSBOW_AMMO1_ITEM, LaraWeaponType::Crossbow },
|
||||
{ ID_REVOLVER_ITEM, ID_REVOLVER_AMMO_ITEM, LaraWeaponType::Revolver },
|
||||
{ ID_HK_ITEM, ID_HK_AMMO_ITEM, LaraWeaponType::HK },
|
||||
{ ID_GRENADE_GUN_ITEM, ID_GRENADE_AMMO1_ITEM, LaraWeaponType::GrenadeLauncher },
|
||||
{ ID_ROCKET_LAUNCHER_ITEM, ID_ROCKET_LAUNCHER_AMMO_ITEM, LaraWeaponType::RocketLauncher },
|
||||
{ ID_HARPOON_ITEM, ID_HARPOON_AMMO_ITEM, LaraWeaponType::HarpoonGun }
|
||||
{ ID_PISTOLS_ITEM, ID_PISTOLS_AMMO_ITEM, LaraWeaponType::Pistol, HolsterType::Hips },
|
||||
{ ID_UZI_ITEM, ID_UZI_AMMO_ITEM, LaraWeaponType::Uzi, HolsterType::Hips},
|
||||
{ ID_SHOTGUN_ITEM, ID_SHOTGUN_AMMO1_ITEM, LaraWeaponType::Shotgun, HolsterType::Back },
|
||||
{ ID_CROSSBOW_ITEM, ID_CROSSBOW_AMMO1_ITEM, LaraWeaponType::Crossbow, HolsterType::Back},
|
||||
{ ID_REVOLVER_ITEM, ID_REVOLVER_AMMO_ITEM, LaraWeaponType::Revolver, HolsterType::Hips},
|
||||
{ ID_HK_ITEM, ID_HK_AMMO_ITEM, LaraWeaponType::HK, HolsterType::Back},
|
||||
{ ID_GRENADE_GUN_ITEM, ID_GRENADE_AMMO1_ITEM, LaraWeaponType::GrenadeLauncher, HolsterType::Back },
|
||||
{ ID_ROCKET_LAUNCHER_ITEM, ID_ROCKET_LAUNCHER_AMMO_ITEM, LaraWeaponType::RocketLauncher, HolsterType::Back },
|
||||
{ ID_HARPOON_ITEM, ID_HARPOON_AMMO_ITEM, LaraWeaponType::HarpoonGun, HolsterType::Back }
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -41,7 +49,7 @@ static int GetWeapon(GAME_OBJECT_ID objectID)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static bool TryModifyWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, int ammoAmount, bool add)
|
||||
bool TryModifyWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> count, ModificationType type)
|
||||
{
|
||||
int arrayPos = GetArraySlot(kWeapons, objectID);
|
||||
if (-1 == arrayPos)
|
||||
|
@ -51,25 +59,56 @@ static bool TryModifyWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, int ammoAmo
|
|||
|
||||
// Set the SelectedAmmo type to WeaponAmmoType::Ammo1 (0) if adding the weapon for the first time.
|
||||
// Note that this refers to the index of the weapon's ammo array, and not the weapon's actual ammunition count.
|
||||
if (!lara.Weapons[(int)info.LaraWeaponType].Present)
|
||||
lara.Weapons[(int)info.LaraWeaponType].SelectedAmmo = WeaponAmmoType::Ammo1;
|
||||
auto& currWeapon = lara.Weapons[(int)info.LaraWeaponType];
|
||||
|
||||
lara.Weapons[(int)info.LaraWeaponType].Present = add;
|
||||
auto ammoID = info.AmmoID;
|
||||
return add ? TryAddingAmmo(lara, ammoID, ammoAmount) : TryRemovingAmmo(lara, ammoID, ammoAmount);
|
||||
if (!currWeapon.Present)
|
||||
currWeapon.SelectedAmmo = WeaponAmmoType::Ammo1;
|
||||
|
||||
bool add = ModificationType::Add == type || ((ModificationType::Set == type) && count != 0);
|
||||
currWeapon.Present = add;
|
||||
|
||||
if(!add)
|
||||
{
|
||||
if (info.LaraWeaponType == lara.Control.Weapon.GunType || info.LaraWeaponType == lara.Control.Weapon.LastGunType)
|
||||
{
|
||||
lara.Control.Weapon.RequestGunType = LaraWeaponType::None;
|
||||
|
||||
// If Lara has pistols and it's not the pistols we're removing, set them
|
||||
// as the "next weapon" so that Lara equips them next.
|
||||
if (LaraWeaponType::Pistol == info.LaraWeaponType || !lara.Weapons[(int)LaraWeaponType::Pistol].Present)
|
||||
{
|
||||
lara.Control.Weapon.LastGunType = LaraWeaponType::None;
|
||||
}
|
||||
else
|
||||
{
|
||||
lara.Control.Weapon.LastGunType = LaraWeaponType::Pistol;
|
||||
}
|
||||
}
|
||||
|
||||
if (HolsterType::Hips == info.Holster && lara.Control.Weapon.HolsterInfo.LeftHolster == HolsterSlotForWeapon(info.LaraWeaponType))
|
||||
{
|
||||
lara.Control.Weapon.HolsterInfo.LeftHolster = HolsterSlot::Empty;
|
||||
lara.Control.Weapon.HolsterInfo.RightHolster = HolsterSlot::Empty;
|
||||
}
|
||||
else if (HolsterType::Back == info.Holster && lara.Control.Weapon.HolsterInfo.BackHolster == HolsterSlotForWeapon(info.LaraWeaponType))
|
||||
{
|
||||
lara.Control.Weapon.HolsterInfo.BackHolster = HolsterSlot::Empty;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adding a weapon will either give the player the weapon + an amount of ammo, or,
|
||||
// if they already have the weapon, simply the ammo.
|
||||
bool TryAddingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount)
|
||||
// Adding a weapon will not give the player any ammo even if they already have the weapon
|
||||
bool TryAddingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
{
|
||||
return TryModifyWeapon(lara, objectID, amount, true);
|
||||
return TryModifyWeapon(lara, objectID, 1, ModificationType::Add);
|
||||
}
|
||||
|
||||
// Removing a weapon is the reverse of the above; it will remove the weapon (if it's there) and the amount of ammo.
|
||||
bool TryRemovingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount)
|
||||
// Removing a weapon is the reverse of the above; it will remove the weapon (if it's there).
|
||||
bool TryRemovingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
{
|
||||
return TryModifyWeapon(lara, objectID, amount, false);
|
||||
return TryModifyWeapon(lara, objectID, 1, ModificationType::Remove);
|
||||
}
|
||||
|
||||
std::optional<bool> HasWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
enum class ModificationType;
|
||||
enum GAME_OBJECT_ID : short;
|
||||
struct LaraInfo;
|
||||
|
||||
bool TryAddingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount = 0);
|
||||
bool TryRemovingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, int amount = 0);
|
||||
bool TryAddingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID);
|
||||
bool TryRemovingWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID);
|
||||
bool TryModifyWeapon(LaraInfo& lara, GAME_OBJECT_ID objectID, std::optional<int> count, ModificationType type);
|
||||
std::optional<bool> HasWeapon(LaraInfo&, GAME_OBJECT_ID objectID);
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
enum GAME_OBJECT_ID : short;
|
||||
|
||||
enum class ModificationType
|
||||
{
|
||||
Add,
|
||||
Remove,
|
||||
Set
|
||||
};
|
||||
|
||||
// Given an array and an Object ID, iterate through the array until we find
|
||||
// an ID that matches the ID we've passed in.
|
||||
template <typename T, size_t N> int GetArraySlot(std::array<T, N> const& arr, GAME_OBJECT_ID objectID)
|
||||
|
|
|
@ -42,6 +42,7 @@ struct ROOM_LIGHT
|
|||
struct MESH_INFO
|
||||
{
|
||||
PHD_3DPOS pos;
|
||||
int roomNumber;
|
||||
float scale;
|
||||
short staticNumber;
|
||||
short flags;
|
||||
|
|
|
@ -818,7 +818,7 @@ bool SaveGame::Save(int slot)
|
|||
|
||||
staticMesh.add_flags(room->mesh[j].flags);
|
||||
staticMesh.add_hit_points(room->mesh[j].HitPoints);
|
||||
staticMesh.add_room_number(i);
|
||||
staticMesh.add_room_number(room->mesh[j].roomNumber);
|
||||
staticMesh.add_number(j);
|
||||
staticMeshes.push_back(staticMesh.Finish());
|
||||
}
|
||||
|
@ -1027,43 +1027,45 @@ bool SaveGame::Save(int slot)
|
|||
alternatePendulumOffset = alternatePendulumInfo.Finish();
|
||||
}
|
||||
|
||||
|
||||
std::vector<flatbuffers::Offset<Save::ScriptTable>> levelTableVec;
|
||||
std::vector<flatbuffers::Offset<flatbuffers::String>> levelStringVec2;
|
||||
|
||||
//std::vector<savedTable> savedTables;
|
||||
std::vector<std::string> savedStrings;
|
||||
std::vector<SavedVar> savedVars;
|
||||
|
||||
g_GameScript->GetVariables(savedVars);
|
||||
|
||||
|
||||
std::vector<flatbuffers::Offset<Save::UnionTable>> varsVec;
|
||||
for (auto const& s : savedVars)
|
||||
{
|
||||
flatbuffers::Offset<Save::ScriptTable> scriptTableOffset;
|
||||
flatbuffers::Offset<Save::stringTable> strOffset;
|
||||
flatbuffers::Offset<Save::doubleTable> doubleOffset;
|
||||
flatbuffers::Offset<Save::boolTable> boolOffset;
|
||||
auto putDataInVec = [&varsVec, &fbb](Save::VarUnion type, auto const & offsetVar)
|
||||
{
|
||||
Save::UnionTableBuilder ut{ fbb };
|
||||
ut.add_u_type(type);
|
||||
ut.add_u(offsetVar.Union());
|
||||
varsVec.push_back(ut.Finish());
|
||||
};
|
||||
|
||||
if (std::holds_alternative<std::string>(s))
|
||||
{
|
||||
auto strOffset2 = fbb.CreateString(std::get<std::string>(s));
|
||||
Save::stringTableBuilder stb{ fbb };
|
||||
stb.add_str(strOffset2);
|
||||
strOffset = stb.Finish();
|
||||
auto strOffset = stb.Finish();
|
||||
|
||||
putDataInVec(Save::VarUnion::str, strOffset);
|
||||
}
|
||||
else if (std::holds_alternative<double>(s))
|
||||
{
|
||||
Save::doubleTableBuilder dtb{ fbb };
|
||||
dtb.add_scalar(std::get<double>(s));
|
||||
doubleOffset = dtb.Finish();
|
||||
auto doubleOffset = dtb.Finish();
|
||||
|
||||
putDataInVec(Save::VarUnion::num, doubleOffset);
|
||||
}
|
||||
else if (std::holds_alternative<bool>(s))
|
||||
{
|
||||
Save::boolTableBuilder btb{ fbb };
|
||||
btb.add_scalar(std::get<bool>(s));
|
||||
boolOffset = btb.Finish();
|
||||
auto boolOffset = btb.Finish();
|
||||
|
||||
putDataInVec(Save::VarUnion::boolean, boolOffset);
|
||||
}
|
||||
else if (std::holds_alternative<IndexTable>(s))
|
||||
{
|
||||
|
@ -1077,37 +1079,43 @@ bool SaveGame::Save(int slot)
|
|||
auto vecOffset = fbb.CreateVectorOfStructs(keyValVec);
|
||||
Save::ScriptTableBuilder stb{ fbb };
|
||||
stb.add_keys_vals(vecOffset);
|
||||
scriptTableOffset = stb.Finish();
|
||||
}
|
||||
auto scriptTableOffset = stb.Finish();
|
||||
|
||||
Save::UnionTableBuilder ut{ fbb };
|
||||
if (std::holds_alternative<std::string>(s))
|
||||
{
|
||||
ut.add_u_type(Save::VarUnion::str);
|
||||
ut.add_u(strOffset.Union());
|
||||
putDataInVec(Save::VarUnion::tab, scriptTableOffset);
|
||||
}
|
||||
else if (std::holds_alternative<double>(s))
|
||||
else if (std::holds_alternative<FuncName>(s))
|
||||
{
|
||||
ut.add_u_type(Save::VarUnion::num);
|
||||
ut.add_u(doubleOffset.Union());
|
||||
std::string data = std::get<FuncName>(s).name;
|
||||
auto strOffset = fbb.CreateString(data);
|
||||
Save::funcNameTableBuilder ftb{ fbb };
|
||||
ftb.add_str(strOffset);
|
||||
auto funcNameOffset = ftb.Finish();
|
||||
|
||||
putDataInVec(Save::VarUnion::funcName, funcNameOffset);
|
||||
}
|
||||
else if (std::holds_alternative<bool>(s))
|
||||
else if (std::holds_alternative<Vector3Int>(s))
|
||||
{
|
||||
ut.add_u_type(Save::VarUnion::boolean);
|
||||
ut.add_u(boolOffset.Union());
|
||||
Save::vec3TableBuilder vtb{ fbb };
|
||||
Vector3Int data = std::get<Vector3Int>(s);
|
||||
Save::Vector3 saveVec = FromVector3(std::get<Vector3Int>(s));
|
||||
vtb.add_vec(&saveVec);
|
||||
auto vec3Offset = vtb.Finish();
|
||||
|
||||
putDataInVec(Save::VarUnion::vec3, vec3Offset);
|
||||
}
|
||||
else if (std::holds_alternative<IndexTable>(s))
|
||||
{
|
||||
ut.add_u_type(Save::VarUnion::tab);
|
||||
ut.add_u(scriptTableOffset.Union());
|
||||
}
|
||||
varsVec.push_back(ut.Finish());
|
||||
}
|
||||
auto unionVec = fbb.CreateVector(varsVec);
|
||||
Save::UnionVecBuilder uvb{ fbb };
|
||||
uvb.add_members(unionVec);
|
||||
auto unionVecOffset = uvb.Finish();
|
||||
|
||||
std::vector<std::string> callbackVecPreControl;
|
||||
std::vector<std::string> callbackVecPostControl;
|
||||
g_GameScript->GetCallbackStrings(callbackVecPreControl, callbackVecPostControl);
|
||||
|
||||
auto stringsCallbackPreControl = fbb.CreateVectorOfStrings(callbackVecPreControl);
|
||||
auto stringsCallbackPostControl = fbb.CreateVectorOfStrings(callbackVecPostControl);
|
||||
|
||||
Save::SaveGameBuilder sgb{ fbb };
|
||||
|
||||
sgb.add_header(headerOffset);
|
||||
|
@ -1151,6 +1159,8 @@ bool SaveGame::Save(int slot)
|
|||
}
|
||||
|
||||
sgb.add_script_vars(unionVecOffset);
|
||||
sgb.add_callbacks_pre_control(stringsCallbackPreControl);
|
||||
sgb.add_callbacks_post_control(stringsCallbackPostControl);
|
||||
|
||||
auto sg = sgb.Finish();
|
||||
fbb.Finish(sg);
|
||||
|
@ -1235,6 +1245,7 @@ bool SaveGame::Load(int slot)
|
|||
int number = staticMesh->number();
|
||||
|
||||
room->mesh[number].pos = ToPHD(staticMesh->pose());
|
||||
room->mesh[number].roomNumber = staticMesh->room_number();
|
||||
room->mesh[number].scale = staticMesh->scale();
|
||||
room->mesh[number].color = ToVector4(staticMesh->color());
|
||||
|
||||
|
@ -1294,9 +1305,6 @@ bool SaveGame::Load(int slot)
|
|||
|
||||
ZeroMemory(&Lara, sizeof(LaraInfo));
|
||||
|
||||
// Items
|
||||
InitialiseItemArray(NUM_ITEMS);
|
||||
|
||||
NextItemFree = s->next_item_free();
|
||||
NextItemActive = s->next_item_active();
|
||||
|
||||
|
@ -1924,11 +1932,32 @@ bool SaveGame::Load(int slot)
|
|||
std::get<IndexTable>(loadedTab).push_back(std::make_pair(p->key(), p->val()));
|
||||
}
|
||||
}
|
||||
else if (var->u_type() == Save::VarUnion::vec3)
|
||||
{
|
||||
loadedVars.push_back(ToVector3Int(var->u_as_vec3()->vec()));
|
||||
}
|
||||
else if (var->u_type() == Save::VarUnion::funcName)
|
||||
{
|
||||
loadedVars.push_back(FuncName{var->u_as_funcName()->str()->str()});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
g_GameScript->SetVariables(loadedVars);
|
||||
|
||||
std::vector<std::string> callbacksPreControlVec;
|
||||
auto callbacksPreControlOffsetVec = s->callbacks_pre_control();
|
||||
for (auto const& s : *callbacksPreControlOffsetVec)
|
||||
callbacksPreControlVec.push_back(s->str());
|
||||
|
||||
std::vector<std::string> callbacksPostControlVec;
|
||||
auto callbacksPostControlOffsetVec = s->callbacks_post_control();
|
||||
for (auto const& s : *callbacksPostControlOffsetVec)
|
||||
callbacksPostControlVec.push_back(s->str());
|
||||
|
||||
g_GameScript->SetCallbackStrings(callbacksPreControlVec, callbacksPostControlVec);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ namespace TEN::Entities::Effects
|
|||
return;
|
||||
}
|
||||
|
||||
if (ItemNearLara(&fx->pos, 200))
|
||||
if (ItemNearLara(&fx->pos.Position, 200))
|
||||
{
|
||||
LaraItem->HitStatus = true;
|
||||
if (fx->flag1 != 6)
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace TEN::Entities::Effects
|
|||
SoundEffect(SFX_TR4_LOOP_FOR_SMALL_FIRES, &item->Pose);
|
||||
|
||||
if (!Lara.Burn &&
|
||||
ItemNearLara(&item->Pose, 600) &&
|
||||
ItemNearLara(&item->Pose.Position, 600) &&
|
||||
(pow(LaraItem->Pose.Position.x - item->Pose.Position.x, 2) +
|
||||
pow(LaraItem->Pose.Position.z - item->Pose.Position.z, 2) < pow(SECTOR(0.5f), 2)) &&
|
||||
Lara.Control.WaterStatus != WaterStatus::FlyCheat)
|
||||
|
@ -625,8 +625,7 @@ namespace TEN::Entities::Effects
|
|||
|
||||
TriggerDynamicLight(x, item->Pose.Position.y, z, 12, (GetRandomControl() & 0x3F) + 192, ((GetRandomControl() >> 4) & 0x1F) + 96, 0);
|
||||
|
||||
auto pos = PHD_3DPOS(item->Pose.Position);
|
||||
|
||||
auto pos = item->Pose.Position;
|
||||
if (ItemNearLara(&pos, 600))
|
||||
{
|
||||
if ((!Lara.Burn) && Lara.Control.WaterStatus != WaterStatus::FlyCheat)
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace TEN::Entities::TR4
|
|||
locust->pos.Position.y += locust->randomRotation * phd_sin(-locust->pos.Orientation.x);
|
||||
locust->pos.Position.z += locust->randomRotation * phd_cos(locust->pos.Orientation.x) * phd_cos(locust->pos.Orientation.y);
|
||||
|
||||
if (ItemNearTarget(&locust->pos, LaraItem, CLICK(1) / 2))
|
||||
if (ItemNearTarget(&locust->pos.Position, LaraItem, CLICK(1) / 2))
|
||||
{
|
||||
TriggerBlood(locust->pos.Position.x, locust->pos.Position.y, locust->pos.Position.z, 2 * GetRandomControl(), 2);
|
||||
DoDamage(LaraItem, LOCUST_LARA_DAMAGE);
|
||||
|
|
|
@ -15,19 +15,23 @@
|
|||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto APE_ATTACK_DAMAGE = 200;
|
||||
|
||||
constexpr auto APE_ATTACK_RANGE = SQUARE(SECTOR(0.42f));
|
||||
constexpr auto APE_PANIC_RANGE = SQUARE(SECTOR(2));
|
||||
|
||||
constexpr auto APE_JUMP_CHANCE = 0xA0;
|
||||
constexpr auto APE_POUND_CHEST_CHANCE = APE_JUMP_CHANCE + 0xA0;
|
||||
constexpr auto APE_POUND_GROUND_CHANCE = APE_POUND_CHEST_CHANCE + 0xA0;
|
||||
constexpr auto APE_RUN_LEFT_CHANCE = APE_POUND_GROUND_CHANCE + 0xA0;
|
||||
constexpr auto APE_IDLE_JUMP_CHANCE = 1.0f / 6;
|
||||
constexpr auto APE_IDLE_POUND_CHEST_CHANCE = 1.0f / 3;
|
||||
constexpr auto APE_IDLE_POUND_GROUND_CHANCE = 1.0f / 2;
|
||||
constexpr auto APE_IDLE_RUN_LEFT_CHANCE = 1.0f / 2;
|
||||
constexpr auto APE_RUN_JUMP_CHANCE = APE_IDLE_JUMP_CHANCE / 32;
|
||||
constexpr auto APE_RUN_POUND_CHEST_CHANCE = APE_IDLE_POUND_CHEST_CHANCE / 32;
|
||||
constexpr auto APE_RUN_POUND_GROUND_CHANCE = APE_IDLE_POUND_GROUND_CHANCE / 32;
|
||||
constexpr auto APE_RUN_RUN_LEFT_CHANCE = APE_IDLE_RUN_LEFT_CHANCE / 32;
|
||||
|
||||
constexpr auto SHIFT = 75;
|
||||
constexpr auto APE_SHIFT = 75;
|
||||
|
||||
#define APE_RUN_TURN_RATE_MAX ANGLE(5.0f)
|
||||
#define APE_DISPLAY_ANGLE ANGLE(45.0f)
|
||||
|
@ -118,12 +122,12 @@ namespace TEN::Entities::TR1
|
|||
|
||||
if (yy < yFloor)
|
||||
{
|
||||
item->Pose.Position.x = (yFloor * SECTOR(1)) - SHIFT;
|
||||
item->Pose.Position.x = (yFloor * SECTOR(1)) - APE_SHIFT;
|
||||
item->Pose.Orientation.y = ANGLE(90.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Pose.Position.x = (yy * SECTOR(1)) + SHIFT;
|
||||
item->Pose.Position.x = (yy * SECTOR(1)) + APE_SHIFT;
|
||||
item->Pose.Orientation.y = -ANGLE(90.0f);
|
||||
}
|
||||
}
|
||||
|
@ -131,12 +135,12 @@ namespace TEN::Entities::TR1
|
|||
{
|
||||
if (xx < xFloor)
|
||||
{
|
||||
item->Pose.Position.z = (xFloor * SECTOR(1)) - SHIFT;
|
||||
item->Pose.Position.z = (xFloor * SECTOR(1)) - APE_SHIFT;
|
||||
item->Pose.Orientation.y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Pose.Position.z = (xx * SECTOR(1)) + SHIFT;
|
||||
item->Pose.Position.z = (xx * SECTOR(1)) + APE_SHIFT;
|
||||
item->Pose.Orientation.y = -ANGLE(180.0f);
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +149,7 @@ namespace TEN::Entities::TR1
|
|||
// diagonal
|
||||
}
|
||||
|
||||
if (CreatureVault(itemNumber, angle, 2, SHIFT) == 2)
|
||||
if (CreatureVault(itemNumber, angle, 2, APE_SHIFT) == 2)
|
||||
{
|
||||
item->Pose.Position.y = y;
|
||||
SetAnimation(item, APE_ANIM_VAULT);
|
||||
|
@ -184,8 +188,6 @@ namespace TEN::Entities::TR1
|
|||
if (item->HitStatus || AI.distance < APE_PANIC_RANGE)
|
||||
creatureInfo->Flags |= APE_FLAG_ATTACK;
|
||||
|
||||
short random;
|
||||
|
||||
switch (item->Animation.ActiveState)
|
||||
{
|
||||
case APE_STATE_IDLE:
|
||||
|
@ -207,14 +209,13 @@ namespace TEN::Entities::TR1
|
|||
else if (!(creatureInfo->Flags & APE_FLAG_ATTACK) &&
|
||||
AI.zoneNumber == AI.enemyZone && AI.ahead)
|
||||
{
|
||||
random = (short)(GetRandomControl() / 32);
|
||||
if (random < APE_JUMP_CHANCE)
|
||||
if (TestProbability(APE_IDLE_JUMP_CHANCE))
|
||||
item->Animation.TargetState = APE_STATE_JUMP;
|
||||
else if (random < APE_POUND_CHEST_CHANCE)
|
||||
else if (TestProbability(APE_IDLE_POUND_CHEST_CHANCE))
|
||||
item->Animation.TargetState = APE_STATE_POUND_CHEST;
|
||||
else if (random < APE_POUND_GROUND_CHANCE)
|
||||
else if (TestProbability(APE_IDLE_POUND_GROUND_CHANCE))
|
||||
item->Animation.TargetState = APE_STATE_POUND_GROUND;
|
||||
else if (random < APE_RUN_LEFT_CHANCE)
|
||||
else if (TestProbability(APE_IDLE_RUN_LEFT_CHANCE))
|
||||
{
|
||||
item->Animation.TargetState = APE_STATE_RUN_LEFT;
|
||||
creatureInfo->MaxTurn = 0;
|
||||
|
@ -246,18 +247,17 @@ namespace TEN::Entities::TR1
|
|||
}
|
||||
else if (creatureInfo->Mood != MoodType::Escape)
|
||||
{
|
||||
random = (short)GetRandomControl();
|
||||
if (random < APE_JUMP_CHANCE)
|
||||
if (TestProbability(APE_RUN_JUMP_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = APE_STATE_JUMP;
|
||||
item->Animation.TargetState = APE_STATE_IDLE;
|
||||
}
|
||||
else if (random < APE_POUND_CHEST_CHANCE)
|
||||
else if (TestProbability(APE_RUN_POUND_CHEST_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = APE_STATE_POUND_CHEST;
|
||||
item->Animation.TargetState = APE_STATE_IDLE;
|
||||
}
|
||||
else if (random < APE_POUND_GROUND_CHANCE)
|
||||
else if (TestProbability(APE_RUN_POUND_GROUND_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = APE_STATE_POUND_GROUND;
|
||||
item->Animation.TargetState = APE_STATE_IDLE;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void ApeControl(short itemNumber);
|
||||
}
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
#include "Game/Lara/lara.h"
|
||||
#include "Game/misc.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/setup.h"
|
||||
|
||||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto BEAR_RUN_DAMAGE = 3;
|
||||
constexpr auto BEAR_ATTACK_DAMAGE = 200;
|
||||
|
@ -25,9 +27,9 @@ namespace TEN::Entities::TR1
|
|||
constexpr auto BEAR_REAR_SWIPE_ATTACK_RANGE = SECTOR(0.6f);
|
||||
constexpr auto BEAR_EAT_RANGE = CLICK(3);
|
||||
|
||||
constexpr auto BEAR_ROAR_CHANCE = 0x50;
|
||||
constexpr auto BEAR_REAR_CHANCE = 0x300;
|
||||
constexpr auto BEAR_DROP_CHANCE = 0x600;
|
||||
constexpr auto BEAR_ROAR_CHANCE = 1.0f / 400;
|
||||
constexpr auto BEAR_REAR_CHANCE = 1.0f / 40;
|
||||
constexpr auto BEAR_DROP_CHANCE = 1.0f / 22;
|
||||
|
||||
#define BEAR_WALK_TURN_RATE_MAX ANGLE(2.0f)
|
||||
#define BEAR_RUN_TURN_RATE_MAX ANGLE(5.0f)
|
||||
|
@ -81,8 +83,8 @@ namespace TEN::Entities::TR1
|
|||
auto* item = &g_Level.Items[itemNumber];
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
|
||||
short head = 0;
|
||||
short angle = 0;
|
||||
short head = 0;
|
||||
|
||||
if (item->HitPoints <= 0)
|
||||
{
|
||||
|
@ -117,8 +119,8 @@ namespace TEN::Entities::TR1
|
|||
{
|
||||
if (creature->Flags && item->TestBits(JointBitType::Touch, BearAttackJoints))
|
||||
{
|
||||
creature->Flags = 0;
|
||||
DoDamage(creature->Enemy, BEAR_SLAM_DAMAGE);
|
||||
creature->Flags = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -141,12 +143,12 @@ namespace TEN::Entities::TR1
|
|||
if (item->HitStatus)
|
||||
creature->Flags = 1;
|
||||
|
||||
const bool laraDead = LaraItem->HitPoints <= 0;
|
||||
bool isLaraDead = LaraItem->HitPoints <= 0;
|
||||
|
||||
switch (item->Animation.ActiveState)
|
||||
{
|
||||
case BEAR_STATE_IDLE:
|
||||
if (laraDead)
|
||||
if (isLaraDead)
|
||||
{
|
||||
if (AI.bite && AI.distance < pow(BEAR_EAT_RANGE, 2))
|
||||
item->Animation.TargetState = BEAR_STATE_EAT;
|
||||
|
@ -165,7 +167,7 @@ namespace TEN::Entities::TR1
|
|||
case BEAR_STATE_STROLL:
|
||||
creature->MaxTurn = BEAR_WALK_TURN_RATE_MAX;
|
||||
|
||||
if (laraDead && item->TestBits(JointBitType::Touch, BearAttackJoints) && AI.ahead)
|
||||
if (isLaraDead && item->TestBits(JointBitType::Touch, BearAttackJoints) && AI.ahead)
|
||||
item->Animation.TargetState = BEAR_STATE_IDLE;
|
||||
else if (creature->Mood != MoodType::Bored)
|
||||
{
|
||||
|
@ -174,10 +176,10 @@ namespace TEN::Entities::TR1
|
|||
if (creature->Mood == MoodType::Escape)
|
||||
item->Animation.RequiredState = BEAR_STATE_STROLL;
|
||||
}
|
||||
else if (GetRandomControl() < BEAR_ROAR_CHANCE)
|
||||
else if (TestProbability(BEAR_ROAR_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = BEAR_STATE_ROAR;
|
||||
item->Animation.TargetState = BEAR_STATE_IDLE;
|
||||
item->Animation.RequiredState = BEAR_STATE_ROAR;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -186,16 +188,14 @@ namespace TEN::Entities::TR1
|
|||
creature->MaxTurn = BEAR_RUN_TURN_RATE_MAX;
|
||||
|
||||
if (item->TestBits(JointBitType::Touch, BearAttackJoints))
|
||||
{
|
||||
DoDamage(creature->Enemy, BEAR_RUN_DAMAGE);
|
||||
}
|
||||
|
||||
if (creature->Mood == MoodType::Bored || laraDead)
|
||||
if (creature->Mood == MoodType::Bored || isLaraDead)
|
||||
item->Animation.TargetState = BEAR_STATE_IDLE;
|
||||
else if (AI.ahead && !item->Animation.RequiredState)
|
||||
{
|
||||
if (AI.distance < pow(BEAR_REAR_RANGE, 2) &&
|
||||
GetRandomControl() < BEAR_REAR_CHANCE &&
|
||||
TestProbability(BEAR_REAR_CHANCE) &&
|
||||
!creature->Flags)
|
||||
{
|
||||
item->Animation.RequiredState = BEAR_STATE_REAR;
|
||||
|
@ -227,8 +227,8 @@ namespace TEN::Entities::TR1
|
|||
case BEAR_STATE_WALK_FORWARD:
|
||||
if (creature->Flags)
|
||||
{
|
||||
item->Animation.RequiredState = BEAR_STATE_STROLL;
|
||||
item->Animation.TargetState = BEAR_STATE_REAR;
|
||||
item->Animation.RequiredState = BEAR_STATE_STROLL;
|
||||
}
|
||||
else if (AI.ahead && item->TestBits(JointBitType::Touch, BearAttackJoints))
|
||||
item->Animation.TargetState = BEAR_STATE_REAR;
|
||||
|
@ -237,15 +237,15 @@ namespace TEN::Entities::TR1
|
|||
item->Animation.TargetState = BEAR_STATE_REAR;
|
||||
item->Animation.RequiredState = BEAR_STATE_STROLL;
|
||||
}
|
||||
else if (creature->Mood == MoodType::Bored || GetRandomControl() < BEAR_ROAR_CHANCE)
|
||||
else if (creature->Mood == MoodType::Bored || TestProbability(BEAR_ROAR_CHANCE))
|
||||
{
|
||||
item->Animation.TargetState = BEAR_STATE_REAR;
|
||||
item->Animation.RequiredState = BEAR_STATE_ROAR;
|
||||
item->Animation.TargetState = BEAR_STATE_REAR;
|
||||
}
|
||||
else if (AI.distance > pow(BEAR_REAR_RANGE, 2) || GetRandomControl() < BEAR_DROP_CHANCE)
|
||||
else if (AI.distance > pow(BEAR_REAR_RANGE, 2) || TestProbability(BEAR_DROP_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = BEAR_STATE_IDLE;
|
||||
item->Animation.TargetState = BEAR_STATE_REAR;
|
||||
item->Animation.RequiredState = BEAR_STATE_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -264,8 +264,8 @@ namespace TEN::Entities::TR1
|
|||
if (!item->Animation.RequiredState &&
|
||||
item->TestBits(JointBitType::Touch, BearAttackJoints))
|
||||
{
|
||||
CreatureEffect(item, BearBite, DoBloodSplat);
|
||||
DoDamage(creature->Enemy, BEAR_ATTACK_DAMAGE);
|
||||
CreatureEffect(item, BearBite, DoBloodSplat);
|
||||
item->Animation.RequiredState = BEAR_STATE_IDLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void BearControl(short itemNumber);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto BIG_RAT_BITE_ATTACK_DAMAGE = 20;
|
||||
constexpr auto BIG_RAT_POUNCE_ATTACK_DAMAGE = 25;
|
||||
|
@ -27,7 +27,7 @@ namespace TEN::Entities::TR1
|
|||
constexpr auto BIG_RAT_POUNCE_ATTACK_RANGE = SQUARE(SECTOR(0.5f));
|
||||
constexpr auto BIG_RAT_WATER_BITE_ATTACK_RANGE = SQUARE(SECTOR(0.3f));
|
||||
|
||||
constexpr auto BIG_RAT_REAR_POSE_CHANCE = 0.008f;
|
||||
constexpr auto BIG_RAT_REAR_POSE_CHANCE = 1.0f / 128;
|
||||
constexpr auto BIG_RAT_SWIM_UP_DOWN_SPEED = 32;
|
||||
constexpr auto BIG_RAT_WATER_SURFACE_OFFSET = 10;
|
||||
|
||||
|
@ -115,10 +115,11 @@ namespace TEN::Entities::TR1
|
|||
auto* creature = GetCreatureInfo(item);
|
||||
|
||||
int waterHeight = GetRatWaterHeight(item);
|
||||
short head = 0;
|
||||
short angle = 0;
|
||||
bool isOnWater = waterHeight != NO_HEIGHT;
|
||||
|
||||
short angle = 0;
|
||||
short head = 0;
|
||||
|
||||
if (item->HitPoints <= 0)
|
||||
{
|
||||
if (item->Animation.ActiveState != BIG_RAT_STATE_LAND_DEATH &&
|
||||
|
@ -183,9 +184,9 @@ namespace TEN::Entities::TR1
|
|||
if (!item->Animation.RequiredState && AI.ahead &&
|
||||
item->TestBits(JointBitType::Touch, BigRatBite.meshNum))
|
||||
{
|
||||
item->Animation.RequiredState = BIG_RAT_STATE_IDLE;
|
||||
DoDamage(creature->Enemy, BIG_RAT_BITE_ATTACK_DAMAGE);
|
||||
CreatureEffect(item, BigRatBite, DoBloodSplat);
|
||||
item->Animation.RequiredState = BIG_RAT_STATE_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -194,9 +195,9 @@ namespace TEN::Entities::TR1
|
|||
if (!item->Animation.RequiredState && AI.ahead &&
|
||||
item->TestBits(JointBitType::Touch, BigRatBite.meshNum))
|
||||
{
|
||||
item->Animation.RequiredState = BIG_RAT_STATE_RUN_FORWARD;
|
||||
DoDamage(creature->Enemy, BIG_RAT_POUNCE_ATTACK_DAMAGE);
|
||||
CreatureEffect(item, BigRatBite, DoBloodSplat);
|
||||
item->Animation.RequiredState = BIG_RAT_STATE_RUN_FORWARD;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void InitialiseBigRat(short itemNumber);
|
||||
void BigRatControl(short itemNumber);
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
#include "Game/people.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/setup.h"
|
||||
|
||||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto CENTAUR_REAR_DAMAGE = 200;
|
||||
constexpr auto CENTAUR_REAR_RANGE = SECTOR(1.5f);
|
||||
constexpr auto CENTAUR_REAR_CHANCE = 0x60;
|
||||
constexpr auto CENTAUR_REAR_CHANCE = 1.0f / 340;
|
||||
constexpr auto CENTAUR_BOMB_VELOCITY = 20;
|
||||
|
||||
#define CENTAUR_TURN_RATE_MAX ANGLE(4.0f)
|
||||
|
@ -56,17 +58,14 @@ namespace TEN::Entities::TR1
|
|||
|
||||
auto* item = &g_Level.Items[itemNumber];
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
short head = 0;
|
||||
|
||||
short angle = 0;
|
||||
short head = 0;
|
||||
|
||||
if (item->HitPoints <= 0)
|
||||
{
|
||||
if (item->Animation.ActiveState != CENTAUR_STATE_DEATH)
|
||||
{
|
||||
item->Animation.AnimNumber = Objects[ID_CENTAUR_MUTANT].animIndex + CENTAUR_ANIM_DEATH;
|
||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||
item->Animation.ActiveState = CENTAUR_STATE_DEATH;
|
||||
}
|
||||
SetAnimation(item, CENTAUR_ANIM_DEATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -98,18 +97,18 @@ namespace TEN::Entities::TR1
|
|||
case CENTAUR_STATE_RUN_FORWARD:
|
||||
if (AI.bite && AI.distance < pow(CENTAUR_REAR_RANGE, 2))
|
||||
{
|
||||
item->Animation.RequiredState = CENTAUR_STATE_WARNING;
|
||||
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;
|
||||
item->Animation.TargetState = CENTAUR_STATE_IDLE;
|
||||
}
|
||||
else if (GetRandomControl() < CENTAUR_REAR_CHANCE)
|
||||
else if (TestProbability(CENTAUR_REAR_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = CENTAUR_STATE_WARNING;
|
||||
item->Animation.TargetState = CENTAUR_STATE_IDLE;
|
||||
item->Animation.RequiredState = CENTAUR_STATE_WARNING;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -137,8 +136,8 @@ namespace TEN::Entities::TR1
|
|||
if (!item->Animation.RequiredState &&
|
||||
item->TestBits(JointBitType::Touch, CentaurAttackJoints))
|
||||
{
|
||||
CreatureEffect(item, CentaurRearBite, DoBloodSplat);
|
||||
DoDamage(creature->Enemy, CENTAUR_REAR_DAMAGE);
|
||||
CreatureEffect(item, CentaurRearBite, DoBloodSplat);
|
||||
item->Animation.RequiredState = CENTAUR_STATE_IDLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto SHARD_VELOCITY = 250;
|
||||
constexpr auto BOMB_VELOCITY = 220;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
// - Bacon Lara cannot be targeted.
|
||||
// - Bacon Lara cannot move like Lara.
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
// Original:
|
||||
void InitialiseDoppelganger(short itemNumber)
|
||||
|
@ -80,26 +80,24 @@ namespace TEN::Entities::TR1
|
|||
int laraFloorHeight = GetCollision(LaraItem).Position.Floor;
|
||||
|
||||
// Animate bacon Lara, mirroring Lara's position.
|
||||
item->Animation.FrameNumber = LaraItem->Animation.FrameNumber;
|
||||
item->Animation.AnimNumber = LaraItem->Animation.AnimNumber;
|
||||
item->Pose.Position.x = pos.x;
|
||||
item->Pose.Position.y = pos.y;
|
||||
item->Pose.Position.z = pos.z;
|
||||
item->Animation.FrameNumber = LaraItem->Animation.FrameNumber;
|
||||
item->Pose.Position = pos;
|
||||
item->Pose.Orientation.x = LaraItem->Pose.Orientation.x;
|
||||
item->Pose.Orientation.y = LaraItem->Pose.Orientation.y - ANGLE(180.0f);
|
||||
item->Pose.Orientation.z = LaraItem->Pose.Orientation.z;
|
||||
ItemNewRoom(itemNumber, LaraItem->RoomNumber);
|
||||
|
||||
// Compare floor heights.
|
||||
if (item->Floor >= laraFloorHeight + SECTOR(1) + 1 && // Add 1 to avoid bacon Lara dying when exiting water.
|
||||
if (item->Floor >= (laraFloorHeight + SECTOR(1) + 1) && // Add 1 to avoid bacon Lara dying when exiting water.
|
||||
!LaraItem->Animation.IsAirborne)
|
||||
{
|
||||
SetAnimation(item, LA_JUMP_WALL_SMASH_START);
|
||||
item->Animation.Velocity.z = 0;
|
||||
item->Animation.Velocity.y = 0;
|
||||
item->Animation.IsAirborne = true;
|
||||
item->Data = -1;
|
||||
item->Animation.Velocity.y = 0.0f;
|
||||
item->Animation.Velocity.z = 0.0f;
|
||||
item->Pose.Position.y += 50;
|
||||
item->Data = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,8 +112,8 @@ namespace TEN::Entities::TR1
|
|||
item->Pose.Position.y = item->Floor;
|
||||
TestTriggers(item, true);
|
||||
|
||||
item->Animation.Velocity.y = 0;
|
||||
item->Animation.IsAirborne = false;
|
||||
item->Animation.Velocity.y = 0.0f;
|
||||
item->Animation.TargetState = LS_DEATH;
|
||||
item->Animation.RequiredState = LS_DEATH;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void InitialiseDoppelganger(short itemNumber);
|
||||
void DoppelgangerControl(short itemNumber);
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
#include "Game/misc.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/setup.h"
|
||||
|
||||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto MUTANT_ATTACK_DAMAGE = 500;
|
||||
constexpr auto MUTANT_CONTACT_DAMAGE = 6;
|
||||
|
@ -24,8 +26,9 @@ namespace TEN::Entities::TR1
|
|||
constexpr auto MUTANT_ATTACK_RANGE = SQUARE(SECTOR(2.5f));
|
||||
constexpr auto MUTANT_CLOSE_RANGE = SQUARE(SECTOR(2.2f));
|
||||
|
||||
constexpr auto MUTANT_ATTACK_1_CHANCE = 0x2AF8;
|
||||
constexpr auto MUTANT_ATTACK_2_CHANCE = 0x55F0;
|
||||
// TODO: Unused.
|
||||
constexpr auto MUTANT_ATTACK_1_CHANCE = 1.0f / 3.0f;
|
||||
constexpr auto MUTANT_ATTACK_2_CHANCE = MUTANT_ATTACK_1_CHANCE * 2;
|
||||
|
||||
#define MUTANT_NEED_TURN ANGLE(45.0f)
|
||||
#define MUTANT_TURN ANGLE(3.0f)
|
||||
|
@ -33,7 +36,7 @@ namespace TEN::Entities::TR1
|
|||
#define LARA_GIANT_MUTANT_DEATH 6 // TODO: Not 13? Check this.
|
||||
|
||||
const vector<int> MutantAttackJoints = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };
|
||||
const vector<int> MutantAttackLeftJoints = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
|
||||
const vector<int> MutantAttackLeftJoint = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
|
||||
const vector<int> MutantAttackRightJoints = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };
|
||||
|
||||
enum GiantMutantState
|
||||
|
@ -66,17 +69,13 @@ namespace TEN::Entities::TR1
|
|||
auto* item = &g_Level.Items[itemNumber];
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
|
||||
short head = 0;
|
||||
short angle = 0;
|
||||
short head = 0;
|
||||
|
||||
if (item->HitPoints <= 0)
|
||||
{
|
||||
if (item->Animation.ActiveState != MUTANT_STATE_DEATH)
|
||||
{
|
||||
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + MUTANT_ANIM_DEATH;
|
||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||
item->Animation.ActiveState = MUTANT_STATE_DEATH;
|
||||
}
|
||||
SetAnimation(item, MUTANT_ANIM_DEATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -92,9 +91,7 @@ namespace TEN::Entities::TR1
|
|||
angle = (short)phd_atan(creature->Target.z - item->Pose.Position.z, creature->Target.x - item->Pose.Position.x) - item->Pose.Orientation.y;
|
||||
|
||||
if (item->TouchBits)
|
||||
{
|
||||
DoDamage(creature->Enemy, MUTANT_CONTACT_DAMAGE);
|
||||
}
|
||||
|
||||
switch (item->Animation.ActiveState)
|
||||
{
|
||||
|
@ -122,7 +119,7 @@ namespace TEN::Entities::TR1
|
|||
else
|
||||
item->Animation.TargetState = MUTANT_STATE_FORWARD;
|
||||
}
|
||||
else if (GetRandomControl() < 0x4000)
|
||||
else if (TestProbability(0.5f))
|
||||
item->Animation.TargetState = MUTANT_STATE_ATTACK_1;
|
||||
else
|
||||
item->Animation.TargetState = MUTANT_STATE_ATTACK_2;
|
||||
|
@ -178,8 +175,8 @@ namespace TEN::Entities::TR1
|
|||
case MUTANT_STATE_ATTACK_1:
|
||||
if (!creature->Flags && item->TestBits(JointBitType::Touch, MutantAttackRightJoints))
|
||||
{
|
||||
creature->Flags = 1;
|
||||
DoDamage(creature->Enemy, MUTANT_ATTACK_DAMAGE);
|
||||
creature->Flags = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -187,8 +184,8 @@ namespace TEN::Entities::TR1
|
|||
case MUTANT_STATE_ATTACK_2:
|
||||
if (!creature->Flags && item->TestBits(JointBitType::Touch, MutantAttackJoints))
|
||||
{
|
||||
creature->Flags = 1;
|
||||
DoDamage(creature->Enemy, MUTANT_ATTACK_DAMAGE);
|
||||
creature->Flags = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -202,14 +199,11 @@ namespace TEN::Entities::TR1
|
|||
|
||||
LaraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_GIANT_MUTANT_DEATH;
|
||||
LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
||||
LaraItem->Animation.ActiveState = LaraItem->Animation.TargetState = 46;
|
||||
LaraItem->RoomNumber = item->RoomNumber;
|
||||
LaraItem->Pose.Position.x = item->Pose.Position.x;
|
||||
LaraItem->Pose.Position.y = item->Pose.Position.y;
|
||||
LaraItem->Pose.Position.z = item->Pose.Position.z;
|
||||
LaraItem->Pose.Orientation.y = item->Pose.Orientation.y;
|
||||
LaraItem->Pose.Orientation.x = LaraItem->Pose.Orientation.z = 0;
|
||||
LaraItem->Animation.ActiveState = 46;
|
||||
LaraItem->Animation.TargetState = 46;
|
||||
LaraItem->Animation.IsAirborne = false;
|
||||
LaraItem->Pose = PHD_3DPOS(item->Pose.Position, 0, item->Pose.Orientation.y, 0);
|
||||
LaraItem->RoomNumber = item->RoomNumber;
|
||||
LaraItem->HitPoints = -1;
|
||||
Lara.Air = -1;
|
||||
Lara.Control.HandStatus = HandStatus::Busy;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void GiantMutantControl(short itemNumber);
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
#include "Game/people.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/trmath.h"
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
using namespace TEN::Math::Random;
|
||||
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
// TODO: Organise.
|
||||
constexpr auto NATLA_SHOT_DAMAGE = 100;
|
||||
|
@ -20,9 +23,10 @@ namespace TEN::Entities::TR1
|
|||
constexpr auto NATLA_DEATH_TIME = (FPS * 16); // 16 seconds.
|
||||
constexpr auto NATLA_FLYMODE = 0x8000;
|
||||
constexpr auto NATLA_TIMER = 0x7FFF;
|
||||
constexpr auto NATLA_LAND_CHANCE = 0x100;
|
||||
constexpr auto NATLA_GUN_VELOCITY = 400;
|
||||
|
||||
constexpr auto NATLA_LAND_CHANCE = 0.008f;
|
||||
|
||||
#define NATLA_TURN_NEAR_DEATH_SPEED ANGLE(6.0f)
|
||||
#define NATLA_TURN_SPEED ANGLE(5.0f)
|
||||
#define NATLA_FLY_ANGLE_SPEED ANGLE(5.0f)
|
||||
|
@ -183,7 +187,7 @@ namespace TEN::Entities::TR1
|
|||
|
||||
if (item->Animation.ActiveState == NATLA_STATE_FLY && (creature->Flags & NATLA_FLYMODE))
|
||||
{
|
||||
if (creature->Flags & NATLA_FLYMODE && shoot && GetRandomControl() < NATLA_LAND_CHANCE)
|
||||
if (creature->Flags & NATLA_FLYMODE && shoot && TestProbability(NATLA_LAND_CHANCE))
|
||||
creature->Flags -= NATLA_FLYMODE;
|
||||
|
||||
if (!(creature->Flags & NATLA_FLYMODE))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void NatlaControl(short itemNumber);
|
||||
}
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
#include "Game/people.h"
|
||||
#include "Sound/sound.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/trmath.h"
|
||||
|
||||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_DAMAGE = 150;
|
||||
constexpr auto WINGED_MUTANT_RUN_JUMP_ATTACK_DAMAGE = 100;
|
||||
|
@ -29,8 +31,8 @@ namespace TEN::Entities::TR1
|
|||
constexpr auto WINGED_MUTANT_IDLE_JUMP_ATTACK_RANGE = SQUARE(SECTOR(2.5f));
|
||||
constexpr auto WINGED_MUTANT_ATTACK_RANGE = SQUARE(SECTOR(3.75f));
|
||||
|
||||
constexpr auto WINGED_MUTANT_POSE_CHANCE = 85;
|
||||
constexpr auto WINGED_MUTANT_UNPOSE_CHANCE = 200;
|
||||
constexpr auto WINGED_MUTANT_POSE_CHANCE = 1.0f / 400;
|
||||
constexpr auto WINGED_MUTANT_UNPOSE_CHANCE = 1.0f / 164;
|
||||
|
||||
constexpr auto WINGED_MUTANT_FLY_VELOCITY = CLICK(1) / 8;
|
||||
constexpr auto WINGED_MUTANT_SHARD_VELOCITY = 250;
|
||||
|
@ -337,7 +339,7 @@ namespace TEN::Entities::TR1
|
|||
if (AI.distance < WINGED_MUTANT_WALK_RANGE)
|
||||
{
|
||||
if (AI.zoneNumber == AI.enemyZone ||
|
||||
GetRandomControl() < WINGED_MUTANT_UNPOSE_CHANCE)
|
||||
TestProbability(WINGED_MUTANT_UNPOSE_CHANCE))
|
||||
{
|
||||
item->Animation.TargetState = WMUTANT_STATE_WALK_FORWARD;
|
||||
}
|
||||
|
@ -345,7 +347,7 @@ namespace TEN::Entities::TR1
|
|||
else
|
||||
item->Animation.TargetState = WMUTANT_STATE_IDLE;
|
||||
}
|
||||
else if (creature->Mood == MoodType::Bored && GetRandomControl() < WINGED_MUTANT_UNPOSE_CHANCE)
|
||||
else if (creature->Mood == MoodType::Bored && TestProbability(WINGED_MUTANT_UNPOSE_CHANCE))
|
||||
item->Animation.TargetState = WMUTANT_STATE_WALK_FORWARD;
|
||||
else if (creature->Mood == MoodType::Attack ||
|
||||
creature->Mood == MoodType::Escape)
|
||||
|
@ -363,7 +365,7 @@ namespace TEN::Entities::TR1
|
|||
else if (creature->Mood == MoodType::Bored ||
|
||||
(creature->Mood == MoodType::Stalk && AI.zoneNumber != AI.enemyZone))
|
||||
{
|
||||
if (GetRandomControl() < WINGED_MUTANT_POSE_CHANCE)
|
||||
if (TestProbability(WINGED_MUTANT_POSE_CHANCE))
|
||||
item->Animation.TargetState = WMUTANT_STATE_POSE;
|
||||
}
|
||||
else if (creature->Mood == MoodType::Stalk &&
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void InitialiseWingedMutant(short itemNumber);
|
||||
void WingedMutantControl(short itemNumber);
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
#include "Game/Lara/lara.h"
|
||||
#include "Game/misc.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/prng.h"
|
||||
#include "Specific/setup.h"
|
||||
|
||||
using namespace TEN::Math::Random;
|
||||
using std::vector;
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
constexpr auto WOLF_BITE_DAMAGE = 100;
|
||||
constexpr auto WOLF_LUNGE_DAMAGE = 50;
|
||||
|
@ -21,9 +23,9 @@ namespace TEN::Entities::TR1
|
|||
constexpr auto WOLF_ATTACK_RANGE = SQUARE(SECTOR(1.5f));
|
||||
constexpr auto WOLF_STALK_RANGE = SQUARE(SECTOR(2));
|
||||
|
||||
constexpr auto WOLF_WAKE_CHANCE = 0x20;
|
||||
constexpr auto WOLF_SLEEP_CHANCE = 0x20;
|
||||
constexpr auto WOLF_HOWL_CHANCE = 0x180;
|
||||
constexpr auto WOLF_WAKE_CHANCE = 1.0f / 1000;
|
||||
constexpr auto WOLF_SLEEP_CHANCE = 1.0f / 1000;
|
||||
constexpr auto WOLF_HOWL_CHANCE = 1.0f / 85;
|
||||
|
||||
constexpr auto WOLF_SLEEP_FRAME = 96;
|
||||
|
||||
|
@ -110,7 +112,7 @@ namespace TEN::Entities::TR1
|
|||
item->Animation.RequiredState = WOLF_STATE_CROUCH;
|
||||
item->Animation.TargetState = WOLF_STATE_IDLE;
|
||||
}
|
||||
else if (GetRandomControl() < WOLF_WAKE_CHANCE)
|
||||
else if (TestProbability(WOLF_WAKE_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = WOLF_STATE_WALK;
|
||||
item->Animation.TargetState = WOLF_STATE_IDLE;
|
||||
|
@ -133,7 +135,7 @@ namespace TEN::Entities::TR1
|
|||
item->Animation.TargetState = WOLF_STATE_STALK;
|
||||
item->Animation.RequiredState = WOLF_STATE_NONE;
|
||||
}
|
||||
else if (GetRandomControl() < WOLF_SLEEP_CHANCE)
|
||||
else if (TestProbability(WOLF_SLEEP_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = WOLF_STATE_SLEEP;
|
||||
item->Animation.TargetState = WOLF_STATE_IDLE;
|
||||
|
@ -174,7 +176,7 @@ namespace TEN::Entities::TR1
|
|||
item->Animation.TargetState = WOLF_STATE_RUN;
|
||||
}
|
||||
}
|
||||
else if (GetRandomControl() < WOLF_HOWL_CHANCE)
|
||||
else if (TestProbability(WOLF_HOWL_CHANCE))
|
||||
{
|
||||
item->Animation.RequiredState = WOLF_STATE_HOWL;
|
||||
item->Animation.TargetState = WOLF_STATE_CROUCH;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::TR1
|
||||
namespace TEN::Entities::Creatures::TR1
|
||||
{
|
||||
void InitialiseWolf(short itemNumber);
|
||||
void WolfControl(short itemNumber);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "framework.h"
|
||||
#include "Objects/TR1/tr1_objects.h"
|
||||
|
||||
/// necessary import
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/collision/collide_item.h"
|
||||
#include "Game/itemdata/creature_info.h"
|
||||
|
@ -9,7 +8,7 @@
|
|||
#include "Specific/setup.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
/// entities
|
||||
// Creatures
|
||||
#include "Objects/TR1/Entity/tr1_ape.h" // OK
|
||||
#include "Objects/TR1/Entity/tr1_bear.h" // OK
|
||||
#include "Objects/TR1/Entity/tr1_doppelganger.h" // OK
|
||||
|
@ -21,7 +20,7 @@
|
|||
#include "Objects/TR1/Entity/tr1_winged_mutant.h"
|
||||
#include "Objects/Utils/object_helper.h"
|
||||
|
||||
using namespace TEN::Entities::TR1;
|
||||
using namespace TEN::Entities::Creatures::TR1;
|
||||
|
||||
static void StartEntity(ObjectInfo* obj)
|
||||
{
|
||||
|
@ -78,7 +77,7 @@ static void StartEntity(ObjectInfo* obj)
|
|||
obj->saveHitpoints = true;
|
||||
obj->saveAnim = true;
|
||||
obj->saveFlags = true;
|
||||
obj->zoneType = ZONE_APE;
|
||||
obj->ZoneType = ZoneType::Ape;
|
||||
}
|
||||
|
||||
obj = &Objects[ID_BIG_RAT];
|
||||
|
@ -98,7 +97,7 @@ static void StartEntity(ObjectInfo* obj)
|
|||
obj->saveAnim = true;
|
||||
obj->saveFlags = true;
|
||||
obj->waterCreature = true;
|
||||
obj->zoneType = ZONE_WATER;
|
||||
obj->ZoneType = ZoneType::Water;
|
||||
obj->SetBoneRotation(1, ROT_Y); // head
|
||||
}
|
||||
|
||||
|
@ -174,7 +173,7 @@ static void StartEntity(ObjectInfo* obj)
|
|||
obj->saveHitpoints = true;
|
||||
obj->saveAnim = true;
|
||||
obj->saveFlags = true;
|
||||
obj->zoneType = ZONE_BLOCKABLE;
|
||||
obj->ZoneType = ZoneType::Blockable;
|
||||
obj->SetBoneRotation(10, ROT_X | ROT_Y);
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,7 @@ static void StartEntity(ObjectInfo* obj)
|
|||
obj->saveFlags = true;
|
||||
obj->saveHitpoints = true;
|
||||
obj->savePosition = true;
|
||||
obj->zoneType = ZONE_FLYER;
|
||||
obj->ZoneType = ZoneType::Flyer;
|
||||
obj->SetBoneRotation(1, ROT_Y); // torso
|
||||
obj->SetBoneRotation(2, ROT_Y); // head
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue