Skip to content

Commit

Permalink
Create objects from scripting (SuperTux#2564)
Browse files Browse the repository at this point in the history
* Create objects from scripting
Fixes SuperTux#366
Fixes SuperTux#2445

* Fix doxygen comment

* Fix indentation
  • Loading branch information
tobbi committed Aug 7, 2023
1 parent 1396891 commit 96660b9
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/scripting/sector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<GameObject>(name) != nullptr)
{
log_fatal << "Object with name " << name << " already exists in sector" << std::endl;
return;
}

std::unique_ptr<GameObject> obj =
GameObjectFactory::instance().create(class_name, Vector(posX, posY), string_to_dir(direction), data);

if(dynamic_cast<MovingObject*>(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 */
14 changes: 14 additions & 0 deletions src/scripting/sector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ class Sector final : public GameObjectManager
* @param float $gravity
*/
void set_gravity(float gravity);

/**
* Adds a MovingObject to the game.
*
* @param string $class_name GameObject's class.
* @param string $name Name of the created object.
* @param int $posX X position inside the current sector.
* @param int $posY Y position inside the current sector.
* @param string $direction Direction.
* @param string $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
Expand Down
62 changes: 62 additions & 0 deletions src/scripting/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<scripting::Sector*> (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<int> (arg2), static_cast<int> (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<scripting::Spotlight*> (ptr);
Expand Down Expand Up @@ -15275,6 +15330,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'");
}
Expand Down

0 comments on commit 96660b9

Please sign in to comment.