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