From b64305dba794ac1855591286fe035b5e3d7dc982 Mon Sep 17 00:00:00 2001 From: Tobias Markus Date: Tue, 1 Aug 2023 12:00:05 +0200 Subject: [PATCH] Create objects from scripting Fixes #366 Fixes #2445 --- src/scripting/sector.cpp | 33 +++++++++++++++++++++ src/scripting/sector.hpp | 14 +++++++++ src/scripting/wrapper.cpp | 62 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/src/scripting/sector.cpp b/src/scripting/sector.cpp index 7c9dc3ab2ed..4ffc4bc0dc7 100644 --- a/src/scripting/sector.cpp +++ b/src/scripting/sector.cpp @@ -20,7 +20,10 @@ #include "math/easing.hpp" #include "object/ambient_light.hpp" #include "object/music_object.hpp" +#include "supertux/game_object_factory.hpp" +#include "supertux/moving_object.hpp" #include "supertux/sector.hpp" +#include "util/log.hpp" #include "video/color.hpp" namespace scripting { @@ -37,6 +40,36 @@ Sector::set_gravity(float gravity) m_parent->set_gravity(gravity); } +void +Sector::add_object(const std::string& class_name, const std::string& name, + int posX, int posY, const std::string& direction, + const std::string& data) +{ + if(name.empty()) + { + log_fatal << "Object name cannot be empty" << std::endl; + return; + } + + if(m_parent->get_object_by_name(name) != nullptr) + { + log_fatal << "Object with name " << name << " already exists in sector" << std::endl; + return; + } + + std::unique_ptr obj = + GameObjectFactory::instance().create(class_name, Vector(posX, posY), string_to_dir(direction), data); + + if(dynamic_cast(obj.get()) == nullptr) + { + log_fatal << "Only MovingObject instances can be created via scripting" << std::endl; + return; + } + + obj->set_name(name); + m_parent->add_object(std::move(obj)); +} + } // namespace scripting /* EOF */ diff --git a/src/scripting/sector.hpp b/src/scripting/sector.hpp index bb59d2d0b23..0fdd54431b6 100644 --- a/src/scripting/sector.hpp +++ b/src/scripting/sector.hpp @@ -50,6 +50,20 @@ class Sector final : public GameObjectManager * @param float $gravity */ void set_gravity(float gravity); + + /** + * Adds a game object to the game + * + * @param class_name GameObject's class + * @param name Name of the created object + * @param posX X position inside the current sector + * @param posY Y position inside the current sector + * @param direction Direction + * @param data Additional data + */ +void add_object(const std::string& class_name, const std::string& name, + int posX, int posY, const std::string& direction, + const std::string& data); }; } // namespace scripting diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index e61e5653580..576b85d1367 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -8301,6 +8301,61 @@ static SQInteger Sector_set_gravity_wrapper(HSQUIRRELVM vm) } +static SQInteger Sector_add_object_wrapper(HSQUIRRELVM vm) +{ + SQUserPointer data; + if(SQ_FAILED(sq_getinstanceup(vm, 1, &data, nullptr, SQTrue)) || !data) { + sq_throwerror(vm, _SC("'add_object' called without instance")); + return SQ_ERROR; + } + scripting::Sector* _this = reinterpret_cast (data); + + const SQChar* arg0; + if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) { + sq_throwerror(vm, _SC("Argument 1 not a string")); + return SQ_ERROR; + } + const SQChar* arg1; + if(SQ_FAILED(sq_getstring(vm, 3, &arg1))) { + sq_throwerror(vm, _SC("Argument 2 not a string")); + return SQ_ERROR; + } + SQInteger arg2; + if(SQ_FAILED(sq_getinteger(vm, 4, &arg2))) { + sq_throwerror(vm, _SC("Argument 3 not an integer")); + return SQ_ERROR; + } + SQInteger arg3; + if(SQ_FAILED(sq_getinteger(vm, 5, &arg3))) { + sq_throwerror(vm, _SC("Argument 4 not an integer")); + return SQ_ERROR; + } + const SQChar* arg4; + if(SQ_FAILED(sq_getstring(vm, 6, &arg4))) { + sq_throwerror(vm, _SC("Argument 5 not a string")); + return SQ_ERROR; + } + const SQChar* arg5; + if(SQ_FAILED(sq_getstring(vm, 7, &arg5))) { + sq_throwerror(vm, _SC("Argument 6 not a string")); + return SQ_ERROR; + } + + try { + _this->add_object(arg0, arg1, static_cast (arg2), static_cast (arg3), arg4, arg5); + + return 0; + + } catch(std::exception& e) { + sq_throwerror(vm, e.what()); + return SQ_ERROR; + } catch(...) { + sq_throwerror(vm, _SC("Unexpected exception while executing function 'add_object'")); + return SQ_ERROR; + } + +} + static SQInteger Spotlight_release_hook(SQUserPointer ptr, SQInteger ) { scripting::Spotlight* _this = reinterpret_cast (ptr); @@ -15223,6 +15278,13 @@ void register_supertux_wrapper(HSQUIRRELVM v) throw SquirrelError(v, "Couldn't register function 'set_gravity'"); } + sq_pushstring(v, "add_object", -1); + sq_newclosure(v, &Sector_add_object_wrapper, 0); + sq_setparamscheck(v, SQ_MATCHTYPEMASKSTRING, ".ssb|nb|nss"); + if(SQ_FAILED(sq_createslot(v, -3))) { + throw SquirrelError(v, "Couldn't register function 'add_object'"); + } + if(SQ_FAILED(sq_createslot(v, -3))) { throw SquirrelError(v, "Couldn't register class 'Sector'"); }