#include <config.h>
-#include "script_interpreter.h"
+#include "script_interpreter.hpp"
#include <stdarg.h>
#include <stdexcept>
#include <sstream>
+#include <fstream>
#include <sqstdio.h>
#include <sqstdaux.h>
#include <sqstdblob.h>
#include <sqstdmath.h>
#include <sqstdstring.h>
-#include "wrapper.h"
-#include "wrapper_util.h"
-#include "sector.h"
-#include "object/text_object.h"
-#include "object/scripted_object.h"
-#include "object/display_effect.h"
-#include "scripting/sound.h"
-#include "scripting/scripted_object.h"
-#include "scripting/display_effect.h"
+#include "wrapper.hpp"
+#include "wrapper_util.hpp"
+#include "sector.hpp"
+#include "file_system.hpp"
+#include "game_session.hpp"
+#include "resources.hpp"
+#include "physfs/physfs_stream.hpp"
+#include "object/text_object.hpp"
+#include "object/scripted_object.hpp"
+#include "object/display_effect.hpp"
+#include "object/player.hpp"
+#include "scripting/sound.hpp"
+#include "scripting/scripted_object.hpp"
+#include "scripting/display_effect.hpp"
+#include "scripting/squirrel_error.hpp"
static void printfunc(HSQUIRRELVM, const char* str, ...)
{
ScriptInterpreter* ScriptInterpreter::_current = 0;
-ScriptInterpreter::ScriptInterpreter(Sector* sector)
- : sound(0), level(0)
+ScriptInterpreter::ScriptInterpreter(const std::string& new_working_directory)
+ : working_directory(new_working_directory), sound(0), level(0)
{
v = sq_open(1024);
if(v == 0)
// register squirrel libs
sq_pushroottable(v);
if(sqstd_register_bloblib(v) < 0)
- throw SquirrelError(v, "Couldn't register blob lib");
+ throw Scripting::SquirrelError(v, "Couldn't register blob lib");
if(sqstd_register_iolib(v) < 0)
- throw SquirrelError(v, "Couldn't register io lib");
+ throw Scripting::SquirrelError(v, "Couldn't register io lib");
if(sqstd_register_systemlib(v) < 0)
- throw SquirrelError(v, "Couldn't register system lib");
+ throw Scripting::SquirrelError(v, "Couldn't register system lib");
if(sqstd_register_mathlib(v) < 0)
- throw SquirrelError(v, "Couldn't register math lib");
+ throw Scripting::SquirrelError(v, "Couldn't register math lib");
if(sqstd_register_stringlib(v) < 0)
- throw SquirrelError(v, "Couldn't register string lib");
+ throw Scripting::SquirrelError(v, "Couldn't register string lib");
// register print function
sq_setprintfunc(v, printfunc);
// register supertux API
- register_functions(v, supertux_global_functions);
- register_classes(v, supertux_classes);
+ Scripting::register_supertux_wrapper(v);
+ // expose some "global" objects
+ sound = new Scripting::Sound();
+ expose_object(sound, "Sound");
+
+ level = new Scripting::Level();
+ expose_object(level, "Level");
+}
+
+void
+ScriptInterpreter::register_sector(Sector* sector)
+{
// expose ScriptedObjects to the script
for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
i != sector->gameobjects.end(); ++i) {
if(!scripted_object)
continue;
- expose_object(scripted_object, scripted_object->get_name(),
- "ScriptedObject");
+ expose_object(scripted_object, scripted_object->get_name());
}
- // expose some "global" objects
- sound = new Scripting::Sound();
- expose_object(sound, "Sound", "Sound");
-
- level = new Scripting::Level();
- expose_object(level, "Level", "Level");
+ expose_object(static_cast<Scripting::Player*> (sector->player), "Tux");
TextObject* text_object = new TextObject();
sector->add_object(text_object);
Scripting::Text* text = static_cast<Scripting::Text*> (text_object);
- expose_object(text, "Text", "Text");
+ expose_object(text, "Text");
DisplayEffect* display_effect = new DisplayEffect();
sector->add_object(display_effect);
Scripting::DisplayEffect* display_effect_api
= static_cast<Scripting::DisplayEffect*> (display_effect);
- expose_object(display_effect_api, "DisplayEffect", "DisplayEffect");
+ expose_object(display_effect_api, "DisplayEffect");
}
ScriptInterpreter::~ScriptInterpreter()
return c;
}
-
void
-ScriptInterpreter::load_script(std::istream& in, const std::string& sourcename)
+ScriptInterpreter::run_script(std::istream& in, const std::string& sourcename,
+ bool remove_when_terminated)
{
if(sq_compile(v, squirrel_read_char, &in, sourcename.c_str(), true) < 0)
- throw SquirrelError(v, "Couldn't parse script");
-}
-
-void
-ScriptInterpreter::start_script()
-{
+ throw Scripting::SquirrelError(v, "Couldn't parse script");
+
_current = this;
sq_push(v, -2);
if(sq_call(v, 1, false) < 0)
- throw SquirrelError(v, "Couldn't start script");
+ throw Scripting::SquirrelError(v, "Couldn't start script");
_current = 0;
if(sq_getvmstate(v) != SQ_VMSTATE_SUSPENDED) {
- printf("script ended...\n");
- remove_me();
- }
-}
-
-void
-ScriptInterpreter::expose_object(void* object, const std::string& name,
- const std::string& type)
-{
- // part1 of registration of the instance in the root table
- sq_pushroottable(v);
- sq_pushstring(v, name.c_str(), -1);
-
- // resolve class name
- sq_pushroottable(v);
- sq_pushstring(v, type.c_str(), -1);
- if(sq_get(v, -2) < 0) {
- std::ostringstream msg;
- msg << "Couldn't resolve squirrel type '" << type << "'.";
- throw std::runtime_error(msg.str());
- }
- sq_remove(v, -2); // remove roottable
-
- // create an instance and set pointer to c++ object
- if(sq_createinstance(v, -1) < 0 || sq_setinstanceup(v, -1, object)) {
- std::ostringstream msg;
- msg << "Couldn't setup squirrel instance for object '"
- << name << "' of type '" << type << "'.";
- throw SquirrelError(v, msg.str());
+ if(remove_when_terminated) {
+ remove_me();
+ }
+ // remove closure from stack
+ sq_pop(v, 1);
}
-
- sq_remove(v, -2); // remove class from stack
-
- // part2 of registration of the instance in the root table
- if(sq_createslot(v, -3) < 0)
- throw SquirrelError(v, "Couldn't register object in squirrel root table"); sq_pop(v, 1);
}
void
}
void
-ScriptInterpreter::action(float )
+ScriptInterpreter::update(float )
{
if(!wakeup_timer.check())
return;
_current = this;
if(sq_wakeupvm(v, false, false) < 0)
- throw SquirrelError(v, "Couldn't resume script");
+ throw Scripting::SquirrelError(v, "Couldn't resume script");
_current = 0;
if(sq_getvmstate(v) != SQ_VMSTATE_SUSPENDED) {
printf("script ended...\n");
ScriptInterpreter::draw(DrawingContext& )
{
}
+
+void
+ScriptInterpreter::add_script_object(Sector* sector, const std::string& name,
+ const std::string& script)
+{
+ try {
+ std::string workdir = GameSession::current()->get_working_directory();
+ std::auto_ptr<ScriptInterpreter> interpreter(
+ new ScriptInterpreter(workdir));
+ interpreter->register_sector(sector);
+
+ // load global default.nut file if it exists
+ //TODO: Load all .nut files from that directory
+ try {
+ std::string filename = "script/default.nut";
+ IFileStream in(filename);
+ interpreter->run_script(in, filename, false);
+ } catch(std::exception& e) {
+ // nothing
+ }
+
+ // load world-specific default.nut file if it exists
+ try {
+ std::string filename = workdir + "/default.nut";
+ IFileStream in(filename);
+ interpreter->run_script(in, filename, false);
+ } catch(std::exception& e) {
+ // nothing
+ }
+
+ std::istringstream in(script);
+ interpreter->run_script(in, name);
+ sector->add_object(interpreter.release());
+ } catch(std::exception& e) {
+ std::cerr << "Couldn't start '" << name << "' script: " << e.what() << "\n";
+ }
+}
+