Skip to content

Pass reference to the player, who has triggered a script #2726

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/object/pushbutton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ PushButton::collision(GameObject& other, const CollisionHit& hit)
SoundManager::current()->play(BUTTON_SOUND, get_pos());

// run script
Sector::get().run_script(m_script, "PushButton");
if (player)
{
Sector::get().run_script(m_script, "PushButton", *this, {
{ player->get_name(), "Tux" } // Create trigger reference to the player
});
}
else
Sector::get().run_script(m_script, "PushButton", *this, {});

return FORCE_MOVE;
}
Expand Down
6 changes: 4 additions & 2 deletions src/object/scripted_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ ScriptedObject::get_settings()
result.add_bool(_("Solid"), &solid, "solid", true);
result.add_bool(_("Physics enabled"), &physic_enabled, "physic-enabled", true);
result.add_bool(_("Visible"), &visible, "visible", true);
result.add_text(_("Hit script"), &hit_script, "hit-script");
result.add_script(_("Hit script"), &hit_script, "hit-script");

result.reorder({"z-pos", "visible", "physic-enabled", "solid", "name", "sprite", "script", "button", "x", "y"});

Expand Down Expand Up @@ -200,7 +200,9 @@ ScriptedObject::collision(GameObject& other, const CollisionHit& )
{
auto player = dynamic_cast<Player*> (&other);
if (player && !hit_script.empty()) {
Sector::get().run_script(hit_script, "hit-script");
Sector::get().run_script(hit_script, "hit-script", *this, {
{ player->get_name(), "Tux" } // Create trigger reference to the player
});
}

return FORCE_MOVE;
Expand Down
40 changes: 40 additions & 0 deletions src/squirrel/squirrel_environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,46 @@ SquirrelEnvironment::run_script(const std::string& script, const std::string& so
run_script(stream, sourcename);
}

void
SquirrelEnvironment::create_reference(const std::string& name, const std::string& ref_name,
const std::string& ref_table, const std::string& ref_sub_table)
{
const SQInteger old_top = sq_gettop(m_vm.get_vm());

sq_pushobject(m_vm.get_vm(), m_table);
sq_pushstring(m_vm.get_vm(), name.c_str(), -1);
if (SQ_FAILED(sq_get(m_vm.get_vm(), -2)))
{
log_warning << "Failed to get entry '" << name << "' from '" << m_name << "'. "
<< "Cannot create reference." << std::endl;
}
else
{
const SQInteger entry_top = sq_gettop(m_vm.get_vm());

sq_pushobject(m_vm.get_vm(), m_table);
m_vm.get_or_create_table_entry(ref_table);
if (!ref_sub_table.empty())
m_vm.get_or_create_table_entry(ref_sub_table);

sq_pushstring(m_vm.get_vm(), ref_name.c_str(), -1);
sq_weakref(m_vm.get_vm(), entry_top);
if (SQ_FAILED(sq_createslot(m_vm.get_vm(), -3)))
log_warning << "Unable to create reference to entry '" << name << "' from '" << m_name << "'." << std::endl;
}

sq_settop(m_vm.get_vm(), old_top);
}

void
SquirrelEnvironment::modify_table(const std::function<void(SquirrelVM&)>& function)
{
const SQInteger old_top = sq_gettop(m_vm.get_vm());
sq_pushobject(m_vm.get_vm(), m_table);
function(m_vm);
sq_settop(m_vm.get_vm(), old_top);
}

void
SquirrelEnvironment::garbage_collect()
{
Expand Down
8 changes: 8 additions & 0 deletions src/squirrel/squirrel_environment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <string>
#include <vector>
#include <functional>

#include <squirrel.h>

Expand Down Expand Up @@ -71,6 +72,13 @@ class SquirrelEnvironment
destroyed). */
void run_script(std::istream& in, const std::string& sourcename);

/** Pushes a reference to an entry in the environment table, if it exists,
to a sub-table in the environment table. */
void create_reference(const std::string& name, const std::string& ref_name,
const std::string& ref_table, const std::string& ref_sub_table);

void modify_table(const std::function<void(SquirrelVM&)>& function);

void update(float dt_sec);
void wait_for_seconds(HSQUIRRELVM vm, float seconds);
void skippable_wait_for_seconds(HSQUIRRELVM vm, float seconds);
Expand Down
25 changes: 23 additions & 2 deletions src/supertux/sector_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

#include "supertux/sector_base.hpp"

#include "util/log.hpp"

namespace Base {

Sector::Sector(const std::string& type) :
Expand All @@ -33,6 +31,29 @@ Sector::run_script(const std::string& script, const std::string& sourcename)
m_squirrel_environment->run_script(script, sourcename);
}

void
Sector::run_script(const std::string& script, const std::string& sourcename,
const GameObject& object, std::map<std::string, std::string> triggers)
{
if (!object.get_name().empty())
{
// Delete any existing trigger references
m_squirrel_environment->modify_table([&object](SquirrelVM& vm) {
try
{
vm.get_table_entry("triggers");
vm.delete_table_entry(object.get_name().c_str());
}
catch (...) {}
});

for (const auto& [name, ref_name] : triggers)
m_squirrel_environment->create_reference(name, ref_name, "triggers", object.get_name());
}

m_squirrel_environment->run_script(script, sourcename);
}

bool
Sector::before_object_add(GameObject& object)
{
Expand Down
4 changes: 4 additions & 0 deletions src/supertux/sector_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include "supertux/game_object_manager.hpp"

#include <map>

#include "squirrel/squirrel_environment.hpp"

class Level;
Expand Down Expand Up @@ -47,6 +49,8 @@ class Sector : public GameObjectManager

void set_init_script(const std::string& init_script) { m_init_script = init_script; }
void run_script(const std::string& script, const std::string& sourcename);
void run_script(const std::string& script, const std::string& sourcename,
const GameObject& object, std::map<std::string, std::string> triggers);

protected:
virtual bool before_object_add(GameObject& object) override;
Expand Down
7 changes: 5 additions & 2 deletions src/trigger/scripttrigger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "trigger/scripttrigger.hpp"

#include "editor/editor.hpp"
#include "object/player.hpp"
#include "supertux/debug.hpp"
#include "supertux/sector.hpp"
#include "util/log.hpp"
Expand Down Expand Up @@ -58,12 +59,14 @@ ScriptTrigger::get_settings()
}

void
ScriptTrigger::event(Player& , EventType type)
ScriptTrigger::event(Player& player, EventType type)
{
if (type != triggerevent || (oneshot && runcount >= 1))
return;

Sector::get().run_script(script, "ScriptTrigger");
Sector::get().run_script(script, "ScriptTrigger", *this, {
{ player.get_name(), "Tux" } // Create trigger reference to the player
});
runcount++;
}

Expand Down
18 changes: 15 additions & 3 deletions src/trigger/switch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <sstream>

#include "audio/sound_manager.hpp"
#include "object/player.hpp"
#include "supertux/flip_level_transformer.hpp"
#include "supertux/sector.hpp"
#include "util/log.hpp"
Expand All @@ -33,6 +34,7 @@ Switch::Switch(const ReaderMapping& reader) :
m_script(),
m_off_script(),
m_state(OFF),
m_player_name(),
m_bistable(),
m_dir(Direction::NONE)
{
Expand Down Expand Up @@ -78,9 +80,13 @@ Switch::update(float )
break;
case TURN_ON:
if (m_sprite->animation_done()) {
assert(!m_player_name.empty());

std::ostringstream location;
location << "switch" << m_col.m_bbox.p1();
Sector::get().run_script(m_script, location.str());
Sector::get().run_script(m_script, location.str(), *this, {
{ m_player_name, "Tux" } // Create trigger reference to the player
});

set_action("on", m_dir, 1);
m_state = ON;
Expand All @@ -95,9 +101,13 @@ Switch::update(float )
case TURN_OFF:
if (m_sprite->animation_done()) {
if (m_bistable) {
assert(!m_player_name.empty());

std::ostringstream location;
location << "switch" << m_col.m_bbox.p1();
Sector::get().run_script(m_off_script, location.str());
Sector::get().run_script(m_off_script, location.str(), *this, {
{ m_player_name, "Tux" } // Create trigger reference to the player
});
}

set_action("off", m_dir);
Expand All @@ -108,7 +118,7 @@ Switch::update(float )
}

void
Switch::event(Player& , EventType type)
Switch::event(Player& player, EventType type)
{
if (type != EVENT_ACTIVATE) return;

Expand All @@ -117,6 +127,7 @@ Switch::event(Player& , EventType type)
set_action("turnon", m_dir, 1);
SoundManager::current()->play(SWITCH_SOUND, get_pos());
m_state = TURN_ON;
m_player_name = player.get_name();
break;
case TURN_ON:
break;
Expand All @@ -125,6 +136,7 @@ Switch::event(Player& , EventType type)
set_action("turnoff", m_dir, 1);
SoundManager::current()->play(SWITCH_SOUND, get_pos());
m_state = TURN_OFF;
m_player_name = player.get_name();
}
break;
case TURN_OFF:
Expand Down
1 change: 1 addition & 0 deletions src/trigger/switch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class Switch final : public SpritedTrigger
std::string m_script;
std::string m_off_script;
SwitchState m_state;
std::string m_player_name;
bool m_bistable;
Direction m_dir;

Expand Down