Emit particle upgrade (#1542)

* Update to bug report form

* Update bug_report.yaml

* Update AUTHORS.md

- Tomo (general coding, special FX coding, bug fixing)

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update bug_report.yaml

* Expose ObjectSlot

* Docs

* Code Update

* FinalPush

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md

* Expose startRot

* Expose startRot

* Remove Space.

* Code cleanup, revise doc comment

* Nicer defaults in doc

---------

Co-authored-by: Stranger1992 <84292688+Stranger1992@users.noreply.github.com>
Co-authored-by: Nemoel-Tomo <tomo_669@hotmail.com>
Co-authored-by: Jakub <kubabilinski03@gmail.com>
Co-authored-by: Jakub <80340234+Jakub768@users.noreply.github.com>
Co-authored-by: Lwmte <3331699+Lwmte@users.noreply.github.com>
Co-authored-by: Sezz <sezzary@outlook.com>
This commit is contained in:
TrainWrack 2025-02-01 06:22:49 -05:00 committed by GitHub
parent bcbe216508
commit fa0e125f59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 149 additions and 150 deletions

View file

@ -16,7 +16,8 @@ body:
description: |
Please select the TombEngine Version from the dropdown list.
options:
- v1.5 (development build)
- Development Build
- v1.5.0.2 (Latest Release)
- v1.4
validations:
required: true
@ -27,7 +28,8 @@ body:
description: |
Please select the Tomb Editor version used from the dropdown list.
options:
- v1.7.2 (development version)
- Development Build
- v1.7.2
- v1.7.1
- v1.7.0
validations:

View file

@ -18,7 +18,7 @@ This is the credit list of **all** the people who contributed to TombEngine in a
- Squidshire (Hispidence) (Lua implementation, bug fixing)
- Stranger1992 (sound asset refactoring and organisation, assets)
- TokyoSU (entity and vehicle decompilation)
- Tomo (general coding, bug fixing)
- Tomo (general coding, special FX coding, bug fixing)
- Troye (general coding, refactoring)
- Nickelony (general coding)
- JesseG, aka WolfCheese (general coding)

View file

@ -24,6 +24,8 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
### Lua API changes
* Added additional arguments for Sprite object slot and starting rotation value for EmitParticle function.
## [Version 1.7.1] (https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7.4) - 2025-04-01
### Bug fixes

View file

@ -120,7 +120,7 @@
<td class="summary">Emit a lightning arc.</td>
</tr>
<tr>
<td class="name" ><a href="#EmitParticle">EmitParticle(pos, velocity, spriteID, gravity, rot, startColor, endColor, blendMode, startSize, endSize, lifetime, damage, poison)</a></td>
<td class="name" ><a href="#EmitParticle">EmitParticle(pos, vel, spriteID, gravity, rotVel, startColor, endColor, blendMode, startSize, endSize, life, applyDamage, applyPoison, spriteSeqID, startRot)</a></td>
<td class="summary">Emit a particle.</td>
</tr>
<tr>
@ -224,14 +224,10 @@
</dd>
<dt>
<a name = "EmitParticle"></a>
<strong>EmitParticle(pos, velocity, spriteID, gravity, rot, startColor, endColor, blendMode, startSize, endSize, lifetime, damage, poison)</strong>
<strong>EmitParticle(pos, vel, spriteID, gravity, rotVel, startColor, endColor, blendMode, startSize, endSize, life, applyDamage, applyPoison, spriteSeqID, startRot)</strong>
</dt>
<dd>
<p>Emit a particle. </p>
<pre><code> See the sprite editor in WadTool for DEFAULT_SPRITES to see a list of sprite indices.
</code></pre>
Emit a particle.
@ -239,59 +235,63 @@
<ul>
<li><span class="parameter">pos</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span>
World position.
</li>
<li><span class="parameter">velocity</span>
<li><span class="parameter">vel</span>
<span class="types"><a class="type" href="../3 primitive classes/Vec3.html#">Vec3</a></span>
Velocity.
</li>
<li><span class="parameter">spriteID</span>
<span class="types"><span class="type">int</span></span>
ID of the sprite in the DEFAULT_SPRITES sprite sequence object.
ID of the sprite in the sprite sequence object.
</li>
<li><span class="parameter">gravity</span>
<span class="types"><span class="type">int</span></span>
(default 0) Specifies whether particle will fall (positive values) or ascend (negative values) over time. Clamped to [-32768, 32767], but values between -1000 and 1000 are recommended; values too high or too low (e.g. under -2000 or above 2000) will cause the velocity of the particle to "wrap around" and switch directions.
</li>
<li><span class="parameter">rot</span>
<span class="types"><span class="type">float</span></span>
(default 0) specifies a speed with which it will rotate (0 = no rotation, negative = anticlockwise rotation, positive = clockwise rotation).
(default 0) Specifies if the particle will fall over time. Positive values ascend, negative values descend. Recommended range: [-1000 and 1000].
</li>
<li><span class="parameter">rotVel</span>
<span class="types"><span class="type">float</span></span>
(default 0) Rotational velocity in degrees.
</li>
<li><span class="parameter">startColor</span>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
(default Color(255, 255, 255)) color at start of life
(default Color(255, 255, 255)) Color at start of life.
</li>
<li><span class="parameter">endColor</span>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
(default Color(255, 255, 255)) color to fade to - at the time of writing this fade will finish long before the end of the particle's life due to internal maths
(default Color(255, 255, 255)) Color to fade toward. This will finish long before the end of the particle's life due to internal math.
</li>
<li><span class="parameter">blendMode</span>
<span class="types"><a class="type" href="../4 enums/Effects.BlendID.html#">BlendID</a></span>
(default TEN.Effects.BlendID.ALPHABLEND) How will we blend this with its surroundings?
(default TEN.Effects.BlendID.ALPHABLEND) Render blend mode.
</li>
<li><span class="parameter">startSize</span>
<span class="types"><span class="type">int</span></span>
(default 10) Size on spawn. A value of 15 is approximately the size of Lara's head.
<span class="types"><span class="type">float</span></span>
(default 10) Size at start of life.
</li>
<li><span class="parameter">endSize</span>
<span class="types"><span class="type">int</span></span>
(default 0) Size on death - the particle will linearly shrink or grow to this size during its lifespan
</li>
<li><span class="parameter">lifetime</span>
<span class="types"><span class="type">float</span></span>
(default 2) Lifespan in seconds
(default 0) Size at end of life. The particle will linearly shrink or grow toward this size over its lifespan.
</li>
<li><span class="parameter">damage</span>
<span class="types"><span class="type">bool</span></span>
(default false) specifies whether particle can damage Lara (does a very small amount of damage, like the small lava emitters in TR1)
<li><span class="parameter">life</span>
<span class="types"><span class="type">float</span></span>
(default 2) Lifespan in seconds.
</li>
<li><span class="parameter">poison</span>
<li><span class="parameter">applyDamage</span>
<span class="types"><span class="type">bool</span></span>
(default false) specifies whether particle can poison Lara
(default false) Specifies if the particle will harm the player on collision.
</li>
<li><span class="parameter">applyPoison</span>
<span class="types"><span class="type">bool</span></span>
(default false) Specifies if the particle will poison the player on collision.
</li>
<li><span class="parameter">spriteSeqID</span>
<span class="types"><a class="type" href="../4 enums/Objects.ObjID.html#">ObjID</a></span>
(default Objects.ObjID.DEFAULT_SPRITES) ID of the sprite sequence object.
</li>
<li><span class="parameter">startRot</span>
<span class="types"><span class="type">float</span></span>
(default random) Rotation at start of life.
</li>
</ul>
@ -301,19 +301,21 @@
<h3>Usage:</h3>
<ul>
<pre class="example">EmitParticle(
yourPositionVarHere,
pos,
Vec3(<span class="global">math</span>.random(), <span class="global">math</span>.random(), <span class="global">math</span>.random()),
<span class="number">22</span>, <span class="comment">-- spriteID
</span> <span class="number">0</span>, <span class="comment">-- gravity
</span> -<span class="number">2</span>, <span class="comment">-- rot
</span> -<span class="number">2</span>, <span class="comment">-- rotVel
</span> Color(<span class="number">255</span>, <span class="number">0</span>, <span class="number">0</span>), <span class="comment">-- startColor
</span> Color(<span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>), <span class="comment">-- endColor
</span> TEN.Effects.BlendID.ADDITIVE, <span class="comment">-- blendMode
</span> <span class="number">15</span>, <span class="comment">-- startSize
</span> <span class="number">50</span>, <span class="comment">-- endSize
</span> <span class="number">20</span>, <span class="comment">-- lifetime
</span> <span class="keyword">false</span>, <span class="comment">-- damage
</span> <span class="keyword">true</span> <span class="comment">-- poison
</span> <span class="number">20</span>, <span class="comment">-- life
</span> <span class="keyword">false</span>, <span class="comment">-- applyDamage
</span> <span class="keyword">true</span>, <span class="comment">-- applyPoison
</span> Objects.ObjID.DEFAULT_SPRITES, <span class="comment">-- spriteSeqID
</span> <span class="number">180</span> <span class="comment">-- startRot
</span> )</pre>
</ul>

View file

@ -12,6 +12,7 @@
#include "Game/effects/tomb4fx.h"
#include "Game/effects/weather.h"
#include "Game/Setup.h"
#include "Math/Math.h"
#include "Objects/Utils/object_helper.h"
#include "Scripting/Internal/LuaHandler.h"
#include "Scripting/Internal/ReservedScriptNames.h"
@ -25,17 +26,16 @@
#include "Specific/clock.h"
#include "Specific/trutils.h"
/***
Functions to generate effects.
@tentable Effects
@pragma nostrip
*/
/// Functions to generate effects.
// @tentable Effects
// @pragma nostrip
using namespace TEN::Effects::DisplaySprite;
using namespace TEN::Effects::Electricity;
using namespace TEN::Effects::Environment;
using namespace TEN::Effects::Explosion;
using namespace TEN::Effects::Spark;
using namespace TEN::Math;
namespace TEN::Scripting::Effects
{
@ -97,123 +97,116 @@ namespace TEN::Scripting::Effects
SpawnElectricity(p1, p2, byteAmplitude, col.GetR(), col.GetG(), col.GetB(), byteLife, flags, width, segs);
}
/*** Emit a particle.
See the sprite editor in WadTool for DEFAULT_SPRITES to see a list of sprite indices.
@function EmitParticle
@tparam Vec3 pos
@tparam Vec3 velocity
@tparam int spriteID ID of the sprite in the DEFAULT_SPRITES sprite sequence object.
@tparam int gravity (default 0) Specifies whether particle will fall (positive values) or ascend (negative values) over time. Clamped to [-32768, 32767], but values between -1000 and 1000 are recommended; values too high or too low (e.g. under -2000 or above 2000) will cause the velocity of the particle to "wrap around" and switch directions.
@tparam float rot (default 0) specifies a speed with which it will rotate (0 = no rotation, negative = anticlockwise rotation, positive = clockwise rotation).
@tparam Color startColor (default Color(255, 255, 255)) color at start of life
@tparam Color endColor (default Color(255, 255, 255)) color to fade to - at the time of writing this fade will finish long before the end of the particle's life due to internal maths
@tparam Effects.BlendID blendMode (default TEN.Effects.BlendID.ALPHABLEND) How will we blend this with its surroundings?
@tparam int startSize (default 10) Size on spawn. A value of 15 is approximately the size of Lara's head.
@tparam int endSize (default 0) Size on death - the particle will linearly shrink or grow to this size during its lifespan
@tparam float lifetime (default 2) Lifespan in seconds
@tparam bool damage (default false) specifies whether particle can damage Lara (does a very small amount of damage, like the small lava emitters in TR1)
@tparam bool poison (default false) specifies whether particle can poison Lara
@usage
EmitParticle(
yourPositionVarHere,
Vec3(math.random(), math.random(), math.random()),
22, -- spriteID
0, -- gravity
-2, -- rot
Color(255, 0, 0), -- startColor
Color(0, 255, 0), -- endColor
TEN.Effects.BlendID.ADDITIVE, -- blendMode
15, -- startSize
50, -- endSize
20, -- lifetime
false, -- damage
true -- poison
)
*/
static void EmitParticle(Vec3 pos, Vec3 velocity, int spriteID, TypeOrNil<int> gravity, TypeOrNil<float> rot,
/// Emit a particle.
// @function EmitParticle
// @tparam Vec3 pos World position.
// @tparam Vec3 vel Velocity.
// @tparam int spriteID ID of the sprite in the sprite sequence object.
// @tparam float gravity Specifies if the particle will fall over time. Positive values ascend, negative values descend. Recommended range: [-1000 and 1000]. __Default: 0__
// @tparam float rotVel Rotational velocity in degrees. __Default: 0__
// @tparam Color startColor Color at start of life. __Default: Color(255, 255, 255)__
// @tparam Color endColor Color to fade toward. This will finish long before the end of the particle's life due to internal math. __Default: Color(255, 255, 255)__
// @tparam Effects.BlendID blendMode Render blend mode. __TEN.Effects.BlendID.ALPHABLEND__
// @tparam float startSize Size at start of life. __Default: 10__
// @tparam float endSize Size at end of life. The particle will linearly shrink or grow toward this size over its lifespan. __Default: 0__
// @tparam float life Lifespan in seconds. __Default: 2__
// @tparam bool applyDamage Specify if the particle will harm the player on collision. __Default: false__
// @tparam bool applyPoison Specify if the particle will poison the player on collision. __Default: false__
// @tparam Objects.ObjID spriteSeqID ID of the sprite sequence object. __Default: Objects.ObjID.DEFAULT_SPRITES__
// @tparam float startRot Rotation at start of life. __Default: random__
// @usage
// EmitParticle(
// pos,
// Vec3(math.random(), math.random(), math.random()),
// 22, -- spriteID
// 0, -- gravity
// -2, -- rotVel
// Color(255, 0, 0), -- startColor
// Color(0, 255, 0), -- endColor
// TEN.Effects.BlendID.ADDITIVE, -- blendMode
// 15, -- startSize
// 50, -- endSize
// 20, -- life
// false, -- applyDamage
// true, -- applyPoison
// Objects.ObjID.DEFAULT_SPRITES, -- spriteSeqID
// 180 -- startRot
// )
static void EmitParticle(const Vec3& pos, const Vec3& vel, int spriteID, TypeOrNil<float> gravity, TypeOrNil<float> rotVel,
TypeOrNil<ScriptColor> startColor, TypeOrNil<ScriptColor> endColor, TypeOrNil<BlendMode> blendMode,
TypeOrNil<int> startSize, TypeOrNil<int> endSize, TypeOrNil<float> lifetime,
TypeOrNil<bool> damage, TypeOrNil<bool> poison)
TypeOrNil<float> startSize, TypeOrNil<float> endSize, TypeOrNil<float> life,
TypeOrNil<bool> applyDamage, TypeOrNil<bool> applyPoison, TypeOrNil<GAME_OBJECT_ID> spriteSeqID, TypeOrNil<float> startRot)
{
if (!CheckIfSlotExists(ID_DEFAULT_SPRITES, "Particle spawn script function"))
constexpr auto DEFAULT_START_SIZE = 10.0f;
constexpr auto DEFAULT_LIFE = 2.0f;
constexpr auto SECS_PER_FRAME = 1.0f / (float)FPS;
static const auto DEFAULT_COLOR = ScriptColor(255, 255, 255);
auto convertedSpriteSeqID = USE_IF_HAVE(GAME_OBJECT_ID, spriteSeqID, ID_DEFAULT_SPRITES);
if (!CheckIfSlotExists(convertedSpriteSeqID, "EmitParticle() script function."))
return;
int grav = USE_IF_HAVE(int, gravity, 0);
auto& part = *GetFreeParticle();
grav = std::clamp(grav, -32768, 32767);
part.on = true;
part.SpriteSeqID = convertedSpriteSeqID;
part.SpriteID = spriteID;
auto* s = GetFreeParticle();
auto convertedBlendMode = USE_IF_HAVE(BlendMode, blendMode, BlendMode::AlphaBlend);
part.blendMode = BlendMode(std::clamp((int)convertedBlendMode, (int)BlendMode::Opaque, (int)BlendMode::AlphaBlend));
s->on = true;
part.x = pos.x;
part.y = pos.y;
part.z = pos.z;
part.roomNumber = FindRoomNumber(Vector3i(pos.x, pos.y, pos.z));
s->SpriteSeqID = ID_DEFAULT_SPRITES;
s->SpriteID = spriteID;
part.xVel = short(vel.x * 32);
part.yVel = short(vel.y * 32);
part.zVel = short(vel.z * 32);
ScriptColor colorStart = USE_IF_HAVE(ScriptColor, startColor, ScriptColor( 255, 255, 255 ));
ScriptColor colorEnd = USE_IF_HAVE(ScriptColor, endColor, ScriptColor( 255, 255, 255 ));
float rotAdd = USE_IF_HAVE(float, rotVel, 0.0f);
part.rotAng = USE_IF_HAVE(float, startRot, TO_DEGREES(Random::GenerateAngle()));
part.rotAdd = byte(ANGLE(rotAdd) >> 4);
s->sR = colorStart.GetR();
s->sG = colorStart.GetG();
s->sB = colorStart.GetB();
part.sSize =
part.size = USE_IF_HAVE(float, startSize, DEFAULT_START_SIZE);
part.dSize = USE_IF_HAVE(float, endSize, 0.0f);
part.scalar = 2;
s->dR = colorEnd.GetR();
s->dG = colorEnd.GetG();
s->dB = colorEnd.GetB();
part.gravity = (short)std::clamp(USE_IF_HAVE(float, gravity, 0.0f), (float)SHRT_MIN, (float)SHRT_MAX);
part.friction = 0;
part.maxYvel = 0;
//there is no blend mode 7
BlendMode bMode = USE_IF_HAVE(BlendMode, blendMode, BlendMode::AlphaBlend);
s->blendMode = BlendMode(std::clamp(int(bMode), int(BlendMode::Opaque), int(BlendMode::AlphaBlend)));
auto convertedStartColor = USE_IF_HAVE(ScriptColor, startColor, DEFAULT_COLOR);
part.sR = convertedStartColor.GetR();
part.sG = convertedStartColor.GetG();
part.sB = convertedStartColor.GetB();
s->x = pos.x;
s->y = pos.y;
s->z = pos.z;
s->roomNumber = FindRoomNumber(Vector3i(pos.x, pos.y, pos.z));
constexpr float secsPerFrame = 1.0f / (float)FPS;
auto convertedEndColor = USE_IF_HAVE(ScriptColor, endColor, DEFAULT_COLOR);
part.dR = convertedEndColor.GetR();
part.dG = convertedEndColor.GetG();
part.dB = convertedEndColor.GetB();
float life = USE_IF_HAVE(float, lifetime, 2.0f);
life = std::max(0.1f, life);
int lifeInFrames = (int)round(life / secsPerFrame);
float convertedLife = std::max(0.1f, USE_IF_HAVE(float, life, DEFAULT_LIFE));
part.life =
part.sLife = (int)round(convertedLife / SECS_PER_FRAME);
part.colFadeSpeed = part.life / 2;
part.fadeToBlack = part.life / 3;
s->life = s->sLife = lifeInFrames;
s->colFadeSpeed = lifeInFrames / 2;
s->fadeToBlack = lifeInFrames / 3;
part.flags = SP_SCALE | SP_ROTATE | SP_DEF | SP_EXPDEF;
s->xVel = short(velocity.x * 32);
s->yVel = short(velocity.y * 32);
s->zVel = short(velocity.z * 32);
bool convertedApplyPoison = USE_IF_HAVE(bool, applyPoison, false);
if (convertedApplyPoison)
part.flags |= SP_POISON;
int sSize = USE_IF_HAVE(int, startSize, 10);
int eSize = USE_IF_HAVE(int, endSize, 0);
bool convertedApplyDamage = USE_IF_HAVE(bool, applyDamage, false);
if (convertedApplyDamage)
part.flags |= SP_DAMAGE;
s->sSize = s->size = float(sSize);
s->dSize = float(eSize);
s->scalar = 2;
s->flags = SP_SCALE | SP_ROTATE | SP_DEF | SP_EXPDEF;
bool applyPoison = USE_IF_HAVE(bool, poison, false);
bool applyDamage = USE_IF_HAVE(bool, damage, false);
if (applyPoison)
s->flags |= SP_POISON;
if (applyDamage)
s->flags |= SP_DAMAGE;
//todo add option to turn off wind?
if (TestEnvironment(RoomEnvFlags::ENV_FLAG_WIND, s->roomNumber))
s->flags |= SP_WIND;
float rotAdd = USE_IF_HAVE(float, rot, 0.0f);
s->rotAng = (GetRandomControl() & 0x0FFF);
s->rotAdd = byte(ANGLE(rotAdd) >> 4);
s->friction = 0;
s->maxYvel = 0;
s->gravity = grav;
// TODO: Add option to turn off wind.
if (TestEnvironment(RoomEnvFlags::ENV_FLAG_WIND, part.roomNumber))
part.flags |= SP_WIND;
}
/***Emit a shockwave, similar to that seen when a harpy projectile hits something.