Merge pull request #15165 from ZehMatt/scripting/createEntity

Add createEntity API to scripting
This commit is contained in:
ζeh Matt 2021-08-09 07:46:31 -07:00 committed by GitHub
commit 3ed2f8e98e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 177 additions and 9 deletions

View File

@ -2,6 +2,7 @@
------------------------------------------------------------------------
- Feature: [#15084] [Plugin] Add "vehicle.crash" hook.
- Feature: [#15143] Added a shortcut key for Giant Screenshot.
- Feature: [#15165] [Plugin] Add the ability to create entities using "map.createEntity".
- Fix: [#13465] Creating a scenario based on a won save game results in a scenario thats instantly won.
- Fix: [#14316] Closing the Track Designs Manager window causes broken state.
- Fix: [#14667] “Extreme Hawaiian Island” has unpurchaseable land tiles (original bug).

View File

@ -577,6 +577,7 @@ declare global {
getAllEntities(type: "peep"): Peep[];
getAllEntities(type: "guest"): Guest[];
getAllEntities(type: "staff"): Staff[];
createEntity(type: EntityType, initializer: object): Entity;
}
type TileElementType =
@ -1469,6 +1470,34 @@ declare global {
type StaffType = "handyman" | "mechanic" | "security" | "entertainer";
/**
* Represents litter entity.
*/
interface Litter extends Entity {
/**
* The type of the litter.
*/
litterType: LitterType;
/**
* The tick number this entity was created.
*/
creationTime: number;
}
type LitterType = "vomit" |
"vomit_alt" |
"empty_can" |
"rubbish" |
"burger_box" |
"empty_cup" |
"empty_box" |
"empty_bottle" |
"empty_bowl_red" |
"empty_drink_carton" |
"empty_juice_cup" |
"empty_bowl_blue";
/**
* Network APIs
* Use `network.status` to determine whether the current game is a client, server or in single player mode.

View File

@ -17,6 +17,7 @@
# include "../peep/Staff.h"
# include "../util/Util.h"
# include "../world/EntityList.h"
# include "../world/Litter.h"
# include "../world/Sprite.h"
# include "Duktape.hpp"
# include "ScRide.hpp"
@ -1244,6 +1245,71 @@ namespace OpenRCT2::Scripting
}
};
static const DukEnumMap<Litter::Type> LitterTypeMap({
{ "vomit", Litter::Type::Vomit },
{ "vomit_alt", Litter::Type::VomitAlt },
{ "empty_can", Litter::Type::EmptyCan },
{ "rubbish", Litter::Type::Rubbish },
{ "burger_box", Litter::Type::BurgerBox },
{ "empty_cup", Litter::Type::EmptyCup },
{ "empty_box", Litter::Type::EmptyBox },
{ "empty_bottle", Litter::Type::EmptyBottle },
{ "empty_bowl_red", Litter::Type::EmptyBowlRed },
{ "empty_drink_carton", Litter::Type::EmptyDrinkCarton },
{ "empty_juice_cup", Litter::Type::EmptyJuiceCup },
{ "empty_bowl_blue", Litter::Type::EmptyBowlBlue },
});
class ScLitter : public ScEntity
{
public:
ScLitter(uint16_t Id)
: ScEntity(Id)
{
}
static void Register(duk_context* ctx)
{
dukglue_set_base_class<ScEntity, ScLitter>(ctx);
dukglue_register_property(ctx, &ScLitter::litterType_get, &ScLitter::litterType_set, "litterType");
dukglue_register_property(ctx, &ScLitter::creationTick_get, nullptr, "creationTick");
}
private:
Litter* GetLitter() const
{
return ::GetEntity<Litter>(_id);
}
std::string litterType_get() const
{
auto* litter = GetLitter();
auto it = LitterTypeMap.find(litter->SubType);
if (it == LitterTypeMap.end())
return "";
return std::string{ it->first };
}
void litterType_set(const std::string& litterType)
{
ThrowIfGameStateNotMutable();
auto it = LitterTypeMap.find(litterType);
if (it == LitterTypeMap.end())
return;
auto* litter = GetLitter();
litter->SubType = it->second;
}
uint32_t creationTick_get() const
{
auto* litter = GetLitter();
if (litter == nullptr)
return 0;
return litter->creationTick;
}
};
} // namespace OpenRCT2::Scripting
#endif

View File

@ -17,7 +17,11 @@
# include "../world/Balloon.h"
# include "../world/Duck.h"
# include "../world/EntityList.h"
# include "../world/Fountain.h"
# include "../world/Litter.h"
# include "../world/Map.h"
# include "../world/MoneyEffect.h"
# include "../world/Particle.h"
# include "Duktape.hpp"
# include "ScEntity.hpp"
# include "ScRide.hpp"
@ -38,13 +42,7 @@ namespace OpenRCT2::Scripting
DukValue size_get() const
{
auto ctx = _context;
auto objIdx = duk_push_object(ctx);
duk_push_number(ctx, gMapSize);
duk_put_prop_string(ctx, objIdx, "x");
duk_push_number(ctx, gMapSize);
duk_put_prop_string(ctx, objIdx, "y");
return DukValue::take_from_stack(ctx);
return ToDuk(_context, CoordsXY{ gMapSize, gMapSize });
}
int32_t numRides_get() const
@ -110,7 +108,7 @@ namespace OpenRCT2::Scripting
result.push_back(GetObjectAsDukValue(_context, std::make_shared<ScEntity>(sprite->sprite_index)));
}
}
if (type == "car")
else if (type == "car")
{
for (auto trainHead : TrainManager::View())
{
@ -169,6 +167,77 @@ namespace OpenRCT2::Scripting
return result;
}
template<typename TEntityType, typename TScriptType> DukValue createEntityType(const DukValue& initializer)
{
TEntityType* entity = CreateEntity<TEntityType>();
auto entityPos = CoordsXYZ{ AsOrDefault(initializer["x"], 0), AsOrDefault(initializer["y"], 0),
AsOrDefault(initializer["z"], 0) };
entity->MoveTo(entityPos);
return GetObjectAsDukValue(_context, std::make_shared<TScriptType>(entity->sprite_index));
}
DukValue createEntity(const std::string& type, const DukValue& initializer)
{
if (type == "car")
{
return createEntityType<Vehicle, ScVehicle>(initializer);
}
else if (type == "staff")
{
return createEntityType<Staff, ScStaff>(initializer);
}
else if (type == "guest")
{
return createEntityType<Guest, ScGuest>(initializer);
}
else if (type == "steam_particle")
{
return createEntityType<SteamParticle, ScEntity>(initializer);
}
else if (type == "money_effect")
{
return createEntityType<MoneyEffect, ScEntity>(initializer);
}
else if (type == "crashed_vehicle_particle")
{
return createEntityType<VehicleCrashParticle, ScEntity>(initializer);
}
else if (type == "explosion_cloud")
{
return createEntityType<ExplosionCloud, ScEntity>(initializer);
}
else if (type == "crash_splash")
{
return createEntityType<CrashSplashParticle, ScEntity>(initializer);
}
else if (type == "explosion_flare")
{
return createEntityType<ExplosionFlare, ScEntity>(initializer);
}
else if (type == "balloon")
{
return createEntityType<Balloon, ScEntity>(initializer);
}
else if (type == "duck")
{
return createEntityType<Duck, ScEntity>(initializer);
}
else if (type == "jumping_fountain")
{
return createEntityType<JumpingFountain, ScEntity>(initializer);
}
else if (type == "litter")
{
return createEntityType<Litter, ScLitter>(initializer);
}
else
{
duk_error(_context, DUK_ERR_ERROR, "Invalid entity type.");
}
}
static void Register(duk_context* ctx)
{
dukglue_register_property(ctx, &ScMap::size_get, nullptr, "size");
@ -179,6 +248,7 @@ namespace OpenRCT2::Scripting
dukglue_register_method(ctx, &ScMap::getTile, "getTile");
dukglue_register_method(ctx, &ScMap::getEntity, "getEntity");
dukglue_register_method(ctx, &ScMap::getAllEntities, "getAllEntities");
dukglue_register_method(ctx, &ScMap::createEntity, "createEntity");
}
private:
@ -193,6 +263,8 @@ namespace OpenRCT2::Scripting
return GetObjectAsDukValue(_context, std::make_shared<ScStaff>(spriteId));
case EntityType::Guest:
return GetObjectAsDukValue(_context, std::make_shared<ScGuest>(spriteId));
case EntityType::Litter:
return GetObjectAsDukValue(_context, std::make_shared<ScLitter>(spriteId));
default:
return GetObjectAsDukValue(_context, std::make_shared<ScEntity>(spriteId));
}

View File

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