1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

Add plugin API to VehicleCrashedParticle

This commit is contained in:
spacek531
2024-05-29 03:32:41 -07:00
committed by GitHub
parent 37b0dfcb16
commit 94750f4e34
10 changed files with 400 additions and 20 deletions

View File

@@ -6,6 +6,7 @@
- Feature: [#21853] Enlarged UI mode.
- Feature: [#21893, #22065] On launch, the game now indicates what system is being initialised.
- Feature: [#21913] [Plugin] Allow precise and safe control of peep animations.
- Feature: [#22046] [Plugin] Add interface for crashed vehicle particle.
- Feature: [#22087] [Plugin] Expose guests favourite rides to the plugin API.
- Improved: [#19870] Allow using new colours in UI themes.
- Improved: [#21853] Dropdowns now automatically use multiple columns if they are too tall for the screen.

View File

@@ -2123,6 +2123,11 @@ declare global {
supports: number;
}
interface CrashedVehicleColour {
body: number;
trim: number;
}
interface VehicleColour {
body: number;
trim: number;
@@ -2608,6 +2613,63 @@ declare global {
"waiting_to_depart" |
"waiting_to_start";
type CrashParticleType = "corner" | "rod" | "wheel" | "panel" | "seat";
/**
* Override properties for launch data. All properties except colour are randomly
* chosen if not overridden, using the same algorithm as regular crashed particles.
*/
interface CrashParticleLaunchData {
colours?: CrashedVehicleColour;
timeToLive?: number;
velocity?: CoordsXYZ;
crashParticleType?: CrashParticleType;
frame?: number;
}
/**
* Represents a vehicle explosion particle. They are emitted during a vehicle
* crash and will bounce until their timer expires and they are automatically
* removed.
*/
interface CrashedVehicleParticle extends Entity {
/**
* The colour of the particle.
*/
colours: CrashedVehicleColour;
/**
* The lifetime of the particle in ticks. Default value 65535. Entity is
* automatically removed at 0.
*/
timeToLive: number;
/**
* The particle velocity.
*/
velocity: CoordsXYZ;
/**
* The acceleration of the particle in the x, y, and z directions.
*/
acceleration: CoordsXYZ;
/**
* The type of crash particle.
*/
crashParticleType: CrashParticleType;
/**
* The current frame of the crash particle.
*/
frame: number;
/**
* Sets the sprite bounds and launches the particle.
*/
launch(launchData?: CrashParticleLaunchData): void;
}
/**
* Represents a guest or staff member.
* @deprecated since version 34, use guest or staff instead.

View File

@@ -19,7 +19,7 @@
#include <iterator>
// TODO: Create constants in sprites.h
static constexpr uint32_t _VehicleCrashParticleSprites[] = {
static constexpr uint32_t _VehicleCrashParticleSprites[kCrashedVehicleParticleNumberTypes] = {
22577, 22589, 22601, 22613, 22625,
};
@@ -47,6 +47,27 @@ template<> bool EntityBase::Is<CrashSplashParticle>() const
{
return Type == EntityType::CrashSplash;
}
void VehicleCrashParticle::SetSpriteData()
{
SpriteData.Width = 8;
SpriteData.HeightMin = 8;
SpriteData.HeightMax = 8;
}
void VehicleCrashParticle::Launch()
{
frame = (ScenarioRand() & 0xFF) * kCrashedVehicleParticleNumberSprites;
time_to_live = (ScenarioRand() & 0x7F) + 140;
crashed_sprite_base = ScenarioRandMax(kCrashedVehicleParticleNumberTypes);
acceleration_x = (static_cast<int16_t>(ScenarioRand() & 0xFFFF)) * 4;
acceleration_y = (static_cast<int16_t>(ScenarioRand() & 0xFFFF)) * 4;
acceleration_z = (ScenarioRand() & 0xFFFF) * 4 + 0x10000;
velocity_x = 0;
velocity_y = 0;
velocity_z = 0;
}
/**
*
* rct2: 0x006735A1
@@ -56,22 +77,11 @@ void VehicleCrashParticle::Create(VehicleColour& colours, const CoordsXYZ& vehic
VehicleCrashParticle* sprite = CreateEntity<VehicleCrashParticle>();
if (sprite != nullptr)
{
sprite->MoveTo(vehiclePos);
sprite->colour[0] = colours.Body;
sprite->colour[1] = colours.Trim;
sprite->SpriteData.Width = 8;
sprite->SpriteData.HeightMin = 8;
sprite->SpriteData.HeightMax = 8;
sprite->MoveTo(vehiclePos);
sprite->frame = (ScenarioRand() & 0xFF) * 12;
sprite->time_to_live = (ScenarioRand() & 0x7F) + 140;
sprite->crashed_sprite_base = ScenarioRandMax(static_cast<uint32_t>(std::size(_VehicleCrashParticleSprites)));
sprite->acceleration_x = (static_cast<int16_t>(ScenarioRand() & 0xFFFF)) * 4;
sprite->acceleration_y = (static_cast<int16_t>(ScenarioRand() & 0xFFFF)) * 4;
sprite->acceleration_z = (ScenarioRand() & 0xFFFF) * 4 + 0x10000;
sprite->velocity_x = 0;
sprite->velocity_y = 0;
sprite->velocity_z = 0;
sprite->SetSpriteData();
sprite->Launch();
}
}
@@ -129,8 +139,8 @@ void VehicleCrashParticle::Update()
}
MoveTo(newLoc);
frame += 85;
if (frame >= 3072)
frame += kCrashedVehicleParticleFrameIncrement;
if (frame >= (kCrashedVehicleParticleNumberSprites * kCrashedVehicleParticleFrameToSprite))
{
frame = 0;
}

View File

@@ -16,6 +16,11 @@ struct CoordsXYZ;
struct PaintSession;
struct VehicleColour;
constexpr int32_t kCrashedVehicleParticleFrameToSprite = 256;
constexpr int32_t kCrashedVehicleParticleNumberSprites = 12;
constexpr int32_t kCrashedVehicleParticleNumberTypes = 5;
constexpr int32_t kCrashedVehicleParticleFrameIncrement = 85; // 1/3 of 256, rounded up
struct VehicleCrashParticle : EntityBase
{
static constexpr auto cEntityType = EntityType::CrashedVehicleParticle;
@@ -30,6 +35,8 @@ struct VehicleCrashParticle : EntityBase
int32_t acceleration_y;
int32_t acceleration_z;
static void Create(VehicleColour& colours, const CoordsXYZ& vehiclePos);
void SetSpriteData();
void Launch();
void Update();
void Serialise(DataSerialiser& stream);
void Paint(PaintSession& session, int32_t imageDirection) const;

View File

@@ -541,6 +541,7 @@
<ClInclude Include="scenes\title\TitleSequencePlayer.h" />
<ClInclude Include="scripting\bindings\entity\ScGuest.hpp" />
<ClInclude Include="scripting\bindings\entity\ScLitter.hpp" />
<ClInclude Include="scripting\bindings\entity\ScParticle.hpp" />
<ClInclude Include="scripting\bindings\entity\ScPeep.hpp" />
<ClInclude Include="scripting\bindings\entity\ScStaff.hpp" />
<ClInclude Include="scripting\bindings\entity\ScVehicle.hpp" />
@@ -1032,6 +1033,7 @@
<ClCompile Include="scenes\title\TitleSequenceManager.cpp" />
<ClCompile Include="scripting\bindings\entity\ScGuest.cpp" />
<ClCompile Include="scripting\bindings\entity\ScLitter.cpp" />
<ClCompile Include="scripting\bindings\entity\ScParticle.cpp" />
<ClCompile Include="scripting\bindings\entity\ScStaff.cpp" />
<ClCompile Include="scripting\bindings\entity\ScVehicle.cpp" />
<ClCompile Include="scripting\bindings\network\ScNetwork.cpp" />
@@ -1086,4 +1088,4 @@
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>

View File

@@ -27,6 +27,7 @@
# include "bindings/entity/ScEntity.hpp"
# include "bindings/entity/ScGuest.hpp"
# include "bindings/entity/ScLitter.hpp"
# include "bindings/entity/ScParticle.hpp"
# include "bindings/entity/ScPeep.hpp"
# include "bindings/entity/ScStaff.hpp"
# include "bindings/entity/ScVehicle.hpp"
@@ -433,6 +434,7 @@ void ScriptEngine::Initialise()
ScEntity::Register(ctx);
ScLitter::Register(ctx);
ScVehicle::Register(ctx);
ScCrashedVehicleParticle::Register(ctx);
ScPeep::Register(ctx);
ScGuest::Register(ctx);
ScThought::Register(ctx);

View File

@@ -47,7 +47,7 @@ namespace OpenRCT2
namespace OpenRCT2::Scripting
{
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 90;
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 91;
// Versions marking breaking changes.
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;

View File

@@ -0,0 +1,225 @@
/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "ScParticle.hpp"
#include "../ride/ScRide.hpp"
#ifdef ENABLE_SCRIPTING
namespace OpenRCT2::Scripting
{
static const DukEnumMap<uint8_t> CrashParticleTypeMap({
{ "corner", 0 },
{ "rod", 1 },
{ "wheel", 2 },
{ "panel", 3 },
{ "seat", 4 },
});
ScCrashedVehicleParticle::ScCrashedVehicleParticle(EntityId id)
: ScEntity(id)
{
}
void ScCrashedVehicleParticle::Register(duk_context* ctx)
{
dukglue_set_base_class<ScEntity, ScCrashedVehicleParticle>(ctx);
dukglue_register_property(
ctx, &ScCrashedVehicleParticle::acceleration_get, &ScCrashedVehicleParticle::acceleration_set, "acceleration");
dukglue_register_property(
ctx, &ScCrashedVehicleParticle::velocity_get, &ScCrashedVehicleParticle::velocity_set, "velocity");
dukglue_register_property(
ctx, &ScCrashedVehicleParticle::colours_get, &ScCrashedVehicleParticle::colours_set, "colours");
dukglue_register_property(
ctx, &ScCrashedVehicleParticle::timeToLive_get, &ScCrashedVehicleParticle::timeToLive_set, "timeToLive");
dukglue_register_property(
ctx, &ScCrashedVehicleParticle::crashedSpriteBase_get, &ScCrashedVehicleParticle::crashedSpriteBase_set,
"crashParticleType");
dukglue_register_property(ctx, &ScCrashedVehicleParticle::frame_get, &ScCrashedVehicleParticle::frame_set, "frame");
dukglue_register_method(ctx, &ScCrashedVehicleParticle::Launch, "launch");
}
VehicleCrashParticle* ScCrashedVehicleParticle::GetCrashedVehicleParticle() const
{
return ::GetEntity<VehicleCrashParticle>(_id);
}
void ScCrashedVehicleParticle::frame_set(uint8_t value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
entity->frame = std::clamp<uint16_t>(value, 0, kCrashedVehicleParticleNumberSprites - 1)
* kCrashedVehicleParticleFrameToSprite;
}
}
uint8_t ScCrashedVehicleParticle::frame_get() const
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
return entity->frame / kCrashedVehicleParticleFrameToSprite;
}
return 0;
}
void ScCrashedVehicleParticle::crashedSpriteBase_set(const std::string& value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
entity->crashed_sprite_base = CrashParticleTypeMap[value];
}
}
std::string ScCrashedVehicleParticle::crashedSpriteBase_get() const
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
return std::string(CrashParticleTypeMap[entity->crashed_sprite_base]);
}
return {};
}
void ScCrashedVehicleParticle::timeToLive_set(uint16_t value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
entity->time_to_live = value;
}
}
uint16_t ScCrashedVehicleParticle::timeToLive_get() const
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
return entity->time_to_live;
}
return 0;
}
void ScCrashedVehicleParticle::velocity_set(const DukValue& value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
auto velocity = FromDuk<CoordsXYZ>(value);
entity->velocity_x = velocity.x;
entity->velocity_y = velocity.y;
entity->velocity_z = velocity.z;
}
}
DukValue ScCrashedVehicleParticle::velocity_get() const
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
return ToDuk(ctx, CoordsXYZ(entity->velocity_x, entity->velocity_y, entity->velocity_z));
}
return {};
}
void ScCrashedVehicleParticle::acceleration_set(const DukValue& value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
auto acceleration = FromDuk<CoordsXYZ>(value);
entity->acceleration_x = acceleration.x;
entity->acceleration_y = acceleration.y;
entity->acceleration_z = acceleration.z;
}
}
DukValue ScCrashedVehicleParticle::acceleration_get() const
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
return ToDuk(ctx, CoordsXYZ(entity->acceleration_x, entity->acceleration_y, entity->acceleration_z));
}
return {};
}
void ScCrashedVehicleParticle::Launch(const DukValue& value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
entity->SetSpriteData();
entity->Launch();
if (value.type() == DukValue::Type::UNDEFINED)
return;
if (value["colours"].type() == DukValue::Type::OBJECT)
{
auto coloursInt = FromDuk<VehicleColour>(value["colours"]);
entity->colour[0] = coloursInt.Body;
entity->colour[1] = coloursInt.Trim;
}
if (value["acceleration"].type() == DukValue::Type::OBJECT)
{
auto accelerationXYZ = FromDuk<CoordsXYZ>(value["acceleration"]);
entity->acceleration_x = accelerationXYZ.x;
entity->acceleration_y = accelerationXYZ.y;
entity->acceleration_z = accelerationXYZ.z;
}
if (value["velocity"].type() == DukValue::Type::OBJECT)
{
auto velocityXYZ = FromDuk<CoordsXYZ>(value["velocity"]);
entity->velocity_x = velocityXYZ.x;
entity->velocity_y = velocityXYZ.y;
entity->velocity_z = velocityXYZ.z;
}
if (value["timeToLive"].type() == DukValue::Type::NUMBER)
{
entity->time_to_live = value["timeToLive"].as_int();
}
if (value["frame"].type() == DukValue::Type::NUMBER)
{
entity->frame = std::clamp<uint16_t>(value["frame"].as_int(), 0, kCrashedVehicleParticleNumberSprites - 1)
* kCrashedVehicleParticleFrameToSprite;
}
if (value["crashParticleType"].type() == DukValue::Type::STRING)
{
entity->crashed_sprite_base = CrashParticleTypeMap[value["crashParticleType"].as_string()];
}
}
}
DukValue ScCrashedVehicleParticle::colours_get() const
{
auto ctx = GetContext()->GetScriptEngine().GetContext();
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
DukObject dukColour(ctx);
dukColour.Set("body", entity->colour[0]);
dukColour.Set("trim", entity->colour[1]);
return dukColour.Take();
}
return ToDuk(ctx, nullptr);
}
void ScCrashedVehicleParticle::colours_set(const DukValue& value)
{
auto entity = GetCrashedVehicleParticle();
if (entity != nullptr)
{
auto colours = FromDuk<VehicleColour>(value);
entity->colour[0] = colours.Body;
entity->colour[1] = colours.Trim;
}
}
}; // namespace OpenRCT2::Scripting
#endif

View File

@@ -0,0 +1,54 @@
/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#ifdef ENABLE_SCRIPTING
# include "../../../entity/Particle.h"
# include "../../../world/Location.hpp"
# include "ScEntity.hpp"
# include <optional>
namespace OpenRCT2::Scripting
{
class ScCrashedVehicleParticle : public ScEntity
{
public:
ScCrashedVehicleParticle(EntityId id);
static void Register(duk_context* ctx);
private:
VehicleCrashParticle* GetCrashedVehicleParticle() const;
DukValue colours_get() const;
void colours_set(const DukValue& value);
DukValue acceleration_get() const;
void acceleration_set(const DukValue& value);
DukValue velocity_get() const;
void velocity_set(const DukValue& value);
uint8_t frame_get() const;
void frame_set(uint8_t value);
void crashedSpriteBase_set(const std::string& value);
std::string crashedSpriteBase_get() const;
void timeToLive_set(uint16_t value);
uint16_t timeToLive_get() const;
void Launch(const DukValue& value);
};
}; // namespace OpenRCT2::Scripting
#endif

View File

@@ -29,6 +29,7 @@
# include "../entity/ScEntity.hpp"
# include "../entity/ScGuest.hpp"
# include "../entity/ScLitter.hpp"
# include "../entity/ScParticle.hpp"
# include "../entity/ScStaff.hpp"
# include "../entity/ScVehicle.hpp"
# include "../ride/ScRide.hpp"
@@ -161,6 +162,13 @@ namespace OpenRCT2::Scripting
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScStaff>(sprite->Id)));
}
}
else if (type == "crashed_vehicle_particle")
{
for (auto sprite : EntityList<VehicleCrashParticle>())
{
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScCrashedVehicleParticle>(sprite->Id)));
}
}
else
{
duk_error(_context, DUK_ERR_ERROR, "Invalid entity type.");
@@ -221,6 +229,13 @@ namespace OpenRCT2::Scripting
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScStaff>(sprite->Id)));
}
}
else if (type == "crashed_vehicle_particle")
{
for (auto sprite : EntityTileList<VehicleCrashParticle>(pos))
{
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScCrashedVehicleParticle>(sprite->Id)));
}
}
else
{
// If the given type isn't valid, throw an error
@@ -272,7 +287,7 @@ namespace OpenRCT2::Scripting
}
else if (type == "crashed_vehicle_particle")
{
res = createEntityType<VehicleCrashParticle, ScEntity>(_context, initializer);
res = createEntityType<VehicleCrashParticle, ScCrashedVehicleParticle>(_context, initializer);
}
else if (type == "explosion_cloud")
{
@@ -348,6 +363,8 @@ namespace OpenRCT2::Scripting
return GetObjectAsDukValue(_context, std::make_shared<ScGuest>(spriteId));
case EntityType::Litter:
return GetObjectAsDukValue(_context, std::make_shared<ScLitter>(spriteId));
case EntityType::CrashedVehicleParticle:
return GetObjectAsDukValue(_context, std::make_shared<ScCrashedVehicleParticle>(spriteId));
default:
return GetObjectAsDukValue(_context, std::make_shared<ScEntity>(spriteId));
}