1 #ifdef LUACONSOLE
2
3 #include "LuaScriptInterface.h"
4
5 #include <vector>
6 #include <fstream>
7 #include <algorithm>
8
9 #include "Config.h"
10 #include "Format.h"
11 #include "Platform.h"
12 #include "PowderToy.h"
13
14 #include "TPTScriptInterface.h"
15 #include "LuaScriptHelper.h"
16 #include "LuaLuna.h"
17 #include "LuaBit.h"
18 #include "LuaButton.h"
19 #include "LuaCheckbox.h"
20 #include "LuaEvents.h"
21 #include "LuaLabel.h"
22 #include "LuaProgressBar.h"
23 #include "LuaSlider.h"
24 #include "LuaTextbox.h"
25 #include "LuaWindow.h"
26
27 #include "gui/interface/Window.h"
28 #include "gui/interface/Engine.h"
29 #include "gui/game/GameView.h"
30 #include "gui/game/GameController.h"
31 #include "gui/game/GameModel.h"
32 #include "gui/game/Tool.h"
33 #include "gui/game/Brush.h"
34
35 #include "simulation/Simulation.h"
36 #include "simulation/ElementGraphics.h"
37 #include "simulation/ElementCommon.h"
38 #include "simulation/Air.h"
39
40 #include "simulation/ToolClasses.h"
41 #include "simulation/ElementClasses.h"
42
43 #include "client/GameSave.h"
44 #include "client/SaveFile.h"
45 #include "client/SaveInfo.h"
46 #include "client/Client.h"
47 #include "client/http/Request.h"
48
49 #include "graphics/Graphics.h"
50 #include "graphics/Renderer.h"
51
52 #ifndef WIN
53 #include <unistd.h>
54 #endif
55
56 extern "C"
57 {
58 #ifdef WIN
59 #include <direct.h>
60 #endif
61 #include <sys/stat.h>
62 #include <dirent.h>
63 #include "socket/luasocket.h"
64 }
65 #include "socket/socket.lua.h"
66
67 GameModel * luacon_model;
68 GameController * luacon_controller;
69 Simulation * luacon_sim;
70 LuaScriptInterface * luacon_ci;
71 Graphics * luacon_g;
72 Renderer * luacon_ren;
73
74 bool *luacon_currentCommand;
75 String *luacon_lastError;
76 String lastCode;
77
78 int *lua_el_mode;
79 LuaSmartRef *lua_el_func, *lua_gr_func;
80 std::vector<LuaSmartRef> luaCtypeDrawHandlers, luaCreateHandlers, luaCreateAllowedHandlers, luaChangeTypeHandlers;
81
82 int getPartIndex_curIdx;
83 int tptProperties; //Table for some TPT properties
84 int tptPropertiesVersion;
85 int tptElements; //Table for TPT element names
86 int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, cIndex;
87 LuaSmartRef *tptPart = nullptr;
88
atPanic(lua_State * l)89 int atPanic(lua_State *l)
90 {
91 throw std::runtime_error("Unprotected lua panic: " + ByteString(lua_tostring(l, -1)));
92 }
93
TptIndexClosure(lua_State * l)94 int TptIndexClosure(lua_State *l)
95 {
96 LuaScriptInterface *lsi = (LuaScriptInterface *)lua_touserdata(l, lua_upvalueindex(1));
97 return lsi->tpt_index(l);
98 }
99
TptNewindexClosure(lua_State * l)100 int TptNewindexClosure(lua_State *l)
101 {
102 LuaScriptInterface *lsi = (LuaScriptInterface *)lua_touserdata(l, lua_upvalueindex(1));
103 return lsi->tpt_newIndex(l);
104 }
105
LuaScriptInterface(GameController * c,GameModel * m)106 LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
107 CommandInterface(c, m),
108 luacon_mousex(0),
109 luacon_mousey(0),
110 luacon_mousebutton(0),
111 luacon_selectedl(""),
112 luacon_selectedr(""),
113 luacon_selectedalt(""),
114 luacon_selectedreplace(""),
115 luacon_mousedown(false),
116 currentCommand(false),
117 legacy(new TPTScriptInterface(c, m))
118 {
119 luacon_model = m;
120 luacon_controller = c;
121 luacon_sim = m->GetSimulation();
122 luacon_g = ui::Engine::Ref().g;
123 luacon_ren = m->GetRenderer();
124 luacon_ci = this;
125
126 //New TPT API
127 l = luaL_newstate();
128 lua_atpanic(l, atPanic);
129 luaL_openlibs(l);
130 luaopen_bit(l);
131 luaopen_socket_core(l);
132 lua_getglobal(l, "package");
133 lua_pushstring(l, "loaded");
134 lua_rawget(l, -2);
135 lua_pushstring(l, "socket");
136 lua_rawget(l, -2);
137 lua_pushstring(l, "socket.core");
138 lua_pushvalue(l, -2);
139 lua_rawset(l, -4);
140 lua_pop(l, 3);
141 luaopen_socket(l);
142
143 lua_pushstring(l, "Luacon_ci");
144 lua_pushlightuserdata(l, this);
145 lua_settable(l, LUA_REGISTRYINDEX);
146
147 initSimulationAPI();
148 initInterfaceAPI();
149 SetWindow(c->GetView());
150 initRendererAPI();
151 initElementsAPI();
152 initGraphicsAPI();
153 initFileSystemAPI();
154 initPlatformAPI();
155 initEventAPI();
156 initHttpAPI();
157
158 //Old TPT API
159 int currentElementMeta, currentElement;
160 const static struct luaL_Reg tptluaapi [] = {
161 {"drawtext", &luatpt_drawtext},
162 {"create", &luatpt_create},
163 {"set_pause", &luatpt_setpause},
164 {"toggle_pause", &luatpt_togglepause},
165 {"set_console", &luatpt_setconsole},
166 {"log", &luatpt_log},
167 {"set_pressure", &luatpt_set_pressure},
168 {"set_gravity", &luatpt_set_gravity},
169 {"reset_gravity_field", &luatpt_reset_gravity_field},
170 {"reset_velocity", &luatpt_reset_velocity},
171 {"reset_spark", &luatpt_reset_spark},
172 {"set_property", &luatpt_set_property},
173 {"get_property", &luatpt_get_property},
174 {"set_wallmap", &luatpt_set_wallmap},
175 {"get_wallmap", &luatpt_get_wallmap},
176 {"set_elecmap", &luatpt_set_elecmap},
177 {"get_elecmap", &luatpt_get_elecmap},
178 {"drawpixel", &luatpt_drawpixel},
179 {"drawrect", &luatpt_drawrect},
180 {"fillrect", &luatpt_fillrect},
181 {"drawline", &luatpt_drawline},
182 {"textwidth", &luatpt_textwidth},
183 {"get_name", &luatpt_get_name},
184 {"delete", &luatpt_delete},
185 {"input", &luatpt_input},
186 {"message_box", &luatpt_message_box},
187 {"confirm", &luatpt_confirm},
188 {"get_numOfParts", &luatpt_get_numOfParts},
189 {"start_getPartIndex", &luatpt_start_getPartIndex},
190 {"next_getPartIndex", &luatpt_next_getPartIndex},
191 {"getPartIndex", &luatpt_getPartIndex},
192 {"hud", &luatpt_hud},
193 {"newtonian_gravity", &luatpt_gravity},
194 {"ambient_heat", &luatpt_airheat},
195 {"active_menu", &luatpt_active_menu},
196 {"menu_enabled", &luatpt_menu_enabled},
197 {"num_menus", &luatpt_num_menus},
198 {"decorations_enable", &luatpt_decorations_enable},
199 {"display_mode", &luatpt_cmode_set},
200 {"throw_error", &luatpt_error},
201 {"heat", &luatpt_heat},
202 {"setfire", &luatpt_setfire},
203 {"setdebug", &luatpt_setdebug},
204 {"setfpscap",&luatpt_setfpscap},
205 {"getscript",&luatpt_getscript},
206 {"setwindowsize",&luatpt_setwindowsize},
207 {"watertest",&luatpt_togglewater},
208 {"screenshot",&luatpt_screenshot},
209 {"record",&luatpt_record},
210 {"element",&luatpt_getelement},
211 {"element_func",&luatpt_element_func},
212 {"graphics_func",&luatpt_graphics_func},
213 {"get_clipboard", &platform_clipboardCopy},
214 {"set_clipboard", &platform_clipboardPaste},
215 {NULL,NULL}
216 };
217
218 luacon_mousedown = false;
219 luacon_mousebutton = 0;
220
221 luacon_currentCommand = ¤tCommand;
222 luacon_lastError = &lastError;
223
224 lastCode = "";
225
226 //Replace print function with our screen logging thingy
227 lua_pushcfunction(l, luatpt_log);
228 lua_setglobal(l, "print");
229
230 //Register all tpt functions
231 luaL_register(l, "tpt", tptluaapi);
232
233 tptProperties = lua_gettop(l);
234
235 lua_newtable(l);
236 tptPropertiesVersion = lua_gettop(l);
237 lua_pushinteger(l, SAVE_VERSION);
238 lua_setfield(l, tptPropertiesVersion, "major");
239 lua_pushinteger(l, MINOR_VERSION);
240 lua_setfield(l, tptPropertiesVersion, "minor");
241 lua_pushinteger(l, BUILD_NUM);
242 lua_setfield(l, tptPropertiesVersion, "build");
243 #if defined(SNAPSHOT) || MOD_ID > 0
244 lua_pushinteger(l, SNAPSHOT_ID);
245 #else
246 lua_pushinteger(l, 0);
247 #endif
248 lua_setfield(l, tptPropertiesVersion, "snapshot");
249 lua_pushinteger(l, MOD_ID);
250 lua_setfield(l, tptPropertiesVersion, "modid");
251 lua_setfield(l, tptProperties, "version");
252
253 lua_sethook(l, &luacon_hook, LUA_MASKCOUNT, 200);
254 #ifdef FFI
255 //LuaJIT's ffi gives us direct access to parts data, no need for nested metatables. HOWEVER, this is in no way safe, it's entirely possible for someone to try to read parts[-10]
256 lua_pushlightuserdata(l, parts);
257 lua_setfield(l, tptProperties, "partsdata");
258
259 luaL_dostring (l, "ffi = require(\"ffi\")\n\
260 ffi.cdef[[\n\
261 typedef struct { int type; int life, ctype; float x, y, vx, vy; float temp; float pavg[2]; int flags; int tmp; int tmp2; unsigned int dcolour; } particle;\n\
262 ]]\n\
263 tpt.parts = ffi.cast(\"particle *\", tpt.partsdata)\n\
264 ffi = nil\n\
265 tpt.partsdata = nil");
266 //Since ffi is REALLY REALLY dangrous, we'll remove it from the environment completely (TODO)
267 //lua_pushstring(l, "parts");
268 //tptPartsCData = lua_gettable(l, tptProperties);
269 #else
270 lua_newtable(l);
271 tptParts = lua_gettop(l);
272 lua_newtable(l);
273 tptPartsMeta = lua_gettop(l);
274 lua_pushcfunction(l, luacon_partswrite);
275 lua_setfield(l, tptPartsMeta, "__newindex");
276 lua_pushcfunction(l, luacon_partsread);
277 lua_setfield(l, tptPartsMeta, "__index");
278 lua_setmetatable(l, tptParts);
279 lua_setfield(l, tptProperties, "parts");
280
281 lua_newtable(l);
282 {
283 int top = lua_gettop(l);
284 lua_newtable(l);
285 tptPartMeta = lua_gettop(l);
286 lua_pushcfunction(l, luacon_partwrite);
287 lua_setfield(l, tptPartMeta, "__newindex");
288 lua_pushcfunction(l, luacon_partread);
289 lua_setfield(l, tptPartMeta, "__index");
290 lua_setmetatable(l, top);
291 }
292
293 tptPart = new LuaSmartRef(l);
294 tptPart->Assign(-1);
295 lua_pop(l, 1);
296 #endif
297
298 lua_newtable(l);
299 tptElements = lua_gettop(l);
300 for (int i = 1; i < PT_NUM; i++)
301 {
302 lua_newtable(l);
303 currentElement = lua_gettop(l);
304 lua_pushinteger(l, i);
305 lua_setfield(l, currentElement, "id");
306
307 lua_newtable(l);
308 currentElementMeta = lua_gettop(l);
309 lua_pushcfunction(l, luacon_elementwrite);
310 lua_setfield(l, currentElementMeta, "__newindex");
311 lua_pushcfunction(l, luacon_elementread);
312 lua_setfield(l, currentElementMeta, "__index");
313 lua_setmetatable(l, currentElement);
314
315 lua_setfield(l, tptElements, luacon_sim->elements[i].Name.ToUtf8().ToLower().c_str());
316 }
317 lua_setfield(l, tptProperties, "el");
318
319 lua_newtable(l);
320 tptElementTransitions = lua_gettop(l);
321 for (int i = 1; i < PT_NUM; i++)
322 {
323 lua_newtable(l);
324 currentElement = lua_gettop(l);
325 lua_newtable(l);
326 currentElementMeta = lua_gettop(l);
327 lua_pushinteger(l, i);
328 lua_setfield(l, currentElement, "id");
329 lua_pushcfunction(l, luacon_transitionwrite);
330 lua_setfield(l, currentElementMeta, "__newindex");
331 lua_pushcfunction(l, luacon_transitionread);
332 lua_setfield(l, currentElementMeta, "__index");
333 lua_setmetatable(l, currentElement);
334
335 lua_setfield(l, tptElementTransitions, luacon_sim->elements[i].Name.ToUtf8().ToLower().c_str());
336 }
337 lua_setfield(l, tptProperties, "eltransition");
338
339 lua_gr_func_v = std::vector<LuaSmartRef>(PT_NUM, l);
340 lua_gr_func = &lua_gr_func_v[0];
341 lua_el_func_v = std::vector<LuaSmartRef>(PT_NUM, l);
342 lua_el_func = &lua_el_func_v[0];
343 lua_el_mode_v = std::vector<int>(PT_NUM, 0);
344 lua_el_mode = &lua_el_mode_v[0];
345
346 luaCtypeDrawHandlers = std::vector<LuaSmartRef>(PT_NUM, l);
347 luaCreateHandlers = std::vector<LuaSmartRef>(PT_NUM, l);
348 luaCreateAllowedHandlers = std::vector<LuaSmartRef>(PT_NUM, l);
349 luaChangeTypeHandlers = std::vector<LuaSmartRef>(PT_NUM, l);
350
351 //make tpt.* a metatable
352 lua_newtable(l);
353 lua_pushlightuserdata(l, this);
354 lua_pushcclosure(l, TptIndexClosure, 1);
355 lua_setfield(l, -2, "__index");
356 lua_pushlightuserdata(l, this);
357 lua_pushcclosure(l, TptNewindexClosure, 1);
358 lua_setfield(l, -2, "__newindex");
359 lua_setmetatable(l, -2);
360
361 initLegacyProps();
362
363 ui::Engine::Ref().LastTick(Platform::GetTime());
364 luaopen_eventcompat(l);
365 }
366
Init()367 void LuaScriptInterface::Init()
368 {
369 if(Client::Ref().FileExists("autorun.lua"))
370 {
371 lua_State *l = luacon_ci->l;
372 if(luaL_loadfile(l, "autorun.lua") || lua_pcall(l, 0, 0, 0))
373 luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
374 else
375 luacon_ci->Log(CommandInterface::LogWarning, "Loaded autorun.lua");
376 }
377 }
378
SetWindow(ui::Window * window)379 void LuaScriptInterface::SetWindow(ui::Window * window)
380 {
381 Window = window;
382 }
383
tpt_index(lua_State * l)384 int LuaScriptInterface::tpt_index(lua_State *l)
385 {
386 ByteString key = luaL_checkstring(l, 2);
387 if (!key.compare("mousex"))
388 return lua_pushnumber(l, c->GetView()->GetMousePosition().X), 1;
389 else if (!key.compare("mousey"))
390 return lua_pushnumber(l, c->GetView()->GetMousePosition().Y), 1;
391 else if (!key.compare("selectedl"))
392 return lua_pushstring(l, m->GetActiveTool(0)->GetIdentifier().c_str()), 1;
393 else if (!key.compare("selectedr"))
394 return lua_pushstring(l, m->GetActiveTool(1)->GetIdentifier().c_str()), 1;
395 else if (!key.compare("selecteda"))
396 return lua_pushstring(l, m->GetActiveTool(2)->GetIdentifier().c_str()), 1;
397 else if (!key.compare("selectedreplace"))
398 return lua_pushstring(l, m->GetActiveTool(3)->GetIdentifier().c_str()), 1;
399 else if (!key.compare("brushx"))
400 return lua_pushnumber(l, m->GetBrush()->GetRadius().X), 1;
401 else if (!key.compare("brushy"))
402 return lua_pushnumber(l, m->GetBrush()->GetRadius().Y), 1;
403 else if (!key.compare("brushID"))
404 return lua_pushnumber(l, m->GetBrushID()), 1;
405 else if (!key.compare("decoSpace"))
406 return lua_pushnumber(l, m->GetDecoSpace()), 1;
407
408 //if not a special key, return the value in the table
409 return lua_rawget(l, 1), 1;
410 }
411
tpt_newIndex(lua_State * l)412 int LuaScriptInterface::tpt_newIndex(lua_State *l)
413 {
414 ByteString key = luaL_checkstring(l, 2);
415 if (!key.compare("selectedl"))
416 {
417 Tool *t = m->GetToolFromIdentifier(luaL_checkstring(l, 3));
418 if (t)
419 c->SetActiveTool(0, t);
420 else
421 luaL_error(l, "Invalid tool identifier: %s", lua_tostring(l, 3));
422 }
423 else if (!key.compare("selectedr"))
424 {
425 Tool *t = m->GetToolFromIdentifier(luaL_checkstring(l, 3));
426 if (t)
427 c->SetActiveTool(1, t);
428 else
429 luaL_error(l, "Invalid tool identifier: %s", lua_tostring(l, 3));
430 }
431 else if (!key.compare("selecteda"))
432 {
433 Tool *t = m->GetToolFromIdentifier(luaL_checkstring(l, 3));
434 if (t)
435 c->SetActiveTool(2, t);
436 else
437 luaL_error(l, "Invalid tool identifier: %s", lua_tostring(l, 3));
438 }
439 else if (!key.compare("selectedreplace"))
440 {
441 Tool *t = m->GetToolFromIdentifier(luaL_checkstring(l, 3));
442 if( t)
443 c->SetActiveTool(3, t);
444 else
445 luaL_error(l, "Invalid tool identifier: %s", lua_tostring(l, 3));
446 }
447 else if (!key.compare("brushx"))
448 c->SetBrushSize(ui::Point(luaL_checkinteger(l, 3), m->GetBrush()->GetRadius().Y));
449 else if (!key.compare("brushy"))
450 c->SetBrushSize(ui::Point(m->GetBrush()->GetRadius().X, luaL_checkinteger(l, 3)));
451 else if (!key.compare("brushID"))
452 m->SetBrushID(luaL_checkinteger(l, 3));
453 else if (!key.compare("decoSpace"))
454 m->SetDecoSpace(luaL_checkinteger(l, 3));
455 else
456 {
457 //if not a special key, set a value in the table
458 return lua_rawset(l, 1), 1;
459 }
460 return 0;
461 }
462
463 //// Begin Interface API
464
initInterfaceAPI()465 void LuaScriptInterface::initInterfaceAPI()
466 {
467 struct luaL_Reg interfaceAPIMethods [] = {
468 {"showWindow", interface_showWindow},
469 {"closeWindow", interface_closeWindow},
470 {"addComponent", interface_addComponent},
471 {"removeComponent", interface_removeComponent},
472 {NULL, NULL}
473 };
474 luaL_register(l, "interface", interfaceAPIMethods);
475
476 //Ren shortcut
477 lua_getglobal(l, "interface");
478 lua_setglobal(l, "ui");
479
480 Luna<LuaWindow>::Register(l);
481 Luna<LuaButton>::Register(l);
482 Luna<LuaLabel>::Register(l);
483 Luna<LuaTextbox>::Register(l);
484 Luna<LuaCheckbox>::Register(l);
485 Luna<LuaSlider>::Register(l);
486 Luna<LuaProgressBar>::Register(l);
487 }
488
interface_addComponent(lua_State * l)489 int LuaScriptInterface::interface_addComponent(lua_State * l)
490 {
491 void *opaque = nullptr;
492 LuaComponent *luaComponent = nullptr;
493 if ((opaque = Luna<LuaButton>::tryGet(l, 1)))
494 luaComponent = Luna<LuaButton>::get(opaque);
495 else if ((opaque = Luna<LuaLabel>::tryGet(l, 1)))
496 luaComponent = Luna<LuaLabel>::get(opaque);
497 else if ((opaque = Luna<LuaTextbox>::tryGet(l, 1)))
498 luaComponent = Luna<LuaTextbox>::get(opaque);
499 else if ((opaque = Luna<LuaCheckbox>::tryGet(l, 1)))
500 luaComponent = Luna<LuaCheckbox>::get(opaque);
501 else if ((opaque = Luna<LuaSlider>::tryGet(l, 1)))
502 luaComponent = Luna<LuaSlider>::get(opaque);
503 else if ((opaque = Luna<LuaProgressBar>::tryGet(l, 1)))
504 luaComponent = Luna<LuaProgressBar>::get(opaque);
505 else
506 luaL_typerror(l, 1, "Component");
507 if (luacon_ci->Window && luaComponent)
508 {
509 auto ok = luacon_ci->grabbed_components.insert(std::make_pair(luaComponent, LuaSmartRef(l)));
510 if (ok.second)
511 {
512 auto it = ok.first;
513 it->second.Assign(1);
514 it->first->owner_ref = it->second;
515 }
516 luacon_ci->Window->AddComponent(luaComponent->GetComponent());
517 }
518 return 0;
519 }
520
interface_removeComponent(lua_State * l)521 int LuaScriptInterface::interface_removeComponent(lua_State * l)
522 {
523 void *opaque = nullptr;
524 LuaComponent *luaComponent = nullptr;
525 if ((opaque = Luna<LuaButton>::tryGet(l, 1)))
526 luaComponent = Luna<LuaButton>::get(opaque);
527 else if ((opaque = Luna<LuaLabel>::tryGet(l, 1)))
528 luaComponent = Luna<LuaLabel>::get(opaque);
529 else if ((opaque = Luna<LuaTextbox>::tryGet(l, 1)))
530 luaComponent = Luna<LuaTextbox>::get(opaque);
531 else if ((opaque = Luna<LuaCheckbox>::tryGet(l, 1)))
532 luaComponent = Luna<LuaCheckbox>::get(opaque);
533 else if ((opaque = Luna<LuaSlider>::tryGet(l, 1)))
534 luaComponent = Luna<LuaSlider>::get(opaque);
535 else if ((opaque = Luna<LuaProgressBar>::tryGet(l, 1)))
536 luaComponent = Luna<LuaProgressBar>::get(opaque);
537 else
538 luaL_typerror(l, 1, "Component");
539 if(luacon_ci->Window && luaComponent)
540 {
541 ui::Component *component = luaComponent->GetComponent();
542 luacon_ci->Window->RemoveComponent(component);
543 auto it = luacon_ci->grabbed_components.find(luaComponent);
544 if (it != luacon_ci->grabbed_components.end())
545 {
546 it->second.Clear();
547 it->first->owner_ref = it->second;
548 luacon_ci->grabbed_components.erase(it);
549 }
550 }
551 return 0;
552 }
553
interface_showWindow(lua_State * l)554 int LuaScriptInterface::interface_showWindow(lua_State * l)
555 {
556 LuaWindow * window = Luna<LuaWindow>::check(l, 1);
557
558 if(window && ui::Engine::Ref().GetWindow()!=window->GetWindow())
559 ui::Engine::Ref().ShowWindow(window->GetWindow());
560 return 0;
561 }
562
interface_closeWindow(lua_State * l)563 int LuaScriptInterface::interface_closeWindow(lua_State * l)
564 {
565 LuaWindow * window = Luna<LuaWindow>::check(l, 1);
566 if (window)
567 window->GetWindow()->CloseActiveWindow();
568 return 0;
569 }
570
571 //// Begin sim.signs API
572
simulation_signIndex(lua_State * l)573 int LuaScriptInterface::simulation_signIndex(lua_State *l)
574 {
575 ByteString key = luaL_checkstring(l, 2);
576
577 //Get Raw Index value for element. Maybe there is a way to get the sign index some other way?
578 lua_pushstring(l, "id");
579 lua_rawget(l, 1);
580 int id = lua_tointeger(l, lua_gettop(l))-1;
581
582 if (id < 0 || id >= MAXSIGNS)
583 {
584 luaL_error(l, "Invalid sign ID (stop messing with things): %i", id);
585 return 0;
586 }
587 if (id >= (int)luacon_sim->signs.size())
588 {
589 return lua_pushnil(l), 1;
590 }
591
592 int x, y, w, h;
593 if (!key.compare("text"))
594 return lua_pushstring(l, luacon_sim->signs[id].text.ToUtf8().c_str()), 1;
595 else if (!key.compare("displayText"))
596 return lua_pushstring(l, luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h, false).ToUtf8().c_str()), 1;
597 else if (!key.compare("justification"))
598 return lua_pushnumber(l, (int)luacon_sim->signs[id].ju), 1;
599 else if (!key.compare("x"))
600 return lua_pushnumber(l, luacon_sim->signs[id].x), 1;
601 else if (!key.compare("y"))
602 return lua_pushnumber(l, luacon_sim->signs[id].y), 1;
603 else if (!key.compare("screenX"))
604 {
605 luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h);
606 lua_pushnumber(l, x);
607 return 1;
608 }
609 else if (!key.compare("screenY"))
610 {
611 luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h);
612 lua_pushnumber(l, y);
613 return 1;
614 }
615 else if (!key.compare("width"))
616 {
617 luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h);
618 lua_pushnumber(l, w);
619 return 1;
620 }
621 else if (!key.compare("height"))
622 {
623 luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h);
624 lua_pushnumber(l, h);
625 return 1;
626 }
627 else
628 return lua_pushnil(l), 1;
629 }
630
simulation_signNewIndex(lua_State * l)631 int LuaScriptInterface::simulation_signNewIndex(lua_State *l)
632 {
633 ByteString key = luaL_checkstring(l, 2);
634
635 //Get Raw Index value for element. Maybe there is a way to get the sign index some other way?
636 lua_pushstring(l, "id");
637 lua_rawget(l, 1);
638 int id = lua_tointeger(l, lua_gettop(l))-1;
639
640 if (id < 0 || id >= MAXSIGNS)
641 {
642 luaL_error(l, "Invalid sign ID (stop messing with things)");
643 return 0;
644 }
645 if (id >= (int)luacon_sim->signs.size())
646 {
647 luaL_error(l, "Sign doesn't exist");
648 }
649
650 if (!key.compare("text"))
651 {
652 const char *temp = luaL_checkstring(l, 3);
653 String cleaned = format::CleanString(ByteString(temp).FromUtf8(), false, true, true).Substr(0, 45);
654 if (!cleaned.empty())
655 luacon_sim->signs[id].text = cleaned;
656 else
657 luaL_error(l, "Text is empty");
658 return 0;
659 }
660 else if (!key.compare("justification"))
661 {
662 int ju = luaL_checkinteger(l, 3);
663 if (ju >= 0 && ju <= 3)
664 return luacon_sim->signs[id].ju = (sign::Justification)ju, 1;
665 else
666 luaL_error(l, "Invalid justification");
667 return 0;
668 }
669 else if (!key.compare("x"))
670 {
671 int x = luaL_checkinteger(l, 3);
672 if (x >= 0 && x < XRES)
673 return luacon_sim->signs[id].x = x, 1;
674 else
675 luaL_error(l, "Invalid X coordinate");
676 return 0;
677 }
678 else if (!key.compare("y"))
679 {
680 int y = luaL_checkinteger(l, 3);
681 if (y >= 0 && y < YRES)
682 return luacon_sim->signs[id].y = y, 1;
683 else
684 luaL_error(l, "Invalid Y coordinate");
685 return 0;
686 }
687 else if (!key.compare("displayText") || !key.compare("screenX") || !key.compare("screenY") || !key.compare("width") || !key.compare("height"))
688 {
689 luaL_error(l, "That property can't be directly set");
690 }
691 return 0;
692 }
693
694 // Creates a new sign at the first open index
simulation_newsign(lua_State * l)695 int LuaScriptInterface::simulation_newsign(lua_State *l)
696 {
697 if (luacon_sim->signs.size() >= MAXSIGNS)
698 return lua_pushnil(l), 1;
699
700 String text = format::CleanString(ByteString(luaL_checkstring(l, 1)).FromUtf8(), false, true, true).Substr(0, 45);
701 int x = luaL_checkinteger(l, 2);
702 int y = luaL_checkinteger(l, 3);
703 int ju = luaL_optinteger(l, 4, 1);
704 if (ju < 0 || ju > 3)
705 return luaL_error(l, "Invalid justification");
706 if (x < 0 || x >= XRES)
707 return luaL_error(l, "Invalid X coordinate");
708 if (y < 0 || y >= YRES)
709 return luaL_error(l, "Invalid Y coordinate");
710
711 luacon_sim->signs.push_back(sign(text, x, y, (sign::Justification)ju));
712
713 lua_pushnumber(l, luacon_sim->signs.size());
714 return 1;
715 }
716
717 // Deletes a sign
simulation_deletesign(lua_State * l)718 int simulation_deletesign(lua_State *l)
719 {
720 int signID = luaL_checkinteger(l, 1);
721 if (signID <= 0 || signID > (int)luacon_sim->signs.size())
722 return luaL_error(l, "Sign doesn't exist");
723
724 luacon_sim->signs.erase(luacon_sim->signs.begin()+signID-1);
725 return 1;
726 }
727
728 //// Begin Simulation API
729
initSimulationAPI()730 void LuaScriptInterface::initSimulationAPI()
731 {
732 //Methods
733 struct luaL_Reg simulationAPIMethods [] = {
734 {"partNeighbours", simulation_partNeighbours},
735 {"partNeighbors", simulation_partNeighbours},
736 {"partChangeType", simulation_partChangeType},
737 {"partCreate", simulation_partCreate},
738 {"partProperty", simulation_partProperty},
739 {"partPosition", simulation_partPosition},
740 {"partID", simulation_partID},
741 {"partKill", simulation_partKill},
742 {"pressure", simulation_pressure},
743 {"ambientHeat", simulation_ambientHeat},
744 {"velocityX", simulation_velocityX},
745 {"velocityY", simulation_velocityY},
746 {"gravMap", simulation_gravMap},
747 {"createParts", simulation_createParts},
748 {"createLine", simulation_createLine},
749 {"createBox", simulation_createBox},
750 {"floodParts", simulation_floodParts},
751 {"createWalls", simulation_createWalls},
752 {"createWallLine", simulation_createWallLine},
753 {"createWallBox", simulation_createWallBox},
754 {"floodWalls", simulation_floodWalls},
755 {"toolBrush", simulation_toolBrush},
756 {"toolLine", simulation_toolLine},
757 {"toolBox", simulation_toolBox},
758 {"decoBrush", simulation_decoBrush},
759 {"decoLine", simulation_decoLine},
760 {"decoBox", simulation_decoBox},
761 {"decoColor", simulation_decoColor},
762 {"decoColour", simulation_decoColor},
763 {"clearSim", simulation_clearSim},
764 {"clearRect", simulation_clearRect},
765 {"resetTemp", simulation_resetTemp},
766 {"resetPressure", simulation_resetPressure},
767 {"saveStamp", simulation_saveStamp},
768 {"loadStamp", simulation_loadStamp},
769 {"deleteStamp", simulation_deleteStamp},
770 {"loadSave", simulation_loadSave},
771 {"reloadSave", simulation_reloadSave},
772 {"getSaveID", simulation_getSaveID},
773 {"adjustCoords", simulation_adjustCoords},
774 {"prettyPowders", simulation_prettyPowders},
775 {"gravityGrid", simulation_gravityGrid},
776 {"edgeMode", simulation_edgeMode},
777 {"gravityMode", simulation_gravityMode},
778 {"airMode", simulation_airMode},
779 {"waterEqualisation", simulation_waterEqualisation},
780 {"waterEqualization", simulation_waterEqualisation},
781 {"ambientAirTemp", simulation_ambientAirTemp},
782 {"elementCount", simulation_elementCount},
783 {"can_move", simulation_canMove},
784 {"brush", simulation_brush},
785 {"parts", simulation_parts},
786 {"pmap", simulation_pmap},
787 {"photons", simulation_photons},
788 {"neighbours", simulation_neighbours},
789 {"neighbors", simulation_neighbours},
790 {"framerender", simulation_framerender},
791 {"gspeed", simulation_gspeed},
792 {"takeSnapshot", simulation_takeSnapshot},
793 {NULL, NULL}
794 };
795 luaL_register(l, "simulation", simulationAPIMethods);
796
797 //Sim shortcut
798 lua_getglobal(l, "simulation");
799 lua_setglobal(l, "sim");
800
801 //Static values
802 SETCONST(l, XRES);
803 SETCONST(l, YRES);
804 SETCONST(l, CELL);
805 SETCONST(l, NT);
806 SETCONST(l, ST);
807 SETCONST(l, ITH);
808 SETCONST(l, ITL);
809 SETCONST(l, IPH);
810 SETCONST(l, IPL);
811 SETCONST(l, PT_NUM);
812 lua_pushinteger(l, 0); lua_setfield(l, -2, "NUM_PARTS");
813 SETCONST(l, R_TEMP);
814 SETCONST(l, MAX_TEMP);
815 SETCONST(l, MIN_TEMP);
816
817 SETCONST(l, TOOL_HEAT);
818 SETCONST(l, TOOL_COOL);
819 SETCONST(l, TOOL_VAC);
820 SETCONST(l, TOOL_AIR);
821 SETCONST(l, TOOL_PGRV);
822 SETCONST(l, TOOL_NGRV);
823 SETCONST(l, TOOL_MIX);
824 SETCONST(l, TOOL_CYCL);
825 lua_pushinteger(l, luacon_sim->tools.size()); lua_setfield(l, -2, "TOOL_WIND");
826 SETCONST(l, DECO_DRAW);
827 SETCONST(l, DECO_CLEAR);
828 SETCONST(l, DECO_ADD);
829 SETCONST(l, DECO_SUBTRACT);
830 SETCONST(l, DECO_MULTIPLY);
831 SETCONST(l, DECO_DIVIDE);
832 SETCONST(l, DECO_SMUDGE);
833
834 SETCONST(l, PMAPBITS);
835 SETCONST(l, PMAPMASK);
836
837 //Declare FIELD_BLAH constants
838 {
839 int particlePropertiesCount = 0;
840 for (auto &prop : Particle::GetProperties())
841 {
842 lua_pushinteger(l, particlePropertiesCount++);
843 lua_setfield(l, -2, ("FIELD_" + prop.Name.ToUpper()).c_str());
844 }
845 }
846
847 lua_newtable(l);
848 for (int i = 1; i <= MAXSIGNS; i++)
849 {
850 lua_newtable(l);
851 lua_pushinteger(l, i); //set "id" to table index
852 lua_setfield(l, -2, "id");
853 lua_newtable(l);
854 lua_pushcfunction(l, simulation_signIndex);
855 lua_setfield(l, -2, "__index");
856 lua_pushcfunction(l, simulation_signNewIndex);
857 lua_setfield(l, -2, "__newindex");
858 lua_setmetatable(l, -2);
859 lua_pushinteger(l, i); //table index
860 lua_insert(l, -2); //swap k and v
861 lua_settable(l, -3); //set metatable to signs[i]
862 }
863 lua_pushcfunction(l, simulation_newsign);
864 lua_setfield(l, -2, "new");
865 lua_pushcfunction(l, simulation_deletesign);
866 lua_setfield(l, -2, "delete");
867 lua_setfield(l, -2, "signs");
868 }
869
set_map(int x,int y,int width,int height,float value,int map)870 void LuaScriptInterface::set_map(int x, int y, int width, int height, float value, int map) // A function so this won't need to be repeated many times later
871 {
872 int nx, ny;
873 if(x > (XRES/CELL)-1)
874 x = (XRES/CELL)-1;
875 if(y > (YRES/CELL)-1)
876 y = (YRES/CELL)-1;
877 if(x+width > (XRES/CELL)-1)
878 width = (XRES/CELL)-x;
879 if(y+height > (YRES/CELL)-1)
880 height = (YRES/CELL)-y;
881 for (nx = x; nx<x+width; nx++)
882 for (ny = y; ny<y+height; ny++)
883 {
884 if (map == 1)
885 luacon_sim->pv[ny][nx] = value;
886 else if (map == 2)
887 luacon_sim->hv[ny][nx] = value;
888 else if (map == 3)
889 luacon_sim->vx[ny][nx] = value;
890 else if (map == 4)
891 luacon_sim->vy[ny][nx] = value;
892 else if (map == 5)
893 luacon_sim->gravmap[ny*XRES/CELL+nx] = value; //gravx/y don't seem to work, but this does. opposite of tpt
894 }
895 }
896
simulation_partNeighbours(lua_State * l)897 int LuaScriptInterface::simulation_partNeighbours(lua_State * l)
898 {
899 lua_newtable(l);
900 int id = 0;
901 int x = lua_tointeger(l, 1), y = lua_tointeger(l, 2), r = lua_tointeger(l, 3), rx, ry, n;
902 if(lua_gettop(l) == 5) // this is one more than the number of arguments because a table has just been pushed onto the stack with lua_newtable(l);
903 {
904 int t = lua_tointeger(l, 4);
905 for (rx = -r; rx <= r; rx++)
906 for (ry = -r; ry <= r; ry++)
907 if (x+rx >= 0 && y+ry >= 0 && x+rx < XRES && y+ry < YRES && (rx || ry))
908 {
909 n = luacon_sim->pmap[y+ry][x+rx];
910 if (!n || TYP(n) != t)
911 n = luacon_sim->photons[y+ry][x+rx];
912 if (n && TYP(n) == t)
913 {
914 lua_pushinteger(l, ID(n));
915 lua_rawseti(l, -2, id++);
916 }
917 }
918
919 }
920 else
921 {
922 for (rx = -r; rx <= r; rx++)
923 for (ry = -r; ry <= r; ry++)
924 if (x+rx >= 0 && y+ry >= 0 && x+rx < XRES && y+ry < YRES && (rx || ry))
925 {
926 n = luacon_sim->pmap[y+ry][x+rx];
927 if (!n)
928 n = luacon_sim->photons[y+ry][x+rx];
929 if (n)
930 {
931 lua_pushinteger(l, ID(n));
932 lua_rawseti(l, -2, id++);
933 }
934 }
935 }
936 return 1;
937 }
938
simulation_partChangeType(lua_State * l)939 int LuaScriptInterface::simulation_partChangeType(lua_State * l)
940 {
941 int partIndex = lua_tointeger(l, 1);
942 if(partIndex < 0 || partIndex >= NPART || !luacon_sim->parts[partIndex].type)
943 return 0;
944 luacon_sim->part_change_type(partIndex, luacon_sim->parts[partIndex].x+0.5f, luacon_sim->parts[partIndex].y+0.5f, lua_tointeger(l, 2));
945 return 0;
946 }
947
simulation_partCreate(lua_State * l)948 int LuaScriptInterface::simulation_partCreate(lua_State * l)
949 {
950 int newID = lua_tointeger(l, 1);
951 if (newID >= NPART || newID < -3)
952 {
953 lua_pushinteger(l, -1);
954 return 1;
955 }
956 if (newID >= 0 && !luacon_sim->parts[newID].type)
957 {
958 lua_pushinteger(l, -1);
959 return 1;
960 }
961 int type = lua_tointeger(l, 4);
962 int v = -1;
963 if (ID(type))
964 {
965 v = ID(type);
966 type = TYP(type);
967 }
968 lua_pushinteger(l, luacon_sim->create_part(newID, lua_tointeger(l, 2), lua_tointeger(l, 3), type, v));
969 return 1;
970 }
971
simulation_partID(lua_State * l)972 int LuaScriptInterface::simulation_partID(lua_State * l)
973 {
974 int x = lua_tointeger(l, 1);
975 int y = lua_tointeger(l, 2);
976
977 if(x < 0 || x >= XRES || y < 0 || y >= YRES)
978 {
979 lua_pushnil(l);
980 return 1;
981 }
982
983 int amalgam = luacon_sim->pmap[y][x];
984 if(!amalgam)
985 amalgam = luacon_sim->photons[y][x];
986 if (!amalgam)
987 lua_pushnil(l);
988 else
989 lua_pushinteger(l, ID(amalgam));
990 return 1;
991 }
992
simulation_partPosition(lua_State * l)993 int LuaScriptInterface::simulation_partPosition(lua_State * l)
994 {
995 int particleID = lua_tointeger(l, 1);
996 int argCount = lua_gettop(l);
997 if(particleID < 0 || particleID >= NPART || !luacon_sim->parts[particleID].type)
998 {
999 if(argCount == 1)
1000 {
1001 lua_pushnil(l);
1002 lua_pushnil(l);
1003 return 2;
1004 } else {
1005 return 0;
1006 }
1007 }
1008
1009 if(argCount == 3)
1010 {
1011 luacon_sim->parts[particleID].x = lua_tonumber(l, 2);
1012 luacon_sim->parts[particleID].y = lua_tonumber(l, 3);
1013 return 0;
1014 }
1015 else
1016 {
1017 lua_pushnumber(l, luacon_sim->parts[particleID].x);
1018 lua_pushnumber(l, luacon_sim->parts[particleID].y);
1019 return 2;
1020 }
1021 }
1022
simulation_partProperty(lua_State * l)1023 int LuaScriptInterface::simulation_partProperty(lua_State * l)
1024 {
1025 int argCount = lua_gettop(l);
1026 int particleID = luaL_checkinteger(l, 1);
1027 StructProperty property;
1028
1029 if(particleID < 0 || particleID >= NPART || !luacon_sim->parts[particleID].type)
1030 {
1031 if(argCount == 3)
1032 {
1033 lua_pushnil(l);
1034 return 1;
1035 } else {
1036 return 0;
1037 }
1038 }
1039
1040 auto &properties = Particle::GetProperties();
1041 auto prop = properties.end();
1042
1043 //Get field
1044 if (lua_type(l, 2) == LUA_TNUMBER)
1045 {
1046 int fieldID = lua_tointeger(l, 2);
1047 if (fieldID < 0 || fieldID >= (int)properties.size())
1048 return luaL_error(l, "Invalid field ID (%d)", fieldID);
1049 prop = properties.begin() + fieldID;
1050 }
1051 else if (lua_type(l, 2) == LUA_TSTRING)
1052 {
1053 ByteString fieldName = lua_tostring(l, 2);
1054 prop = std::find_if(properties.begin(), properties.end(), [&fieldName](StructProperty const &p) {
1055 return p.Name == fieldName;
1056 });
1057 if (prop == properties.end())
1058 return luaL_error(l, "Unknown field (%s)", fieldName.c_str());
1059 }
1060 else
1061 {
1062 return luaL_error(l, "Field ID must be an name (string) or identifier (integer)");
1063 }
1064
1065 //Calculate memory address of property
1066 intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->parts[particleID]) + prop->Offset);
1067
1068 if(argCount == 3)
1069 {
1070 if (prop == properties.begin() + 0) // i.e. it's .type
1071 {
1072 luacon_sim->part_change_type(particleID, luacon_sim->parts[particleID].x+0.5f, luacon_sim->parts[particleID].y+0.5f, luaL_checkinteger(l, 3));
1073 }
1074 else
1075 {
1076 LuaSetProperty(l, *prop, propertyAddress, 3);
1077 }
1078 return 0;
1079 }
1080 else
1081 {
1082 LuaGetProperty(l, *prop, propertyAddress);
1083 return 1;
1084 }
1085 }
1086
simulation_partKill(lua_State * l)1087 int LuaScriptInterface::simulation_partKill(lua_State * l)
1088 {
1089 if(lua_gettop(l)==2)
1090 luacon_sim->delete_part(lua_tointeger(l, 1), lua_tointeger(l, 2));
1091 else
1092 {
1093 int i = lua_tointeger(l, 1);
1094 if (i>=0 && i<NPART)
1095 luacon_sim->kill_part(i);
1096 }
1097 return 0;
1098 }
1099
simulation_pressure(lua_State * l)1100 int LuaScriptInterface::simulation_pressure(lua_State* l)
1101 {
1102 int argCount = lua_gettop(l);
1103 luaL_checktype(l, 1, LUA_TNUMBER);
1104 luaL_checktype(l, 2, LUA_TNUMBER);
1105 int x = lua_tointeger(l, 1);
1106 int y = lua_tointeger(l, 2);
1107 if (x*CELL<0 || y*CELL<0 || x*CELL>=XRES || y*CELL>=YRES)
1108 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
1109
1110 if (argCount == 2)
1111 {
1112 lua_pushnumber(l, luacon_sim->pv[y][x]);
1113 return 1;
1114 }
1115 int width = 1, height = 1;
1116 float value;
1117 luaL_checktype(l, 3, LUA_TNUMBER);
1118 if (argCount == 3)
1119 value = (float)lua_tonumber(l, 3);
1120 else
1121 {
1122 luaL_checktype(l, 4, LUA_TNUMBER);
1123 luaL_checktype(l, 5, LUA_TNUMBER);
1124 width = lua_tointeger(l, 3);
1125 height = lua_tointeger(l, 4);
1126 value = (float)lua_tonumber(l, 5);
1127 }
1128 if(value > 256.0f)
1129 value = 256.0f;
1130 else if(value < -256.0f)
1131 value = -256.0f;
1132
1133 set_map(x, y, width, height, value, 1);
1134 return 0;
1135 }
1136
simulation_ambientHeat(lua_State * l)1137 int LuaScriptInterface::simulation_ambientHeat(lua_State* l)
1138 {
1139 int argCount = lua_gettop(l);
1140 luaL_checktype(l, 1, LUA_TNUMBER);
1141 luaL_checktype(l, 2, LUA_TNUMBER);
1142 int x = lua_tointeger(l, 1);
1143 int y = lua_tointeger(l, 2);
1144 if (x*CELL<0 || y*CELL<0 || x*CELL>=XRES || y*CELL>=YRES)
1145 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
1146
1147 if (argCount == 2)
1148 {
1149 lua_pushnumber(l, luacon_sim->hv[y][x]);
1150 return 1;
1151 }
1152 int width = 1, height = 1;
1153 float value;
1154 luaL_checktype(l, 3, LUA_TNUMBER);
1155 if (argCount == 3)
1156 value = (float)lua_tonumber(l, 3);
1157 else
1158 {
1159 luaL_checktype(l, 4, LUA_TNUMBER);
1160 luaL_checktype(l, 5, LUA_TNUMBER);
1161 width = lua_tointeger(l, 3);
1162 height = lua_tointeger(l, 4);
1163 value = (float)lua_tonumber(l, 5);
1164 }
1165 if(value > MAX_TEMP)
1166 value = MAX_TEMP;
1167 else if(value < MIN_TEMP)
1168 value = MIN_TEMP;
1169
1170 set_map(x, y, width, height, value, 2);
1171 return 0;
1172 }
1173
simulation_velocityX(lua_State * l)1174 int LuaScriptInterface::simulation_velocityX(lua_State* l)
1175 {
1176 int argCount = lua_gettop(l);
1177 luaL_checktype(l, 1, LUA_TNUMBER);
1178 luaL_checktype(l, 2, LUA_TNUMBER);
1179 int x = lua_tointeger(l, 1);
1180 int y = lua_tointeger(l, 2);
1181 if (x*CELL<0 || y*CELL<0 || x*CELL>=XRES || y*CELL>=YRES)
1182 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
1183
1184 if (argCount == 2)
1185 {
1186 lua_pushnumber(l, luacon_sim->vx[y][x]);
1187 return 1;
1188 }
1189 int width = 1, height = 1;
1190 float value;
1191 luaL_checktype(l, 3, LUA_TNUMBER);
1192 if (argCount == 3)
1193 value = (float)lua_tonumber(l, 3);
1194 else
1195 {
1196 luaL_checktype(l, 4, LUA_TNUMBER);
1197 luaL_checktype(l, 5, LUA_TNUMBER);
1198 width = lua_tointeger(l, 3);
1199 height = lua_tointeger(l, 4);
1200 value = (float)lua_tonumber(l, 5);
1201 }
1202 if(value > 256.0f)
1203 value = 256.0f;
1204 else if(value < -256.0f)
1205 value = -256.0f;
1206
1207 set_map(x, y, width, height, value, 3);
1208 return 0;
1209 }
1210
simulation_velocityY(lua_State * l)1211 int LuaScriptInterface::simulation_velocityY(lua_State* l)
1212 {
1213 int argCount = lua_gettop(l);
1214 luaL_checktype(l, 1, LUA_TNUMBER);
1215 luaL_checktype(l, 2, LUA_TNUMBER);
1216 int x = lua_tointeger(l, 1);
1217 int y = lua_tointeger(l, 2);
1218 if (x*CELL<0 || y*CELL<0 || x*CELL>=XRES || y*CELL>=YRES)
1219 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
1220
1221 if (argCount == 2)
1222 {
1223 lua_pushnumber(l, luacon_sim->vy[y][x]);
1224 return 1;
1225 }
1226 int width = 1, height = 1;
1227 float value;
1228 luaL_checktype(l, 3, LUA_TNUMBER);
1229 if (argCount == 3)
1230 value = (float)lua_tonumber(l, 3);
1231 else
1232 {
1233 luaL_checktype(l, 4, LUA_TNUMBER);
1234 luaL_checktype(l, 5, LUA_TNUMBER);
1235 width = lua_tointeger(l, 3);
1236 height = lua_tointeger(l, 4);
1237 value = (float)lua_tonumber(l, 5);
1238 }
1239 if(value > 256.0f)
1240 value = 256.0f;
1241 else if(value < -256.0f)
1242 value = -256.0f;
1243
1244 set_map(x, y, width, height, value, 4);
1245 return 0;
1246 }
1247
simulation_gravMap(lua_State * l)1248 int LuaScriptInterface::simulation_gravMap(lua_State* l)
1249 {
1250 int argCount = lua_gettop(l);
1251 luaL_checktype(l, 1, LUA_TNUMBER);
1252 luaL_checktype(l, 2, LUA_TNUMBER);
1253 int x = lua_tointeger(l, 1);
1254 int y = lua_tointeger(l, 2);
1255 if (x*CELL<0 || y*CELL<0 || x*CELL>=XRES || y*CELL>=YRES)
1256 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
1257
1258 if (argCount == 2)
1259 {
1260 lua_pushnumber(l, luacon_sim->gravp[y*XRES/CELL+x]);
1261 return 1;
1262 }
1263 int width = 1, height = 1;
1264 float value;
1265 luaL_checktype(l, 3, LUA_TNUMBER);
1266 if (argCount == 3)
1267 value = (float)lua_tonumber(l, 3);
1268 else
1269 {
1270 luaL_checktype(l, 4, LUA_TNUMBER);
1271 luaL_checktype(l, 5, LUA_TNUMBER);
1272 width = lua_tointeger(l, 3);
1273 height = lua_tointeger(l, 4);
1274 value = (float)lua_tonumber(l, 5);
1275 }
1276
1277 set_map(x, y, width, height, value, 5);
1278 return 0;
1279 }
1280
simulation_createParts(lua_State * l)1281 int LuaScriptInterface::simulation_createParts(lua_State * l)
1282 {
1283 int x = luaL_optint(l,1,-1);
1284 int y = luaL_optint(l,2,-1);
1285 int rx = luaL_optint(l,3,5);
1286 int ry = luaL_optint(l,4,5);
1287 int c = luaL_optint(l,5,luacon_model->GetActiveTool(0)->GetToolID());
1288 int brush = luaL_optint(l,6,CIRCLE_BRUSH);
1289 int flags = luaL_optint(l,7,luacon_sim->replaceModeFlags);
1290
1291 std::vector<Brush*> brushList = luacon_model->GetBrushList();
1292 if (brush < 0 || brush >= (int)brushList.size())
1293 return luaL_error(l, "Invalid brush id '%d'", brush);
1294 ui::Point tempRadius = brushList[brush]->GetRadius();
1295 brushList[brush]->SetRadius(ui::Point(rx, ry));
1296
1297 int ret = luacon_sim->CreateParts(x, y, c, brushList[brush], flags);
1298 brushList[brush]->SetRadius(tempRadius);
1299 lua_pushinteger(l, ret);
1300 return 1;
1301 }
1302
simulation_createLine(lua_State * l)1303 int LuaScriptInterface::simulation_createLine(lua_State * l)
1304 {
1305 int x1 = luaL_optint(l,1,-1);
1306 int y1 = luaL_optint(l,2,-1);
1307 int x2 = luaL_optint(l,3,-1);
1308 int y2 = luaL_optint(l,4,-1);
1309 int rx = luaL_optint(l,5,5);
1310 int ry = luaL_optint(l,6,5);
1311 int c = luaL_optint(l,7,luacon_model->GetActiveTool(0)->GetToolID());
1312 int brush = luaL_optint(l,8,CIRCLE_BRUSH);
1313 int flags = luaL_optint(l,9,luacon_sim->replaceModeFlags);
1314
1315 std::vector<Brush*> brushList = luacon_model->GetBrushList();
1316 if (brush < 0 || brush >= (int)brushList.size())
1317 return luaL_error(l, "Invalid brush id '%d'", brush);
1318 ui::Point tempRadius = brushList[brush]->GetRadius();
1319 brushList[brush]->SetRadius(ui::Point(rx, ry));
1320
1321 luacon_sim->CreateLine(x1, y1, x2, y2, c, brushList[brush], flags);
1322 brushList[brush]->SetRadius(tempRadius);
1323 return 0;
1324 }
1325
simulation_createBox(lua_State * l)1326 int LuaScriptInterface::simulation_createBox(lua_State * l)
1327 {
1328 int x1 = luaL_optint(l,1,-1);
1329 int y1 = luaL_optint(l,2,-1);
1330 int x2 = luaL_optint(l,3,-1);
1331 int y2 = luaL_optint(l,4,-1);
1332 int c = luaL_optint(l,5,luacon_model->GetActiveTool(0)->GetToolID());
1333 int flags = luaL_optint(l,6,luacon_sim->replaceModeFlags);
1334
1335 luacon_sim->CreateBox(x1, y1, x2, y2, c, flags);
1336 return 0;
1337 }
1338
simulation_floodParts(lua_State * l)1339 int LuaScriptInterface::simulation_floodParts(lua_State * l)
1340 {
1341 int x = luaL_optint(l,1,-1);
1342 int y = luaL_optint(l,2,-1);
1343 int c = luaL_optint(l,3,luacon_model->GetActiveTool(0)->GetToolID());
1344 int cm = luaL_optint(l,4,-1);
1345 int flags = luaL_optint(l,5,luacon_sim->replaceModeFlags);
1346 int ret = luacon_sim->FloodParts(x, y, c, cm, flags);
1347 lua_pushinteger(l, ret);
1348 return 1;
1349 }
1350
simulation_createWalls(lua_State * l)1351 int LuaScriptInterface::simulation_createWalls(lua_State * l)
1352 {
1353 int x = luaL_optint(l,1,-1);
1354 int y = luaL_optint(l,2,-1);
1355 int rx = luaL_optint(l,3,0);
1356 int ry = luaL_optint(l,4,0);
1357 int c = luaL_optint(l,5,8);
1358 if (c < 0 || c >= UI_WALLCOUNT)
1359 return luaL_error(l, "Unrecognised wall id '%d'", c);
1360
1361 int ret = luacon_sim->CreateWalls(x, y, rx, ry, c, NULL);
1362 lua_pushinteger(l, ret);
1363 return 1;
1364 }
1365
simulation_createWallLine(lua_State * l)1366 int LuaScriptInterface::simulation_createWallLine(lua_State * l)
1367 {
1368 int x1 = luaL_optint(l,1,-1);
1369 int y1 = luaL_optint(l,2,-1);
1370 int x2 = luaL_optint(l,3,-1);
1371 int y2 = luaL_optint(l,4,-1);
1372 int rx = luaL_optint(l,5,0);
1373 int ry = luaL_optint(l,6,0);
1374 int c = luaL_optint(l,7,8);
1375 if (c < 0 || c >= UI_WALLCOUNT)
1376 return luaL_error(l, "Unrecognised wall id '%d'", c);
1377
1378 luacon_sim->CreateWallLine(x1, y1, x2, y2, rx, ry, c, NULL);
1379 return 0;
1380 }
1381
simulation_createWallBox(lua_State * l)1382 int LuaScriptInterface::simulation_createWallBox(lua_State * l)
1383 {
1384 int x1 = luaL_optint(l,1,-1);
1385 int y1 = luaL_optint(l,2,-1);
1386 int x2 = luaL_optint(l,3,-1);
1387 int y2 = luaL_optint(l,4,-1);
1388 int c = luaL_optint(l,5,8);
1389 if (c < 0 || c >= UI_WALLCOUNT)
1390 return luaL_error(l, "Unrecognised wall id '%d'", c);
1391
1392 luacon_sim->CreateWallBox(x1, y1, x2, y2, c);
1393 return 0;
1394 }
1395
simulation_floodWalls(lua_State * l)1396 int LuaScriptInterface::simulation_floodWalls(lua_State * l)
1397 {
1398 int x = luaL_optint(l,1,-1);
1399 int y = luaL_optint(l,2,-1);
1400 int c = luaL_optint(l,3,8);
1401 int bm = luaL_optint(l,4,-1);
1402 if (c < 0 || c >= UI_WALLCOUNT)
1403 return luaL_error(l, "Unrecognised wall id '%d'", c);
1404 if (c == WL_STREAM)
1405 {
1406 lua_pushinteger(l, 0);
1407 return 1;
1408 }
1409 int ret = luacon_sim->FloodWalls(x, y, c, bm);
1410 lua_pushinteger(l, ret);
1411 return 1;
1412 }
1413
simulation_toolBrush(lua_State * l)1414 int LuaScriptInterface::simulation_toolBrush(lua_State * l)
1415 {
1416 int x = luaL_optint(l,1,-1);
1417 int y = luaL_optint(l,2,-1);
1418 int rx = luaL_optint(l,3,5);
1419 int ry = luaL_optint(l,4,5);
1420 int tool = luaL_optint(l,5,0);
1421 int brush = luaL_optint(l,6,CIRCLE_BRUSH);
1422 float strength = luaL_optnumber(l,7,1.0f);
1423 if (tool == (int)luacon_sim->tools.size())
1424 {
1425 lua_pushinteger(l, 0);
1426 return 1;
1427 }
1428 else if (tool < 0 || tool > (int)luacon_sim->tools.size())
1429 return luaL_error(l, "Invalid tool id '%d'", tool);
1430
1431 std::vector<Brush*> brushList = luacon_model->GetBrushList();
1432 if (brush < 0 || brush >= (int)brushList.size())
1433 return luaL_error(l, "Invalid brush id '%d'", brush);
1434 ui::Point tempRadius = brushList[brush]->GetRadius();
1435 brushList[brush]->SetRadius(ui::Point(rx, ry));
1436
1437 int ret = luacon_sim->ToolBrush(x, y, tool, brushList[brush], strength);
1438 brushList[brush]->SetRadius(tempRadius);
1439 lua_pushinteger(l, ret);
1440 return 1;
1441 }
1442
simulation_toolLine(lua_State * l)1443 int LuaScriptInterface::simulation_toolLine(lua_State * l)
1444 {
1445 int x1 = luaL_optint(l,1,-1);
1446 int y1 = luaL_optint(l,2,-1);
1447 int x2 = luaL_optint(l,3,-1);
1448 int y2 = luaL_optint(l,4,-1);
1449 int rx = luaL_optint(l,5,5);
1450 int ry = luaL_optint(l,6,5);
1451 int tool = luaL_optint(l,7,0);
1452 int brush = luaL_optint(l,8,CIRCLE_BRUSH);
1453 float strength = luaL_optnumber(l,9,1.0f);
1454 if (tool < 0 || tool >= (int)luacon_sim->tools.size()+1)
1455 return luaL_error(l, "Invalid tool id '%d'", tool);
1456
1457 std::vector<Brush*> brushList = luacon_model->GetBrushList();
1458 if (brush < 0 || brush >= (int)brushList.size())
1459 return luaL_error(l, "Invalid brush id '%d'", brush);
1460 ui::Point tempRadius = brushList[brush]->GetRadius();
1461 brushList[brush]->SetRadius(ui::Point(rx, ry));
1462
1463 if (tool == (int)luacon_sim->tools.size())
1464 {
1465 Tool *windTool = luacon_model->GetToolFromIdentifier("DEFAULT_UI_WIND");
1466 float oldStrength = windTool->GetStrength();
1467 windTool->SetStrength(strength);
1468 windTool->DrawLine(luacon_sim, brushList[brush], ui::Point(x1, y1), ui::Point(x2, y2));
1469 windTool->SetStrength(oldStrength);
1470 }
1471 else
1472 luacon_sim->ToolLine(x1, y1, x2, y2, tool, brushList[brush], strength);
1473 brushList[brush]->SetRadius(tempRadius);
1474 return 0;
1475 }
1476
simulation_toolBox(lua_State * l)1477 int LuaScriptInterface::simulation_toolBox(lua_State * l)
1478 {
1479 int x1 = luaL_optint(l,1,-1);
1480 int y1 = luaL_optint(l,2,-1);
1481 int x2 = luaL_optint(l,3,-1);
1482 int y2 = luaL_optint(l,4,-1);
1483 int tool = luaL_optint(l,5,0);
1484 float strength = luaL_optnumber(l,6,1.0f);
1485 if (tool == (int)luacon_sim->tools.size())
1486 {
1487 lua_pushinteger(l, 0);
1488 return 1;
1489 }
1490 else if (tool < 0 || tool >= (int)luacon_sim->tools.size())
1491 return luaL_error(l, "Invalid tool id '%d'", tool);
1492
1493 luacon_sim->ToolBox(x1, y1, x2, y2, tool, strength);
1494 return 0;
1495 }
1496
simulation_decoBrush(lua_State * l)1497 int LuaScriptInterface::simulation_decoBrush(lua_State * l)
1498 {
1499 int x = luaL_optint(l,1,-1);
1500 int y = luaL_optint(l,2,-1);
1501 int rx = luaL_optint(l,3,5);
1502 int ry = luaL_optint(l,4,5);
1503 int r = luaL_optint(l,5,255);
1504 int g = luaL_optint(l,6,255);
1505 int b = luaL_optint(l,7,255);
1506 int a = luaL_optint(l,8,255);
1507 int tool = luaL_optint(l,9,DECO_DRAW);
1508 int brush = luaL_optint(l,10,CIRCLE_BRUSH);
1509
1510 std::vector<Brush*> brushList = luacon_model->GetBrushList();
1511 if (brush < 0 || brush >= (int)brushList.size())
1512 return luaL_error(l, "Invalid brush id '%d'", brush);
1513 ui::Point tempRadius = brushList[brush]->GetRadius();
1514 brushList[brush]->SetRadius(ui::Point(rx, ry));
1515
1516 luacon_sim->ApplyDecorationPoint(x, y, r, g, b, a, tool, brushList[brush]);
1517 brushList[brush]->SetRadius(tempRadius);
1518 return 0;
1519 }
1520
simulation_decoLine(lua_State * l)1521 int LuaScriptInterface::simulation_decoLine(lua_State * l)
1522 {
1523 int x1 = luaL_optint(l,1,-1);
1524 int y1 = luaL_optint(l,2,-1);
1525 int x2 = luaL_optint(l,3,-1);
1526 int y2 = luaL_optint(l,4,-1);
1527 int rx = luaL_optint(l,5,5);
1528 int ry = luaL_optint(l,6,5);
1529 int r = luaL_optint(l,7,255);
1530 int g = luaL_optint(l,8,255);
1531 int b = luaL_optint(l,9,255);
1532 int a = luaL_optint(l,10,255);
1533 int tool = luaL_optint(l,11,DECO_DRAW);
1534 int brush = luaL_optint(l,12,CIRCLE_BRUSH);
1535
1536 std::vector<Brush*> brushList = luacon_model->GetBrushList();
1537 if (brush < 0 || brush >= (int)brushList.size())
1538 return luaL_error(l, "Invalid brush id '%d'", brush);
1539 ui::Point tempRadius = brushList[brush]->GetRadius();
1540 brushList[brush]->SetRadius(ui::Point(rx, ry));
1541
1542 luacon_sim->ApplyDecorationLine(x1, y1, x2, y2, r, g, b, a, tool, brushList[brush]);
1543 brushList[brush]->SetRadius(tempRadius);
1544 return 0;
1545 }
1546
simulation_decoBox(lua_State * l)1547 int LuaScriptInterface::simulation_decoBox(lua_State * l)
1548 {
1549 int x1 = luaL_optint(l,1,-1);
1550 int y1 = luaL_optint(l,2,-1);
1551 int x2 = luaL_optint(l,3,-1);
1552 int y2 = luaL_optint(l,4,-1);
1553 int r = luaL_optint(l,5,255);
1554 int g = luaL_optint(l,6,255);
1555 int b = luaL_optint(l,7,255);
1556 int a = luaL_optint(l,8,255);
1557 int tool = luaL_optint(l,9,0);
1558
1559 luacon_sim->ApplyDecorationBox(x1, y1, x2, y2, r, g, b, a, tool);
1560 return 0;
1561 }
1562
simulation_decoColor(lua_State * l)1563 int LuaScriptInterface::simulation_decoColor(lua_State * l)
1564 {
1565 int acount = lua_gettop(l);
1566 unsigned int color;
1567 if (acount == 0)
1568 {
1569 ui::Colour tempColor = luacon_model->GetColourSelectorColour();
1570 unsigned int color = (tempColor.Alpha << 24) | PIXRGB(tempColor.Red, tempColor.Green, tempColor.Blue);
1571 lua_pushnumber(l, color);
1572 return 1;
1573 }
1574 else if (acount == 1)
1575 color = (unsigned int)luaL_optnumber(l, 1, 0xFFFF0000);
1576 else
1577 {
1578 int r, g, b, a;
1579 r = luaL_optint(l, 1, 255);
1580 g = luaL_optint(l, 2, 255);
1581 b = luaL_optint(l, 3, 255);
1582 a = luaL_optint(l, 4, 255);
1583
1584 if (r < 0) r = 0;
1585 if (r > 255) r = 255;
1586 if (g < 0) g = 0;
1587 if (g > 255) g = 255;
1588 if (b < 0) b = 0;
1589 if (b > 255) b = 255;
1590 if (a < 0) a = 0;
1591 if (a > 255) a = 255;
1592
1593 color = (a << 24) + PIXRGB(r, g, b);
1594 }
1595 luacon_model->SetColourSelectorColour(ui::Colour(PIXR(color), PIXG(color), PIXB(color), color >> 24));
1596 return 0;
1597 }
1598
simulation_clearSim(lua_State * l)1599 int LuaScriptInterface::simulation_clearSim(lua_State * l)
1600 {
1601 luacon_sim->clear_sim();
1602 Client::Ref().ClearAuthorInfo();
1603 return 0;
1604 }
1605
simulation_clearRect(lua_State * l)1606 int LuaScriptInterface::simulation_clearRect(lua_State * l)
1607 {
1608 int x = luaL_checkint(l,1);
1609 int y = luaL_checkint(l,2);
1610 int w = luaL_checkint(l,3)-1;
1611 int h = luaL_checkint(l,4)-1;
1612 luacon_sim->clear_area(x, y, w, h);
1613 return 0;
1614 }
1615
simulation_resetTemp(lua_State * l)1616 int LuaScriptInterface::simulation_resetTemp(lua_State * l)
1617 {
1618 bool onlyConductors = luaL_optint(l, 1, 0);
1619 for (int i = 0; i < luacon_sim->parts_lastActiveIndex; i++)
1620 {
1621 if (luacon_sim->parts[i].type && (luacon_sim->elements[luacon_sim->parts[i].type].HeatConduct || !onlyConductors))
1622 {
1623 luacon_sim->parts[i].temp = luacon_sim->elements[luacon_sim->parts[i].type].DefaultProperties.temp;
1624 }
1625 }
1626 return 0;
1627 }
1628
simulation_resetPressure(lua_State * l)1629 int LuaScriptInterface::simulation_resetPressure(lua_State * l)
1630 {
1631 int aCount = lua_gettop(l), width = XRES/CELL, height = YRES/CELL;
1632 int x1 = abs(luaL_optint(l, 1, 0));
1633 int y1 = abs(luaL_optint(l, 2, 0));
1634 if (aCount > 2)
1635 {
1636 width = abs(luaL_optint(l, 3, XRES/CELL));
1637 height = abs(luaL_optint(l, 4, YRES/CELL));
1638 }
1639 else if (aCount)
1640 {
1641 width = 1;
1642 height = 1;
1643 }
1644 if(x1 > (XRES/CELL)-1)
1645 x1 = (XRES/CELL)-1;
1646 if(y1 > (YRES/CELL)-1)
1647 y1 = (YRES/CELL)-1;
1648 if(x1+width > (XRES/CELL)-1)
1649 width = (XRES/CELL)-x1;
1650 if(y1+height > (YRES/CELL)-1)
1651 height = (YRES/CELL)-y1;
1652 for (int nx = x1; nx<x1+width; nx++)
1653 for (int ny = y1; ny<y1+height; ny++)
1654 {
1655 luacon_sim->air->pv[ny][nx] = 0;
1656 }
1657 return 0;
1658 }
1659
simulation_saveStamp(lua_State * l)1660 int LuaScriptInterface::simulation_saveStamp(lua_State * l)
1661 {
1662 int x = luaL_optint(l,1,0);
1663 int y = luaL_optint(l,2,0);
1664 int w = luaL_optint(l,3,XRES-1);
1665 int h = luaL_optint(l,4,YRES-1);
1666 ByteString name = luacon_controller->StampRegion(ui::Point(x, y), ui::Point(x+w, y+h));
1667 lua_pushstring(l, name.c_str());
1668 return 1;
1669 }
1670
simulation_loadStamp(lua_State * l)1671 int LuaScriptInterface::simulation_loadStamp(lua_State * l)
1672 {
1673 int i = -1;
1674 SaveFile * tempfile = NULL;
1675 int x = luaL_optint(l,2,0);
1676 int y = luaL_optint(l,3,0);
1677 if (lua_isstring(l, 1)) //Load from 10 char name, or full filename
1678 {
1679 const char * filename = luaL_optstring(l, 1, "");
1680 tempfile = Client::Ref().GetStamp(filename);
1681 }
1682 if ((!tempfile || !tempfile->GetGameSave()) && lua_isnumber(l, 1)) //Load from stamp ID
1683 {
1684 i = luaL_optint(l, 1, 0);
1685 int stampCount = Client::Ref().GetStampsCount();
1686 if (i < 0 || i >= stampCount)
1687 return luaL_error(l, "Invalid stamp ID: %d", i);
1688 tempfile = Client::Ref().GetStamp(Client::Ref().GetStamps(0, stampCount)[i]);
1689 }
1690
1691 if (tempfile)
1692 {
1693 if (!luacon_sim->Load(tempfile->GetGameSave(), !luacon_controller->GetView()->ShiftBehaviour(), x, y))
1694 {
1695 //luacon_sim->sys_pause = (tempfile->GetGameSave()->paused | luacon_model->GetPaused())?1:0;
1696 lua_pushinteger(l, 1);
1697
1698 if (tempfile->GetGameSave()->authors.size())
1699 {
1700 tempfile->GetGameSave()->authors["type"] = "luastamp";
1701 Client::Ref().MergeStampAuthorInfo(tempfile->GetGameSave()->authors);
1702 }
1703 }
1704 else
1705 lua_pushnil(l);
1706 delete tempfile;
1707 }
1708 else
1709 lua_pushnil(l);
1710 return 1;
1711 }
1712
simulation_deleteStamp(lua_State * l)1713 int LuaScriptInterface::simulation_deleteStamp(lua_State * l)
1714 {
1715 int stampCount = Client::Ref().GetStampsCount();
1716 std::vector<ByteString> stamps = Client::Ref().GetStamps(0, stampCount);
1717
1718 if (lua_isstring(l, 1)) //note: lua_isstring returns true on numbers too
1719 {
1720 const char * filename = luaL_optstring(l, 1, "");
1721 for (std::vector<ByteString>::const_iterator iterator = stamps.begin(), end = stamps.end(); iterator != end; ++iterator)
1722 {
1723 if (*iterator == filename)
1724 {
1725 Client::Ref().DeleteStamp(*iterator);
1726 return 0;
1727 }
1728 }
1729 }
1730 if (lua_isnumber(l, 1)) //Load from stamp ID
1731 {
1732 int i = luaL_optint(l, 1, 0);
1733 if (i < 0 || i >= stampCount)
1734 return luaL_error(l, "Invalid stamp ID: %d", i);
1735 Client::Ref().DeleteStamp(stamps[i]);
1736 return 0;
1737 }
1738 lua_pushnumber(l, -1);
1739 return 1;
1740 }
1741
simulation_loadSave(lua_State * l)1742 int LuaScriptInterface::simulation_loadSave(lua_State * l)
1743 {
1744 int saveID = luaL_optint(l,1,0);
1745 int instant = luaL_optint(l,2,0);
1746 int history = luaL_optint(l,3,0); //Exact second a previous save was saved
1747 luacon_controller->OpenSavePreview(saveID, history, instant?true:false);
1748 return 0;
1749 }
1750
simulation_reloadSave(lua_State * l)1751 int LuaScriptInterface::simulation_reloadSave(lua_State * l)
1752 {
1753 luacon_controller->ReloadSim();
1754 return 0;
1755 }
1756
simulation_getSaveID(lua_State * l)1757 int LuaScriptInterface::simulation_getSaveID(lua_State *l)
1758 {
1759 SaveInfo *tempSave = luacon_model->GetSave();
1760 if (tempSave)
1761 {
1762 lua_pushinteger(l, tempSave->GetID());
1763 return 1;
1764 }
1765 return 0;
1766 }
1767
simulation_adjustCoords(lua_State * l)1768 int LuaScriptInterface::simulation_adjustCoords(lua_State * l)
1769 {
1770 int x = luaL_optint(l,1,0);
1771 int y = luaL_optint(l,2,0);
1772 ui::Point Coords = luacon_controller->PointTranslate(ui::Point(x, y));
1773 lua_pushinteger(l, Coords.X);
1774 lua_pushinteger(l, Coords.Y);
1775 return 2;
1776 }
1777
simulation_prettyPowders(lua_State * l)1778 int LuaScriptInterface::simulation_prettyPowders(lua_State * l)
1779 {
1780 int acount = lua_gettop(l);
1781 if (acount == 0)
1782 {
1783 lua_pushnumber(l, luacon_sim->pretty_powder);
1784 return 1;
1785 }
1786 int prettyPowder = luaL_optint(l, 1, 0);
1787 luacon_sim->pretty_powder = prettyPowder;
1788 luacon_model->UpdateQuickOptions();
1789 return 0;
1790 }
1791
simulation_gravityGrid(lua_State * l)1792 int LuaScriptInterface::simulation_gravityGrid(lua_State * l)
1793 {
1794 int acount = lua_gettop(l);
1795 if (acount == 0)
1796 {
1797 lua_pushnumber(l, luacon_model->GetGravityGrid());
1798 return 1;
1799 }
1800 int gravityGrid = luaL_optint(l, 1, 0);
1801 luacon_model->ShowGravityGrid(gravityGrid);
1802 luacon_model->UpdateQuickOptions();
1803 return 0;
1804 }
1805
simulation_edgeMode(lua_State * l)1806 int LuaScriptInterface::simulation_edgeMode(lua_State * l)
1807 {
1808 int acount = lua_gettop(l);
1809 if (acount == 0)
1810 {
1811 lua_pushnumber(l, luacon_model->GetEdgeMode());
1812 return 1;
1813 }
1814 int edgeMode = luaL_optint(l, 1, 0);
1815 luacon_model->SetEdgeMode(edgeMode);
1816 return 0;
1817 }
1818
simulation_gravityMode(lua_State * l)1819 int LuaScriptInterface::simulation_gravityMode(lua_State * l)
1820 {
1821 int acount = lua_gettop(l);
1822 if (acount == 0)
1823 {
1824 lua_pushnumber(l, luacon_sim->gravityMode);
1825 return 1;
1826 }
1827 int gravityMode = luaL_optint(l, 1, 0);
1828 luacon_sim->gravityMode = gravityMode;
1829 return 0;
1830 }
1831
simulation_airMode(lua_State * l)1832 int LuaScriptInterface::simulation_airMode(lua_State * l)
1833 {
1834 int acount = lua_gettop(l);
1835 if (acount == 0)
1836 {
1837 lua_pushnumber(l, luacon_sim->air->airMode);
1838 return 1;
1839 }
1840 int airMode = luaL_optint(l, 1, 0);
1841 luacon_sim->air->airMode = airMode;
1842 return 0;
1843 }
1844
simulation_waterEqualisation(lua_State * l)1845 int LuaScriptInterface::simulation_waterEqualisation(lua_State * l)
1846 {
1847 int acount = lua_gettop(l);
1848 if (acount == 0)
1849 {
1850 lua_pushnumber(l, luacon_sim->water_equal_test);
1851 return 1;
1852 }
1853 int waterMode = luaL_optint(l, 1, 0);
1854 luacon_sim->water_equal_test = waterMode;
1855 return 0;
1856 }
1857
simulation_ambientAirTemp(lua_State * l)1858 int LuaScriptInterface::simulation_ambientAirTemp(lua_State * l)
1859 {
1860 int acount = lua_gettop(l);
1861 if (acount == 0)
1862 {
1863 lua_pushnumber(l, luacon_sim->air->ambientAirTemp);
1864 return 1;
1865 }
1866 float ambientAirTemp = luaL_optnumber(l, 1, 295.15f);
1867 luacon_sim->air->ambientAirTemp = ambientAirTemp;
1868 return 0;
1869 }
1870
simulation_elementCount(lua_State * l)1871 int LuaScriptInterface::simulation_elementCount(lua_State * l)
1872 {
1873 int element = luaL_optint(l, 1, 0);
1874 if (element < 0 || element >= PT_NUM)
1875 return luaL_error(l, "Invalid element ID (%d)", element);
1876
1877 lua_pushnumber(l, luacon_sim->elementCount[element]);
1878 return 1;
1879 }
1880
simulation_canMove(lua_State * l)1881 int LuaScriptInterface::simulation_canMove(lua_State * l)
1882 {
1883 int movingElement = luaL_checkint(l, 1);
1884 int destinationElement = luaL_checkint(l, 2);
1885 if (movingElement < 0 || movingElement >= PT_NUM)
1886 return luaL_error(l, "Invalid element ID (%d)", movingElement);
1887 if (destinationElement < 0 || destinationElement >= PT_NUM)
1888 return luaL_error(l, "Invalid element ID (%d)", destinationElement);
1889
1890 if (lua_gettop(l) < 3)
1891 {
1892 lua_pushnumber(l, luacon_sim->can_move[movingElement][destinationElement]);
1893 return 1;
1894 }
1895 else
1896 {
1897 luacon_sim->can_move[movingElement][destinationElement] = luaL_checkint(l, 3);
1898 return 0;
1899 }
1900 }
1901
BrushClosure(lua_State * l)1902 int BrushClosure(lua_State * l)
1903 {
1904 // see Simulation::ToolBrush
1905 int positionX = lua_tointeger(l, lua_upvalueindex(1));
1906 int positionY = lua_tointeger(l, lua_upvalueindex(2));
1907 int radiusX = lua_tointeger(l, lua_upvalueindex(3));
1908 int radiusY = lua_tointeger(l, lua_upvalueindex(4));
1909 int sizeX = lua_tointeger(l, lua_upvalueindex(5));
1910 int sizeY = lua_tointeger(l, lua_upvalueindex(6));
1911 int x = lua_tointeger(l, lua_upvalueindex(7));
1912 int y = lua_tointeger(l, lua_upvalueindex(8));
1913 unsigned char *bitmap = (unsigned char *)lua_touserdata(l, lua_upvalueindex(9));
1914
1915
1916 int yield_x, yield_y;
1917 while (true)
1918 {
1919 if (!(y < sizeY))
1920 return 0;
1921 if (x < sizeX)
1922 {
1923 bool yield_coords = false;
1924 if (bitmap[(y*sizeX)+x] && (positionX+(x-radiusX) >= 0 && positionY+(y-radiusY) >= 0 && positionX+(x-radiusX) < XRES && positionY+(y-radiusY) < YRES))
1925 {
1926 yield_coords = true;
1927 yield_x = positionX+(x-radiusX);
1928 yield_y = positionY+(y-radiusY);
1929 }
1930 x++;
1931 if (yield_coords)
1932 break;
1933 }
1934 else
1935 {
1936 x = 0;
1937 y++;
1938 }
1939 }
1940
1941 lua_pushnumber(l, x);
1942 lua_replace(l, lua_upvalueindex(7));
1943 lua_pushnumber(l, y);
1944 lua_replace(l, lua_upvalueindex(8));
1945
1946 lua_pushnumber(l, yield_x);
1947 lua_pushnumber(l, yield_y);
1948 return 2;
1949 }
1950
simulation_brush(lua_State * l)1951 int LuaScriptInterface::simulation_brush(lua_State * l)
1952 {
1953 int argCount = lua_gettop(l);
1954 int positionX = luaL_checkint(l, 1);
1955 int positionY = luaL_checkint(l, 2);
1956 int brushradiusX, brushradiusY;
1957 if (argCount >= 4 || !luacon_model->GetBrush())
1958 {
1959 brushradiusX = luaL_checkint(l, 3);
1960 brushradiusY = luaL_checkint(l, 4);
1961 }
1962 else
1963 {
1964 ui::Point radius = luacon_model->GetBrush()->GetRadius();
1965 brushradiusX = radius.X;
1966 brushradiusY = radius.Y;
1967 }
1968 int brushID = luaL_optint(l, 5, luacon_model->GetBrushID());
1969
1970 std::vector<Brush *> brushList = luacon_model->GetBrushList();
1971 if (brushID < 0 || brushID >= (int)brushList.size())
1972 return luaL_error(l, "Invalid brush id '%d'", brushID);
1973
1974 ui::Point tempRadius = brushList[brushID]->GetRadius();
1975 brushList[brushID]->SetRadius(ui::Point(brushradiusX, brushradiusY));
1976 lua_pushnumber(l, positionX);
1977 lua_pushnumber(l, positionY);
1978 int radiusX = brushList[brushID]->GetRadius().X;
1979 int radiusY = brushList[brushID]->GetRadius().Y;
1980 int sizeX = brushList[brushID]->GetSize().X;
1981 int sizeY = brushList[brushID]->GetSize().Y;
1982 lua_pushnumber(l, radiusX);
1983 lua_pushnumber(l, radiusY);
1984 lua_pushnumber(l, sizeX);
1985 lua_pushnumber(l, sizeY);
1986 lua_pushnumber(l, 0);
1987 lua_pushnumber(l, 0);
1988 int bitmapSize = sizeX * sizeY * sizeof(unsigned char);
1989 void *bitmapCopy = lua_newuserdata(l, bitmapSize);
1990 memcpy(bitmapCopy, brushList[brushID]->GetBitmap(), bitmapSize);
1991 brushList[brushID]->SetRadius(tempRadius);
1992
1993 lua_pushcclosure(l, BrushClosure, 9);
1994 return 1;
1995 }
1996
PartsClosure(lua_State * l)1997 int PartsClosure(lua_State *l)
1998 {
1999 for (int i = lua_tointeger(l, lua_upvalueindex(1)); i <= luacon_sim->parts_lastActiveIndex; ++i)
2000 {
2001 if (luacon_sim->parts[i].type)
2002 {
2003 lua_pushnumber(l, i + 1);
2004 lua_replace(l, lua_upvalueindex(1));
2005 lua_pushnumber(l, i);
2006 return 1;
2007 }
2008 }
2009 return 0;
2010 }
2011
simulation_parts(lua_State * l)2012 int LuaScriptInterface::simulation_parts(lua_State *l)
2013 {
2014 lua_pushnumber(l, 0);
2015 lua_pushcclosure(l, PartsClosure, 1);
2016 return 1;
2017 }
2018
simulation_pmap(lua_State * l)2019 int LuaScriptInterface::simulation_pmap(lua_State * l)
2020 {
2021 int x = luaL_checkint(l, 1);
2022 int y = luaL_checkint(l, 2);
2023 if (x < 0 || x >= XRES || y < 0 || y >= YRES)
2024 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
2025 int r = luacon_sim->pmap[y][x];
2026 if (!TYP(r))
2027 return 0;
2028 lua_pushnumber(l, ID(r));
2029 return 1;
2030 }
2031
simulation_photons(lua_State * l)2032 int LuaScriptInterface::simulation_photons(lua_State * l)
2033 {
2034 int x = luaL_checkint(l, 1);
2035 int y = luaL_checkint(l, 2);
2036 if (x < 0 || x >= XRES || y < 0 || y >= YRES)
2037 return luaL_error(l, "coordinates out of range (%d,%d)", x, y);
2038 int r = luacon_sim->photons[y][x];
2039 if (!TYP(r))
2040 return 0;
2041 lua_pushnumber(l, ID(r));
2042 return 1;
2043 }
2044
NeighboursClosure(lua_State * l)2045 int NeighboursClosure(lua_State * l)
2046 {
2047 int rx=lua_tointeger(l, lua_upvalueindex(1));
2048 int ry=lua_tointeger(l, lua_upvalueindex(2));
2049 int sx=lua_tointeger(l, lua_upvalueindex(3));
2050 int sy=lua_tointeger(l, lua_upvalueindex(4));
2051 int x=lua_tointeger(l, lua_upvalueindex(5));
2052 int y=lua_tointeger(l, lua_upvalueindex(6));
2053 int i = 0;
2054 do
2055 {
2056 x++;
2057 if(x>rx)
2058 {
2059 x=-rx;
2060 y++;
2061 if(y>ry)
2062 return 0;
2063 }
2064 if(!(x || y) || sx+x<0 || sy+y<0 || sx+x>=XRES*CELL || sy+y>=YRES*CELL)
2065 {
2066 continue;
2067 }
2068 i=luacon_sim->pmap[y+sy][x+sx];
2069 if(!i)
2070 i=luacon_sim->photons[y+sy][x+sx];
2071 } while(!TYP(i));
2072 lua_pushnumber(l, x);
2073 lua_replace(l, lua_upvalueindex(5));
2074 lua_pushnumber(l, y);
2075 lua_replace(l, lua_upvalueindex(6));
2076 lua_pushnumber(l, ID(i));
2077 lua_pushnumber(l, x+sx);
2078 lua_pushnumber(l, y+sy);
2079 return 3;
2080 }
2081
simulation_neighbours(lua_State * l)2082 int LuaScriptInterface::simulation_neighbours(lua_State * l)
2083 {
2084 int x=luaL_checkint(l, 1);
2085 int y=luaL_checkint(l, 2);
2086 int rx=luaL_optint(l, 3, 2);
2087 int ry=luaL_optint(l, 4, 2);
2088 lua_pushnumber(l, rx);
2089 lua_pushnumber(l, ry);
2090 lua_pushnumber(l, x);
2091 lua_pushnumber(l, y);
2092 lua_pushnumber(l, -rx-1);
2093 lua_pushnumber(l, -ry);
2094 lua_pushcclosure(l, NeighboursClosure, 6);
2095 return 1;
2096 }
2097
simulation_framerender(lua_State * l)2098 int LuaScriptInterface::simulation_framerender(lua_State * l)
2099 {
2100 if (lua_gettop(l) == 0)
2101 {
2102 lua_pushinteger(l, luacon_sim->framerender);
2103 return 1;
2104 }
2105 int frames = luaL_checkinteger(l, 1);
2106 if (frames < 0)
2107 return luaL_error(l, "Can't simulate a negative number of frames");
2108 luacon_sim->framerender = frames;
2109 return 0;
2110 }
2111
simulation_gspeed(lua_State * l)2112 int LuaScriptInterface::simulation_gspeed(lua_State * l)
2113 {
2114 if (lua_gettop(l) == 0)
2115 {
2116 lua_pushinteger(l, luacon_sim->GSPEED);
2117 return 1;
2118 }
2119 int gspeed = luaL_checkinteger(l, 1);
2120 if (gspeed < 1)
2121 return luaL_error(l, "GSPEED must be at least 1");
2122 luacon_sim->GSPEED = gspeed;
2123 return 0;
2124 }
2125
simulation_takeSnapshot(lua_State * l)2126 int LuaScriptInterface::simulation_takeSnapshot(lua_State * l)
2127 {
2128 luacon_controller->HistorySnapshot();
2129 return 0;
2130 }
2131
2132 //// Begin Renderer API
2133
initRendererAPI()2134 void LuaScriptInterface::initRendererAPI()
2135 {
2136 //Methods
2137 struct luaL_Reg rendererAPIMethods [] = {
2138 {"renderModes", renderer_renderModes},
2139 {"displayModes", renderer_displayModes},
2140 {"colourMode", renderer_colourMode},
2141 {"colorMode", renderer_colourMode}, //Duplicate of above to make Americans happy
2142 {"decorations", renderer_decorations}, //renderer_debugHUD
2143 {"grid", renderer_grid},
2144 {"debugHUD", renderer_debugHUD},
2145 {"depth3d", renderer_depth3d},
2146 {"zoomEnabled", renderer_zoomEnabled},
2147 {"zoomWindow", renderer_zoomWindowInfo},
2148 {"zoomScope", renderer_zoomScopeInfo},
2149 {NULL, NULL}
2150 };
2151 luaL_register(l, "renderer", rendererAPIMethods);
2152
2153 //Ren shortcut
2154 lua_getglobal(l, "renderer");
2155 lua_setglobal(l, "ren");
2156
2157 //Static values
2158 //Particle pixel modes/fire mode/effects
2159 SETCONST(l, PMODE);
2160 SETCONST(l, PMODE_NONE);
2161 SETCONST(l, PMODE_FLAT);
2162 SETCONST(l, PMODE_BLOB);
2163 SETCONST(l, PMODE_BLUR);
2164 SETCONST(l, PMODE_GLOW);
2165 SETCONST(l, PMODE_SPARK);
2166 SETCONST(l, PMODE_FLARE);
2167 SETCONST(l, PMODE_LFLARE);
2168 SETCONST(l, PMODE_ADD);
2169 SETCONST(l, PMODE_BLEND);
2170 SETCONST(l, PSPEC_STICKMAN);
2171 SETCONST(l, OPTIONS);
2172 SETCONST(l, NO_DECO);
2173 SETCONST(l, DECO_FIRE);
2174 SETCONST(l, FIREMODE);
2175 SETCONST(l, FIRE_ADD);
2176 SETCONST(l, FIRE_BLEND);
2177 SETCONST(l, EFFECT);
2178 SETCONST(l, EFFECT_GRAVIN);
2179 SETCONST(l, EFFECT_GRAVOUT);
2180 SETCONST(l, EFFECT_LINES);
2181 SETCONST(l, EFFECT_DBGLINES);
2182
2183 //Display/Render/Colour modes
2184 SETCONST(l, RENDER_EFFE);
2185 SETCONST(l, RENDER_FIRE);
2186 SETCONST(l, RENDER_GLOW);
2187 SETCONST(l, RENDER_BLUR);
2188 SETCONST(l, RENDER_BLOB);
2189 SETCONST(l, RENDER_BASC);
2190 SETCONST(l, RENDER_NONE);
2191 SETCONST(l, COLOUR_HEAT);
2192 SETCONST(l, COLOUR_LIFE);
2193 SETCONST(l, COLOUR_GRAD);
2194 SETCONST(l, COLOUR_BASC);
2195 SETCONST(l, COLOUR_DEFAULT);
2196 SETCONST(l, DISPLAY_AIRC);
2197 SETCONST(l, DISPLAY_AIRP);
2198 SETCONST(l, DISPLAY_AIRV);
2199 SETCONST(l, DISPLAY_AIRH);
2200 SETCONST(l, DISPLAY_AIR);
2201 SETCONST(l, DISPLAY_WARP);
2202 SETCONST(l, DISPLAY_PERS);
2203 SETCONST(l, DISPLAY_EFFE);
2204 }
2205
2206 //get/set render modes list
renderer_renderModes(lua_State * l)2207 int LuaScriptInterface::renderer_renderModes(lua_State * l)
2208 {
2209 int args = lua_gettop(l);
2210 if(args)
2211 {
2212 int size = 0;
2213 luaL_checktype(l, 1, LUA_TTABLE);
2214 size = lua_objlen(l, 1);
2215
2216 std::vector<unsigned int> renderModes;
2217 for(int i = 1; i <= size; i++)
2218 {
2219 lua_rawgeti(l, 1, i);
2220 renderModes.push_back(lua_tointeger(l, -1));
2221 lua_pop(l, 1);
2222 }
2223 luacon_ren->SetRenderMode(renderModes);
2224 return 0;
2225 }
2226 else
2227 {
2228 lua_newtable(l);
2229 std::vector<unsigned int> renderModes = luacon_ren->GetRenderMode();
2230 int i = 1;
2231 for(std::vector<unsigned int>::iterator iter = renderModes.begin(), end = renderModes.end(); iter != end; ++iter)
2232 {
2233 lua_pushinteger(l, *iter);
2234 lua_rawseti(l, -2, i++);
2235 }
2236 return 1;
2237 }
2238 }
2239
renderer_displayModes(lua_State * l)2240 int LuaScriptInterface::renderer_displayModes(lua_State * l)
2241 {
2242 int args = lua_gettop(l);
2243 if(args)
2244 {
2245 int size = 0;
2246 luaL_checktype(l, 1, LUA_TTABLE);
2247 size = lua_objlen(l, 1);
2248
2249 std::vector<unsigned int> displayModes;
2250 for(int i = 1; i <= size; i++)
2251 {
2252 lua_rawgeti(l, 1, i);
2253 displayModes.push_back(lua_tointeger(l, -1));
2254 lua_pop(l, 1);
2255 }
2256 luacon_ren->SetDisplayMode(displayModes);
2257 return 0;
2258 }
2259 else
2260 {
2261 lua_newtable(l);
2262 std::vector<unsigned int> displayModes = luacon_ren->GetDisplayMode();
2263 int i = 1;
2264 for(std::vector<unsigned int>::iterator iter = displayModes.begin(), end = displayModes.end(); iter != end; ++iter)
2265 {
2266 lua_pushinteger(l, *iter);
2267 lua_rawseti(l, -2, i++);
2268 }
2269 return 1;
2270 }
2271 }
2272
renderer_colourMode(lua_State * l)2273 int LuaScriptInterface::renderer_colourMode(lua_State * l)
2274 {
2275 int args = lua_gettop(l);
2276 if(args)
2277 {
2278 luaL_checktype(l, 1, LUA_TNUMBER);
2279 luacon_ren->SetColourMode(lua_tointeger(l, 1));
2280 return 0;
2281 }
2282 else
2283 {
2284 lua_pushinteger(l, luacon_ren->GetColourMode());
2285 return 1;
2286 }
2287 }
2288
renderer_decorations(lua_State * l)2289 int LuaScriptInterface::renderer_decorations(lua_State * l)
2290 {
2291 int args = lua_gettop(l);
2292 if(args)
2293 {
2294 luacon_ren->decorations_enable = lua_toboolean(l, 1);
2295 return 0;
2296 }
2297 else
2298 {
2299 lua_pushboolean(l, luacon_ren->decorations_enable);
2300 return 1;
2301 }
2302 }
2303
renderer_grid(lua_State * l)2304 int LuaScriptInterface::renderer_grid(lua_State * l)
2305 {
2306 int acount = lua_gettop(l);
2307 if (acount == 0)
2308 {
2309 lua_pushnumber(l, luacon_ren->GetGridSize());
2310 return 1;
2311 }
2312 int grid = luaL_optint(l, 1, -1);
2313 luacon_ren->SetGridSize(grid);
2314 return 0;
2315 }
2316
renderer_debugHUD(lua_State * l)2317 int LuaScriptInterface::renderer_debugHUD(lua_State * l)
2318 {
2319 int acount = lua_gettop(l);
2320 if (acount == 0)
2321 {
2322 lua_pushnumber(l, luacon_controller->GetDebugHUD());
2323 return 1;
2324 }
2325 int debug = luaL_optint(l, 1, -1);
2326 luacon_controller->SetDebugHUD(debug);
2327 return 0;
2328 }
2329
renderer_depth3d(lua_State * l)2330 int LuaScriptInterface::renderer_depth3d(lua_State * l)
2331 {
2332 return luaL_error(l, "This feature is no longer supported");
2333 }
2334
renderer_zoomEnabled(lua_State * l)2335 int LuaScriptInterface::renderer_zoomEnabled(lua_State * l)
2336 {
2337 if (lua_gettop(l) == 0)
2338 {
2339 lua_pushboolean(l, luacon_ren->zoomEnabled);
2340 return 1;
2341 }
2342 else
2343 {
2344 luaL_checktype(l, -1, LUA_TBOOLEAN);
2345 luacon_ren->zoomEnabled = lua_toboolean(l, -1);
2346 return 0;
2347 }
2348 }
renderer_zoomWindowInfo(lua_State * l)2349 int LuaScriptInterface::renderer_zoomWindowInfo(lua_State * l)
2350 {
2351 if (lua_gettop(l) == 0)
2352 {
2353 ui::Point location = luacon_ren->zoomWindowPosition;
2354 lua_pushnumber(l, location.X);
2355 lua_pushnumber(l, location.Y);
2356 lua_pushnumber(l, luacon_ren->ZFACTOR);
2357 lua_pushnumber(l, luacon_ren->zoomScopeSize * luacon_ren->ZFACTOR);
2358 return 4;
2359 }
2360 int x = luaL_optint(l, 1, 0);
2361 int y = luaL_optint(l, 2, 0);
2362 int f = luaL_optint(l, 3, 0);
2363 if (f <= 0)
2364 return luaL_error(l, "Zoom factor must be greater than 0");
2365
2366 // To prevent crash when zoom window is outside screen
2367 if (x < 0 || y < 0 || luacon_ren->zoomScopeSize * f + x > XRES || luacon_ren->zoomScopeSize * f + y > YRES)
2368 return luaL_error(l, "Zoom window outside of bounds");
2369
2370 luacon_ren->zoomWindowPosition = ui::Point(x, y);
2371 luacon_ren->ZFACTOR = f;
2372 return 0;
2373 }
renderer_zoomScopeInfo(lua_State * l)2374 int LuaScriptInterface::renderer_zoomScopeInfo(lua_State * l)
2375 {
2376 if (lua_gettop(l) == 0)
2377 {
2378 ui::Point location = luacon_ren->zoomScopePosition;
2379 lua_pushnumber(l, location.X);
2380 lua_pushnumber(l, location.Y);
2381 lua_pushnumber(l, luacon_ren->zoomScopeSize);
2382 return 3;
2383 }
2384 int x = luaL_optint(l, 1, 0);
2385 int y = luaL_optint(l, 2, 0);
2386 int s = luaL_optint(l, 3, 0);
2387 if (s <= 0)
2388 return luaL_error(l, "Zoom scope size must be greater than 0");
2389
2390 // To prevent crash when zoom or scope window is outside screen
2391 int windowEdgeRight = luacon_ren->ZFACTOR * s + luacon_ren->zoomWindowPosition.X;
2392 int windowEdgeBottom = luacon_ren->ZFACTOR * s + luacon_ren->zoomWindowPosition.Y;
2393 if (x < 0 || y < 0 || x + s > XRES || y + s > YRES)
2394 return luaL_error(l, "Zoom scope outside of bounds");
2395 if (windowEdgeRight > XRES || windowEdgeBottom > YRES)
2396 return luaL_error(l, "Zoom window outside of bounds");
2397
2398 luacon_ren->zoomScopePosition = ui::Point(x, y);
2399 luacon_ren->zoomScopeSize = s;
2400 return 0;
2401 }
2402
initElementsAPI()2403 void LuaScriptInterface::initElementsAPI()
2404 {
2405 //Methods
2406 struct luaL_Reg elementsAPIMethods [] = {
2407 {"allocate", elements_allocate},
2408 {"element", elements_element},
2409 {"property", elements_property},
2410 {"free", elements_free},
2411 {"loadDefault", elements_loadDefault},
2412 {NULL, NULL}
2413 };
2414 luaL_register(l, "elements", elementsAPIMethods);
2415
2416 //elem shortcut
2417 lua_getglobal(l, "elements");
2418 lua_setglobal(l, "elem");
2419
2420 //Static values
2421 //Element types/properties/states
2422 SETCONST(l, TYPE_PART);
2423 SETCONST(l, TYPE_LIQUID);
2424 SETCONST(l, TYPE_SOLID);
2425 SETCONST(l, TYPE_GAS);
2426 SETCONST(l, TYPE_ENERGY);
2427 SETCONST(l, PROP_CONDUCTS);
2428 SETCONST(l, PROP_BLACK);
2429 SETCONST(l, PROP_NEUTPENETRATE);
2430 SETCONST(l, PROP_NEUTABSORB);
2431 SETCONST(l, PROP_NEUTPASS);
2432 SETCONST(l, PROP_DEADLY);
2433 SETCONST(l, PROP_HOT_GLOW);
2434 SETCONST(l, PROP_LIFE);
2435 SETCONST(l, PROP_RADIOACTIVE);
2436 SETCONST(l, PROP_LIFE_DEC);
2437 SETCONST(l, PROP_LIFE_KILL);
2438 SETCONST(l, PROP_LIFE_KILL_DEC);
2439 SETCONST(l, PROP_SPARKSETTLE);
2440 SETCONST(l, PROP_NOAMBHEAT);
2441 lua_pushinteger(l, 0); lua_setfield(l, -2, "PROP_DRAWONCTYPE");
2442 SETCONST(l, PROP_NOCTYPEDRAW);
2443 SETCONST(l, FLAG_STAGNANT);
2444 SETCONST(l, FLAG_SKIPMOVE);
2445 SETCONST(l, FLAG_MOVABLE);
2446 SETCONST(l, FLAG_PHOTDECO);
2447 lua_pushinteger(l, 0);
2448 lua_setfield(l, -2, "ST_NONE");
2449 lua_pushinteger(l, 0);
2450 lua_setfield(l, -2, "ST_SOLID");
2451 lua_pushinteger(l, 0);
2452 lua_setfield(l, -2, "ST_LIQUID");
2453 lua_pushinteger(l, 0);
2454 lua_setfield(l, -2, "ST_GAS");
2455
2456 SETCONST(l, SC_WALL);
2457 SETCONST(l, SC_ELEC);
2458 SETCONST(l, SC_POWERED);
2459 SETCONST(l, SC_SENSOR);
2460 SETCONST(l, SC_FORCE);
2461 SETCONST(l, SC_EXPLOSIVE);
2462 SETCONST(l, SC_GAS);
2463 SETCONST(l, SC_LIQUID);
2464 SETCONST(l, SC_POWDERS);
2465 SETCONST(l, SC_SOLIDS);
2466 SETCONST(l, SC_NUCLEAR);
2467 SETCONST(l, SC_SPECIAL);
2468 SETCONST(l, SC_LIFE);
2469 SETCONST(l, SC_TOOL);
2470 SETCONST(l, SC_DECO);
2471
2472 //Element identifiers
2473 for(int i = 0; i < PT_NUM; i++)
2474 {
2475 if(luacon_sim->elements[i].Enabled)
2476 {
2477 lua_pushinteger(l, i);
2478 lua_setfield(l, -2, luacon_sim->elements[i].Identifier.c_str());
2479 ByteString realIdentifier = ByteString::Build("DEFAULT_PT_", luacon_sim->elements[i].Name.ToUtf8());
2480 if (i != 0 && i != PT_NBHL && i != PT_NWHL && luacon_sim->elements[i].Identifier != realIdentifier)
2481 {
2482 lua_pushinteger(l, i);
2483 lua_setfield(l, -2, realIdentifier.c_str());
2484 }
2485 }
2486 }
2487 }
2488
LuaGetProperty(lua_State * l,StructProperty property,intptr_t propertyAddress)2489 void LuaScriptInterface::LuaGetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress)
2490 {
2491 switch (property.Type)
2492 {
2493 case StructProperty::TransitionType:
2494 case StructProperty::ParticleType:
2495 case StructProperty::Integer:
2496 lua_pushnumber(l, *((int*)propertyAddress));
2497 break;
2498 case StructProperty::UInteger:
2499 lua_pushnumber(l, *((unsigned int*)propertyAddress));
2500 break;
2501 case StructProperty::Float:
2502 lua_pushnumber(l, *((float*)propertyAddress));
2503 break;
2504 case StructProperty::Char:
2505 lua_pushnumber(l, *((char*)propertyAddress));
2506 break;
2507 case StructProperty::UChar:
2508 lua_pushnumber(l, *((unsigned char*)propertyAddress));
2509 break;
2510 case StructProperty::BString:
2511 {
2512 ByteString byteStringProperty = *((ByteString*)propertyAddress);
2513 lua_pushstring(l, byteStringProperty.c_str());
2514 break;
2515 }
2516 case StructProperty::String:
2517 {
2518 ByteString byteStringProperty = (*((String*)propertyAddress)).ToUtf8();
2519 lua_pushstring(l, byteStringProperty.c_str());
2520 break;
2521 }
2522 case StructProperty::Colour:
2523 #if PIXELSIZE == 4
2524 lua_pushinteger(l, *((unsigned int*)propertyAddress));
2525 #else
2526 lua_pushinteger(l, *((unsigned short*)propertyAddress));
2527 #endif
2528 break;
2529 case StructProperty::Removed:
2530 lua_pushnil(l);
2531 }
2532 }
2533
LuaSetProperty(lua_State * l,StructProperty property,intptr_t propertyAddress,int stackPos)2534 void LuaScriptInterface::LuaSetProperty(lua_State* l, StructProperty property, intptr_t propertyAddress, int stackPos)
2535 {
2536 switch (property.Type)
2537 {
2538 case StructProperty::TransitionType:
2539 case StructProperty::ParticleType:
2540 case StructProperty::Integer:
2541 *((int*)propertyAddress) = luaL_checkinteger(l, stackPos);
2542 break;
2543 case StructProperty::UInteger:
2544 *((unsigned int*)propertyAddress) = luaL_checkinteger(l, stackPos);
2545 break;
2546 case StructProperty::Float:
2547 *((float*)propertyAddress) = luaL_checknumber(l, stackPos);
2548 break;
2549 case StructProperty::Char:
2550 *((char*)propertyAddress) = luaL_checkinteger(l, stackPos);
2551 break;
2552 case StructProperty::UChar:
2553 *((unsigned char*)propertyAddress) = luaL_checkinteger(l, stackPos);
2554 break;
2555 case StructProperty::BString:
2556 *((ByteString*)propertyAddress) = ByteString(luaL_checkstring(l, stackPos));
2557 break;
2558 case StructProperty::String:
2559 *((String*)propertyAddress) = ByteString(luaL_checkstring(l, stackPos)).FromUtf8();
2560 break;
2561 case StructProperty::Colour:
2562 #if PIXELSIZE == 4
2563 *((unsigned int*)propertyAddress) = luaL_checkinteger(l, stackPos);
2564 #else
2565 *((unsigned short*)propertyAddress) = luaL_checkinteger(l, stackPos);
2566 #endif
2567 break;
2568 case StructProperty::Removed:
2569 break;
2570 }
2571 }
2572
elements_loadDefault(lua_State * l)2573 int LuaScriptInterface::elements_loadDefault(lua_State * l)
2574 {
2575 int args = lua_gettop(l);
2576 if (args)
2577 {
2578 luaL_checktype(l, 1, LUA_TNUMBER);
2579 int id = lua_tointeger(l, 1);
2580 if (id < 0 || id >= PT_NUM)
2581 return luaL_error(l, "Invalid element");
2582
2583 lua_getglobal(l, "elements");
2584 lua_pushnil(l);
2585 lua_setfield(l, -2, luacon_sim->elements[id].Identifier.c_str());
2586
2587 auto const &elementList = GetElements();
2588 if (id < (int)elementList.size())
2589 luacon_sim->elements[id] = elementList[id];
2590 else
2591 luacon_sim->elements[id] = Element();
2592
2593 lua_pushinteger(l, id);
2594 lua_setfield(l, -2, luacon_sim->elements[id].Identifier.c_str());
2595 lua_pop(l, 1);
2596 }
2597 else
2598 {
2599 auto const &elementList = GetElements();
2600 for (int i = 0; i < PT_NUM; i++)
2601 {
2602 if (i < (int)elementList.size())
2603 luacon_sim->elements[i] = elementList[i];
2604 else
2605 luacon_sim->elements[i] = Element();
2606 }
2607 lua_pushnil(l);
2608 lua_setglobal(l, "elements");
2609 lua_pushnil(l);
2610 lua_setglobal(l, "elem");
2611
2612 lua_getglobal(l, "package");
2613 lua_getfield(l, -1, "loaded");
2614 lua_pushnil(l);
2615 lua_setfield(l, -2, "elements");
2616
2617 luacon_ci->initElementsAPI();
2618 }
2619
2620 luacon_model->BuildMenus();
2621 luacon_sim->init_can_move();
2622 std::fill(luacon_ren->graphicscache, luacon_ren->graphicscache+PT_NUM, gcache_item());
2623 return 0;
2624 }
2625
elements_allocate(lua_State * l)2626 int LuaScriptInterface::elements_allocate(lua_State * l)
2627 {
2628 ByteString group, id, identifier;
2629 luaL_checktype(l, 1, LUA_TSTRING);
2630 luaL_checktype(l, 2, LUA_TSTRING);
2631 group = ByteString(lua_tostring(l, 1)).ToUpper();
2632 id = ByteString(lua_tostring(l, 2)).ToUpper();
2633
2634 if (id.Contains("_"))
2635 {
2636 return luaL_error(l, "The element name may not contain '_'.");
2637 }
2638 if (group.Contains("_"))
2639 {
2640 return luaL_error(l, "The group name may not contain '_'.");
2641 }
2642 if (group == "DEFAULT")
2643 {
2644 return luaL_error(l, "You cannot create elements in the 'DEFAULT' group.");
2645 }
2646
2647 identifier = group + "_PT_" + id;
2648
2649 for(int i = 0; i < PT_NUM; i++)
2650 {
2651 if(luacon_sim->elements[i].Enabled && ByteString(luacon_sim->elements[i].Identifier) == identifier)
2652 return luaL_error(l, "Element identifier already in use");
2653 }
2654
2655 int newID = -1;
2656 // Start out at 255 so that lua element IDs are still one byte (better save compatibility)
2657 for (int i = PT_NUM >= 255 ? 255 : PT_NUM; i >= 0; i--)
2658 {
2659 if (!luacon_sim->elements[i].Enabled)
2660 {
2661 newID = i;
2662 break;
2663 }
2664 }
2665 // If not enough space, then we start with the new maimum ID
2666 if (newID == -1)
2667 {
2668 for (int i = PT_NUM-1; i >= 255; i--)
2669 {
2670 if (!luacon_sim->elements[i].Enabled)
2671 {
2672 newID = i;
2673 break;
2674 }
2675 }
2676 }
2677
2678 if (newID != -1)
2679 {
2680 luacon_sim->elements[newID] = Element();
2681 luacon_sim->elements[newID].Enabled = true;
2682 luacon_sim->elements[newID].Identifier = identifier;
2683
2684 lua_getglobal(l, "elements");
2685 lua_pushinteger(l, newID);
2686 lua_setfield(l, -2, identifier.c_str());
2687 lua_pop(l, 1);
2688 }
2689
2690 lua_pushinteger(l, newID);
2691 return 1;
2692 }
2693
luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS)2694 void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS)
2695 {
2696 if (luaCreateHandlers[sim->parts[i].type])
2697 {
2698 lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaCreateHandlers[sim->parts[i].type]);
2699 lua_pushinteger(luacon_ci->l, i);
2700 lua_pushinteger(luacon_ci->l, x);
2701 lua_pushinteger(luacon_ci->l, y);
2702 lua_pushinteger(luacon_ci->l, t);
2703 lua_pushinteger(luacon_ci->l, v);
2704 if (lua_pcall(luacon_ci->l, 5, 0, 0))
2705 {
2706 luacon_ci->Log(CommandInterface::LogError, "In create func: " + luacon_geterror());
2707 lua_pop(luacon_ci->l, 1);
2708 }
2709 }
2710 }
2711
luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS)2712 bool luaCreateAllowedWrapper(ELEMENT_CREATE_ALLOWED_FUNC_ARGS)
2713 {
2714 bool ret = false;
2715 if (luaCreateAllowedHandlers[t])
2716 {
2717 lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaCreateAllowedHandlers[t]);
2718 lua_pushinteger(luacon_ci->l, i);
2719 lua_pushinteger(luacon_ci->l, x);
2720 lua_pushinteger(luacon_ci->l, y);
2721 lua_pushinteger(luacon_ci->l, t);
2722 if (lua_pcall(luacon_ci->l, 4, 1, 0))
2723 {
2724 luacon_ci->Log(CommandInterface::LogError, "In create allowed: " + luacon_geterror());
2725 lua_pop(luacon_ci->l, 1);
2726 }
2727 else
2728 {
2729 if (lua_isboolean(luacon_ci->l, -1))
2730 ret = lua_toboolean(luacon_ci->l, -1);
2731 lua_pop(luacon_ci->l, 1);
2732 }
2733 }
2734 return ret;
2735 }
2736
luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS)2737 void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS)
2738 {
2739 if (luaChangeTypeHandlers[sim->parts[i].type])
2740 {
2741 lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaChangeTypeHandlers[sim->parts[i].type]);
2742 lua_pushinteger(luacon_ci->l, i);
2743 lua_pushinteger(luacon_ci->l, x);
2744 lua_pushinteger(luacon_ci->l, y);
2745 lua_pushinteger(luacon_ci->l, from);
2746 lua_pushinteger(luacon_ci->l, to);
2747 if (lua_pcall(luacon_ci->l, 5, 0, 0))
2748 {
2749 luacon_ci->Log(CommandInterface::LogError, "In change type: " + luacon_geterror());
2750 lua_pop(luacon_ci->l, 1);
2751 }
2752 }
2753 }
2754
luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS)2755 static bool luaCtypeDrawWrapper(CTYPEDRAW_FUNC_ARGS)
2756 {
2757 bool ret = false;
2758 if (luaCtypeDrawHandlers[sim->parts[i].type])
2759 {
2760 lua_rawgeti(luacon_ci->l, LUA_REGISTRYINDEX, luaCtypeDrawHandlers[sim->parts[i].type]);
2761 lua_pushinteger(luacon_ci->l, i);
2762 lua_pushinteger(luacon_ci->l, t);
2763 lua_pushinteger(luacon_ci->l, v);
2764 if (lua_pcall(luacon_ci->l, 3, 1, 0))
2765 {
2766 luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
2767 lua_pop(luacon_ci->l, 1);
2768 }
2769 else
2770 {
2771 if (lua_isboolean(luacon_ci->l, -1))
2772 ret = lua_toboolean(luacon_ci->l, -1);
2773 lua_pop(luacon_ci->l, 1);
2774 }
2775 }
2776 return ret;
2777 }
2778
elements_element(lua_State * l)2779 int LuaScriptInterface::elements_element(lua_State * l)
2780 {
2781 int id = luaL_checkinteger(l, 1);
2782 if (!luacon_sim->IsValidElement(id))
2783 {
2784 return luaL_error(l, "Invalid element");
2785 }
2786
2787 if (lua_gettop(l) > 1)
2788 {
2789 luaL_checktype(l, 2, LUA_TTABLE);
2790 //Write values from native data to a table
2791 for (auto &prop : Element::GetProperties())
2792 {
2793 lua_getfield(l, -1, prop.Name.c_str());
2794 if (lua_type(l, -1) != LUA_TNIL)
2795 {
2796 intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset);
2797 LuaSetProperty(l, prop, propertyAddress, -1);
2798 }
2799 lua_pop(l, 1);
2800 }
2801
2802 lua_getfield(l, -1, "Update");
2803 if (lua_type(l, -1) == LUA_TFUNCTION)
2804 {
2805 lua_el_func[id].Assign(-1);
2806 lua_el_mode[id] = 1;
2807 }
2808 else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
2809 {
2810 lua_el_func[id].Clear();
2811 lua_el_mode[id] = 0;
2812 luacon_sim->elements[id].Update = nullptr;
2813 }
2814 lua_pop(l, 1);
2815
2816 lua_getfield(l, -1, "Graphics");
2817 if (lua_type(l, -1) == LUA_TFUNCTION)
2818 {
2819 lua_gr_func[id].Assign(-1);
2820 }
2821 else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
2822 {
2823 lua_gr_func[id].Clear();
2824 luacon_sim->elements[id].Graphics = nullptr;
2825 }
2826 lua_pop(l, 1);
2827
2828 lua_getfield(l, -1, "Create");
2829 if (lua_type(l, -1) == LUA_TFUNCTION)
2830 {
2831 luaCreateHandlers[id].Assign(-1);
2832 luacon_sim->elements[id].Create = luaCreateWrapper;
2833 }
2834 else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
2835 {
2836 luaCreateHandlers[id].Clear();
2837 luacon_sim->elements[id].Create = nullptr;
2838 }
2839 lua_pop(l, 1);
2840
2841 lua_getfield(l, -1, "CreateAllowed");
2842 if (lua_type(l, -1) == LUA_TFUNCTION)
2843 {
2844 luaCreateAllowedHandlers[id].Assign(-1);
2845 luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper;
2846 }
2847 else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
2848 {
2849 luaCreateAllowedHandlers[id].Clear();
2850 luacon_sim->elements[id].CreateAllowed = nullptr;
2851 }
2852 lua_pop(l, 1);
2853
2854 lua_getfield(l, -1, "ChangeType");
2855 if (lua_type(l, -1) == LUA_TFUNCTION)
2856 {
2857 luaChangeTypeHandlers[id].Assign(-1);
2858 luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper;
2859 }
2860 else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
2861 {
2862 luaChangeTypeHandlers[id].Clear();
2863 luacon_sim->elements[id].ChangeType = nullptr;
2864 }
2865 lua_pop(l, 1);
2866
2867 lua_getfield(l, -1, "CtypeDraw");
2868 if (lua_type(l, -1) == LUA_TFUNCTION)
2869 {
2870 luaCtypeDrawHandlers[id].Assign(-1);
2871 luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper;
2872 }
2873 else if (lua_type(l, -1) == LUA_TBOOLEAN && !lua_toboolean(l, -1))
2874 {
2875 luaCtypeDrawHandlers[id].Clear();
2876 luacon_sim->elements[id].CtypeDraw = nullptr;
2877 }
2878 lua_pop(l, 1);
2879
2880 lua_getfield(l, -1, "DefaultProperties");
2881 if (lua_type(l, -1) == LUA_TTABLE)
2882 {
2883 for (auto &prop : Particle::GetProperties())
2884 {
2885 lua_getfield(l, -1, prop.Name.c_str());
2886 if (lua_type(l, -1) != LUA_TNIL)
2887 {
2888 auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
2889 LuaSetProperty(l, prop, propertyAddress, -1);
2890 }
2891 lua_pop(l, 1);
2892 }
2893 }
2894 lua_pop(l, 1);
2895
2896 luacon_model->BuildMenus();
2897 luacon_sim->init_can_move();
2898 luacon_ren->graphicscache[id].isready = 0;
2899
2900 return 0;
2901 }
2902 else
2903 {
2904 //Write values from native data to a table
2905 lua_newtable(l);
2906 for (auto &prop : Element::GetProperties())
2907 {
2908 intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop.Offset);
2909 LuaGetProperty(l, prop, propertyAddress);
2910 lua_setfield(l, -2, prop.Name.c_str());
2911 }
2912
2913 lua_pushstring(l, luacon_sim->elements[id].Identifier.c_str());
2914 lua_setfield(l, -2, "Identifier");
2915
2916 lua_newtable(l);
2917 int tableIdx = lua_gettop(l);
2918 for (auto &prop : Particle::GetProperties())
2919 {
2920 auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
2921 LuaGetProperty(l, prop, propertyAddress);
2922 lua_setfield(l, tableIdx, prop.Name.c_str());
2923 }
2924 lua_setfield(l, -2, "DefaultProperties");
2925
2926 return 1;
2927 }
2928 }
2929
elements_property(lua_State * l)2930 int LuaScriptInterface::elements_property(lua_State * l)
2931 {
2932 int id = luaL_checkinteger(l, 1);
2933 if (!luacon_sim->IsValidElement(id))
2934 {
2935 return luaL_error(l, "Invalid element");
2936 }
2937 ByteString propertyName(luaL_checklstring(l, 2, NULL));
2938
2939 auto &properties = Element::GetProperties();
2940 auto prop = std::find_if(properties.begin(), properties.end(), [&propertyName](StructProperty const &p) {
2941 return p.Name == propertyName;
2942 });
2943
2944 if (lua_gettop(l) > 2)
2945 {
2946 if (prop != properties.end())
2947 {
2948 if (lua_type(l, 3) != LUA_TNIL)
2949 {
2950 if (prop->Type == StructProperty::TransitionType)
2951 {
2952 int type = luaL_checkinteger(l, 3);
2953 if (!luacon_sim->IsValidElement(type) && type != NT && type != ST)
2954 {
2955 return luaL_error(l, "Invalid element");
2956 }
2957 }
2958
2959 intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop->Offset);
2960 LuaSetProperty(l, *prop, propertyAddress, 3);
2961 }
2962
2963 luacon_model->BuildMenus();
2964 luacon_sim->init_can_move();
2965 luacon_ren->graphicscache[id].isready = 0;
2966 }
2967 else if (propertyName == "Update")
2968 {
2969 if (lua_type(l, 3) == LUA_TFUNCTION)
2970 {
2971 switch (luaL_optint(l, 4, 0))
2972 {
2973 case 2:
2974 lua_el_mode[id] = 3; //update before
2975 break;
2976
2977 case 1:
2978 lua_el_mode[id] = 2; //replace
2979 break;
2980
2981 default:
2982 lua_el_mode[id] = 1; //update after
2983 break;
2984 }
2985 lua_el_func[id].Assign(3);
2986 }
2987 else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
2988 {
2989 lua_el_func[id].Clear();
2990 lua_el_mode[id] = 0;
2991 luacon_sim->elements[id].Update = NULL;
2992 }
2993 }
2994 else if (propertyName == "Graphics")
2995 {
2996 if (lua_type(l, 3) == LUA_TFUNCTION)
2997 {
2998 lua_gr_func[id].Assign(3);
2999 }
3000 else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
3001 {
3002 lua_gr_func[id].Clear();
3003 luacon_sim->elements[id].Graphics = NULL;
3004 }
3005 luacon_ren->graphicscache[id].isready = 0;
3006 }
3007 else if (propertyName == "Create")
3008 {
3009 if (lua_type(l, 3) == LUA_TFUNCTION)
3010 {
3011 luaCreateHandlers[id].Assign(3);
3012 luacon_sim->elements[id].Create = luaCreateWrapper;
3013 }
3014 else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
3015 {
3016 luaCreateHandlers[id].Clear();
3017 luacon_sim->elements[id].Create = nullptr;
3018 }
3019 }
3020 else if (propertyName == "CreateAllowed")
3021 {
3022 if (lua_type(l, 3) == LUA_TFUNCTION)
3023 {
3024 luaCreateAllowedHandlers[id].Assign(3);
3025 luacon_sim->elements[id].CreateAllowed = luaCreateAllowedWrapper;
3026 }
3027 else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
3028 {
3029 luaCreateAllowedHandlers[id].Clear();
3030 luacon_sim->elements[id].CreateAllowed = nullptr;
3031 }
3032 }
3033 else if (propertyName == "ChangeType")
3034 {
3035 if (lua_type(l, 3) == LUA_TFUNCTION)
3036 {
3037 luaChangeTypeHandlers[id].Assign(3);
3038 luacon_sim->elements[id].ChangeType = luaChangeTypeWrapper;
3039 }
3040 else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
3041 {
3042 luaChangeTypeHandlers[id].Clear();
3043 luacon_sim->elements[id].ChangeType = nullptr;
3044 }
3045 }
3046 else if (propertyName == "CtypeDraw")
3047 {
3048 if (lua_type(l, 3) == LUA_TFUNCTION)
3049 {
3050 luaCtypeDrawHandlers[id].Assign(3);
3051 luacon_sim->elements[id].CtypeDraw = luaCtypeDrawWrapper;
3052 }
3053 else if (lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
3054 {
3055 luaCtypeDrawHandlers[id].Clear();
3056 luacon_sim->elements[id].CtypeDraw = nullptr;
3057 }
3058 }
3059 else if (propertyName == "DefaultProperties")
3060 {
3061 luaL_checktype(l, 3, LUA_TTABLE);
3062 for (auto &prop : Particle::GetProperties())
3063 {
3064 lua_getfield(l, -1, prop.Name.c_str());
3065 if (lua_type(l, -1) != LUA_TNIL)
3066 {
3067 auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
3068 LuaSetProperty(l, prop, propertyAddress, -1);
3069 }
3070 lua_pop(l, 1);
3071 }
3072 }
3073 else
3074 {
3075 return luaL_error(l, "Invalid element property");
3076 }
3077 return 0;
3078 }
3079 else
3080 {
3081 if (prop != properties.end())
3082 {
3083 intptr_t propertyAddress = (intptr_t)(((unsigned char*)&luacon_sim->elements[id]) + prop->Offset);
3084 LuaGetProperty(l, *prop, propertyAddress);
3085 return 1;
3086 }
3087 else if (propertyName == "Identifier")
3088 {
3089 lua_pushstring(l, luacon_sim->elements[id].Identifier.c_str());
3090 return 1;
3091 }
3092 else if (propertyName == "DefaultProperties")
3093 {
3094 lua_newtable(l);
3095 int tableIdx = lua_gettop(l);
3096 for (auto &prop : Particle::GetProperties())
3097 {
3098 auto propertyAddress = reinterpret_cast<intptr_t>((reinterpret_cast<unsigned char*>(&luacon_sim->elements[id].DefaultProperties)) + prop.Offset);
3099 LuaGetProperty(l, prop, propertyAddress);
3100 lua_setfield(l, tableIdx, prop.Name.c_str());
3101 }
3102 return 1;
3103 }
3104 else
3105 {
3106 return luaL_error(l, "Invalid element property");
3107 }
3108 }
3109 }
3110
elements_free(lua_State * l)3111 int LuaScriptInterface::elements_free(lua_State * l)
3112 {
3113 int id = luaL_checkinteger(l, 1);
3114 if (!luacon_sim->IsValidElement(id))
3115 {
3116 return luaL_error(l, "Invalid element");
3117 }
3118
3119 ByteString identifier = luacon_sim->elements[id].Identifier;
3120 if (identifier.BeginsWith("DEFAULT_PT_"))
3121 {
3122 return luaL_error(l, "Cannot free default elements");
3123 }
3124
3125 luacon_sim->elements[id].Enabled = false;
3126 luacon_model->BuildMenus();
3127
3128 lua_getglobal(l, "elements");
3129 lua_pushnil(l);
3130 lua_setfield(l, -2, identifier.c_str());
3131 lua_pop(l, 1);
3132
3133 return 0;
3134 }
3135
initGraphicsAPI()3136 void LuaScriptInterface::initGraphicsAPI()
3137 {
3138 //Methods
3139 struct luaL_Reg graphicsAPIMethods [] = {
3140 {"textSize", graphics_textSize},
3141 {"drawText", graphics_drawText},
3142 {"drawLine", graphics_drawLine},
3143 {"drawRect", graphics_drawRect},
3144 {"fillRect", graphics_fillRect},
3145 {"drawCircle", graphics_drawCircle},
3146 {"fillCircle", graphics_fillCircle},
3147 {"getColors", graphics_getColors},
3148 {"getHexColor", graphics_getHexColor},
3149 {NULL, NULL}
3150 };
3151 luaL_register(l, "graphics", graphicsAPIMethods);
3152
3153 //elem shortcut
3154 lua_getglobal(l, "graphics");
3155 lua_setglobal(l, "gfx");
3156
3157 lua_pushinteger(l, WINDOWW); lua_setfield(l, -2, "WIDTH");
3158 lua_pushinteger(l, WINDOWH); lua_setfield(l, -2, "HEIGHT");
3159 }
3160
graphics_textSize(lua_State * l)3161 int LuaScriptInterface::graphics_textSize(lua_State * l)
3162 {
3163 int width, height;
3164 const char* text = luaL_optstring(l, 1, "");
3165 Graphics::textsize(ByteString(text).FromUtf8(), width, height);
3166
3167 lua_pushinteger(l, width);
3168 lua_pushinteger(l, height);
3169 return 2;
3170 }
3171
graphics_drawText(lua_State * l)3172 int LuaScriptInterface::graphics_drawText(lua_State * l)
3173 {
3174 int x = lua_tointeger(l, 1);
3175 int y = lua_tointeger(l, 2);
3176 const char * text = luaL_optstring(l, 3, "");
3177 int r = luaL_optint(l, 4, 255);
3178 int g = luaL_optint(l, 5, 255);
3179 int b = luaL_optint(l, 6, 255);
3180 int a = luaL_optint(l, 7, 255);
3181
3182 if (r<0) r = 0;
3183 else if (r>255) r = 255;
3184 if (g<0) g = 0;
3185 else if (g>255) g = 255;
3186 if (b<0) b = 0;
3187 else if (b>255) b = 255;
3188 if (a<0) a = 0;
3189 else if (a>255) a = 255;
3190
3191 luacon_g->drawtext(x, y, ByteString(text).FromUtf8(), r, g, b, a);
3192 return 0;
3193 }
3194
graphics_drawLine(lua_State * l)3195 int LuaScriptInterface::graphics_drawLine(lua_State * l)
3196 {
3197 int x1 = lua_tointeger(l, 1);
3198 int y1 = lua_tointeger(l, 2);
3199 int x2 = lua_tointeger(l, 3);
3200 int y2 = lua_tointeger(l, 4);
3201 int r = luaL_optint(l, 5, 255);
3202 int g = luaL_optint(l, 6, 255);
3203 int b = luaL_optint(l, 7, 255);
3204 int a = luaL_optint(l, 8, 255);
3205
3206 if (r<0) r = 0;
3207 else if (r>255) r = 255;
3208 if (g<0) g = 0;
3209 else if (g>255) g = 255;
3210 if (b<0) b = 0;
3211 else if (b>255) b = 255;
3212 if (a<0) a = 0;
3213 else if (a>255) a = 255;
3214
3215 luacon_g->draw_line(x1, y1, x2, y2, r, g, b, a);
3216 return 0;
3217 }
3218
graphics_drawRect(lua_State * l)3219 int LuaScriptInterface::graphics_drawRect(lua_State * l)
3220 {
3221 int x = lua_tointeger(l, 1);
3222 int y = lua_tointeger(l, 2);
3223 int width = lua_tointeger(l, 3);
3224 int height = lua_tointeger(l, 4);
3225 int r = luaL_optint(l, 5, 255);
3226 int g = luaL_optint(l, 6, 255);
3227 int b = luaL_optint(l, 7, 255);
3228 int a = luaL_optint(l, 8, 255);
3229
3230 if (r<0) r = 0;
3231 else if (r>255) r = 255;
3232 if (g<0) g = 0;
3233 else if (g>255) g = 255;
3234 if (b<0) b = 0;
3235 else if (b>255) b = 255;
3236 if (a<0) a = 0;
3237 else if (a>255) a = 255;
3238
3239 luacon_g->drawrect(x, y, width, height, r, g, b, a);
3240 return 0;
3241 }
3242
graphics_fillRect(lua_State * l)3243 int LuaScriptInterface::graphics_fillRect(lua_State * l)
3244 {
3245 int x = lua_tointeger(l, 1);
3246 int y = lua_tointeger(l, 2);
3247 int width = lua_tointeger(l, 3);
3248 int height = lua_tointeger(l, 4);
3249 int r = luaL_optint(l, 5, 255);
3250 int g = luaL_optint(l, 6, 255);
3251 int b = luaL_optint(l, 7, 255);
3252 int a = luaL_optint(l, 8, 255);
3253
3254 if (r<0) r = 0;
3255 else if (r>255) r = 255;
3256 if (g<0) g = 0;
3257 else if (g>255) g = 255;
3258 if (b<0) b = 0;
3259 else if (b>255) b = 255;
3260 if (a<0) a = 0;
3261 else if (a>255) a = 255;
3262
3263 luacon_g->fillrect(x, y, width, height, r, g, b, a);
3264 return 0;
3265 }
3266
graphics_drawCircle(lua_State * l)3267 int LuaScriptInterface::graphics_drawCircle(lua_State * l)
3268 {
3269 int x = lua_tointeger(l, 1);
3270 int y = lua_tointeger(l, 2);
3271 int rx = lua_tointeger(l, 3);
3272 int ry = lua_tointeger(l, 4);
3273 int r = luaL_optint(l, 5, 255);
3274 int g = luaL_optint(l, 6, 255);
3275 int b = luaL_optint(l, 7, 255);
3276 int a = luaL_optint(l, 8, 255);
3277
3278 if (r<0) r = 0;
3279 else if (r>255) r = 255;
3280 if (g<0) g = 0;
3281 else if (g>255) g = 255;
3282 if (b<0) b = 0;
3283 else if (b>255) b = 255;
3284 if (a<0) a = 0;
3285 else if (a>255) a = 255;
3286
3287 luacon_g->drawcircle(x, y, abs(rx), abs(ry), r, g, b, a);
3288 return 0;
3289 }
3290
graphics_fillCircle(lua_State * l)3291 int LuaScriptInterface::graphics_fillCircle(lua_State * l)
3292 {
3293 int x = lua_tointeger(l, 1);
3294 int y = lua_tointeger(l, 2);
3295 int rx = lua_tointeger(l, 3);
3296 int ry = lua_tointeger(l, 4);
3297 int r = luaL_optint(l, 5, 255);
3298 int g = luaL_optint(l, 6, 255);
3299 int b = luaL_optint(l, 7, 255);
3300 int a = luaL_optint(l, 8, 255);
3301
3302 if (r<0) r = 0;
3303 else if (r>255) r = 255;
3304 if (g<0) g = 0;
3305 else if (g>255) g = 255;
3306 if (b<0) b = 0;
3307 else if (b>255) b = 255;
3308 if (a<0) a = 0;
3309 else if (a>255) a = 255;
3310
3311 luacon_g->fillcircle(x, y, abs(rx), abs(ry), r, g, b, a);
3312 return 0;
3313 }
3314
graphics_getColors(lua_State * l)3315 int LuaScriptInterface::graphics_getColors(lua_State * l)
3316 {
3317 unsigned int color = lua_tointeger(l, 1);
3318
3319 int a = color >> 24;
3320 int r = (color >> 16)&0xFF;
3321 int g = (color >> 8)&0xFF;
3322 int b = color&0xFF;
3323
3324 lua_pushinteger(l, r);
3325 lua_pushinteger(l, g);
3326 lua_pushinteger(l, b);
3327 lua_pushinteger(l, a);
3328 return 4;
3329 }
3330
graphics_getHexColor(lua_State * l)3331 int LuaScriptInterface::graphics_getHexColor(lua_State * l)
3332 {
3333 int r = lua_tointeger(l, 1);
3334 int g = lua_tointeger(l, 2);
3335 int b = lua_tointeger(l, 3);
3336 int a = 0;
3337 if (lua_gettop(l) >= 4)
3338 a = lua_tointeger(l, 4);
3339 unsigned int color = (a<<24) + (r<<16) + (g<<8) + b;
3340
3341 lua_pushinteger(l, color);
3342 return 1;
3343 }
3344
initFileSystemAPI()3345 void LuaScriptInterface::initFileSystemAPI()
3346 {
3347 //Methods
3348 struct luaL_Reg fileSystemAPIMethods [] = {
3349 {"list", fileSystem_list},
3350 {"exists", fileSystem_exists},
3351 {"isFile", fileSystem_isFile},
3352 {"isDirectory", fileSystem_isDirectory},
3353 {"makeDirectory", fileSystem_makeDirectory},
3354 {"removeDirectory", fileSystem_removeDirectory},
3355 {"removeFile", fileSystem_removeFile},
3356 {"move", fileSystem_move},
3357 {"copy", fileSystem_copy},
3358 {NULL, NULL}
3359 };
3360 luaL_register(l, "fileSystem", fileSystemAPIMethods);
3361
3362 //elem shortcut
3363 lua_getglobal(l, "fileSystem");
3364 lua_setglobal(l, "fs");
3365 }
3366
fileSystem_list(lua_State * l)3367 int LuaScriptInterface::fileSystem_list(lua_State * l)
3368 {
3369 const char * directoryName = luaL_checkstring(l, 1);
3370
3371 int index = 1;
3372 lua_newtable(l);
3373
3374 DIR * directory;
3375 struct dirent * entry;
3376
3377 directory = opendir(directoryName);
3378 if (directory != NULL)
3379 {
3380 while ((entry = readdir(directory)))
3381 {
3382 if(strncmp(entry->d_name, "..", 3) && strncmp(entry->d_name, ".", 2))
3383 {
3384 lua_pushstring(l, entry->d_name);
3385 lua_rawseti(l, -2, index++);
3386 }
3387 }
3388 closedir(directory);
3389 }
3390 else
3391 {
3392 lua_pushnil(l);
3393 }
3394
3395 return 1;
3396 }
3397
fileSystem_exists(lua_State * l)3398 int LuaScriptInterface::fileSystem_exists(lua_State * l)
3399 {
3400 const char * filename = luaL_checkstring(l, 1);
3401
3402 bool exists = false;
3403 #ifdef WIN
3404 struct _stat s;
3405 if(_stat(filename, &s) == 0)
3406 #else
3407 struct stat s;
3408 if(stat(filename, &s) == 0)
3409 #endif
3410 {
3411 exists = true;
3412 }
3413 else
3414 {
3415 exists = false;
3416 }
3417
3418 lua_pushboolean(l, exists);
3419 return 1;
3420 }
3421
fileSystem_isFile(lua_State * l)3422 int LuaScriptInterface::fileSystem_isFile(lua_State * l)
3423 {
3424 const char * filename = luaL_checkstring(l, 1);
3425
3426 bool isFile = false;
3427 #ifdef WIN
3428 struct _stat s;
3429 if(_stat(filename, &s) == 0)
3430 #else
3431 struct stat s;
3432 if(stat(filename, &s) == 0)
3433 #endif
3434 {
3435 if(s.st_mode & S_IFREG)
3436 {
3437 isFile = true; //Is file
3438 }
3439 else
3440 {
3441 isFile = false; //Is directory or something else
3442 }
3443 }
3444 else
3445 {
3446 isFile = false; //Doesn't exist
3447 }
3448
3449 lua_pushboolean(l, isFile);
3450 return 1;
3451 }
3452
fileSystem_isDirectory(lua_State * l)3453 int LuaScriptInterface::fileSystem_isDirectory(lua_State * l)
3454 {
3455 const char * filename = luaL_checkstring(l, 1);
3456
3457 bool isDir = false;
3458 #ifdef WIN
3459 struct _stat s;
3460 if(_stat(filename, &s) == 0)
3461 #else
3462 struct stat s;
3463 if(stat(filename, &s) == 0)
3464 #endif
3465 {
3466 if(s.st_mode & S_IFDIR)
3467 {
3468 isDir = true; //Is directory
3469 }
3470 else
3471 {
3472 isDir = false; //Is file or something else
3473 }
3474 }
3475 else
3476 {
3477 isDir = false; //Doesn't exist
3478 }
3479
3480 lua_pushboolean(l, isDir);
3481 return 1;
3482 }
3483
fileSystem_makeDirectory(lua_State * l)3484 int LuaScriptInterface::fileSystem_makeDirectory(lua_State * l)
3485 {
3486 const char * dirname = luaL_checkstring(l, 1);
3487
3488 int ret = 0;
3489 ret = Client::Ref().MakeDirectory(dirname);
3490 lua_pushboolean(l, ret == 0);
3491 return 1;
3492 }
3493
fileSystem_removeDirectory(lua_State * l)3494 int LuaScriptInterface::fileSystem_removeDirectory(lua_State * l)
3495 {
3496 const char * filename = luaL_checkstring(l, 1);
3497
3498 int ret = 0;
3499 #ifdef WIN
3500 ret = _rmdir(filename);
3501 #else
3502 ret = rmdir(filename);
3503 #endif
3504 lua_pushboolean(l, ret == 0);
3505 return 1;
3506 }
3507
fileSystem_removeFile(lua_State * l)3508 int LuaScriptInterface::fileSystem_removeFile(lua_State * l)
3509 {
3510 const char * filename = luaL_checkstring(l, 1);
3511
3512 int ret = 0;
3513 #ifdef WIN
3514 ret = _unlink(filename);
3515 #else
3516 ret = unlink(filename);
3517 #endif
3518 lua_pushboolean(l, ret == 0);
3519 return 1;
3520 }
3521
fileSystem_move(lua_State * l)3522 int LuaScriptInterface::fileSystem_move(lua_State * l)
3523 {
3524 const char * filename = luaL_checkstring(l, 1);
3525 const char * newFilename = luaL_checkstring(l, 2);
3526 int ret = 0;
3527
3528 ret = rename(filename, newFilename);
3529
3530 lua_pushboolean(l, ret == 0);
3531 return 1;
3532 }
3533
fileSystem_copy(lua_State * l)3534 int LuaScriptInterface::fileSystem_copy(lua_State * l)
3535 {
3536 const char * filename = luaL_checkstring(l, 1);
3537 const char * newFilename = luaL_checkstring(l, 2);
3538 int ret = 0;
3539
3540 try
3541 {
3542 std::ifstream source(filename, std::ios::binary);
3543 std::ofstream dest(newFilename, std::ios::binary);
3544 source.exceptions(std::ifstream::failbit | std::ifstream::badbit);
3545 dest.exceptions(std::ifstream::failbit | std::ifstream::badbit);
3546
3547 std::istreambuf_iterator<char> begin_source(source);
3548 std::istreambuf_iterator<char> end_source;
3549 std::ostreambuf_iterator<char> begin_dest(dest);
3550 std::copy(begin_source, end_source, begin_dest);
3551
3552 source.close();
3553 dest.close();
3554
3555 ret = 0;
3556 }
3557 catch (std::exception & e)
3558 {
3559 ret = 1;
3560 }
3561
3562 lua_pushboolean(l, ret == 0);
3563 return 1;
3564 }
3565
initPlatformAPI()3566 void LuaScriptInterface::initPlatformAPI()
3567 {
3568 //Methods
3569 struct luaL_Reg platformAPIMethods [] = {
3570 {"platform", platform_platform},
3571 {"build", platform_build},
3572 {"releaseType", platform_releaseType},
3573 {"exeName", platform_exeName},
3574 {"restart", platform_restart},
3575 {"openLink", platform_openLink},
3576 {"clipboardCopy", platform_clipboardCopy},
3577 {"clipboardPaste", platform_clipboardPaste},
3578 {NULL, NULL}
3579 };
3580 luaL_register(l, "platform", platformAPIMethods);
3581
3582 //elem shortcut
3583 lua_getglobal(l, "platform");
3584 lua_setglobal(l, "plat");
3585 }
3586
platform_platform(lua_State * l)3587 int LuaScriptInterface::platform_platform(lua_State * l)
3588 {
3589 lua_pushstring(l, IDENT_PLATFORM);
3590 return 1;
3591 }
3592
platform_build(lua_State * l)3593 int LuaScriptInterface::platform_build(lua_State * l)
3594 {
3595 lua_pushstring(l, IDENT_BUILD);
3596 return 1;
3597 }
3598
platform_releaseType(lua_State * l)3599 int LuaScriptInterface::platform_releaseType(lua_State * l)
3600 {
3601 lua_pushstring(l, IDENT_RELTYPE);
3602 return 1;
3603 }
3604
platform_exeName(lua_State * l)3605 int LuaScriptInterface::platform_exeName(lua_State * l)
3606 {
3607 ByteString name = Platform::ExecutableName();
3608 if (name.length())
3609 lua_pushstring(l, name.c_str());
3610 else
3611 luaL_error(l, "Error, could not get executable name");
3612 return 1;
3613 }
3614
platform_restart(lua_State * l)3615 int LuaScriptInterface::platform_restart(lua_State * l)
3616 {
3617 Platform::DoRestart();
3618 return 0;
3619 }
3620
platform_openLink(lua_State * l)3621 int LuaScriptInterface::platform_openLink(lua_State * l)
3622 {
3623 const char * uri = luaL_checkstring(l, 1);
3624 Platform::OpenURI(uri);
3625 return 0;
3626 }
3627
platform_clipboardCopy(lua_State * l)3628 int LuaScriptInterface::platform_clipboardCopy(lua_State * l)
3629 {
3630 lua_pushstring(l, ClipboardPull().c_str());
3631 return 1;
3632 }
3633
platform_clipboardPaste(lua_State * l)3634 int LuaScriptInterface::platform_clipboardPaste(lua_State * l)
3635 {
3636 luaL_checktype(l, 1, LUA_TSTRING);
3637 ClipboardPush(luaL_optstring(l, 1, ""));
3638 return 0;
3639 }
3640
3641
3642 //// Begin Event API
3643
initEventAPI()3644 void LuaScriptInterface::initEventAPI()
3645 {
3646 struct luaL_Reg eventAPIMethods [] = {
3647 {"register", event_register},
3648 {"unregister", event_unregister},
3649 {"getmodifiers", event_getmodifiers},
3650 {NULL, NULL}
3651 };
3652 luaL_register(l, "event", eventAPIMethods);
3653
3654 lua_getglobal(l, "event");
3655 lua_setglobal(l, "evt");
3656
3657 lua_pushinteger(l, LuaEvents::keypress); lua_setfield(l, -2, "keypress");
3658 lua_pushinteger(l, LuaEvents::keyrelease); lua_setfield(l, -2, "keyrelease");
3659 lua_pushinteger(l, LuaEvents::textinput); lua_setfield(l, -2, "textinput");
3660 lua_pushinteger(l, LuaEvents::mousedown); lua_setfield(l, -2, "mousedown");
3661 lua_pushinteger(l, LuaEvents::mouseup); lua_setfield(l, -2, "mouseup");
3662 lua_pushinteger(l, LuaEvents::mousemove); lua_setfield(l, -2, "mousemove");
3663 lua_pushinteger(l, LuaEvents::mousewheel); lua_setfield(l, -2, "mousewheel");
3664 lua_pushinteger(l, LuaEvents::tick); lua_setfield(l, -2, "tick");
3665 lua_pushinteger(l, LuaEvents::blur); lua_setfield(l, -2, "blur");
3666 lua_pushinteger(l, LuaEvents::close); lua_setfield(l, -2, "close");
3667 }
3668
event_register(lua_State * l)3669 int LuaScriptInterface::event_register(lua_State * l)
3670 {
3671 //ByteString eventname = luaL_checkstring(l, 1);
3672 int eventName = luaL_checkinteger(l, 1);
3673 luaL_checktype(l, 2, LUA_TFUNCTION);
3674 return LuaEvents::RegisterEventHook(l, ByteString::Build("tptevents-", eventName));
3675 }
3676
event_unregister(lua_State * l)3677 int LuaScriptInterface::event_unregister(lua_State * l)
3678 {
3679 //ByteString eventname = luaL_checkstring(l, 1);
3680 int eventName = luaL_checkinteger(l, 1);
3681 luaL_checktype(l, 2, LUA_TFUNCTION);
3682 return LuaEvents::UnregisterEventHook(l, ByteString::Build("tptevents-", eventName));
3683 }
3684
event_getmodifiers(lua_State * l)3685 int LuaScriptInterface::event_getmodifiers(lua_State * l)
3686 {
3687 lua_pushnumber(l, GetModifiers());
3688 return 1;
3689 }
3690
3691 class RequestHandle
3692 {
3693 http::Request *request;
3694 bool dead;
3695
3696 public:
RequestHandle(ByteString & uri,bool isPost,std::map<ByteString,ByteString> & post_data,std::map<ByteString,ByteString> & headers)3697 RequestHandle(ByteString &uri, bool isPost, std::map<ByteString, ByteString> &post_data, std::map<ByteString, ByteString> &headers)
3698 {
3699 dead = false;
3700 request = new http::Request(uri);
3701 for (auto &header : headers)
3702 {
3703 request->AddHeader(header.first, header.second);
3704 }
3705 if (isPost)
3706 request->AddPostData(post_data);
3707 request->Start();
3708 }
3709
~RequestHandle()3710 ~RequestHandle()
3711 {
3712 if (!Dead())
3713 {
3714 Cancel();
3715 }
3716 }
3717
Dead() const3718 bool Dead() const
3719 {
3720 return dead;
3721 }
3722
Done() const3723 bool Done() const
3724 {
3725 return dead || request->CheckDone();
3726 }
3727
Progress(int * total,int * done)3728 void Progress(int *total, int *done)
3729 {
3730 if (!dead)
3731 {
3732 request->CheckProgress(total, done);
3733 }
3734 }
3735
Cancel()3736 void Cancel()
3737 {
3738 if (!dead)
3739 {
3740 request->Cancel();
3741 dead = true;
3742 }
3743 }
3744
Finish(int * status_out)3745 ByteString Finish(int *status_out)
3746 {
3747 ByteString data;
3748 if (!dead)
3749 {
3750 if (request->CheckDone())
3751 {
3752 data = request->Finish(status_out);
3753 dead = true;
3754 }
3755 }
3756 return data;
3757 }
3758 };
3759
http_request_gc(lua_State * l)3760 static int http_request_gc(lua_State *l)
3761 {
3762 auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
3763 rh->~RequestHandle();
3764 return 0;
3765 }
3766
http_request_status(lua_State * l)3767 static int http_request_status(lua_State *l)
3768 {
3769 auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
3770 if (rh->Dead())
3771 {
3772 lua_pushliteral(l, "dead");
3773 }
3774 else if (rh->Done())
3775 {
3776 lua_pushliteral(l, "done");
3777 }
3778 else
3779 {
3780 lua_pushliteral(l, "running");
3781 }
3782 return 1;
3783 }
3784
http_request_progress(lua_State * l)3785 static int http_request_progress(lua_State *l)
3786 {
3787 auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
3788 if (!rh->Dead())
3789 {
3790 int total, done;
3791 rh->Progress(&total, &done);
3792 lua_pushinteger(l, total);
3793 lua_pushinteger(l, done);
3794 return 2;
3795 }
3796 return 0;
3797 }
3798
http_request_cancel(lua_State * l)3799 static int http_request_cancel(lua_State *l)
3800 {
3801 auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
3802 if (!rh->Dead())
3803 {
3804 rh->Cancel();
3805 }
3806 return 0;
3807 }
3808
http_request_finish(lua_State * l)3809 static int http_request_finish(lua_State *l)
3810 {
3811 auto *rh = (RequestHandle *)luaL_checkudata(l, 1, "HTTPRequest");
3812 if (!rh->Dead())
3813 {
3814 int status_out;
3815 ByteString data = rh->Finish(&status_out);
3816 lua_pushlstring(l, data.c_str(), data.size());
3817 lua_pushinteger(l, status_out);
3818 return 2;
3819 }
3820 return 0;
3821 }
3822
http_request(lua_State * l,bool isPost)3823 static int http_request(lua_State *l, bool isPost)
3824 {
3825 ByteString uri(luaL_checkstring(l, 1));
3826 std::map<ByteString, ByteString> post_data;
3827 if (isPost)
3828 {
3829 if (lua_istable(l, 2))
3830 {
3831 lua_pushnil(l);
3832 while (lua_next(l, 2))
3833 {
3834 lua_pushvalue(l, -2);
3835 post_data.emplace(lua_tostring(l, -1), lua_tostring(l, -2));
3836 lua_pop(l, 2);
3837 }
3838 }
3839 }
3840
3841 std::map<ByteString, ByteString> headers;
3842 if (lua_istable(l, isPost ? 3 : 2))
3843 {
3844 lua_pushnil(l);
3845 while (lua_next(l, isPost ? 3 : 2))
3846 {
3847 lua_pushvalue(l, -2);
3848 headers.emplace(lua_tostring(l, -1), lua_tostring(l, -2));
3849 lua_pop(l, 2);
3850 }
3851 }
3852 auto *rh = (RequestHandle *)lua_newuserdata(l, sizeof(RequestHandle));
3853 if (!rh)
3854 {
3855 return 0;
3856 }
3857 new(rh) RequestHandle(uri, isPost, post_data, headers);
3858 luaL_newmetatable(l, "HTTPRequest");
3859 lua_setmetatable(l, -2);
3860 return 1;
3861 }
3862
3863
http_get(lua_State * l)3864 int LuaScriptInterface::http_get(lua_State * l)
3865 {
3866 return http_request(l, false);
3867 }
3868
http_post(lua_State * l)3869 int LuaScriptInterface::http_post(lua_State * l)
3870 {
3871 return http_request(l, true);
3872 }
3873
initHttpAPI()3874 void LuaScriptInterface::initHttpAPI()
3875 {
3876 luaL_newmetatable(l, "HTTPRequest");
3877 lua_pushcfunction(l, http_request_gc);
3878 lua_setfield(l, -2, "__gc");
3879 lua_newtable(l);
3880 lua_pushcfunction(l, http_request_status);
3881 lua_setfield(l, -2, "status");
3882 lua_pushcfunction(l, http_request_progress);
3883 lua_setfield(l, -2, "progress");
3884 lua_pushcfunction(l, http_request_cancel);
3885 lua_setfield(l, -2, "cancel");
3886 lua_pushcfunction(l, http_request_finish);
3887 lua_setfield(l, -2, "finish");
3888 lua_setfield(l, -2, "__index");
3889 struct luaL_Reg httpAPIMethods [] = {
3890 {"get", http_get},
3891 {"post", http_post},
3892 {NULL, NULL}
3893 };
3894 luaL_register(l, "http", httpAPIMethods);
3895 }
3896
HandleEvent(LuaEvents::EventTypes eventType,Event * event)3897 bool LuaScriptInterface::HandleEvent(LuaEvents::EventTypes eventType, Event * event)
3898 {
3899 return LuaEvents::HandleEvent(this, event, ByteString::Build("tptevents-", eventType));
3900 }
3901
OnTick()3902 void LuaScriptInterface::OnTick()
3903 {
3904 lua_getglobal(l, "simulation");
3905 if (lua_istable(l, -1))
3906 {
3907 lua_pushinteger(l, luacon_sim->NUM_PARTS);
3908 lua_setfield(l, -2, "NUM_PARTS");
3909 }
3910 lua_pop(l, 1);
3911 TickEvent ev;
3912 HandleEvent(LuaEvents::tick, &ev);
3913 }
3914
Command(String command)3915 int LuaScriptInterface::Command(String command)
3916 {
3917 if (command[0] == '!')
3918 {
3919 lastError = "";
3920 int ret = legacy->Command(command.Substr(1));
3921 lastError = legacy->GetLastError();
3922 return ret;
3923 }
3924 else
3925 {
3926 int level = lua_gettop(l), ret = -1;
3927 String text = "";
3928 lastError = "";
3929 currentCommand = true;
3930 if (lastCode.length())
3931 lastCode += "\n";
3932 lastCode += command;
3933 String tmp = "return " + lastCode;
3934 ui::Engine::Ref().LastTick(Platform::GetTime());
3935 luaL_loadbuffer(l, tmp.ToUtf8().c_str(), tmp.length(), "@console");
3936 if (lua_type(l, -1) != LUA_TFUNCTION)
3937 {
3938 lua_pop(l, 1);
3939 luaL_loadbuffer(l, lastCode.ToUtf8().c_str(), lastCode.length(), "@console");
3940 }
3941 if (lua_type(l, -1) != LUA_TFUNCTION)
3942 {
3943 lastError = luacon_geterror();
3944 String err = lastError;
3945 if (err.Contains("near '<eof>'")) //the idea stolen from lua-5.1.5/lua.c
3946 lastError = "...";
3947 else
3948 lastCode = "";
3949 }
3950 else
3951 {
3952 lastCode = "";
3953 ret = lua_pcall(l, 0, LUA_MULTRET, 0);
3954 if (ret)
3955 lastError = luacon_geterror();
3956 else
3957 {
3958 for (level++;level<=lua_gettop(l);level++)
3959 {
3960 luaL_tostring(l, level);
3961 if (text.length())
3962 text += ", " + ByteString(luaL_optstring(l, -1, "")).FromUtf8();
3963 else
3964 text = ByteString(luaL_optstring(l, -1, "")).FromUtf8();
3965 lua_pop(l, 1);
3966 }
3967 if (text.length())
3968 {
3969 if (lastError.length())
3970 lastError += "; " + text;
3971 else
3972 lastError = text;
3973 }
3974
3975 }
3976 }
3977 currentCommand = false;
3978 return ret;
3979 }
3980 }
3981
strlcmp(const char * a,const char * b,int len)3982 int strlcmp(const char* a, const char* b, int len)
3983 {
3984 while(len)
3985 {
3986 if(!*b)
3987 return 1;
3988 if(*a>*b)
3989 return -1;
3990 if(*a<*b)
3991 return 1;
3992 a++;
3993 b++;
3994 len--;
3995 }
3996 if(!*b)
3997 return 0;
3998 return -1;
3999 }
4000
highlight(String command)4001 String highlight(String command)
4002 {
4003 StringBuilder result;
4004 int pos = 0;
4005 String::value_type const*raw = command.c_str();
4006 String::value_type c;
4007 while ((c = raw[pos]))
4008 {
4009 if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
4010 {
4011 int len = 0;
4012 String::value_type w;
4013 String::value_type const* wstart = raw+pos;
4014 while((w = wstart[len]) && ((w >= 'A' && w <= 'Z') || (w >= 'a' && w <= 'z') || (w >= '0' && w <= '9') || w == '_'))
4015 len++;
4016 #define CMP(X) (String(wstart, len) == X)
4017 if(CMP("and") || CMP("break") || CMP("do") || CMP("else") || CMP("elseif") || CMP("end") || CMP("for") || CMP("function") || CMP("if") || CMP("in") || CMP("local") || CMP("not") || CMP("or") || CMP("repeat") || CMP("return") || CMP("then") || CMP("until") || CMP("while"))
4018 result << "\x0F\xB5\x89\x01" << String(wstart, len) << "\bw";
4019 else if(CMP("false") || CMP("nil") || CMP("true"))
4020 result << "\x0F\xCB\x4B\x16" << String(wstart, len) << "\bw";
4021 else
4022 result << "\x0F\x2A\xA1\x98" << String(wstart, len) << "\bw";
4023 #undef CMP
4024 pos += len;
4025 }
4026 else if((c >= '0' && c <= '9') || (c == '.' && raw[pos + 1] >= '0' && raw[pos + 1] <= '9'))
4027 {
4028 if(c == '0' && raw[pos + 1] == 'x')
4029 {
4030 int len = 2;
4031 String::value_type w;
4032 String::value_type const* wstart = raw+pos;
4033 while((w = wstart[len]) && ((w >= '0' && w <= '9') || (w >= 'A' && w <= 'F') || (w >= 'a' && w <= 'f')))
4034 len++;
4035 result << "\x0F\xD3\x36\x82" << String(wstart, len) << "\bw";
4036 pos += len;
4037 }
4038 else
4039 {
4040 int len = 0;
4041 String::value_type w;
4042 String::value_type const* wstart = raw+pos;
4043 bool seendot = false;
4044 while((w = wstart[len]) && ((w >= '0' && w <= '9') || w == '.'))
4045 {
4046 if(w == '.')
4047 {
4048 if(seendot)
4049 break;
4050 else
4051 seendot = true;
4052 }
4053 len++;
4054 }
4055 if(w == 'e')
4056 {
4057 len++;
4058 w = wstart[len];
4059 if(w == '+' || w == '-')
4060 len++;
4061 while((w = wstart[len]) && (w >= '0' && w <= '9'))
4062 len++;
4063 }
4064 result << "\x0F\xD3\x36\x82" << String(wstart, len) << "\bw";
4065 pos += len;
4066 }
4067 }
4068 else if(c == '\'' || c == '"' || (c == '[' && (raw[pos + 1] == '[' || raw[pos + 1] == '=')))
4069 {
4070 if(c == '[')
4071 {
4072 int len = 1, eqs=0;
4073 String::value_type w;
4074 String::value_type const* wstart = raw + pos;
4075 while((w = wstart[len]) && (w == '='))
4076 {
4077 eqs++;
4078 len++;
4079 }
4080 while((w = wstart[len]))
4081 {
4082 if(w == ']')
4083 {
4084 int nlen = 1;
4085 String::value_type const* cstart = wstart + len;
4086 while((w = cstart[nlen]) && (w == '='))
4087 nlen++;
4088 if(w == ']' && nlen == eqs+1)
4089 {
4090 len += nlen+1;
4091 break;
4092 }
4093 }
4094 len++;
4095 }
4096 result << "\x0F\xDC\x32\x2F" << String(wstart, len) << "\bw";
4097 pos += len;
4098 }
4099 else
4100 {
4101 int len = 1;
4102 String::value_type w;
4103 String::value_type const* wstart = raw+pos;
4104 while((w = wstart[len]) && (w != c))
4105 {
4106 if(w == '\\' && wstart[len + 1])
4107 len++;
4108 len++;
4109 }
4110 if(w == c)
4111 len++;
4112 result << "\x0F\xDC\x32\x2F" << String(wstart, len) << "\bw";
4113 pos += len;
4114 }
4115 }
4116 else if(c == '-' && raw[pos + 1] == '-')
4117 {
4118 if(raw[pos + 2] == '[')
4119 {
4120 int len = 3, eqs = 0;
4121 String::value_type w;
4122 String::value_type const* wstart = raw + pos;
4123 while((w = wstart[len]) && (w == '='))
4124 {
4125 eqs++;
4126 len++;
4127 }
4128 while((w = wstart[len]))
4129 {
4130 if(w == ']')
4131 {
4132 int nlen = 1;
4133 String::value_type const* cstart = wstart + len;
4134 while((w = cstart[nlen]) && (w == '='))
4135 nlen++;
4136 if(w == ']' && nlen == eqs + 1)
4137 {
4138 len += nlen+1;
4139 break;
4140 }
4141 }
4142 len++;
4143 }
4144 result << "\x0F\x85\x99\x01" << String(wstart, len) << "\bw";
4145 pos += len;
4146 }
4147 else
4148 {
4149 int len = 2;
4150 String::value_type w;
4151 String::value_type const* wstart = raw + pos;
4152 while((w = wstart[len]) && (w != '\n'))
4153 len++;
4154 result << "\x0F\x85\x99\x01" << String(wstart, len) << "\bw";
4155 pos += len;
4156 }
4157 }
4158 else if(c == '{' || c == '}')
4159 {
4160 result << "\x0F\xCB\x4B\x16" << c << "\bw";
4161 pos++;
4162 }
4163 else if(c == '.' && raw[pos + 1] == '.' && raw[pos + 2] == '.')
4164 {
4165 result << "\x0F\x2A\xA1\x98...\bw";
4166 pos += 3;
4167 }
4168 else
4169 {
4170 result << c;
4171 pos++;
4172 }
4173 }
4174 return result.Build();
4175 }
4176
FormatCommand(String command)4177 String LuaScriptInterface::FormatCommand(String command)
4178 {
4179 if(command.size() && command[0] == '!')
4180 {
4181 return "!"+legacy->FormatCommand(command.Substr(1));
4182 }
4183 else
4184 return highlight(command);
4185 }
4186
~LuaScriptInterface()4187 LuaScriptInterface::~LuaScriptInterface() {
4188 delete tptPart;
4189 for (auto &component_and_ref : grabbed_components)
4190 {
4191 luacon_ci->Window->RemoveComponent(component_and_ref.first->GetComponent());
4192 component_and_ref.second.Clear();
4193 component_and_ref.first->owner_ref = component_and_ref.second;
4194 }
4195 lua_el_mode_v.clear();
4196 lua_el_func_v.clear();
4197 lua_gr_func_v.clear();
4198 lua_cd_func_v.clear();
4199 lua_close(l);
4200 delete legacy;
4201 }
4202 #endif
4203