3 #include "script_interpreter.h"
11 #include <sqstdblob.h>
12 #include <sqstdsystem.h>
13 #include <sqstdmath.h>
14 #include <sqstdstring.h>
17 #include "wrapper_util.h"
19 #include "file_system.h"
20 #include "game_session.h"
21 #include "resources.h"
22 #include "physfs/physfs_stream.h"
23 #include "object/text_object.h"
24 #include "object/scripted_object.h"
25 #include "object/display_effect.h"
26 #include "scripting/sound.h"
27 #include "scripting/scripted_object.h"
28 #include "scripting/display_effect.h"
30 static void printfunc(HSQUIRRELVM, const char* str, ...)
33 va_start(arglist, str);
34 vprintf(str, arglist);
38 ScriptInterpreter* ScriptInterpreter::_current = 0;
40 ScriptInterpreter::ScriptInterpreter(const std::string& new_working_directory)
41 : working_directory(new_working_directory), sound(0), level(0)
45 throw std::runtime_error("Couldn't initialize squirrel vm");
47 // register default error handlers
48 sqstd_seterrorhandlers(v);
49 // register squirrel libs
51 if(sqstd_register_bloblib(v) < 0)
52 throw SquirrelError(v, "Couldn't register blob lib");
53 if(sqstd_register_iolib(v) < 0)
54 throw SquirrelError(v, "Couldn't register io lib");
55 if(sqstd_register_systemlib(v) < 0)
56 throw SquirrelError(v, "Couldn't register system lib");
57 if(sqstd_register_mathlib(v) < 0)
58 throw SquirrelError(v, "Couldn't register math lib");
59 if(sqstd_register_stringlib(v) < 0)
60 throw SquirrelError(v, "Couldn't register string lib");
62 // register print function
63 sq_setprintfunc(v, printfunc);
65 // register supertux API
66 register_functions(v, supertux_global_functions);
67 register_classes(v, supertux_classes);
69 // expose some "global" objects
70 sound = new Scripting::Sound();
71 expose_object(sound, "Sound", "Sound");
73 level = new Scripting::Level();
74 expose_object(level, "Level", "Level");
78 ScriptInterpreter::register_sector(Sector* sector)
80 // expose ScriptedObjects to the script
81 for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
82 i != sector->gameobjects.end(); ++i) {
83 GameObject* object = *i;
84 Scripting::ScriptedObject* scripted_object
85 = dynamic_cast<Scripting::ScriptedObject*> (object);
89 expose_object(scripted_object, scripted_object->get_name(),
93 TextObject* text_object = new TextObject();
94 sector->add_object(text_object);
95 Scripting::Text* text = static_cast<Scripting::Text*> (text_object);
96 expose_object(text, "Text", "Text");
98 DisplayEffect* display_effect = new DisplayEffect();
99 sector->add_object(display_effect);
100 Scripting::DisplayEffect* display_effect_api
101 = static_cast<Scripting::DisplayEffect*> (display_effect);
102 expose_object(display_effect_api, "DisplayEffect", "DisplayEffect");
105 ScriptInterpreter::~ScriptInterpreter()
112 static SQInteger squirrel_read_char(SQUserPointer file)
114 std::istream* in = reinterpret_cast<std::istream*> (file);
122 ScriptInterpreter::run_script(std::istream& in, const std::string& sourcename)
124 if(sq_compile(v, squirrel_read_char, &in, sourcename.c_str(), true) < 0)
125 throw SquirrelError(v, "Couldn't parse script");
129 if(sq_call(v, 1, false) < 0)
130 throw SquirrelError(v, "Couldn't start script");
132 if(sq_getvmstate(v) != SQ_VMSTATE_SUSPENDED) {
133 printf("script ended...\n");
139 ScriptInterpreter::expose_object(void* object, const std::string& name,
140 const std::string& type)
142 // part1 of registration of the instance in the root table
144 sq_pushstring(v, name.c_str(), -1);
146 // resolve class name
148 sq_pushstring(v, type.c_str(), -1);
149 if(sq_get(v, -2) < 0) {
150 std::ostringstream msg;
151 msg << "Couldn't resolve squirrel type '" << type << "'.";
152 throw std::runtime_error(msg.str());
154 sq_remove(v, -2); // remove roottable
156 // create an instance and set pointer to c++ object
157 if(sq_createinstance(v, -1) < 0 || sq_setinstanceup(v, -1, object)) {
158 std::ostringstream msg;
159 msg << "Couldn't setup squirrel instance for object '"
160 << name << "' of type '" << type << "'.";
161 throw SquirrelError(v, msg.str());
164 sq_remove(v, -2); // remove class from stack
166 // part2 of registration of the instance in the root table
167 if(sq_createslot(v, -3) < 0)
168 throw SquirrelError(v, "Couldn't register object in squirrel root table"); sq_pop(v, 1);
172 ScriptInterpreter::set_wakeup_time(float seconds)
174 wakeup_timer.start(seconds);
178 ScriptInterpreter::update(float )
180 if(!wakeup_timer.check())
184 if(sq_wakeupvm(v, false, false) < 0)
185 throw SquirrelError(v, "Couldn't resume script");
187 if(sq_getvmstate(v) != SQ_VMSTATE_SUSPENDED) {
188 printf("script ended...\n");
194 ScriptInterpreter::draw(DrawingContext& )
199 ScriptInterpreter::add_script_object(Sector* sector, const std::string& name,
200 const std::string& script)
203 std::string workdir = GameSession::current()->get_working_directory();
204 std::auto_ptr<ScriptInterpreter> interpreter(
205 new ScriptInterpreter(workdir));
206 interpreter->register_sector(sector);
208 // load default.nut file if it exists
210 std::string filename = workdir + "/default.nut";
211 IFileStream in(filename);
212 interpreter->run_script(in, filename);
213 } catch(std::exception& e) {
217 std::istringstream in(script);
218 interpreter->run_script(in, name);
219 sector->add_object(interpreter.release());
220 } catch(std::exception& e) {
221 std::cerr << "Couldn't start '" << name << "' script: " << e.what() << "\n";