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 /*
24 * This code is based on Broken Sword 2.5 engine
25 *
26 * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
27 *
28 * Licensed under GNU GPL v2
29 *
30 */
31
32 #include "sword25/kernel/common.h"
33 #include "sword25/kernel/kernel.h"
34 #include "sword25/kernel/filesystemutil.h"
35 #include "sword25/kernel/resmanager.h"
36 #include "sword25/kernel/persistenceservice.h"
37 #include "sword25/script/script.h"
38 #include "sword25/script/luabindhelper.h"
39
40 namespace Sword25 {
41
42 // Marks a function that should never be used
dummyFuncError(lua_State * L)43 static int dummyFuncError(lua_State *L) {
44 error("Dummy function invoked by LUA");
45 return 1;
46 }
47
getMilliTicks(lua_State * L)48 static int getMilliTicks(lua_State *L) {
49 Kernel *pKernel = Kernel::getInstance();
50 assert(pKernel);
51
52 lua_pushnumber(L, pKernel->getMilliTicks());
53
54 return 1;
55 }
56
getTimer(lua_State * L)57 static int getTimer(lua_State *L) {
58 Kernel *pKernel = Kernel::getInstance();
59 assert(pKernel);
60
61 lua_pushnumber(L, static_cast<lua_Number>(pKernel->getMilliTicks()) / 1000.0);
62
63 return 1;
64 }
65
startService(lua_State * L)66 static int startService(lua_State *L) {
67 // This function is used by system/boot.lua to init all services.
68 // However, we do nothing here, as we just hard code the init sequence.
69 lua_pushbooleancpp(L, true);
70
71 return 1;
72 }
73
sleep(lua_State * L)74 static int sleep(lua_State *L) {
75 Kernel *pKernel = Kernel::getInstance();
76 assert(pKernel);
77 pKernel->sleep(static_cast<uint>(luaL_checknumber(L, 1) * 1000));
78 return 0;
79 }
80
crash(lua_State * L)81 static int crash(lua_State *L) {
82 Kernel *pKernel = Kernel::getInstance();
83 assert(pKernel);
84 pKernel->crash();
85 return 0;
86 }
87
executeFile(lua_State * L)88 static int executeFile(lua_State *L) {
89 Kernel *pKernel = Kernel::getInstance();
90 assert(pKernel);
91 ScriptEngine *pSE = pKernel->getScript();
92 assert(pSE);
93
94 lua_pushbooleancpp(L, pSE->executeFile(luaL_checkstring(L, 1)));
95
96 return 0;
97 }
98
getUserdataDirectory(lua_State * L)99 static int getUserdataDirectory(lua_State *L) {
100 lua_pushstring(L, FileSystemUtil::getUserdataDirectory().c_str());
101 return 1;
102 }
103
getPathSeparator(lua_State * L)104 static int getPathSeparator(lua_State *L) {
105 lua_pushstring(L, FileSystemUtil::getPathSeparator().c_str());
106 return 1;
107 }
108
fileExists(lua_State * L)109 static int fileExists(lua_State *L) {
110 lua_pushbooleancpp(L, FileSystemUtil::fileExists(luaL_checkstring(L, 1)));
111 return 1;
112 }
113
createDirectory(lua_State * L)114 static int createDirectory(lua_State *L) {
115 // ScummVM engines cannot create directories, so we do nothing here.
116 lua_pushbooleancpp(L, false);
117 return 1;
118 }
119
getWinCode(lua_State * L)120 static int getWinCode(lua_State *L) {
121 lua_pushstring(L, "ScummVM");
122 return 1;
123 }
124
getSubversionRevision(lua_State * L)125 static int getSubversionRevision(lua_State *L) {
126 // ScummVM is 1337
127 lua_pushnumber(L, 1337);
128 return 1;
129 }
130
getUsedMemory(lua_State * L)131 static int getUsedMemory(lua_State *L) {
132 // It doesn't really matter what this call returns,
133 // as it's used in a debug function.
134 lua_pushnumber(L, 0);
135 return 1;
136 }
137
138 static const char *KERNEL_LIBRARY_NAME = "Kernel";
139
140 static const luaL_reg KERNEL_FUNCTIONS[] = {
141 {"DisconnectService", dummyFuncError},
142 {"GetActiveServiceIdentifier", dummyFuncError},
143 {"GetSuperclassCount", dummyFuncError},
144 {"GetSuperclassIdentifier", dummyFuncError},
145 {"GetServiceCount", dummyFuncError},
146 {"GetServiceIdentifier", dummyFuncError},
147 {"GetMilliTicks", getMilliTicks},
148 {"GetTimer", getTimer},
149 {"StartService", startService},
150 {"Sleep", sleep},
151 {"Crash", crash},
152 {"ExecuteFile", executeFile},
153 {"GetUserdataDirectory", getUserdataDirectory},
154 {"GetPathSeparator", getPathSeparator},
155 {"FileExists", fileExists},
156 {"CreateDirectory", createDirectory},
157 {"GetWinCode", getWinCode},
158 {"GetSubversionRevision", getSubversionRevision},
159 {"GetUsedMemory", getUsedMemory},
160 {0, 0}
161 };
162
isVisible(lua_State * L)163 static int isVisible(lua_State *L) {
164 // This function apparently is not used by the game scripts
165 lua_pushbooleancpp(L, true);
166
167 return 1;
168 }
169
setVisible(lua_State * L)170 static int setVisible(lua_State *L) {
171 // This function apparently is not used by the game scripts
172 // pWindow->setVisible(lua_tobooleancpp(L, 1));
173
174 return 0;
175 }
176
getX(lua_State * L)177 static int getX(lua_State *L) {
178 // This function apparently is not used by the game scripts
179 lua_pushnumber(L, 0);
180
181 return 1;
182 }
183
getY(lua_State * L)184 static int getY(lua_State *L) {
185 // This function apparently is not used by the game scripts
186 lua_pushnumber(L, 0);
187
188 return 1;
189 }
190
setX(lua_State * L)191 static int setX(lua_State *L) {
192 // This is called by system/boot.lua with -1 as value.
193 // pWindow->setX(static_cast<int>(luaL_checknumber(L, 1)));
194
195 return 0;
196 }
197
setY(lua_State * L)198 static int setY(lua_State *L) {
199 // This is called by system/boot.lua with -1 as value.
200 // pWindow->setY(static_cast<int>(luaL_checknumber(L, 1)));
201
202 return 0;
203 }
204
getWidth(lua_State * L)205 static int getWidth(lua_State *L) {
206 // This function apparently is not used by the game scripts
207 lua_pushnumber(L, 800);
208
209 return 1;
210 }
211
getHeight(lua_State * L)212 static int getHeight(lua_State *L) {
213 // This function apparently is not used by the game scripts
214 lua_pushnumber(L, 600);
215
216 return 1;
217 }
218
setWidth(lua_State * L)219 static int setWidth(lua_State *L) {
220 // This is called by system/boot.lua with 800 as value.
221 // pWindow->setWidth(static_cast<int>(luaL_checknumber(L, 1)));
222
223 return 0;
224 }
225
setHeight(lua_State * L)226 static int setHeight(lua_State *L) {
227 // This is called by system/boot.lua with 600 as value.
228 // pWindow->setHeight(static_cast<int>(luaL_checknumber(L, 1)));
229
230 return 0;
231 }
232
getTitle(lua_State * L)233 static int getTitle(lua_State *L) {
234 // This function apparently is not used by the game scripts
235 lua_pushstring(L, "");
236
237 return 1;
238 }
239
setTitle(lua_State * L)240 static int setTitle(lua_State *L) {
241 // This is called by system/boot.lua and system/menu.lua, to
242 // set the window title to the (localized) game name.
243 // FIXME: Should we call OSystem::setWindowCaption() here?
244 // pWindow->setTitle(luaL_checkstring(L, 1));
245
246 return 0;
247 }
248
processMessages(lua_State * L)249 static int processMessages(lua_State *L) {
250 // This is called by the main loop in system/boot.lua,
251 // and the game keeps running as true is returned here.
252 // It terminates if we return false.
253
254 // TODO: We could do more stuff here if desired...
255
256 // TODO: We could always return true here, and leave quit handling
257 // to the closeWanted() opcode; see also the TODO comment in there.
258
259 lua_pushbooleancpp(L, !Engine::shouldQuit());
260 g_system->delayMillis(10);
261
262 return 1;
263 }
264
closeWanted(lua_State * L)265 static int closeWanted(lua_State *L) {
266 // This is called by system/interface.lua to determine whether the
267 // user requested the game to close (e.g. by clicking the 'close' widget
268 // of the game window). As a consequence (i.e. this function returns true),
269 // a quit confirmation dialog is shown.
270
271 // TODO: ScummVM currently has a bug / misfeature where some engines provide
272 // quit confirmation dialogs, some don't; in addition, we have a global confirmation
273 // dialog (but the user has to explicitly activate that in the config).
274 // Anyway, this can lead to *two* confirmation dialogs being shown.
275 // If it wasn't for that, we could simply check for Engine::shouldQuit() here,
276 // and then invoke EventMan::resetQuit. But currently this would result in
277 // the user seeing two confirmation dialogs. Bad.
278 lua_pushbooleancpp(L, false);
279
280 return 1;
281 }
282
283 static const char *WINDOW_LIBRARY_NAME = "Window";
284
285 static const luaL_reg WINDOW_FUNCTIONS[] = {
286 {"IsVisible", isVisible},
287 {"SetVisible", setVisible},
288 {"GetX", getX},
289 {"SetX", setX},
290 {"GetY", getY},
291 {"SetY", setY},
292 {"GetClientX", dummyFuncError},
293 {"GetClientY", dummyFuncError},
294 {"GetWidth", getWidth},
295 {"GetHeight", getHeight},
296 {"SetWidth", setWidth},
297 {"SetHeight", setHeight},
298 {"GetTitle", getTitle},
299 {"SetTitle", setTitle},
300 {"ProcessMessages", processMessages},
301 {"CloseWanted", closeWanted},
302 {"WaitForFocus", dummyFuncError},
303 {"HasFocus", dummyFuncError},
304 {0, 0}
305 };
306
precacheResource(lua_State * L)307 static int precacheResource(lua_State *L) {
308 Kernel *pKernel = Kernel::getInstance();
309 assert(pKernel);
310 ResourceManager *pResource = pKernel->getResourceManager();
311 assert(pResource);
312
313 #ifdef PRECACHE_RESOURCES
314 lua_pushbooleancpp(L, pResource->precacheResource(luaL_checkstring(L, 1)));
315 #else
316 lua_pushbooleancpp(L, true);
317 #endif
318
319 return 1;
320 }
321
forcePrecacheResource(lua_State * L)322 static int forcePrecacheResource(lua_State *L) {
323 Kernel *pKernel = Kernel::getInstance();
324 assert(pKernel);
325 ResourceManager *pResource = pKernel->getResourceManager();
326 assert(pResource);
327
328 #ifdef PRECACHE_RESOURCES
329 lua_pushbooleancpp(L, pResource->precacheResource(luaL_checkstring(L, 1), true));
330 #else
331 lua_pushbooleancpp(L, true);
332 #endif
333
334 return 1;
335 }
336
getMaxMemoryUsage(lua_State * L)337 static int getMaxMemoryUsage(lua_State *L) {
338 Kernel *pKernel = Kernel::getInstance();
339 assert(pKernel);
340 ResourceManager *pResource = pKernel->getResourceManager();
341 assert(pResource);
342
343 // This is used for debugging, so it doesn't really matter.
344 // The default value set by the scripts is 256000000 bytes
345 lua_pushnumber(L, 256000000);
346
347 return 1;
348 }
349
setMaxMemoryUsage(lua_State * L)350 static int setMaxMemoryUsage(lua_State *L) {
351 Kernel *pKernel = Kernel::getInstance();
352 assert(pKernel);
353 ResourceManager *pResource = pKernel->getResourceManager();
354 assert(pResource);
355
356 // This call is ignored, we set a limit on the number of
357 // simultaneous resources loaded instead.
358
359 return 0;
360 }
361
emptyCache(lua_State * L)362 static int emptyCache(lua_State *L) {
363 Kernel *pKernel = Kernel::getInstance();
364 assert(pKernel);
365 ResourceManager *pResource = pKernel->getResourceManager();
366 assert(pResource);
367
368 pResource->emptyCache();
369
370 return 0;
371 }
372
dumpLockedResources(lua_State * L)373 static int dumpLockedResources(lua_State *L) {
374 Kernel *pKernel = Kernel::getInstance();
375 assert(pKernel);
376 ResourceManager *pResource = pKernel->getResourceManager();
377 assert(pResource);
378
379 pResource->dumpLockedResources();
380
381 return 0;
382 }
383
384 static const char *RESOURCE_LIBRARY_NAME = "Resource";
385
386 static const luaL_reg RESOURCE_FUNCTIONS[] = {
387 {"PrecacheResource", precacheResource},
388 {"ForcePrecacheResource", forcePrecacheResource},
389 {"GetMaxMemoryUsage", getMaxMemoryUsage},
390 {"SetMaxMemoryUsage", setMaxMemoryUsage},
391 {"EmptyCache", emptyCache},
392 {"IsLogCacheMiss", dummyFuncError},
393 {"SetLogCacheMiss", dummyFuncError},
394 {"DumpLockedResources", dumpLockedResources},
395 {0, 0}
396 };
397
reloadSlots(lua_State * L)398 static int reloadSlots(lua_State *L) {
399 PersistenceService::getInstance().reloadSlots();
400 lua_pushnil(L);
401 return 1;
402 }
403
getSlotCount(lua_State * L)404 static int getSlotCount(lua_State *L) {
405 lua_pushnumber(L, PersistenceService::getInstance().getSlotCount());
406 return 1;
407 }
408
isSlotOccupied(lua_State * L)409 static int isSlotOccupied(lua_State *L) {
410 lua_pushbooleancpp(L, PersistenceService::getInstance().isSlotOccupied(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
411 return 1;
412 }
413
getSavegameDirectory(lua_State * L)414 static int getSavegameDirectory(lua_State *L) {
415 lua_pushstring(L, PersistenceService::getInstance().getSavegameDirectory().c_str());
416 return 1;
417 }
418
isSavegameCompatible(lua_State * L)419 static int isSavegameCompatible(lua_State *L) {
420 lua_pushbooleancpp(L, PersistenceService::getInstance().isSavegameCompatible(
421 static_cast<uint>(luaL_checknumber(L, 1)) - 1));
422 return 1;
423 }
424
getSavegameDescription(lua_State * L)425 static int getSavegameDescription(lua_State *L) {
426 lua_pushstring(L, PersistenceService::getInstance().getSavegameDescription(
427 static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
428 return 1;
429 }
430
getSavegameFilename(lua_State * L)431 static int getSavegameFilename(lua_State *L) {
432 lua_pushstring(L, PersistenceService::getInstance().getSavegameFilename(static_cast<uint>(luaL_checknumber(L, 1)) - 1).c_str());
433 return 1;
434 }
435
loadGame(lua_State * L)436 static int loadGame(lua_State *L) {
437 lua_pushbooleancpp(L, PersistenceService::getInstance().loadGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1));
438 return 1;
439 }
440
saveGame(lua_State * L)441 static int saveGame(lua_State *L) {
442 lua_pushbooleancpp(L, PersistenceService::getInstance().saveGame(static_cast<uint>(luaL_checknumber(L, 1)) - 1, luaL_checkstring(L, 2)));
443 return 1;
444 }
445
446 static const char *PERSISTENCE_LIBRARY_NAME = "Persistence";
447
448 static const luaL_reg PERSISTENCE_FUNCTIONS[] = {
449 {"ReloadSlots", reloadSlots},
450 {"GetSlotCount", getSlotCount},
451 {"IsSlotOccupied", isSlotOccupied},
452 {"GetSavegameDirectory", getSavegameDirectory},
453 {"IsSavegameCompatible", isSavegameCompatible},
454 {"GetSavegameDescription", getSavegameDescription},
455 {"GetSavegameFilename", getSavegameFilename},
456 {"LoadGame", loadGame},
457 {"SaveGame", saveGame},
458 {0, 0}
459 };
460
registerScriptBindings()461 bool Kernel::registerScriptBindings() {
462 ScriptEngine *pScript = getScript();
463 assert(pScript);
464 lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
465 assert(L);
466
467 if (!LuaBindhelper::addFunctionsToLib(L, KERNEL_LIBRARY_NAME, KERNEL_FUNCTIONS)) return false;
468 if (!LuaBindhelper::addFunctionsToLib(L, WINDOW_LIBRARY_NAME, WINDOW_FUNCTIONS)) return false;
469 if (!LuaBindhelper::addFunctionsToLib(L, RESOURCE_LIBRARY_NAME, RESOURCE_FUNCTIONS)) return false;
470 if (!LuaBindhelper::addFunctionsToLib(L, PERSISTENCE_LIBRARY_NAME, PERSISTENCE_FUNCTIONS)) return false;
471
472 return true;
473 }
474
475 } // End of namespace Sword25
476