3 #include "script_interpreter.hpp"
11 #include <sqstdblob.h>
12 #include <sqstdsystem.h>
13 #include <sqstdmath.h>
14 #include <sqstdstring.h>
16 #include "wrapper.hpp"
17 #include "wrapper_util.hpp"
19 #include "file_system.hpp"
20 #include "game_session.hpp"
21 #include "resources.hpp"
22 #include "physfs/physfs_stream.hpp"
23 #include "object/text_object.hpp"
24 #include "object/scripted_object.hpp"
25 #include "object/display_effect.hpp"
26 #include "object/player.hpp"
27 #include "scripting/sound.hpp"
28 #include "scripting/scripted_object.hpp"
29 #include "scripting/display_effect.hpp"
30 #include "scripting/squirrel_error.hpp"
32 static void printfunc(HSQUIRRELVM, const char* str, ...)
35 va_start(arglist, str);
36 vprintf(str, arglist);
40 ScriptInterpreter* ScriptInterpreter::_current = 0;
42 ScriptInterpreter::ScriptInterpreter(const std::string& new_working_directory)
43 : working_directory(new_working_directory), sound(0), level(0)
47 throw std::runtime_error("Couldn't initialize squirrel vm");
49 // register default error handlers
50 sqstd_seterrorhandlers(v);
51 // register squirrel libs
53 if(sqstd_register_bloblib(v) < 0)
54 throw Scripting::SquirrelError(v, "Couldn't register blob lib");
55 if(sqstd_register_iolib(v) < 0)
56 throw Scripting::SquirrelError(v, "Couldn't register io lib");
57 if(sqstd_register_systemlib(v) < 0)
58 throw Scripting::SquirrelError(v, "Couldn't register system lib");
59 if(sqstd_register_mathlib(v) < 0)
60 throw Scripting::SquirrelError(v, "Couldn't register math lib");
61 if(sqstd_register_stringlib(v) < 0)
62 throw Scripting::SquirrelError(v, "Couldn't register string lib");
64 // register print function
65 sq_setprintfunc(v, printfunc);
67 // register supertux API
68 Scripting::register_supertux_wrapper(v);
70 // expose some "global" objects
71 sound = new Scripting::Sound();
72 expose_object(sound, "Sound");
74 level = new Scripting::Level();
75 expose_object(level, "Level");
79 ScriptInterpreter::register_sector(Sector* sector)
81 // expose ScriptedObjects to the script
82 for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
83 i != sector->gameobjects.end(); ++i) {
84 GameObject* object = *i;
85 Scripting::ScriptedObject* scripted_object
86 = dynamic_cast<Scripting::ScriptedObject*> (object);
90 expose_object(scripted_object, scripted_object->get_name());
93 expose_object(static_cast<Scripting::Player*> (sector->player), "Tux");
94 TextObject* text_object = new TextObject();
95 sector->add_object(text_object);
96 Scripting::Text* text = static_cast<Scripting::Text*> (text_object);
97 expose_object(text, "Text");
99 DisplayEffect* display_effect = new DisplayEffect();
100 sector->add_object(display_effect);
101 Scripting::DisplayEffect* display_effect_api
102 = static_cast<Scripting::DisplayEffect*> (display_effect);
103 expose_object(display_effect_api, "DisplayEffect");
106 ScriptInterpreter::~ScriptInterpreter()
113 static SQInteger squirrel_read_char(SQUserPointer file)
115 std::istream* in = reinterpret_cast<std::istream*> (file);
123 ScriptInterpreter::run_script(std::istream& in, const std::string& sourcename,
124 bool remove_when_terminated)
126 printf("Stackbefore:\n");
127 print_squirrel_stack(v);
128 if(sq_compile(v, squirrel_read_char, &in, sourcename.c_str(), true) < 0)
129 throw Scripting::SquirrelError(v, "Couldn't parse script");
133 if(sq_call(v, 1, false) < 0)
134 throw Scripting::SquirrelError(v, "Couldn't start script");
136 if(sq_getvmstate(v) != SQ_VMSTATE_SUSPENDED) {
137 if(remove_when_terminated) {
141 // remove closure from stack
145 print_squirrel_stack(v);
149 ScriptInterpreter::set_wakeup_time(float seconds)
151 wakeup_timer.start(seconds);
155 ScriptInterpreter::update(float )
157 if(!wakeup_timer.check())
161 if(sq_wakeupvm(v, false, false) < 0)
162 throw Scripting::SquirrelError(v, "Couldn't resume script");
164 if(sq_getvmstate(v) != SQ_VMSTATE_SUSPENDED) {
165 printf("script ended...\n");
171 ScriptInterpreter::draw(DrawingContext& )
176 ScriptInterpreter::add_script_object(Sector* sector, const std::string& name,
177 const std::string& script)
180 std::string workdir = GameSession::current()->get_working_directory();
181 std::auto_ptr<ScriptInterpreter> interpreter(
182 new ScriptInterpreter(workdir));
183 interpreter->register_sector(sector);
185 // load global default.nut file if it exists
186 //TODO: Load all .nut files from that directory
188 std::string filename = "script/default.nut";
189 IFileStream in(filename);
190 interpreter->run_script(in, filename, false);
191 } catch(std::exception& e) {
195 // load world-specific default.nut file if it exists
197 std::string filename = workdir + "/default.nut";
198 IFileStream in(filename);
199 interpreter->run_script(in, filename, false);
200 } catch(std::exception& e) {
204 std::istringstream in(script);
205 interpreter->run_script(in, name);
206 sector->add_object(interpreter.release());
207 } catch(std::exception& e) {
208 std::cerr << "Couldn't start '" << name << "' script: " << e.what() << "\n";