1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/endian.h"
24 #include "common/savefile.h"
25 #include "common/system.h"
26 #include "common/config-manager.h"
27 
28 #include "graphics/pixelbuffer.h"
29 #include "graphics/renderer.h"
30 #include "graphics/colormasks.h"
31 
32 #include "math/matrix3.h"
33 
34 #include "engines/grim/debug.h"
35 #include "engines/grim/lua_v1.h"
36 #include "engines/grim/registry.h"
37 #include "engines/grim/grim.h"
38 #include "engines/grim/savegame.h"
39 #include "engines/grim/resource.h"
40 #include "engines/grim/bitmap.h"
41 #include "engines/grim/font.h"
42 #include "engines/grim/gfx_base.h"
43 #include "engines/grim/localize.h"
44 
45 #include "engines/grim/lua/lauxlib.h"
46 #include "engines/grim/lua/luadebug.h"
47 
48 namespace Grim {
49 
clamp_color(int c)50 byte clamp_color(int c) {
51 	if (c < 0)
52 		return 0;
53 	else if (c > 255)
54 		return 255;
55 	else
56 		return c;
57 }
58 
59 int luaA_passresults();
60 
new_dofile()61 void Lua_V1::new_dofile() {
62 	const char *fname_str = luaL_check_string(1);
63 	if (dofile(fname_str) == 0)
64 		if (luaA_passresults() == 0)
65 			lua_pushuserdata(0);
66 }
67 
68 // Debugging message functions
69 
PrintDebug()70 void Lua_V1::PrintDebug() {
71 	if (Debug::isChannelEnabled(Debug::Scripts | Debug::Info)) {
72 		Common::String msg("Debug: ");
73 		lua_Object strObj = lua_getparam(1);
74 		if (lua_isnil(strObj))
75 			msg += "(nil)";
76 		if (!lua_isstring(strObj))
77 			return;
78 		msg += Common::String(lua_getstring(strObj));
79 		debugN("%s", msg.c_str());
80 	}
81 }
82 
PrintError()83 void Lua_V1::PrintError() {
84 	if (Debug::isChannelEnabled(Debug::Scripts | Debug::Error)) {
85 		Common::String msg("Error: ");
86 		lua_Object strObj = lua_getparam(1);
87 		if (lua_isnil(strObj))
88 			msg += "(nil)";
89 		if (!lua_isstring(strObj))
90 			return;
91 		msg += Common::String(lua_getstring(strObj));
92 		debugN("%s", msg.c_str());
93 	}
94 }
95 
PrintWarning()96 void Lua_V1::PrintWarning() {
97 	if (Debug::isChannelEnabled(Debug::Scripts | Debug::Warning)) {
98 		Common::String msg("Warning: ");
99 		lua_Object strObj = lua_getparam(1);
100 		if (lua_isnil(strObj))
101 			msg += "(nil)";
102 		if (!lua_isstring(strObj))
103 			return;
104 		msg += Common::String(lua_getstring(strObj));
105 		debugN("%s", msg.c_str());
106 	}
107 }
108 
FunctionName()109 void Lua_V1::FunctionName() {
110 	const char *name;
111 	char buf[256];
112 	const char *filename = nullptr;
113 	int32 line;
114 	lua_Object param1 = lua_getparam(1);
115 
116 	if (!lua_isfunction(param1)) {
117 		sprintf(buf, "function InvalidArgsToFunctionName");
118 		lua_pushstring(buf);
119 		return;
120 	}
121 
122 	lua_funcinfo(param1, &filename, &line);
123 	switch (*lua_getobjname(param1, &name)) {
124 	case 'g':
125 		sprintf(buf, "function %.100s", name);
126 		break;
127 	case 't':
128 		sprintf(buf, "`%.100s' tag method", name);
129 		break;
130 	default:
131 		{
132 			if (line == 0)
133 				sprintf(buf, "main of %.100s", filename);
134 			else if (line < 0)
135 				sprintf(buf, "%.100s", filename);
136 			else {
137 				sprintf(buf, "function (%.100s:%d)", filename, (int)line);
138 				filename = nullptr;
139 			}
140 		}
141 	}
142 	int curr_line = lua_currentline(param1);
143 	if (curr_line > 0)
144 		sprintf(buf + strlen(buf), " at line %d", curr_line);
145 	if (filename)
146 		sprintf(buf + strlen(buf), " [in file %.100s]", filename);
147 	lua_pushstring(buf);
148 }
149 
CheckForFile()150 void Lua_V1::CheckForFile() {
151 	lua_Object strObj = lua_getparam(1);
152 
153 	if (!lua_isstring(strObj))
154 		return;
155 
156 	const char *filename = lua_getstring(strObj);
157 	pushbool(SearchMan.hasFile(filename));
158 }
159 
MakeColor()160 void Lua_V1::MakeColor() {
161 	lua_Object rObj = lua_getparam(1);
162 	lua_Object gObj = lua_getparam(2);
163 	lua_Object bObj = lua_getparam(3);
164 	int r, g, b;
165 
166 	if (!lua_isnumber(rObj))
167 		r = 0;
168 	else
169 		r = clamp_color((int)lua_getnumber(rObj));
170 
171 	if (!lua_isnumber(gObj))
172 		g = 0;
173 	else
174 		g = clamp_color((int)lua_getnumber(gObj));
175 
176 	if (!lua_isnumber(bObj))
177 		b = 0;
178 	else
179 		b = clamp_color((int)lua_getnumber(bObj));
180 
181 	Color c(r, g, b);
182 	int32 cTag = c.toEncodedValue();
183 	if (g_grim->getGameType() == GType_MONKEY4)
184 		cTag |= (0xFF << 24);
185 	lua_pushusertag(cTag, MKTAG('C','O','L','R'));
186 }
187 
GetColorComponents()188 void Lua_V1::GetColorComponents() {
189 	lua_Object colorObj = lua_getparam(1);
190 	Color c(getcolor(colorObj));
191 	lua_pushnumber(c.getRed());
192 	lua_pushnumber(c.getGreen());
193 	lua_pushnumber(c.getBlue());
194 }
195 
ReadRegistryValue()196 void Lua_V1::ReadRegistryValue() {
197 	lua_Object keyObj = lua_getparam(1);
198 
199 	if (!lua_isstring(keyObj)) {
200 		lua_pushnil();
201 		return;
202 	}
203 	const char *key = lua_getstring(keyObj);
204 
205 	Registry::ValueType type = g_registry->getValueType(key);
206 	switch (type) {
207 	case Registry::String:
208 		lua_pushstring(g_registry->getString(key).c_str());
209 		break;
210 	case Registry::Integer:
211 		lua_pushnumber(g_registry->getInt(key));
212 		break;
213 	case Registry::Boolean:
214 		pushbool(g_registry->getBool(key));
215 		break;
216 	}
217 }
218 
WriteRegistryValue()219 void Lua_V1::WriteRegistryValue() {
220 	lua_Object keyObj = lua_getparam(1);
221 	lua_Object valObj = lua_getparam(2);
222 
223 	if (!lua_isstring(keyObj))
224 		return;
225 
226 	const char *key = lua_getstring(keyObj);
227 	if (strcmp(key, "GrimMannyState") == 0) //This isn't used. it's probably a left over from testing phase.
228 		return;
229 
230 	// Check isnumber first, because isstring returns true for numbers
231 	if (lua_isnumber(valObj)) {
232 		int val = (int)lua_getnumber(valObj);
233 		g_registry->setInt(key, val);
234 	} else if (lua_isstring(valObj)) {
235 		const char *val = lua_getstring(valObj);
236 		g_registry->setString(key, val);
237 	}
238 }
239 
GetAngleBetweenVectors()240 void Lua_V1::GetAngleBetweenVectors() {
241 	lua_Object vec1Obj = lua_getparam(1);
242 	lua_Object vec2Obj = lua_getparam(2);
243 
244 	if (!lua_istable(vec1Obj) || !lua_istable(vec2Obj)) {
245 		lua_pushnil();
246 		return;
247 	}
248 
249 	lua_pushobject(vec1Obj);
250 	lua_pushstring("x");
251 	lua_Object table = lua_gettable();
252 	float x1 = lua_getnumber(table);
253 	lua_pushobject(vec1Obj);
254 	lua_pushstring("y");
255 	table = lua_gettable();
256 	float y1 = lua_getnumber(table);
257 	lua_pushobject(vec1Obj);
258 	lua_pushstring("z");
259 	table = lua_gettable();
260 	float z1 = lua_getnumber(table);
261 	lua_pushobject(vec2Obj);
262 	lua_pushstring("x");
263 	table = lua_gettable();
264 	float x2 = lua_getnumber(table);
265 	lua_pushobject(vec2Obj);
266 	lua_pushstring("y");
267 	table = lua_gettable();
268 	float y2 = lua_getnumber(table);
269 	lua_pushobject(vec2Obj);
270 	lua_pushstring("z");
271 	table = lua_gettable();
272 	float z2 = lua_getnumber(table);
273 
274 	Math::Vector3d vec1(x1, y1, z1);
275 	Math::Vector3d vec2(x2, y2, z2);
276 	vec1.normalize();
277 	vec2.normalize();
278 
279 	float dot = vec1.dotProduct(vec2);
280 	float angle = 90.0f - (180.0f * asin(dot)) / LOCAL_PI;
281 	if (angle < 0)
282 		angle = -angle;
283 	lua_pushnumber(angle);
284 }
285 
Is3DHardwareEnabled()286 void Lua_V1::Is3DHardwareEnabled() {
287 	pushbool(g_driver->isHardwareAccelerated());
288 }
289 
SetHardwareState()290 void Lua_V1::SetHardwareState() {
291 	// changing only in config setup (software/hardware rendering)
292 	bool accel = getbool(1);
293 
294 	Graphics::RendererType renderer = accel ? Graphics::kRendererTypeOpenGL : Graphics::kRendererTypeTinyGL;
295 	renderer = Graphics::getBestMatchingAvailableRendererType(renderer);
296 	ConfMan.set("renderer", Graphics::getRendererTypeCode(renderer));
297 
298 	g_grim->changeHardwareState();
299 }
300 
SetVideoDevices()301 void Lua_V1::SetVideoDevices() {
302 	/*int devId = (int)*/lua_getnumber(lua_getparam(1));
303 	/*int modeId = (int)*/lua_getnumber(lua_getparam(2));
304 	// ignore setting video devices
305 }
306 
GetVideoDevices()307 void Lua_V1::GetVideoDevices() {
308 	lua_pushnumber(0.0);
309 	lua_pushnumber(-1.0);
310 }
311 
EnumerateVideoDevices()312 void Lua_V1::EnumerateVideoDevices() {
313 	lua_Object result = lua_createtable();
314 	lua_pushobject(result);
315 	lua_pushnumber(0.0); // id of device
316 	lua_pushstring(g_driver->getVideoDeviceName()); // name of device
317 	lua_settable();
318 	lua_pushobject(result);
319 }
320 
Enumerate3DDevices()321 void Lua_V1::Enumerate3DDevices() {
322 	lua_Object result = lua_createtable();
323 	lua_Object numObj = lua_getparam(1);
324 	if (!lua_isnumber(numObj))
325 		return;
326 /*	int num = (int)lua_getnumber(numObj);*/
327 	lua_pushobject(result);
328 	lua_pushnumber(-1.0);
329 	if (g_driver->isHardwareAccelerated()) {
330 		lua_pushstring("OpenGL"); // type of 3d renderer
331 	} else {
332 		lua_pushstring("/engn003/Software"); // type of 3d renderer
333 	}
334 	lua_settable();
335 	lua_pushobject(result);
336 }
337 
338 /* RotateVector takes a vector and rotates it around
339  * the point (0,0,0) by the requested number of degrees.
340  * This function is used to calculate the locations for
341  * getting on and off of the Bone Wagon and for going up
342  * and down the slide with the chain at the end of the world.
343  */
RotateVector()344 void Lua_V1::RotateVector() {
345 	lua_Object vecObj = lua_getparam(1);
346 	lua_Object rotObj = lua_getparam(2);
347 
348 	if (!lua_istable(vecObj) || !lua_istable(rotObj)) {
349 		lua_pushnil();
350 		return;
351 	}
352 
353 	lua_pushobject(vecObj);
354 	lua_pushstring("x");
355 	float x = lua_getnumber(lua_gettable());
356 	lua_pushobject(vecObj);
357 	lua_pushstring("y");
358 	float y = lua_getnumber(lua_gettable());
359 	lua_pushobject(vecObj);
360 	lua_pushstring("z");
361 	float z = lua_getnumber(lua_gettable());
362 	Math::Vector3d vec(x, y, z);
363 
364 	lua_pushobject(rotObj);
365 	lua_pushstring("x");
366 	Math::Angle pitch = lua_getnumber(lua_gettable());
367 	lua_pushobject(rotObj);
368 	lua_pushstring("y");
369 	Math::Angle yaw = lua_getnumber(lua_gettable());
370 	lua_pushobject(rotObj);
371 	lua_pushstring("z");
372 	Math::Angle roll = lua_getnumber(lua_gettable());
373 
374 	Math::Matrix3 mat;
375 	mat.buildFromEuler(yaw, pitch, roll, Math::EO_ZXY);
376 	mat.transformVector(&vec);
377 
378 	lua_Object resObj = lua_createtable();
379 	lua_pushobject(resObj);
380 	lua_pushstring("x");
381 	lua_pushnumber(vec.x());
382 	lua_settable();
383 	lua_pushobject(resObj);
384 	lua_pushstring("y");
385 	lua_pushnumber(vec.y());
386 	lua_settable();
387 	lua_pushobject(resObj);
388 	lua_pushstring("z");
389 	lua_pushnumber(vec.z());
390 	lua_settable();
391 
392 	lua_pushobject(resObj);
393 }
394 
FileFindDispose()395 void Lua_V1::FileFindDispose() {
396 	g_grim->_listFiles.clear();
397 	g_grim->_listFilesIter = nullptr;
398 }
399 
FileFindNext()400 void Lua_V1::FileFindNext() {
401 	if (g_grim->_listFilesIter == g_grim->_listFiles.end()) {
402 		lua_pushnil();
403 		Lua_V1::FileFindDispose();
404 	} else {
405 		lua_pushstring(g_grim->_listFilesIter->c_str());
406 		g_grim->_listFilesIter++;
407 	}
408 }
409 
FileFindFirst()410 void Lua_V1::FileFindFirst() {
411 	lua_Object extObj = lua_getparam(1);
412 	if (!lua_isstring(extObj)) {
413 		lua_pushnil();
414 		return;
415 	}
416 
417 	Lua_V1::FileFindDispose();
418 
419 	const char *extension = lua_getstring(extObj);
420 	Common::String searchString = extension;
421 	if (searchString == "*.gsv") {
422 		searchString = "grim##.gsv";
423 	}
424 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
425 	g_grim->_listFiles = saveFileMan->listSavefiles(searchString);
426 	Common::sort(g_grim->_listFiles.begin(), g_grim->_listFiles.end());
427 	g_grim->_listFilesIter = g_grim->_listFiles.begin();
428 
429 	if (g_grim->_listFilesIter == g_grim->_listFiles.end())
430 		lua_pushnil();
431 	else
432 		Lua_V1::FileFindNext();
433 }
434 
PerSecond()435 void Lua_V1::PerSecond() {
436 	lua_Object rateObj = lua_getparam(1);
437 
438 	if (!lua_isnumber(rateObj)) {
439 		lua_pushnil();
440 		return;
441 	}
442 	float rate = lua_getnumber(rateObj);
443 	lua_pushnumber(g_grim->getPerSecond(rate));
444 }
445 
EnableControl()446 void Lua_V1::EnableControl() {
447 	lua_Object numObj = lua_getparam(1);
448 
449 	if (!lua_isnumber(numObj)) {
450 		lua_pushnil();
451 		return;
452 	}
453 	int num = (int)lua_getnumber(numObj);
454 	if (num < 0 || num >= KEYCODE_EXTRA_LAST)
455 		error("control identifier out of range");
456 
457 	g_grim->enableControl(num);
458 }
459 
DisableControl()460 void Lua_V1::DisableControl() {
461 	lua_Object numObj = lua_getparam(1);
462 
463 	if (!lua_isnumber(numObj)) {
464 		lua_pushnil();
465 		return;
466 	}
467 	int num = (int)lua_getnumber(numObj);
468 	if (num < 0 || num >= KEYCODE_EXTRA_LAST)
469 		error("control identifier out of range");
470 
471 	g_grim->disableControl(num);
472 }
473 
GetControlState()474 void Lua_V1::GetControlState() {
475 	lua_Object numObj = lua_getparam(1);
476 
477 	if (!lua_isnumber(numObj))
478 		return;
479 
480 	int num = (int)lua_getnumber(numObj);
481 	if (num < 0 || num >= KEYCODE_EXTRA_LAST)
482 		error("control identifier out of range");
483 	if (num >= KEYCODE_AXIS_JOY1_X && num <= KEYCODE_AXIS_MOUSE_Z)
484 		lua_pushnumber(g_grim->getControlAxis(num));
485 	else {
486 		pushbool(g_grim->getControlState(num)); // key down, originaly it push number if key down
487 		//pushnil or number, what is is ?
488 	}
489 }
490 
Exit()491 void Lua_V1::Exit() {
492 	g_grim->quitGame();
493 }
494 
SetSpeechMode()495 void Lua_V1::SetSpeechMode() {
496 	GrimEngine::SpeechMode mode = (GrimEngine::SpeechMode)((int)lua_getnumber(lua_getparam(1)));
497 	if (mode >= 1 && mode <= 3)
498 		g_grim->setSpeechMode(mode);
499 }
500 
GetSpeechMode()501 void Lua_V1::GetSpeechMode() {
502 	lua_pushnumber(g_grim->getSpeechMode());
503 }
504 
GetDiskFreeSpace()505 void Lua_V1::GetDiskFreeSpace() {
506 	//the ps2 version of emi wants more than 600 KB
507 	//grim: amount of free space in MB, used for creating saves
508 	lua_pushnumber(700);
509 }
510 
GetCurrentScript()511 void Lua_V1::GetCurrentScript() {
512 	current_script();
513 }
514 
GetSaveGameImage()515 void Lua_V1::GetSaveGameImage() {
516 	int width = 250, height = 188;
517 	Bitmap *screenshot;
518 	int dataSize;
519 
520 	lua_Object param = lua_getparam(1);
521 	if (!lua_isstring(param)) {
522 		lua_pushnil();
523 		return;
524 	}
525 	const char *filename = lua_getstring(param);
526 	SaveGame *savedState = SaveGame::openForLoading(filename);
527 	if (!savedState || !savedState->isCompatible()) {
528 		delete savedState;
529 		lua_pushnil();
530 		return;
531 	}
532 	dataSize = savedState->beginSection('SIMG');
533 	uint16 *data = new uint16[dataSize / 2];
534 	for (int l = 0; l < dataSize / 2; l++) {
535 		data[l] = savedState->readLEUint16();
536 	}
537 	Graphics::PixelBuffer buf(Graphics::createPixelFormat<565>(), (byte *)data);
538 	screenshot = new Bitmap(buf, width, height, "screenshot");
539 	delete[] data;
540 	if (screenshot) {
541 		lua_pushusertag(screenshot->getId(), MKTAG('V','B','U','F'));
542 	} else {
543 		lua_pushnil();
544 		warning("Could not restore screenshot from file");
545 		delete savedState;
546 		return;
547 	}
548 	savedState->endSection();
549 	delete savedState;
550 }
551 
SubmitSaveGameData()552 void Lua_V1::SubmitSaveGameData() {
553 	lua_Object table, table2;
554 	SaveGame *savedState;
555 	const char *str;
556 	table = lua_getparam(1);
557 
558 	savedState = g_grim->savedState();
559 	if (!savedState)
560 		error("Cannot obtain saved game");
561 	savedState->beginSection('SUBS');
562 	int count = 0;
563 	Common::String localized;
564 	for (;;) {
565 		lua_pushobject(table);
566 		lua_pushnumber(count);
567 		count++;
568 		table2 = lua_gettable();
569 		if (lua_isnil(table2))
570 			break;
571 		str = lua_getstring(table2);
572 		if (g_grim->getGameType() == GType_MONKEY4 &&
573 			g_grim->getGamePlatform() == Common::kPlatformPS2) {
574 			if (count == 1) {
575 				localized = g_localizer->localize(str);
576 			}
577 		}
578 		int32 len = strlen(str) + 1;
579 		savedState->writeLESint32(len);
580 		savedState->write(str, len);
581 	}
582 	savedState->endSection();
583 
584 	//give ps2 saves a human-readable name
585 	if (g_grim->getGameType() == GType_MONKEY4 &&
586 		g_grim->getGamePlatform() == Common::kPlatformPS2) {
587 		savedState->beginSection('PS2S');
588 		savedState->writeLESint32(localized.size() + 1);
589 		savedState->write(localized.c_str(), localized.size() + 1);
590 		savedState->endSection();
591 	}
592 }
593 
GetSaveGameData()594 void Lua_V1::GetSaveGameData() {
595 	lua_Object param = lua_getparam(1);
596 	if (!lua_isstring(param))
597 		return;
598 	Common::String filename(lua_getstring(param));
599 	if (g_grim->getGameType() == GType_MONKEY4 &&
600 		g_grim->getGamePlatform() == Common::kPlatformPS2) {
601 		filename += ".ps2";
602 	}
603 	SaveGame *savedState = SaveGame::openForLoading(filename);
604 	lua_Object result = lua_createtable();
605 
606 	if (!savedState || !savedState->isCompatible()) {
607 		lua_pushobject(result);
608 		lua_pushnumber(2);
609 		lua_pushstring("mo.set"); // Just a placeholder to not make it throw a lua error
610 		lua_settable();
611 		lua_pushobject(result);
612 
613 		if (!savedState) {
614 			warning("Savegame %s is invalid", filename.c_str());
615 		} else {
616 			warning("Savegame %s is incompatible with this ResidualVM build. Save version: %d.%d; current version: %d.%d",
617 					filename.c_str(), savedState->saveMajorVersion(), savedState->saveMinorVersion(),
618 					SaveGame::SAVEGAME_MAJOR_VERSION, SaveGame::SAVEGAME_MINOR_VERSION);
619 		}
620 		delete savedState;
621 		return;
622 	}
623 	int32 dataSize = savedState->beginSection('SUBS');
624 
625 	char str[200];
626 	int32 strSize;
627 	int count = 0;
628 
629 	for (;;) {
630 		if (dataSize <= 0)
631 			break;
632 		strSize = savedState->readLESint32();
633 		savedState->read(str, strSize);
634 		lua_pushobject(result);
635 		lua_pushnumber(count);
636 		lua_pushstring(str);
637 		lua_settable();
638 		dataSize -= strSize;
639 		dataSize -= 4;
640 		count++;
641 	}
642 	lua_pushobject(result);
643 
644 	savedState->endSection();
645 	delete savedState;
646 }
647 
Load()648 void Lua_V1::Load() {
649 	lua_Object fileNameObj = lua_getparam(1);
650 	if (lua_isnil(fileNameObj)) {
651 		g_grim->loadGame("");
652 	} else if (lua_isstring(fileNameObj)) {
653 		Common::String fileName(lua_getstring(fileNameObj));
654 		if (g_grim->getGameType() == GType_MONKEY4 &&
655 			g_grim->getGamePlatform() == Common::kPlatformPS2) {
656 			fileName += ".ps2";
657 		}
658 		g_grim->loadGame(fileName);
659 	} else {
660 		warning("Load() fileName is wrong");
661 		return;
662 	}
663 }
664 
Save()665 void Lua_V1::Save() {
666 	lua_Object fileNameObj = lua_getparam(1);
667 	if (lua_isnil(fileNameObj)) {
668 		g_grim->saveGame("");
669 	} else if (lua_isstring(fileNameObj)) {
670 		Common::String fileName(lua_getstring(fileNameObj));
671 		if (g_grim->getGameType() == GType_MONKEY4 &&
672 			g_grim->getGamePlatform() == Common::kPlatformPS2) {
673 			fileName += ".ps2";
674 		}
675 		g_grim->saveGame(fileName);
676 	} else {
677 		warning("Save() fileName is wrong");
678 		return;
679 	}
680 }
681 
Remove()682 void Lua_V1::Remove() {
683 	if (g_system->getSavefileManager()->removeSavefile(luaL_check_string(1)))
684 		lua_pushuserdata(0);
685 	else {
686 		lua_pushnil();
687 		lua_pushstring(g_system->getSavefileManager()->getErrorDesc().c_str());
688 	}
689 }
690 
LockFont()691 void Lua_V1::LockFont() {
692 	lua_Object param1 = lua_getparam(1);
693 	if (lua_isstring(param1)) {
694 		const char *fontName = lua_getstring(param1);
695 		Font *result = g_resourceloader->loadFont(fontName);
696 		if (result) {
697 			lua_pushusertag(result->getId(), MKTAG('F','O','N','T'));
698 			return;
699 		}
700 	}
701 
702 	lua_pushnil();
703 }
704 
EnableDebugKeys()705 void Lua_V1::EnableDebugKeys() {
706 }
707 
LightMgrSetChange()708 void Lua_V1::LightMgrSetChange() {
709 	// that seems only used when some control panel is opened
710 }
711 
LightMgrStartup()712 void Lua_V1::LightMgrStartup() {
713 	// we will not implement this opcode
714 }
715 
JustLoaded()716 void Lua_V1::JustLoaded() {
717 	Debug::error("OPCODE USAGE VERIFICATION: JustLoaded");
718 }
719 
SetEmergencyFont()720 void Lua_V1::SetEmergencyFont() {
721 	Debug::error("OPCODE USAGE VERIFICATION: SetEmergencyFont");
722 }
723 
724 
725 // Stub function for builtin functions not yet implemented
stubWarning(const char * funcName)726 static void stubWarning(const char *funcName) {
727 	warning("Stub function: %s", funcName);
728 }
729 
730 #define STUB_FUNC(name) void name() { stubWarning(#name); }
731 
732 STUB_FUNC(Lua_V1::SetActorInvClipNode)
733 STUB_FUNC(Lua_V1::NukeResources)
734 STUB_FUNC(Lua_V1::ResetTextures)
735 STUB_FUNC(Lua_V1::AttachToResources)
736 STUB_FUNC(Lua_V1::DetachFromResources)
737 STUB_FUNC(Lua_V1::SetActorClipPlane)
738 STUB_FUNC(Lua_V1::SetActorClipActive)
739 STUB_FUNC(Lua_V1::FlushControls)
740 STUB_FUNC(Lua_V1::GetCameraLookVector)
741 STUB_FUNC(Lua_V1::SetCameraRoll)
742 STUB_FUNC(Lua_V1::SetCameraInterest)
743 STUB_FUNC(Lua_V1::GetCameraPosition)
744 STUB_FUNC(Lua_V1::SpewStartup)
745 STUB_FUNC(Lua_V1::WorldToScreen)
746 STUB_FUNC(Lua_V1::SetActorRoll)
747 STUB_FUNC(Lua_V1::SetActorFrustrumCull)
748 STUB_FUNC(Lua_V1::DriveActorTo)
749 STUB_FUNC(Lua_V1::GetTranslationMode)
750 STUB_FUNC(Lua_V1::SetTranslationMode)
751 STUB_FUNC(Lua_V1::WalkActorToAvoiding)
752 STUB_FUNC(Lua_V1::GetActorChores)
753 STUB_FUNC(Lua_V1::SetCameraPosition)
754 STUB_FUNC(Lua_V1::GetCameraFOV)
755 STUB_FUNC(Lua_V1::SetCameraFOV)
756 STUB_FUNC(Lua_V1::GetCameraRoll)
757 STUB_FUNC(Lua_V1::GetMemoryUsage)
758 STUB_FUNC(Lua_V1::GetFontDimensions)
759 STUB_FUNC(Lua_V1::PurgeText)
760 
761 struct luaL_reg grimMainOpcodes[] = {
762 	{ "EngineDisplay", LUA_OPCODE(Lua_V1, EngineDisplay) },
763 	{ "CheckForFile", LUA_OPCODE(Lua_V1, CheckForFile) },
764 	{ "Load", LUA_OPCODE(Lua_V1, Load) },
765 	{ "Save", LUA_OPCODE(Lua_V1, Save) },
766 	{ "remove", LUA_OPCODE(Lua_V1, Remove) },
767 	{ "SetActorColormap", LUA_OPCODE(Lua_V1, SetActorColormap) },
768 	{ "GetActorCostume", LUA_OPCODE(Lua_V1, GetActorCostume) },
769 	{ "SetActorCostume", LUA_OPCODE(Lua_V1, SetActorCostume) },
770 	{ "SetActorScale", LUA_OPCODE(Lua_V1, SetActorScale) },
771 	{ "GetActorTimeScale", LUA_OPCODE(Lua_V1, GetActorTimeScale) },
772 	{ "SetActorTimeScale", LUA_OPCODE(Lua_V1, SetActorTimeScale) },
773 	{ "GetActorNodeLocation", LUA_OPCODE(Lua_V1, GetActorNodeLocation) },
774 	{ "SetActorWalkChore", LUA_OPCODE(Lua_V1, SetActorWalkChore) },
775 	{ "SetActorTurnChores", LUA_OPCODE(Lua_V1, SetActorTurnChores) },
776 	{ "SetActorRestChore", LUA_OPCODE(Lua_V1, SetActorRestChore) },
777 	{ "SetActorMumblechore", LUA_OPCODE(Lua_V1, SetActorMumblechore) },
778 	{ "SetActorTalkChore", LUA_OPCODE(Lua_V1, SetActorTalkChore) },
779 	{ "SetActorWalkRate", LUA_OPCODE(Lua_V1, SetActorWalkRate) },
780 	{ "GetActorWalkRate", LUA_OPCODE(Lua_V1, GetActorWalkRate) },
781 	{ "SetActorTurnRate", LUA_OPCODE(Lua_V1, SetActorTurnRate) },
782 	{ "SetSelectedActor", LUA_OPCODE(Lua_V1, SetSelectedActor) },
783 	{ "LoadActor", LUA_OPCODE(Lua_V1, LoadActor) },
784 	{ "GetActorPos", LUA_OPCODE(Lua_V1, GetActorPos) },
785 	{ "GetActorRect", LUA_OPCODE(Lua_V1, GetActorRect) },
786 	{ "GetActorPuckVector", LUA_OPCODE(Lua_V1, GetActorPuckVector) },
787 	{ "GetActorYawToPoint", LUA_OPCODE(Lua_V1, GetActorYawToPoint) },
788 	{ "SetActorReflection", LUA_OPCODE(Lua_V1, SetActorReflection) },
789 	{ "PutActorAtInterest", LUA_OPCODE(Lua_V1, PutActorAtInterest) },
790 	{ "PutActorAt", LUA_OPCODE(Lua_V1, PutActorAt) },
791 	{ "PutActorInSet", LUA_OPCODE(Lua_V1, PutActorInSet) },
792 	{ "WalkActorVector", LUA_OPCODE(Lua_V1, WalkActorVector) },
793 	{ "WalkActorForward", LUA_OPCODE(Lua_V1, WalkActorForward) },
794 	{ "DriveActorTo", LUA_OPCODE(Lua_V1, DriveActorTo) },
795 	{ "WalkActorTo", LUA_OPCODE(Lua_V1, WalkActorTo) },
796 	{ "WalkActorToAvoiding", LUA_OPCODE(Lua_V1, WalkActorToAvoiding) },
797 	{ "ActorLookAt", LUA_OPCODE(Lua_V1, ActorLookAt) },
798 	{ "SetActorLookRate", LUA_OPCODE(Lua_V1, SetActorLookRate) },
799 	{ "GetActorLookRate", LUA_OPCODE(Lua_V1, GetActorLookRate) },
800 	{ "GetVisibleThings", LUA_OPCODE(Lua_V1, GetVisibleThings) },
801 	{ "GetCameraActor", LUA_OPCODE(Lua_V1, GetCameraActor) },
802 	{ "SetActorHead", LUA_OPCODE(Lua_V1, SetActorHead) },
803 	{ "SetActorVisibility", LUA_OPCODE(Lua_V1, SetActorVisibility) },
804 	{ "SetActorFollowBoxes", LUA_OPCODE(Lua_V1, SetActorFollowBoxes) },
805 	{ "ShutUpActor", LUA_OPCODE(Lua_V1, ShutUpActor) },
806 	{ "SetActorFrustrumCull", LUA_OPCODE(Lua_V1, SetActorFrustrumCull) },
807 	{ "IsActorInSector", LUA_OPCODE(Lua_V1, IsActorInSector) },
808 	{ "GetActorSector", LUA_OPCODE(Lua_V1, GetActorSector) },
809 	{ "IsPointInSector", LUA_OPCODE(Lua_V1, IsPointInSector) },
810 	{ "GetPointSector", LUA_OPCODE(Lua_V1, GetPointSector) },
811 	{ "TurnActor", LUA_OPCODE(Lua_V1, TurnActor) },
812 	{ "GetActorRot", LUA_OPCODE(Lua_V1, GetActorRot) },
813 	{ "SetActorRot", LUA_OPCODE(Lua_V1, SetActorRot) },
814 	{ "SetActorPitch", LUA_OPCODE(Lua_V1, SetActorPitch) },
815 	{ "SetActorRoll", LUA_OPCODE(Lua_V1, SetActorRoll) },
816 	{ "IsActorTurning", LUA_OPCODE(Lua_V1, IsActorTurning) },
817 	{ "PlayActorChore", LUA_OPCODE(Lua_V1, PlayActorChore) },
818 	{ "PlayActorChoreLooping", LUA_OPCODE(Lua_V1, PlayActorChoreLooping) },
819 	{ "StopActorChore", LUA_OPCODE(Lua_V1, StopActorChore) },
820 	{ "CompleteActorChore", LUA_OPCODE(Lua_V1, CompleteActorChore) },
821 	{ "IsActorMoving", LUA_OPCODE(Lua_V1, IsActorMoving) },
822 	{ "IsActorChoring", LUA_OPCODE(Lua_V1, IsActorChoring) },
823 	{ "IsActorResting", LUA_OPCODE(Lua_V1, IsActorResting) },
824 	{ "SetActorChoreLooping", LUA_OPCODE(Lua_V1, SetActorChoreLooping) },
825 	{ "GetActorChores", LUA_OPCODE(Lua_V1, GetActorChores) },
826 	{ "GetActorCostumeDepth", LUA_OPCODE(Lua_V1, GetActorCostumeDepth) },
827 	{ "WorldToScreen", LUA_OPCODE(Lua_V1, WorldToScreen) },
828 	{ "exit", LUA_OPCODE(Lua_V1, Exit) },
829 	{ "FunctionName", LUA_OPCODE(Lua_V1, FunctionName) },
830 	{ "EnableDebugKeys", LUA_OPCODE(Lua_V1, EnableDebugKeys) },
831 	{ "LockFont", LUA_OPCODE(Lua_V1, LockFont) },
832 	{ "EnableControl", LUA_OPCODE(Lua_V1, EnableControl) },
833 	{ "DisableControl", LUA_OPCODE(Lua_V1, DisableControl) },
834 	{ "GetControlState", LUA_OPCODE(Lua_V1, GetControlState) },
835 	{ "PrintError", LUA_OPCODE(Lua_V1, PrintError) },
836 	{ "PrintWarning", LUA_OPCODE(Lua_V1, PrintWarning) },
837 	{ "PrintDebug", LUA_OPCODE(Lua_V1, PrintDebug) },
838 	{ "MakeCurrentSet", LUA_OPCODE(Lua_V1, MakeCurrentSet) },
839 	{ "LockSet", LUA_OPCODE(Lua_V1, LockSet) },
840 	{ "UnLockSet", LUA_OPCODE(Lua_V1, UnLockSet) },
841 	{ "MakeCurrentSetup", LUA_OPCODE(Lua_V1, MakeCurrentSetup) },
842 	{ "GetCurrentSetup", LUA_OPCODE(Lua_V1, GetCurrentSetup) },
843 	{ "NextSetup", LUA_OPCODE(Lua_V1, NextSetup) },
844 	{ "PreviousSetup", LUA_OPCODE(Lua_V1, PreviousSetup) },
845 	{ "StartFullscreenMovie", LUA_OPCODE(Lua_V1, StartFullscreenMovie) },
846 	{ "IsFullscreenMoviePlaying", LUA_OPCODE(Lua_V1, IsFullscreenMoviePlaying) },
847 	{ "StartMovie", LUA_OPCODE(Lua_V1, StartMovie) },
848 	{ "StopMovie", LUA_OPCODE(Lua_V1, StopMovie) },
849 	{ "PauseMovie", LUA_OPCODE(Lua_V1, PauseMovie) },
850 	{ "IsMoviePlaying", LUA_OPCODE(Lua_V1, IsMoviePlaying) },
851 	{ "PlaySound", LUA_OPCODE(Lua_V1, PlaySound) },
852 	{ "PlaySoundAt", LUA_OPCODE(Lua_V1, PlaySoundAt) },
853 	{ "IsSoundPlaying", LUA_OPCODE(Lua_V1, IsSoundPlaying) },
854 	{ "SetSoundPosition", LUA_OPCODE(Lua_V1, SetSoundPosition) },
855 	{ "FileFindFirst", LUA_OPCODE(Lua_V1, FileFindFirst) },
856 	{ "FileFindNext", LUA_OPCODE(Lua_V1, FileFindNext) },
857 	{ "FileFindDispose", LUA_OPCODE(Lua_V1, FileFindDispose) },
858 	{ "InputDialog", LUA_OPCODE(Lua_V1, InputDialog) },
859 	{ "WriteRegistryValue", LUA_OPCODE(Lua_V1, WriteRegistryValue) },
860 	{ "ReadRegistryValue", LUA_OPCODE(Lua_V1, ReadRegistryValue) },
861 	{ "GetSectorOppositeEdge", LUA_OPCODE(Lua_V1, GetSectorOppositeEdge) },
862 	{ "MakeSectorActive", LUA_OPCODE(Lua_V1, MakeSectorActive) },
863 	{ "PreRender", LUA_OPCODE(Lua_V1, PreRender) },
864 	{ "SpewStartup", LUA_OPCODE(Lua_V1, SpewStartup) },
865 	{ "GetCurrentScript", LUA_OPCODE(Lua_V1, GetCurrentScript) },
866 	{ "PrintActorCostumes", LUA_OPCODE(Lua_V1, PrintActorCostumes) },
867 	{ "PushActorCostume", LUA_OPCODE(Lua_V1, PushActorCostume) },
868 	{ "PopActorCostume", LUA_OPCODE(Lua_V1, PopActorCostume) },
869 	{ "LoadCostume", LUA_OPCODE(Lua_V1, LoadCostume) },
870 	{ "RotateVector", LUA_OPCODE(Lua_V1, RotateVector) },
871 	{ "GetCameraPosition", LUA_OPCODE(Lua_V1, GetCameraPosition) },
872 	{ "SetCameraPosition", LUA_OPCODE(Lua_V1, SetCameraPosition) },
873 	{ "SetCameraInterest", LUA_OPCODE(Lua_V1, SetCameraInterest) },
874 	{ "GetCameraFOV", LUA_OPCODE(Lua_V1, GetCameraFOV) },
875 	{ "SetCameraFOV", LUA_OPCODE(Lua_V1, SetCameraFOV) },
876 	{ "GetCameraRoll", LUA_OPCODE(Lua_V1, GetCameraRoll) },
877 	{ "SetCameraRoll", LUA_OPCODE(Lua_V1, SetCameraRoll) },
878 	{ "GetCameraLookVector", LUA_OPCODE(Lua_V1, GetCameraLookVector) },
879 	{ "PointActorAt", LUA_OPCODE(Lua_V1, PointActorAt) },
880 	{ "TurnActorTo", LUA_OPCODE(Lua_V1, TurnActorTo) },
881 	{ "PerSecond", LUA_OPCODE(Lua_V1, PerSecond) },
882 	{ "GetAngleBetweenVectors", LUA_OPCODE(Lua_V1, GetAngleBetweenVectors) },
883 	{ "GetAngleBetweenActors", LUA_OPCODE(Lua_V1, GetAngleBetweenActors) },
884 	{ "SetAmbientLight", LUA_OPCODE(Lua_V1, SetAmbientLight) },
885 	{ "TurnLightOn", LUA_OPCODE(Lua_V1, TurnLightOn) },
886 	{ "SetLightPosition", LUA_OPCODE(Lua_V1, SetLightPosition) },
887 	{ "SetLightIntensity", LUA_OPCODE(Lua_V1, SetLightIntensity) },
888 	{ "LightMgrSetChange", LUA_OPCODE(Lua_V1, LightMgrSetChange) },
889 	{ "LightMgrStartup", LUA_OPCODE(Lua_V1, LightMgrStartup) },
890 	{ "ImStartSound", LUA_OPCODE(Lua_V1, ImStartSound) },
891 	{ "ImStopSound", LUA_OPCODE(Lua_V1, ImStopSound) },
892 	{ "ImStopAllSounds", LUA_OPCODE(Lua_V1, ImStopAllSounds) },
893 	{ "ImGetParam", LUA_OPCODE(Lua_V1, ImGetParam) },
894 	{ "ImSetParam", LUA_OPCODE(Lua_V1, ImSetParam) },
895 	{ "ImFadeParam", LUA_OPCODE(Lua_V1, ImFadeParam) },
896 	{ "ImGetSfxVol", LUA_OPCODE(Lua_V1, ImGetSfxVol) },
897 	{ "ImSetSfxVol", LUA_OPCODE(Lua_V1, ImSetSfxVol) },
898 	{ "ImGetVoiceVol", LUA_OPCODE(Lua_V1, ImGetVoiceVol) },
899 	{ "ImSetVoiceVol", LUA_OPCODE(Lua_V1, ImSetVoiceVol) },
900 	{ "ImGetMusicVol", LUA_OPCODE(Lua_V1, ImGetMusicVol) },
901 	{ "ImSetMusicVol", LUA_OPCODE(Lua_V1, ImSetMusicVol) },
902 	{ "ImSetState", LUA_OPCODE(Lua_V1, ImSetState) },
903 	{ "ImSetSequence", LUA_OPCODE(Lua_V1, ImSetSequence) },
904 	{ "ImPause", LUA_OPCODE(Lua_V1, ImPause) },
905 	{ "ImResume", LUA_OPCODE(Lua_V1, ImResume) },
906 	{ "ImSetVoiceEffect", LUA_OPCODE(Lua_V1, ImSetVoiceEffect) },
907 	{ "LoadBundle", LUA_OPCODE(Lua_V1, LoadBundle) },
908 	{ "SetGamma", LUA_OPCODE(Lua_V1, SetGamma) },
909 	{ "SetActorWalkDominate", LUA_OPCODE(Lua_V1, SetActorWalkDominate) },
910 	{ "SetActorConstrain", LUA_OPCODE(Lua_V1, SetActorConstrain) },
911 	{ "RenderModeUser", LUA_OPCODE(Lua_V1, RenderModeUser) },
912 	{ "ForceRefresh", LUA_OPCODE(Lua_V1, ForceRefresh) },
913 	{ "DimScreen", LUA_OPCODE(Lua_V1, DimScreen) },
914 	{ "DimRegion", LUA_OPCODE(Lua_V1, DimRegion) },
915 	{ "CleanBuffer", LUA_OPCODE(Lua_V1, CleanBuffer) },
916 	{ "Display", LUA_OPCODE(Lua_V1, Display) },
917 	{ "SetSpeechMode", LUA_OPCODE(Lua_V1, SetSpeechMode) },
918 	{ "GetSpeechMode", LUA_OPCODE(Lua_V1, GetSpeechMode) },
919 	{ "SetShadowColor", LUA_OPCODE(Lua_V1, SetShadowColor) },
920 	{ "ActivateActorShadow", LUA_OPCODE(Lua_V1, ActivateActorShadow) },
921 	{ "SetActorShadowPlane", LUA_OPCODE(Lua_V1, SetActorShadowPlane) },
922 	{ "SetActorShadowPoint", LUA_OPCODE(Lua_V1, SetActorShadowPoint) },
923 	{ "SetActiveShadow", LUA_OPCODE(Lua_V1, SetActiveShadow) },
924 	{ "KillActorShadows", LUA_OPCODE(Lua_V1, KillActorShadows) },
925 	{ "AddShadowPlane", LUA_OPCODE(Lua_V1, AddShadowPlane) },
926 	{ "SetActorShadowValid", LUA_OPCODE(Lua_V1, SetActorShadowValid) },
927 	{ "FreeObjectState", LUA_OPCODE(Lua_V1, FreeObjectState) },
928 	{ "NewObjectState", LUA_OPCODE(Lua_V1, NewObjectState) },
929 	{ "SetObjectType", LUA_OPCODE(Lua_V1, SetObjectType) },
930 	{ "SendObjectToBack", LUA_OPCODE(Lua_V1, SendObjectToBack) },
931 	{ "SendObjectToFront", LUA_OPCODE(Lua_V1, SendObjectToFront) },
932 	{ "ActorToClean", LUA_OPCODE(Lua_V1, ActorToClean) },
933 	{ "FlushControls", LUA_OPCODE(Lua_V1, FlushControls) },
934 	{ "SetActorCollisionMode", LUA_OPCODE(Lua_V1, SetActorCollisionMode) },
935 	{ "SetActorCollisionScale", LUA_OPCODE(Lua_V1, SetActorCollisionScale) },
936 	{ "SetActorClipActive", LUA_OPCODE(Lua_V1, SetActorClipActive) },
937 	{ "SetActorClipPlane", LUA_OPCODE(Lua_V1, SetActorClipPlane) },
938 	{ "FadeOutChore", LUA_OPCODE(Lua_V1, FadeOutChore) },
939 	{ "FadeInChore", LUA_OPCODE(Lua_V1, FadeInChore) },
940 	{ "IrisDown", LUA_OPCODE(Lua_V1, IrisDown) },
941 	{ "IrisUp", LUA_OPCODE(Lua_V1, IrisUp) },
942 	{ "TextFileGetLineCount", LUA_OPCODE(Lua_V1, TextFileGetLineCount) },
943 	{ "TextFileGetLine", LUA_OPCODE(Lua_V1, TextFileGetLine) },
944 	{ "ScreenShot", LUA_OPCODE(Lua_V1, ScreenShot) },
945 	{ "GetSaveGameImage", LUA_OPCODE(Lua_V1, GetSaveGameImage) },
946 	{ "GetImage", LUA_OPCODE(Lua_V1, GetImage) },
947 	{ "FreeImage", LUA_OPCODE(Lua_V1, FreeImage) },
948 	{ "BlastImage", LUA_OPCODE(Lua_V1, BlastImage) },
949 	{ "BlastRect", LUA_OPCODE(Lua_V1, BlastRect) },
950 	{ "SubmitSaveGameData", LUA_OPCODE(Lua_V1, SubmitSaveGameData) },
951 	{ "GetSaveGameData", LUA_OPCODE(Lua_V1, GetSaveGameData) },
952 	{ "SetTextSpeed", LUA_OPCODE(Lua_V1, SetTextSpeed) },
953 	{ "GetTextSpeed", LUA_OPCODE(Lua_V1, GetTextSpeed) },
954 	{ "DetachFromResources", LUA_OPCODE(Lua_V1, DetachFromResources) },
955 	{ "AttachToResources", LUA_OPCODE(Lua_V1, AttachToResources) },
956 	{ "ActorPuckOrient", LUA_OPCODE(Lua_V1, ActorPuckOrient) },
957 	{ "JustLoaded", LUA_OPCODE(Lua_V1, JustLoaded) },
958 	{ "ResetTextures", LUA_OPCODE(Lua_V1, ResetTextures) },
959 	{ "ShrinkBoxes", LUA_OPCODE(Lua_V1, ShrinkBoxes) },
960 	{ "UnShrinkBoxes", LUA_OPCODE(Lua_V1, UnShrinkBoxes) },
961 	{ "GetShrinkPos", LUA_OPCODE(Lua_V1, GetShrinkPos) },
962 	{ "NukeResources", LUA_OPCODE(Lua_V1, NukeResources) },
963 	{ "SetActorInvClipNode", LUA_OPCODE(Lua_V1, SetActorInvClipNode) },
964 	{ "GetDiskFreeSpace", LUA_OPCODE(Lua_V1, GetDiskFreeSpace) },
965 	{ "SaveIMuse", LUA_OPCODE(Lua_V1, SaveIMuse) },
966 	{ "RestoreIMuse", LUA_OPCODE(Lua_V1, RestoreIMuse) },
967 	{ "GetMemoryUsage", LUA_OPCODE(Lua_V1, GetMemoryUsage) },
968 	{ "dofile", LUA_OPCODE(Lua_V1, new_dofile) },
969 };
970 
971 static struct luaL_reg grimTextOpcodes[] = {
972 	{ "IsMessageGoing", LUA_OPCODE(Lua_V1, IsMessageGoing) },
973 	{ "SetSayLineDefaults", LUA_OPCODE(Lua_V1, SetSayLineDefaults) },
974 	{ "SetActorTalkColor", LUA_OPCODE(Lua_V1, SetActorTalkColor) },
975 	{ "GetActorTalkColor", LUA_OPCODE(Lua_V1, GetActorTalkColor) },
976 	{ "SayLine", LUA_OPCODE(Lua_V1, SayLine) },
977 	{ "PrintLine", LUA_OPCODE(Lua_V1, PrintLine) },
978 	{ "MakeTextObject", LUA_OPCODE(Lua_V1, MakeTextObject) },
979 	{ "GetTextObjectDimensions", LUA_OPCODE(Lua_V1, GetTextObjectDimensions) },
980 	{ "GetFontDimensions", LUA_OPCODE(Lua_V1, GetFontDimensions) },
981 	{ "ChangeTextObject", LUA_OPCODE(Lua_V1, ChangeTextObject) },
982 	{ "KillTextObject", LUA_OPCODE(Lua_V1, KillTextObject) },
983 	{ "BlastText", LUA_OPCODE(Lua_V1, BlastText) },
984 	{ "ExpireText", LUA_OPCODE(Lua_V1, ExpireText) },
985 	{ "PurgeText", LUA_OPCODE(Lua_V1, PurgeText) },
986 	{ "MakeColor", LUA_OPCODE(Lua_V1, MakeColor) },
987 	{ "GetColorComponents", LUA_OPCODE(Lua_V1, GetColorComponents) },
988 	{ "SetTranslationMode", LUA_OPCODE(Lua_V1, SetTranslationMode) },
989 	{ "GetTranslationMode", LUA_OPCODE(Lua_V1, GetTranslationMode) },
990 	{ "GetTextCharPosition", LUA_OPCODE(Lua_V1, GetTextCharPosition) },
991 	{ "LocalizeString", LUA_OPCODE(Lua_V1, LocalizeString) },
992 	{ "SetEmergencyFont", LUA_OPCODE(Lua_V1, SetEmergencyFont) },
993 	{ "SetOffscreenTextPos", LUA_OPCODE(Lua_V1, SetOffscreenTextPos) }
994 };
995 
996 struct luaL_reg grimPrimitivesOpcodes[] = {
997 	{ "DrawLine", LUA_OPCODE(Lua_V1, DrawLine) },
998 	{ "DrawPolygon", LUA_OPCODE(Lua_V1, DrawPolygon) },
999 	{ "DrawRectangle", LUA_OPCODE(Lua_V1, DrawRectangle) },
1000 	{ "ChangePrimitive", LUA_OPCODE(Lua_V1, ChangePrimitive) },
1001 	{ "KillPrimitive", LUA_OPCODE(Lua_V1, KillPrimitive) },
1002 	{ "PurgePrimitiveQueue", LUA_OPCODE(Lua_V1, PurgePrimitiveQueue) }
1003 };
1004 
1005 struct luaL_reg grimHardwareOpcodes[] = {
1006 	{ "Is3DHardwareEnabled", LUA_OPCODE(Lua_V1, Is3DHardwareEnabled) },
1007 	{ "GetVideoDevices", LUA_OPCODE(Lua_V1, GetVideoDevices) },
1008 	{ "SetVideoDevices", LUA_OPCODE(Lua_V1, SetVideoDevices) },
1009 	{ "SetHardwareState", LUA_OPCODE(Lua_V1, SetHardwareState) },
1010 	{ "Enumerate3DDevices", LUA_OPCODE(Lua_V1, Enumerate3DDevices) },
1011 	{ "EnumerateVideoDevices", LUA_OPCODE(Lua_V1, EnumerateVideoDevices) }
1012 };
1013 
registerOpcodes()1014 void Lua_V1::registerOpcodes() {
1015 	// Register main opcodes functions
1016 	luaL_openlib(grimMainOpcodes, ARRAYSIZE(grimMainOpcodes));
1017 
1018 	// Register text opcodes functions
1019 	luaL_openlib(grimTextOpcodes, ARRAYSIZE(grimTextOpcodes));
1020 
1021 	// Register primitives opcodeEs functions
1022 	luaL_openlib(grimPrimitivesOpcodes, ARRAYSIZE(grimPrimitivesOpcodes));
1023 
1024 	// Register hardware opcode functions
1025 	luaL_openlib(grimHardwareOpcodes, ARRAYSIZE(grimHardwareOpcodes));
1026 
1027 	LuaBase::registerOpcodes();
1028 }
1029 
boot()1030 void Lua_V1::boot() {
1031 	// The default value of these globals, defined in _controls.lua, is 256, 257, 258, 259.
1032 	// These values clash with the numpad 0, 1, 2 and 3 keycodes, so we set them here.
1033 	lua_pushnumber(KEYCODE_JOY1_HLEFT);
1034 	lua_setglobal("JOYSTICK_X_LEFT");
1035 
1036 	lua_pushnumber(KEYCODE_JOY1_HRIGHT);
1037 	lua_setglobal("JOYSTICK_X_RIGHT");
1038 
1039 	lua_pushnumber(KEYCODE_JOY1_HUP);
1040 	lua_setglobal("JOYSTICK_Y_UP");
1041 
1042 	lua_pushnumber(KEYCODE_JOY1_HDOWN);
1043 	lua_setglobal("JOYSTICK_Y_DOWN");
1044 
1045 	LuaBase::boot();
1046 }
1047 
postRestoreHandle()1048 void Lua_V1::postRestoreHandle() {
1049 
1050 	if (g_grim->getGameType() == GType_GRIM) {
1051 		lua_beginblock();
1052 		// Set the developerMode, since the save contains the value of
1053 		// the installation it was made with.
1054 		lua_pushobject(lua_getglobal("developerMode"));
1055 		bool devMode = g_registry->getBool("good_times");
1056 		pushbool(devMode);
1057 		lua_setglobal("developerMode");
1058 		lua_endblock();
1059 	}
1060 
1061 	// Starting a movie calls the function 'music_state.pause()', which saves the current sfx volume to a temp
1062 	// variable and sets it to 0. When the movie finishes 'music_state.unpause()' will be called, which reads
1063 	// the volume from the temp variable and sets it. But if we have modified the sfx volume in the options
1064 	// and than load a savegame made during a movie, at the end of the movie the temp variable will have the
1065 	// old value. So here we call 'music_state.pause()' again, so that it can set the right value to the
1066 	// temp variable.
1067 	lua_beginblock();
1068 	lua_Object o = lua_getglobal("music_state");
1069 	if (!lua_isnil(o)) {
1070 		lua_pushobject(o);
1071 		lua_pushstring("paused");
1072 		if (!lua_isnil(lua_gettable())) {
1073 			lua_pushobject(o);
1074 			lua_pushstring("paused");
1075 			pushbool(false);
1076 			lua_settable();
1077 
1078 			lua_pushobject(o);
1079 			lua_pushstring("pause");
1080 			lua_Object func = lua_gettable();
1081 			lua_pushobject(o);
1082 			lua_callfunction(func);
1083 		}
1084 	}
1085 	lua_endblock();
1086 }
1087 
1088 } // end of namespace Grim
1089