From 62d66ca9d02bb6d78e4f110bef07bc6d9aa22588 Mon Sep 17 00:00:00 2001 From: andrewpratt64 Date: Fri, 30 Jul 2021 08:03:15 -0400 Subject: [PATCH] Add hook for vehicle crashes to plugin api (#15084) * Add initial implementation of "vehicle.crash" hook for the scripting api The hook will fire whenever a vehicle crashes, i.e. an individual car explodes and it's status becomes "Crashed!" * Update contributors.md Add name to contributors list under the "Additional implementation (OpenRCT2)" section. - If the added line needs to be changed or removed entirely let me know - I added this based off of the Github wiki: "If it's the first time you're contributing with the project, make sure to update the contributors.md file by appending your name at the end of the respective list." * Move hook code into function * Rename hook function Renamed function, "FireVehicleCrashHook" to "InvokeVehicleCrashHook" * Wrap InvokeVehicleCrashHook in #ifdef Move the #ifdef from inside the function body to the outside * Update changelog and api version - Added entry to changelog - Increment API version * Fix whitespace Replace tab character with four spaces * Update src/openrct2/scripting/HookEngine.cpp Co-authored-by: Tulio Leao --- contributors.md | 1 + distribution/changelog.txt | 1 + distribution/openrct2.d.ts | 10 ++++++- src/openrct2/ride/Vehicle.cpp | 39 +++++++++++++++++++++++++++ src/openrct2/scripting/HookEngine.cpp | 1 + src/openrct2/scripting/HookEngine.h | 1 + src/openrct2/scripting/ScriptEngine.h | 2 +- 7 files changed, 53 insertions(+), 2 deletions(-) diff --git a/contributors.md b/contributors.md index 38e134adc0..6938da9026 100644 --- a/contributors.md +++ b/contributors.md @@ -93,6 +93,7 @@ The following people are not part of the development team, but have been contrib * Keith Stellyes (keithstellyes) - Misc. * Bas Cantrijn (Basssiiie) - Misc. * Adrian Zdanowicz (CookiePLMonster) - Misc. +* Andrew Pratt (andrewpratt64) - Added api hook for vehicle crashes ## Bug fixes * (KirilAngelov) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index d2c7c26844..34567e9393 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,5 +1,6 @@ 0.3.4.1+ (in development) ------------------------------------------------------------------------ +- Feature: [#15084] [Plugin] Add "vehicle.crash" hook - Fix: [#14316] Closing the Track Designs Manager window causes broken state. - Fix: [#15096] Crash when placing entrances in the scenario editor near the map corner. - Improved: [#3417] Crash dumps are now placed in their own folder. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 72efec0980..e2efcf50df 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -267,6 +267,7 @@ declare global { subscribe(hook: "ride.ratings.calculate", callback: (e: RideRatingsCalculateArgs) => void): IDisposable; subscribe(hook: "action.location", callback: (e: ActionLocationArgs) => void): IDisposable; subscribe(hook: "guest.generation", callback: (id: number) => void): IDisposable; + subscribe(hook: "vehicle.crash", callback: (e: VehicleCrashArgs) => void): IDisposable; /** * Registers a function to be called every so often in realtime, specified by the given delay. @@ -365,7 +366,7 @@ declare global { type HookType = "interval.tick" | "interval.day" | "network.chat" | "network.action" | "network.join" | "network.leave" | - "ride.ratings.calculate" | "action.location"; + "ride.ratings.calculate" | "action.location" | "vehicle.crash"; type ExpenditureType = "ride_construction" | @@ -514,6 +515,13 @@ declare global { readonly isClientOnly: boolean; result: boolean; } + + type VehicleCrashIntoType = "another_vehicle" | "land" | "water"; + + interface VehicleCrashArgs { + readonly id: number; + readonly crashIntoType: VehicleCrashIntoType; + } /** * APIs for the in-game date. diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 0a9f05e8ed..c256d30f82 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -24,6 +24,8 @@ #include "../platform/platform.h" #include "../rct12/RCT12.h" #include "../scenario/Scenario.h" +#include "../scripting/HookEngine.h" +#include "../scripting/ScriptEngine.h" #include "../util/Util.h" #include "../windows/Intent.h" #include "../world/Map.h" @@ -738,6 +740,31 @@ template<> bool SpriteBase::Is() const return Type == EntityType::Vehicle; } +#ifdef ENABLE_SCRIPTING +/** + * Fires the "vehicle.crash" api hook + * @param vehicleId Entity id of the vehicle that just crashed + * @param crashId What the vehicle crashed into. Should be either "another_vehicle", "land", or "water" + */ +static void InvokeVehicleCrashHook(const uint16_t vehicleId, const std::string_view crashId) +{ + auto& hookEngine = OpenRCT2::GetContext()->GetScriptEngine().GetHookEngine(); + if (hookEngine.HasSubscriptions(OpenRCT2::Scripting::HOOK_TYPE::VEHICLE_CRASH)) + { + auto ctx = OpenRCT2::GetContext()->GetScriptEngine().GetContext(); + + // Create event args object + auto obj = OpenRCT2::Scripting::DukObject(ctx); + obj.Set("id", vehicleId); + obj.Set("crashIntoType", crashId); + + // Call the subscriptions + auto e = obj.Take(); + hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::VEHICLE_CRASH, e, true); + } +} +#endif + static bool vehicle_move_info_valid( VehicleTrackSubposition trackSubposition, track_type_t type, uint8_t direction, int32_t offset) { @@ -3598,6 +3625,10 @@ void Vehicle::UpdateCollisionSetup() train->sub_state = 2; +#ifdef ENABLE_SCRIPTING + InvokeVehicleCrashHook(train->sprite_index, "another_vehicle"); +#endif + OpenRCT2::Audio::Play3D(OpenRCT2::Audio::SoundId::Crash, { train->x, train->y, train->z }); ExplosionCloud::Create({ train->x, train->y, train->z }); @@ -5334,6 +5365,10 @@ void Vehicle::CrashOnLand() } SetState(Vehicle::Status::Crashed, sub_state); +#ifdef ENABLE_SCRIPTING + InvokeVehicleCrashHook(sprite_index, "land"); +#endif + if (!(curRide->lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) { auto frontVehicle = GetHead(); @@ -5396,6 +5431,10 @@ void Vehicle::CrashOnWater() } SetState(Vehicle::Status::Crashed, sub_state); +#ifdef ENABLE_SCRIPTING + InvokeVehicleCrashHook(sprite_index, "water"); +#endif + if (!(curRide->lifecycle_flags & RIDE_LIFECYCLE_CRASHED)) { auto frontVehicle = GetHead(); diff --git a/src/openrct2/scripting/HookEngine.cpp b/src/openrct2/scripting/HookEngine.cpp index e857a41025..6c2a750348 100644 --- a/src/openrct2/scripting/HookEngine.cpp +++ b/src/openrct2/scripting/HookEngine.cpp @@ -30,6 +30,7 @@ static const EnumMap HooksLookupTable({ { "ride.ratings.calculate", HOOK_TYPE::RIDE_RATINGS_CALCULATE }, { "action.location", HOOK_TYPE::ACTION_LOCATION }, { "guest.generation", HOOK_TYPE::GUEST_GENERATION }, + { "vehicle.crash", HOOK_TYPE::VEHICLE_CRASH }, }); HOOK_TYPE OpenRCT2::Scripting::GetHookType(const std::string& name) diff --git a/src/openrct2/scripting/HookEngine.h b/src/openrct2/scripting/HookEngine.h index ce94ec8a20..b1a875eaa7 100644 --- a/src/openrct2/scripting/HookEngine.h +++ b/src/openrct2/scripting/HookEngine.h @@ -39,6 +39,7 @@ namespace OpenRCT2::Scripting RIDE_RATINGS_CALCULATE, ACTION_LOCATION, GUEST_GENERATION, + VEHICLE_CRASH, COUNT, UNDEFINED = -1, }; diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index 3eebc71613..132d5055fa 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -46,7 +46,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 31; + static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 32; # ifndef DISABLE_NETWORK class ScSocketBase;