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 "illusions/bbdou/illusions_bbdou.h"
24 #include "illusions/bbdou/bbdou_menukeys.h"
25 #include "illusions/bbdou/bbdou_videoplayer.h"
26 #include "illusions/bbdou/gamestate_bbdou.h"
27 #include "illusions/bbdou/menusystem_bbdou.h"
28 #include "illusions/actor.h"
29 #include "illusions/camera.h"
30 #include "illusions/cursor.h"
31 #include "illusions/dictionary.h"
32 #include "illusions/fileresourcereader.h"
33 #include "illusions/graphics.h"
34 #include "illusions/input.h"
35 #include "illusions/resources/actorresource.h"
36 #include "illusions/resources/backgroundresource.h"
37 #include "illusions/resources/fontresource.h"
38 #include "illusions/resources/scriptresource.h"
39 #include "illusions/resources/soundresource.h"
40 #include "illusions/resources/talkresource.h"
41 #include "illusions/resourcesystem.h"
42 #include "illusions/screen.h"
43 #include "illusions/screentext.h"
44 #include "illusions/scriptstack.h"
45 #include "illusions/bbdou/scriptopcodes_bbdou.h"
46 #include "illusions/sound.h"
47 #include "illusions/specialcode.h"
48 #include "illusions/bbdou/bbdou_specialcode.h"
49 #include "illusions/thread.h"
50 #include "illusions/time.h"
51 #include "illusions/updatefunctions.h"
52
53 #include "illusions/threads/abortablethread.h"
54 #include "illusions/threads/scriptthread.h"
55 #include "illusions/threads/talkthread.h"
56 #include "illusions/threads/timerthread.h"
57
58 #include "audio/audiostream.h"
59 #include "common/config-manager.h"
60 #include "common/debug-channels.h"
61 #include "common/error.h"
62 #include "common/fs.h"
63 #include "common/timer.h"
64 #include "engines/util.h"
65 #include "graphics/cursorman.h"
66 #include "graphics/font.h"
67 #include "graphics/fontman.h"
68 #include "graphics/palette.h"
69 #include "graphics/surface.h"
70
71 namespace Illusions {
72
73 // ActiveScenes
74
ActiveScenes()75 ActiveScenes::ActiveScenes() {
76 clear();
77 }
78
clear()79 void ActiveScenes::clear() {
80 _stack.clear();
81 }
82
push(uint32 sceneId)83 void ActiveScenes::push(uint32 sceneId) {
84 ActiveScene activeScene;
85 activeScene._sceneId = sceneId;
86 activeScene._pauseCtr = 0;
87 _stack.push(activeScene);
88 }
89
pop()90 void ActiveScenes::pop() {
91 _stack.pop();
92 }
93
pauseActiveScene()94 void ActiveScenes::pauseActiveScene() {
95 ++_stack.top()._pauseCtr;
96 }
97
unpauseActiveScene()98 void ActiveScenes::unpauseActiveScene() {
99 --_stack.top()._pauseCtr;
100 }
101
getActiveScenesCount()102 uint ActiveScenes::getActiveScenesCount() {
103 return _stack.size();
104 }
105
getActiveSceneInfo(uint index,uint32 * sceneId,int * pauseCtr)106 void ActiveScenes::getActiveSceneInfo(uint index, uint32 *sceneId, int *pauseCtr) {
107 if (sceneId)
108 *sceneId = _stack[index - 1]._sceneId;
109 if (pauseCtr)
110 *pauseCtr = _stack[index - 1]._pauseCtr;
111 }
112
getCurrentScene()113 uint32 ActiveScenes::getCurrentScene() {
114 if (_stack.size() > 0)
115 return _stack.top()._sceneId;
116 return 0;
117 }
118
isSceneActive(uint32 sceneId)119 bool ActiveScenes::isSceneActive(uint32 sceneId) {
120 for (uint i = 0; i < _stack.size(); ++i) {
121 if (_stack[i]._sceneId == sceneId && _stack[i]._pauseCtr <= 0)
122 return true;
123 }
124 return false;
125 }
126
127 // IllusionsEngine_BBDOU
128
IllusionsEngine_BBDOU(OSystem * syst,const IllusionsGameDescription * gd)129 IllusionsEngine_BBDOU::IllusionsEngine_BBDOU(OSystem *syst, const IllusionsGameDescription *gd)
130 : IllusionsEngine(syst, gd) {
131 }
132
run()133 Common::Error IllusionsEngine_BBDOU::run() {
134
135 // Init search paths
136 const Common::FSNode gameDataDir(ConfMan.get("path"));
137 SearchMan.addSubDirectoryMatching(gameDataDir, "music");
138 SearchMan.addSubDirectoryMatching(gameDataDir, "resource");
139 SearchMan.addSubDirectoryMatching(gameDataDir, "resrem");
140 SearchMan.addSubDirectoryMatching(gameDataDir, "savegame");
141 SearchMan.addSubDirectoryMatching(gameDataDir, "sfx", 0, 2);
142 SearchMan.addSubDirectoryMatching(gameDataDir, "video");
143 SearchMan.addSubDirectoryMatching(gameDataDir, "voice");
144
145 _dict = new Dictionary();
146
147 _resReader = new ResourceReaderFileReader();
148
149 _resSys = new ResourceSystem(this);
150 _resSys->addResourceLoader(0x00060000, new ActorResourceLoader(this));
151 _resSys->addResourceLoader(0x00080000, new SoundGroupResourceLoader(this));
152 _resSys->addResourceLoader(0x000D0000, new ScriptResourceLoader(this));
153 _resSys->addResourceLoader(0x000F0000, new TalkResourceLoader(this));
154 _resSys->addResourceLoader(0x00100000, new ActorResourceLoader(this));
155 _resSys->addResourceLoader(0x00110000, new BackgroundResourceLoader(this));
156 _resSys->addResourceLoader(0x00120000, new FontResourceLoader(this));
157 _resSys->addResourceLoader(0x00170000, new SpecialCodeLoader(this));
158
159 _screen = new Screen16Bit(this, 640, 480);
160 _screenPalette = new NullScreenPalette();
161 _screenText = new ScreenText(this);
162 _input = new Input();
163 _actorInstances = new ActorInstanceList(this);
164 _backgroundInstances = new BackgroundInstanceList(this);
165 _camera = new Camera(this);
166 _controls = new Controls(this);
167 _cursor = new Cursor(this);
168 _talkItems = new TalkInstanceList(this);
169 _triggerFunctions = new TriggerFunctions();
170 _threads = new ThreadList(this);
171 _updateFunctions = new UpdateFunctions();
172 _soundMan = new SoundMan(this);
173 _menuSystem = new BBDOUMenuSystem(this);
174 _videoPlayer = new BBDOUVideoPlayer(this);
175 _gameState = new BBDOU_GameState(this);
176 _menuKeys = new BBDOUMenuKeys(this);
177
178 _screen->setColorKey1(0xF81F);
179
180 initInput();
181
182 initUpdateFunctions();
183
184 _fader = 0;
185
186 _scriptOpcodes = new ScriptOpcodes_BBDOU(this);
187 _stack = new ScriptStack();
188
189 _resGetCtr = 0;
190 _unpauseControlActorFlag = false;
191 _lastUpdateTime = 0;
192
193 _pauseCtr = 0;
194 _field8 = 1;
195 _fieldA = 0;
196 ConfMan.registerDefault("talkspeed", 240);
197 _subtitleDuration = (uint16)ConfMan.getInt("talkspeed");
198
199 _globalSceneId = 0x00010003;
200
201 setDefaultTextCoords();
202
203 _resSys->loadResource(0x000D0001, 0, 0);
204
205 _doScriptThreadInit = false;
206 startScriptThread(0x00020004, 0, 0, 0, 0);
207 _doScriptThreadInit = true;
208
209 if (ConfMan.hasKey("save_slot")) {
210 loadGameState(ConfMan.getInt("save_slot"));
211 }
212
213 _walkthroughStarted = false;
214 _canResumeFromSavegame = false;
215
216 while (!shouldQuit()) {
217 if (_walkthroughStarted) {
218 //enterScene(0x10003, 0);
219 startScriptThread(0x00020404, 0, 0, 0, 0);
220 _walkthroughStarted = false;
221 }
222 if (_resumeFromSavegameRequested && _canResumeFromSavegame) {
223 resumeFromSavegame();
224 _resumeFromSavegameRequested = false;
225 }
226 runUpdateFunctions();
227 _system->updateScreen();
228 updateEvents();
229 }
230
231 delete _stack;
232 delete _scriptOpcodes;
233
234 delete _menuKeys;
235 delete _gameState;
236 delete _videoPlayer;
237 delete _menuSystem;
238 delete _soundMan;
239 delete _updateFunctions;
240 delete _threads;
241 delete _triggerFunctions;
242 delete _talkItems;
243 delete _cursor;
244 delete _controls;
245 delete _camera;
246 delete _backgroundInstances;
247 delete _actorInstances;
248 delete _input;
249 delete _screenText;
250 delete _screen;
251 delete _resSys;
252 delete _resReader;
253 delete _dict;
254
255 debug("Ok");
256
257 return Common::kNoError;
258 }
259
hasFeature(EngineFeature f) const260 bool IllusionsEngine_BBDOU::hasFeature(EngineFeature f) const {
261 return
262 (f == kSupportsRTL) ||
263 (f == kSupportsLoadingDuringRuntime) ||
264 (f == kSupportsSavingDuringRuntime);
265 }
266
initInput()267 void IllusionsEngine_BBDOU::initInput() {
268 _input->setInputEvent(kEventLeftClick, 0x01)
269 .addMouseButton(MOUSE_LEFT_BUTTON)
270 .addKey(Common::KEYCODE_RETURN);
271 _input->setInputEvent(kEventRightClick, 0x02)
272 .addMouseButton(MOUSE_RIGHT_BUTTON);
273 _input->setInputEvent(kEventInventory, 0x04)
274 .addMouseButton(MOUSE_RIGHT_BUTTON)
275 .addKey(Common::KEYCODE_TAB);
276 _input->setInputEvent(kEventAbort, 0x08)
277 .addKey(Common::KEYCODE_ESCAPE);
278 _input->setInputEvent(kEventSkip, 0x10)
279 .addKey(Common::KEYCODE_SPACE);
280 _input->setInputEvent(kEventF1, 0x20)
281 .addKey(Common::KEYCODE_F1);
282 _input->setInputEvent(kEventUp, 0x40)
283 .addKey(Common::KEYCODE_UP);
284 _input->setInputEvent(kEventDown, 0x80)
285 .addMouseButton(MOUSE_RIGHT_BUTTON)
286 .addKey(Common::KEYCODE_DOWN);
287 }
288
289 #define UPDATEFUNCTION(priority, sceneId, callback) \
290 _updateFunctions->add(priority, sceneId, new Common::Functor1Mem<uint, int, IllusionsEngine_BBDOU> \
291 (this, &IllusionsEngine_BBDOU::callback));
292
initUpdateFunctions()293 void IllusionsEngine_BBDOU::initUpdateFunctions() {
294 UPDATEFUNCTION(30, 0, updateScript);
295 UPDATEFUNCTION(50, 0, updateActors);
296 UPDATEFUNCTION(60, 0, updateMenuKeys);
297 UPDATEFUNCTION(60, 0, updateSequences);
298 UPDATEFUNCTION(70, 0, updateGraphics);
299 UPDATEFUNCTION(70, 0, updateVideoPlayer);
300 UPDATEFUNCTION(90, 0, updateSprites);
301 UPDATEFUNCTION(120, 0, updateSoundMan);
302 }
303
304 #undef UPDATEFUNCTION
305
updateScript(uint flags)306 int IllusionsEngine_BBDOU::updateScript(uint flags) {
307 _threads->updateThreads();
308 return kUFNext;
309 }
310
updateMenuKeys(uint flags)311 int IllusionsEngine_BBDOU::updateMenuKeys(uint flags) {
312 _menuKeys->update();
313 return kUFNext;
314 }
315
causeIsDeclared(uint32 sceneId,uint32 verbId,uint32 objectId2,uint32 objectId)316 bool IllusionsEngine_BBDOU::causeIsDeclared(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId) {
317 uint32 codeOffs;
318 return
319 _triggerFunctions->find(sceneId, verbId, objectId2, objectId) ||
320 findTriggerCause(sceneId, verbId, objectId2, objectId, codeOffs);
321 }
322
causeDeclare(uint32 verbId,uint32 objectId2,uint32 objectId,TriggerFunctionCallback * callback)323 void IllusionsEngine_BBDOU::causeDeclare(uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback) {
324 _triggerFunctions->add(getCurrentScene(), verbId, objectId2, objectId, callback);
325 }
326
causeTrigger(uint32 sceneId,uint32 verbId,uint32 objectId2,uint32 objectId,uint32 callingThreadId)327 uint32 IllusionsEngine_BBDOU::causeTrigger(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 callingThreadId) {
328 uint32 codeOffs;
329 uint32 causeThreadId = 0;
330 TriggerFunction *triggerFunction = _triggerFunctions->find(sceneId, verbId, objectId2, objectId);
331 if (triggerFunction) {
332 triggerFunction->run(callingThreadId);
333 } else if (findTriggerCause(sceneId, verbId, objectId2, objectId, codeOffs)) {
334 causeThreadId = startTempScriptThread(_scriptResource->getCode(codeOffs),
335 callingThreadId, verbId, objectId2, objectId);
336 }
337 return causeThreadId;
338 }
339
updateVideoPlayer(uint flags)340 int IllusionsEngine_BBDOU::updateVideoPlayer(uint flags) {
341 if (_videoPlayer->isPlaying())
342 _videoPlayer->update();
343 return kUFNext;
344 }
345
playVideo(uint32 videoId,uint32 objectId,uint32 priority,uint32 callingThreadId)346 void IllusionsEngine_BBDOU::playVideo(uint32 videoId, uint32 objectId, uint32 priority, uint32 callingThreadId) {
347 _videoPlayer->start(videoId, objectId, priority, callingThreadId);
348 }
349
isVideoPlaying()350 bool IllusionsEngine_BBDOU::isVideoPlaying() {
351 return _videoPlayer->isPlaying();
352 }
353
setDefaultTextCoords()354 void IllusionsEngine_BBDOU::setDefaultTextCoords() {
355 WidthHeight dimensions;
356 dimensions._width = 480;
357 dimensions._height = 48;
358 Common::Point pt(320, 448);
359 setDefaultTextDimensions(dimensions);
360 setDefaultTextPosition(pt);
361 }
362
loadSpecialCode(uint32 resId)363 void IllusionsEngine_BBDOU::loadSpecialCode(uint32 resId) {
364 _specialCode = new BbdouSpecialCode(this);
365 _specialCode->init();
366 }
367
unloadSpecialCode(uint32 resId)368 void IllusionsEngine_BBDOU::unloadSpecialCode(uint32 resId) {
369 delete _specialCode;
370 _specialCode = 0;
371 }
372
notifyThreadId(uint32 & threadId)373 void IllusionsEngine_BBDOU::notifyThreadId(uint32 &threadId) {
374 if (threadId) {
375 uint32 tempThreadId = threadId;
376 threadId = 0;
377 _threads->notifyId(tempThreadId);
378 }
379 }
380
testMainActorFastWalk(Control * control)381 bool IllusionsEngine_BBDOU::testMainActorFastWalk(Control *control) {
382 return false;
383 }
384
testMainActorCollision(Control * control)385 bool IllusionsEngine_BBDOU::testMainActorCollision(Control *control) {
386 // Not used in BBDOU
387 return false;
388 }
389
getObjectControl(uint32 objectId)390 Control *IllusionsEngine_BBDOU::getObjectControl(uint32 objectId) {
391 return _dict->getObjectControl(objectId);
392 }
393
getNamedPointPosition(uint32 namedPointId)394 Common::Point IllusionsEngine_BBDOU::getNamedPointPosition(uint32 namedPointId) {
395 Common::Point pt;
396 if (_backgroundInstances->findActiveBackgroundNamedPoint(namedPointId, pt) ||
397 _actorInstances->findNamedPoint(namedPointId, pt) ||
398 _controls->findNamedPoint(namedPointId, pt))
399 return pt;
400 // TODO
401 switch (namedPointId) {
402 case 0x70001:
403 return Common::Point(0, 0);
404 case 0x70002:
405 return Common::Point(640, 0);
406 case 0x70023:
407 return Common::Point(320, 240);
408 }
409 debug("getNamedPointPosition(%08X) UNKNOWN", namedPointId);
410 return Common::Point(0, 0);
411 }
412
getPriorityFromBase(int16 priority)413 uint32 IllusionsEngine_BBDOU::getPriorityFromBase(int16 priority) {
414 return 32000000 * priority;
415 }
416
getCurrentScene()417 uint32 IllusionsEngine_BBDOU::getCurrentScene() {
418 return _activeScenes.getCurrentScene();
419 }
420
getPrevScene()421 uint32 IllusionsEngine_BBDOU::getPrevScene() {
422 return _prevSceneId;
423 }
424
isCursorObject(uint32 actorTypeId,uint32 objectId)425 bool IllusionsEngine_BBDOU::isCursorObject(uint32 actorTypeId, uint32 objectId) {
426 return actorTypeId == 0x50001 && objectId == Illusions::CURSOR_OBJECT_ID;
427 }
428
setCursorControlRoutine(Control * control)429 void IllusionsEngine_BBDOU::setCursorControlRoutine(Control *control) {
430 control->_actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, IllusionsEngine_BBDOU>
431 (this, &IllusionsEngine_BBDOU::cursorControlRoutine));
432 }
433
placeCursorControl(Control * control,uint32 sequenceId)434 void IllusionsEngine_BBDOU::placeCursorControl(Control *control, uint32 sequenceId) {
435 _cursor->place(control, sequenceId);
436 }
437
setCursorControl(Control * control)438 void IllusionsEngine_BBDOU::setCursorControl(Control *control) {
439 _cursor->setControl(control);
440 }
441
showCursor()442 void IllusionsEngine_BBDOU::showCursor() {
443 _cursor->show();
444 }
445
hideCursor()446 void IllusionsEngine_BBDOU::hideCursor() {
447 _cursor->hide();
448 }
449
cursorControlRoutine(Control * control,uint32 deltaTime)450 void IllusionsEngine_BBDOU::cursorControlRoutine(Control *control, uint32 deltaTime) {
451 control->_actor->_seqCodeValue1 = 100 * deltaTime;
452 if (control->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) {
453 switch (_cursor->_status) {
454 case 2:
455 // Unused nullsub_1(control);
456 break;
457 case 3:
458 _menuSystem->update(control);
459 break;
460 }
461 }
462 }
463
startScriptThreadSimple(uint32 threadId,uint32 callingThreadId)464 void IllusionsEngine_BBDOU::startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) {
465 startScriptThread(threadId, callingThreadId, 0, 0, 0);
466 }
467
startScriptThread(uint32 threadId,uint32 callingThreadId,uint32 value8,uint32 valueC,uint32 value10)468 void IllusionsEngine_BBDOU::startScriptThread(uint32 threadId, uint32 callingThreadId,
469 uint32 value8, uint32 valueC, uint32 value10) {
470 if (threadId == 0x0002041E && ConfMan.hasKey("save_slot")) {
471 // Skip intro videos when loading a savegame from the launcher (kludge)
472 notifyThreadId(callingThreadId);
473 return;
474 }
475 debug(2, "Starting script thread %08X", threadId);
476 byte *scriptCodeIp = _scriptResource->getThreadCode(threadId);
477 newScriptThread(threadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10);
478 }
479
startAnonScriptThread(int32 threadId,uint32 callingThreadId,uint32 value8,uint32 valueC,uint32 value10)480 void IllusionsEngine_BBDOU::startAnonScriptThread(int32 threadId, uint32 callingThreadId,
481 uint32 value8, uint32 valueC, uint32 value10) {
482 debug(2, "Starting anonymous script thread %08X", threadId);
483 uint32 tempThreadId = newTempThreadId();
484 byte *scriptCodeIp = _scriptResource->getThreadCode(threadId);
485 scriptCodeIp = _scriptResource->getThreadCode(threadId);
486 newScriptThread(tempThreadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10);
487 }
488
startAbortableTimerThread(uint32 duration,uint32 threadId)489 uint32 IllusionsEngine_BBDOU::startAbortableTimerThread(uint32 duration, uint32 threadId) {
490 return newTimerThread(duration, threadId, true);
491 }
492
startTimerThread(uint32 duration,uint32 threadId)493 uint32 IllusionsEngine_BBDOU::startTimerThread(uint32 duration, uint32 threadId) {
494 return newTimerThread(duration, threadId, false);
495 }
496
startAbortableThread(byte * scriptCodeIp1,byte * scriptCodeIp2,uint32 callingThreadId)497 uint32 IllusionsEngine_BBDOU::startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId) {
498 uint32 tempThreadId = newTempThreadId();
499 debug(2, "Starting abortable thread %08X", tempThreadId);
500 uint32 scriptThreadId = startTempScriptThread(scriptCodeIp1, tempThreadId, 0, 0, 0);
501 AbortableThread *abortableThread = new AbortableThread(this, tempThreadId, callingThreadId, 0,
502 scriptThreadId, scriptCodeIp2);
503 _threads->startThread(abortableThread);
504 return tempThreadId;
505 }
506
startTalkThread(int16 duration,uint32 objectId,uint32 talkId,uint32 sequenceId1,uint32 sequenceId2,uint32 namedPointId,uint32 callingThreadId)507 uint32 IllusionsEngine_BBDOU::startTalkThread(int16 duration, uint32 objectId, uint32 talkId, uint32 sequenceId1,
508 uint32 sequenceId2, uint32 namedPointId, uint32 callingThreadId) {
509 debug(2, "Starting talk thread");
510 uint32 tempThreadId = newTempThreadId();
511 _threads->endTalkThreadsNoNotify();
512 TalkThread *talkThread = new TalkThread(this, tempThreadId, callingThreadId, 0,
513 duration, objectId, talkId, sequenceId1, sequenceId2, namedPointId);
514 _threads->startThread(talkThread);
515 return tempThreadId;
516 }
517
startTempScriptThread(byte * scriptCodeIp,uint32 callingThreadId,uint32 value8,uint32 valueC,uint32 value10)518 uint32 IllusionsEngine_BBDOU::startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId,
519 uint32 value8, uint32 valueC, uint32 value10) {
520 uint32 tempThreadId = newTempThreadId();
521 debug(2, "Starting temp script thread %08X", tempThreadId);
522 newScriptThread(tempThreadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10);
523 return tempThreadId;
524 }
525
newScriptThread(uint32 threadId,uint32 callingThreadId,uint notifyFlags,byte * scriptCodeIp,uint32 value8,uint32 valueC,uint32 value10)526 void IllusionsEngine_BBDOU::newScriptThread(uint32 threadId, uint32 callingThreadId, uint notifyFlags,
527 byte *scriptCodeIp, uint32 value8, uint32 valueC, uint32 value10) {
528 ScriptThread *scriptThread = new ScriptThread(this, threadId, callingThreadId, notifyFlags,
529 scriptCodeIp, value8, valueC, value10);
530 _threads->startThread(scriptThread);
531 if (_pauseCtr > 0)
532 scriptThread->pause();
533 if (_doScriptThreadInit) {
534 int updateResult = kTSRun;
535 while (scriptThread->_pauseCtr <= 0 && updateResult != kTSTerminate && updateResult != kTSYield) {
536 updateResult = scriptThread->update();
537 }
538 }
539 }
540
newTimerThread(uint32 duration,uint32 callingThreadId,bool isAbortable)541 uint32 IllusionsEngine_BBDOU::newTimerThread(uint32 duration, uint32 callingThreadId, bool isAbortable) {
542 uint32 tempThreadId = newTempThreadId();
543 TimerThread *timerThread = new TimerThread(this, tempThreadId, callingThreadId, 0,
544 duration, isAbortable);
545 _threads->startThread(timerThread);
546 return tempThreadId;
547 }
548
newTempThreadId()549 uint32 IllusionsEngine_BBDOU::newTempThreadId() {
550 uint32 threadId = _nextTempThreadId + 2 * _scriptResource->_codeCount;
551 if (threadId > 65535) {
552 _nextTempThreadId = 0;
553 threadId = 2 * _scriptResource->_codeCount;
554 }
555 ++_nextTempThreadId;
556 return 0x00020000 | threadId;
557 }
558
enterScene(uint32 sceneId,uint32 threadId)559 bool IllusionsEngine_BBDOU::enterScene(uint32 sceneId, uint32 threadId) {
560 SceneInfo *sceneInfo = _scriptResource->getSceneInfo(sceneId & 0xFFFF);
561 if (!sceneInfo) {
562 dumpActiveScenes(_globalSceneId, threadId);
563 sceneId = _theSceneId;
564 }
565 _activeScenes.push(sceneId);
566 if (sceneId == 0x0001007D) {
567 // Savegame loading from the ScummVM GUI or command line is only
568 // possible after resources have been initialized by the startup script.
569 // Once that script is done, it switches to the start menu scene.
570 // After that the game is ready and a savegame can finally be loaded.
571 _canResumeFromSavegame = true;
572 }
573 return sceneInfo != 0;
574 }
575
exitScene(uint32 threadId)576 void IllusionsEngine_BBDOU::exitScene(uint32 threadId) {
577 uint32 sceneId = _activeScenes.getCurrentScene();
578 _updateFunctions->terminateByScene(sceneId);
579 _threads->terminateThreadsBySceneId(sceneId, threadId);
580 _controls->destroyControlsBySceneId(sceneId);
581 _triggerFunctions->removeBySceneId(sceneId);
582 _resSys->unloadResourcesBySceneId(sceneId);
583 _activeScenes.pop();
584 }
585
enterPause(uint32 threadId)586 void IllusionsEngine_BBDOU::enterPause(uint32 threadId) {
587 uint32 sceneId = _activeScenes.getCurrentScene();
588 _camera->pushCameraMode();
589 _threads->suspendThreadsBySceneId(sceneId, threadId);
590 _controls->pauseControlsBySceneId(sceneId);
591 _actorInstances->pauseBySceneId(sceneId);
592 _backgroundInstances->pauseBySceneId(sceneId);
593 _activeScenes.pauseActiveScene();
594 }
595
leavePause(uint32 threadId)596 void IllusionsEngine_BBDOU::leavePause(uint32 threadId) {
597 uint32 sceneId = _activeScenes.getCurrentScene();
598 _backgroundInstances->unpauseBySceneId(sceneId);
599 _actorInstances->unpauseBySceneId(sceneId);
600 _controls->unpauseControlsBySceneId(sceneId);
601 _threads->notifyThreadsBySceneId(sceneId, threadId);
602 _camera->popCameraMode();
603 _activeScenes.unpauseActiveScene();
604 }
605
dumpActiveScenes(uint32 sceneId,uint32 threadId)606 void IllusionsEngine_BBDOU::dumpActiveScenes(uint32 sceneId, uint32 threadId) {
607 uint activeScenesCount = _activeScenes.getActiveScenesCount();
608 while (activeScenesCount > 0) {
609 uint32 activeSceneId;
610 _activeScenes.getActiveSceneInfo(activeScenesCount, &activeSceneId, 0);
611 if (activeSceneId == sceneId)
612 break;
613 exitScene(threadId);
614 --activeScenesCount;
615 }
616 _camera->clearCameraModeStack();
617 }
618
pause(uint32 callerThreadId)619 void IllusionsEngine_BBDOU::pause(uint32 callerThreadId) {
620 if (++_pauseCtr == 1) {
621 _threads->pauseThreads(callerThreadId);
622 _camera->pause();
623 pauseFader();
624 _controls->pauseActors(0x40004);
625 }
626 }
627
unpause(uint32 callerThreadId)628 void IllusionsEngine_BBDOU::unpause(uint32 callerThreadId) {
629 if (--_pauseCtr == 0) {
630 _controls->unpauseActors(0x40004);
631 unpauseFader();
632 _camera->unpause();
633 _threads->unpauseThreads(callerThreadId);
634 }
635 }
636
enterMenuPause()637 void IllusionsEngine_BBDOU::enterMenuPause() {
638 // TODO suspendAudio();
639 _screenText->clearText();
640 }
641
leaveMenuPause()642 void IllusionsEngine_BBDOU::leaveMenuPause() {
643 _screenText->removeText();
644 // TODO unsuspendAudio();
645 }
646
setSceneIdThreadId(uint32 theSceneId,uint32 theThreadId)647 void IllusionsEngine_BBDOU::setSceneIdThreadId(uint32 theSceneId, uint32 theThreadId) {
648 _theSceneId = theSceneId;
649 _theThreadId = theThreadId;
650 }
651
findTriggerCause(uint32 sceneId,uint32 verbId,uint32 objectId2,uint32 objectId,uint32 & codeOffs)652 bool IllusionsEngine_BBDOU::findTriggerCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs) {
653 SceneInfo *sceneInfo = _scriptResource->getSceneInfo(sceneId & 0xFFFF);
654 if (sceneInfo)
655 return sceneInfo->findTriggerCause(verbId, objectId2, objectId, codeOffs);
656 return false;
657 }
658
reset()659 void IllusionsEngine_BBDOU::reset() {
660 _scriptResource->_blockCounters.clear();
661 _scriptResource->_properties.clear();
662 setTextDuration(1, 0);
663 }
664
loadSavegameFromScript(int16 slotNum,uint32 callingThreadId)665 void IllusionsEngine_BBDOU::loadSavegameFromScript(int16 slotNum, uint32 callingThreadId) {
666 // NOTE Just loads the savegame, doesn't activate it yet
667 const char *fileName = getSavegameFilename(_savegameSlotNum);
668 _loadGameResult = loadgame(fileName);
669 }
670
saveSavegameFromScript(int16 slotNum,uint32 callingThreadId)671 void IllusionsEngine_BBDOU::saveSavegameFromScript(int16 slotNum, uint32 callingThreadId) {
672 // TODO
673 // const char *fileName = getSavegameFilename(slotNum);
674 _saveGameResult = false;//savegame(fileName, _savegameDescription.c_str());
675 }
676
activateSavegame(uint32 callingThreadId)677 void IllusionsEngine_BBDOU::activateSavegame(uint32 callingThreadId) {
678 uint32 sceneId, threadId;
679 _prevSceneId = 0x10000;
680 _gameState->readState(sceneId, threadId);
681 enterScene(sceneId, callingThreadId);
682 // TODO Check if value8, valueC, value10 are needed at all
683 startAnonScriptThread(threadId, 0, 0, 0, 0);
684 _gameState->deleteReadStream();
685 }
686
resumeFromSavegame()687 void IllusionsEngine_BBDOU::resumeFromSavegame() {
688 // Resetting the game is usually done by the script, when loading from the ScummVM menu or
689 // command line this has to be done manually.
690 _specialCode->resetBeforeResumeSavegame();
691 dumpActiveScenes(0x00010003, 0);
692 activateSavegame(0);
693 }
694
695 } // End of namespace Illusions
696