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 = &currentCommand;
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