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 "bladerunner/scene.h"
24
25 #include "bladerunner/actor.h"
26 #include "bladerunner/actor_dialogue_queue.h"
27 #include "bladerunner/bladerunner.h"
28 #include "bladerunner/chapters.h"
29 #include "bladerunner/game_info.h"
30 #include "bladerunner/items.h"
31 #include "bladerunner/overlays.h"
32 #include "bladerunner/regions.h"
33 #include "bladerunner/savefile.h"
34 #include "bladerunner/scene_objects.h"
35 #include "bladerunner/screen_effects.h"
36 #include "bladerunner/set.h"
37 #include "bladerunner/settings.h"
38 #include "bladerunner/slice_renderer.h"
39 #include "bladerunner/script/police_maze.h"
40 #include "bladerunner/script/scene_script.h"
41 #include "bladerunner/ui/spinner.h"
42 #include "bladerunner/vqa_player.h"
43 #include "bladerunner/zbuffer.h"
44
45 #include "common/str.h"
46
47 namespace BladeRunner {
48
Scene(BladeRunnerEngine * vm)49 Scene::Scene(BladeRunnerEngine *vm)
50 : _vm(vm),
51 _setId(-1),
52 _sceneId(-1),
53 _vqaPlayer(nullptr),
54 _defaultLoop(0),
55 _defaultLoopSet(false),
56 _specialLoopMode(kSceneLoopModeLoseControl),
57 _specialLoop(0),
58 _defaultLoopPreloadedSet(false),
59 // _introFinished(false),
60 _nextSetId(-1),
61 _nextSceneId(-1),
62 _frame(0),
63 _actorStartFacing(0),
64 _playerWalkedIn(false),
65 _set(new Set(vm)),
66 _regions(new Regions()),
67 _exits(new Regions()) {
68 }
69
~Scene()70 Scene::~Scene() {
71 delete _set;
72 delete _regions;
73 delete _exits;
74 delete _vqaPlayer;
75 }
76
open(int setId,int sceneId,bool isLoadingGame)77 bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
78 if (!isLoadingGame) {
79 _vm->_actorDialogueQueue->flush(1, false);
80 }
81
82 _vm->walkingReset();
83
84 _setId = setId;
85 _sceneId = sceneId;
86
87 const Common::String sceneName = _vm->_gameInfo->getSceneName(_sceneId);
88
89 if (isLoadingGame) {
90 _vm->_overlays->resume(true);
91 } else {
92 _regions->clear();
93 _exits->clear();
94 #if BLADERUNNER_ORIGINAL_BUGS
95 #else
96 _vm->_screenEffects->toggleEntry(-1, false); // clear the skip list
97 #endif
98 _vm->_screenEffects->_entries.clear();
99 _vm->_overlays->removeAll();
100 _defaultLoop = 0;
101 _defaultLoopSet = false;
102 _defaultLoopPreloadedSet = false;
103 _specialLoopMode = kSceneLoopModeNone;
104 _specialLoop = -1;
105 _frame = -1;
106 }
107
108 Common::String vqaName;
109 int currentResourceId = _vm->_chapters->currentResourceId();
110 if (currentResourceId == 1) {
111 vqaName = Common::String::format("%s.VQA", sceneName.c_str());
112 } else {
113 vqaName = Common::String::format("%s_%d.VQA", sceneName.c_str(), MIN(currentResourceId, 3));
114 }
115
116 if (_vqaPlayer != nullptr) {
117 delete _vqaPlayer;
118 }
119
120 _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, vqaName);
121
122 if (!_vm->_sceneScript->open(sceneName)) {
123 return false;
124 }
125
126 if (!isLoadingGame) {
127 _vm->_sceneScript->initializeScene();
128 }
129
130 Common::String setResourceName = Common::String::format("%s-MIN.SET", sceneName.c_str());
131 if (!_set->open(setResourceName)) {
132 return false;
133 }
134
135 _vm->_sliceRenderer->setView(_vm->_view);
136
137 if (isLoadingGame) {
138 resume(true);
139 if (sceneId == kScenePS10 // police maze
140 || sceneId == kScenePS11 // police maze
141 || sceneId == kScenePS12 // police maze
142 || sceneId == kScenePS13 // police maze
143 #if BLADERUNNER_ORIGINAL_BUGS
144 #else
145 || sceneId == kSceneUG01 // Steam room
146 #endif // BLADERUNNER_ORIGINAL_BUGS
147 ) {
148 _vm->_sceneScript->sceneLoaded();
149 }
150 return true;
151 }
152
153 if (!_vqaPlayer->open()) {
154 return false;
155 }
156
157 if (_specialLoopMode == kSceneLoopModeNone) {
158 startDefaultLoop();
159 }
160
161 // This frame advancement (frame skip) may be required here
162 // It is in the original code and possible initializes some variables
163 // (or perhaps z-buffering related stuff)
164 // It may cause issues when in a scene we need to trigger some action
165 // based on the first frame of the loop when entering the scene (using SceneFrameAdvanced())
166 // (eg. it is contributing to the barrel flame glitch in pan from DR04 to DR01)
167 // However, better to resolve those issues with a workaround (eg. using InitializeScene())
168 advanceFrame();
169
170 _vm->_playerActor->setAtXYZ(_actorStartPosition, _actorStartFacing);
171 _vm->_playerActor->setSetId(setId);
172
173 _vm->_sceneScript->sceneLoaded();
174
175 _vm->_sceneObjects->clear();
176
177 // Init click map
178 int actorCount = _vm->_gameInfo->getActorCount();
179 for (int i = 0; i != actorCount; ++i) {
180 Actor *actor = _vm->_actors[i];
181 if (actor->getSetId() == setId) {
182 //debug("Actor added: %d", i);
183 #if !BLADERUNNER_ORIGINAL_BUGS
184 // ensure that actors' "hotspot" areas from previous scene are cleared up
185 actor->resetScreenRectangleAndBbox();
186 #endif
187 _vm->_sceneObjects->addActor(
188 i + kSceneObjectOffsetActors,
189 actor->getBoundingBox(),
190 actor->getScreenRectangle(),
191 true,
192 false,
193 actor->isTarget(),
194 actor->isRetired()
195 );
196 }
197 }
198
199 _set->addObjectsToScene(_vm->_sceneObjects);
200 _vm->_items->addToSet(setId);
201 _vm->_sceneObjects->updateObstacles();
202
203 if (_specialLoopMode != kSceneLoopModeLoseControl) {
204 _vm->_sceneScript->playerWalkedIn();
205 }
206
207 return true;
208 }
209
close(bool isLoadingGame)210 bool Scene::close(bool isLoadingGame) {
211 bool result = true;
212 if (getSetId() == -1) {
213 return true;
214 }
215
216 _vm->_policeMaze->clear(!isLoadingGame);
217
218 if (isLoadingGame) {
219 _vm->_sceneScript->playerWalkedOut();
220 }
221
222 // if (SceneScript_isLoaded() && !SceneScript_unload()) {
223 // result = false;
224 // }
225 if (_vqaPlayer != nullptr) {
226 //_vqaPlayer->stop();
227 delete _vqaPlayer;
228 _vqaPlayer = nullptr;
229 }
230 _sceneId = -1;
231 _setId = -1;
232
233 return result;
234 }
235
advanceFrame(bool useTime)236 int Scene::advanceFrame(bool useTime) {
237 int frame = _vqaPlayer->update(false, true, useTime);
238 if (frame >= 0) {
239 blit(_vm->_surfaceBack, _vm->_surfaceFront);
240 _vqaPlayer->updateZBuffer(_vm->_zbuffer);
241 _vqaPlayer->updateView(_vm->_view);
242 _vqaPlayer->updateScreenEffects(_vm->_screenEffects);
243 _vqaPlayer->updateLights(_vm->_lights);
244 }
245
246 if (_specialLoopMode == kSceneLoopModeLoseControl || _specialLoopMode == kSceneLoopModeOnce || _specialLoopMode == kSceneLoopModeSpinner) {
247 if (!_defaultLoopSet) {
248 _vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeEnqueue, &Scene::loopEndedStatic, this);
249 _defaultLoopSet = true;
250 if (_specialLoopMode == kSceneLoopModeLoseControl) {
251 _vm->playerLosesControl();
252 }
253 }
254 } else if (_specialLoopMode == kSceneLoopModeChangeSet) {
255 if (frame == -3) { // EOF
256 _vm->_settings->setNewSetAndScene(_nextSetId, _nextSceneId);
257 _vm->playerGainsControl();
258 }
259 } else if (_specialLoopMode == kSceneLoopModeNone) {
260 if (!_defaultLoopPreloadedSet) {
261 _vqaPlayer->setLoop(_defaultLoop + 1, -1, kLoopSetModeJustStart, &Scene::loopEndedStatic, this);
262 _defaultLoopPreloadedSet = true;
263 }
264 }
265
266 if (frame >= 0) {
267 _frame = frame;
268 }
269
270 return frame;
271 }
272
resume(bool isLoadingGame)273 void Scene::resume(bool isLoadingGame) {
274 if (!_vqaPlayer) {
275 return;
276 }
277
278 int targetFrame = _frame;
279
280 if (isLoadingGame) {
281 _vqaPlayer->open();
282 } else {
283 _vm->_zbuffer->disable();
284 }
285
286 if (_specialLoopMode == kSceneLoopModeNone) {
287 startDefaultLoop();
288 } else {
289 if (_specialLoopMode == kSceneLoopModeChangeSet) {
290 _vm->_settings->setNewSetAndScene(_setId, _sceneId);
291 }
292 if (_defaultLoopPreloadedSet) {
293 _specialLoopMode = kSceneLoopModeNone;
294 startDefaultLoop();
295 advanceFrame(false);
296 loopStartSpecial(_specialLoopMode, _specialLoop, false);
297 } else {
298 _defaultLoopPreloadedSet = true;
299 loopStartSpecial(_specialLoopMode, _specialLoop, true);
300 if (_specialLoopMode == kSceneLoopModeLoseControl || _specialLoopMode == kSceneLoopModeChangeSet) {
301 _vm->playerGainsControl();
302 }
303 }
304 if (_specialLoopMode == kSceneLoopModeChangeSet) {
305 _vm->_settings->clearNewSetAndScene();
306 }
307 }
308
309 int frame, frameStart, frameEnd;
310 do {
311 // fast forward to targetFrame but do, at the very least, one advanceFrame() (with time=false)
312 frame = advanceFrame(false);
313 // check if active loop has changed, and we need to adjust targetFrame
314 if (_vqaPlayer->getCurrentBeginAndEndFrame(frame, &frameStart, &frameEnd)
315 && targetFrame >= 0
316 && (targetFrame < frameStart || targetFrame > frameEnd)
317 ) {
318 // active loop has changed, and targetFrame has a remnant frame value from the previous loop's frameset,
319 // so set it to the current loop's start
320 targetFrame = frameStart;
321 }
322 } while (frame >= 0 && frame != targetFrame);
323
324 if (!isLoadingGame) {
325 _vm->_zbuffer->enable();
326 }
327 }
328
startDefaultLoop()329 void Scene::startDefaultLoop() {
330 _vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeImmediate, nullptr, nullptr);
331 _defaultLoopSet = true;
332 _defaultLoopPreloadedSet = false;
333 }
334
setActorStart(Vector3 position,int facing)335 void Scene::setActorStart(Vector3 position, int facing) {
336 _actorStartPosition = position;
337 _actorStartFacing = facing;
338 }
339
loopSetDefault(int loopId)340 void Scene::loopSetDefault(int loopId) {
341 _defaultLoop = loopId;
342 }
343
loopStartSpecial(int specialLoopMode,int loopId,bool immediately)344 void Scene::loopStartSpecial(int specialLoopMode, int loopId, bool immediately) {
345 _specialLoopMode = specialLoopMode;
346 _specialLoop = loopId;
347
348 int repeats = -1;
349 if (_specialLoopMode == kSceneLoopModeChangeSet) {
350 repeats = 0;
351 }
352
353 int loopMode = kLoopSetModeEnqueue;
354 if (immediately) {
355 loopMode = kLoopSetModeImmediate;
356 }
357
358 _vqaPlayer->setLoop(_specialLoop, repeats, loopMode, &Scene::loopEndedStatic, this);
359 if (_specialLoopMode == kSceneLoopModeChangeSet) {
360 _nextSetId = _vm->_settings->getNewSet();
361 _nextSceneId = _vm->_settings->getNewScene();
362 }
363 if (immediately) {
364 _defaultLoopPreloadedSet = true;
365 loopEnded(0, _specialLoop);
366 }
367 }
368
findObject(const Common::String & objectName)369 int Scene::findObject(const Common::String &objectName) {
370 return _set->findObject(objectName);
371 }
372
objectSetHotMouse(int objectId)373 bool Scene::objectSetHotMouse(int objectId) {
374 return _set->objectSetHotMouse(objectId);
375 }
376
objectGetBoundingBox(int objectId,BoundingBox * boundingBox)377 bool Scene::objectGetBoundingBox(int objectId, BoundingBox *boundingBox) {
378 return _set->objectGetBoundingBox(objectId, boundingBox);
379 }
380
objectSetIsClickable(int objectId,bool isClickable,bool sceneLoaded)381 void Scene::objectSetIsClickable(int objectId, bool isClickable, bool sceneLoaded) {
382 _set->objectSetIsClickable(objectId, isClickable);
383 if (sceneLoaded) {
384 _vm->_sceneObjects->setIsClickable(objectId + kSceneObjectOffsetObjects, isClickable);
385 }
386 }
387
objectSetIsObstacle(int objectId,bool isObstacle,bool sceneLoaded,bool updateWalkpath)388 void Scene::objectSetIsObstacle(int objectId, bool isObstacle, bool sceneLoaded, bool updateWalkpath) {
389 _set->objectSetIsObstacle(objectId, isObstacle);
390 if (sceneLoaded) {
391 _vm->_sceneObjects->setIsObstacle(objectId + kSceneObjectOffsetObjects, isObstacle);
392 if (updateWalkpath) {
393 _vm->_sceneObjects->updateObstacles();
394 }
395 }
396 }
397
objectSetIsObstacleAll(bool isObstacle,bool sceneLoaded)398 void Scene::objectSetIsObstacleAll(bool isObstacle, bool sceneLoaded) {
399 int i;
400 for (i = 0; i < (int)_set->getObjectCount(); ++i) {
401 _set->objectSetIsObstacle(i, isObstacle);
402 if (sceneLoaded) {
403 _vm->_sceneObjects->setIsObstacle(i + kSceneObjectOffsetObjects, isObstacle);
404 }
405 }
406 }
407
objectSetIsTarget(int objectId,bool isTarget,bool sceneLoaded)408 void Scene::objectSetIsTarget(int objectId, bool isTarget, bool sceneLoaded) {
409 _set->objectSetIsTarget(objectId, isTarget);
410 if (sceneLoaded) {
411 _vm->_sceneObjects->setIsTarget(objectId + kSceneObjectOffsetObjects, isTarget);
412 }
413 }
414
objectGetName(int objectId)415 const Common::String &Scene::objectGetName(int objectId) {
416 return _set->objectGetName(objectId);
417 }
418
loopEnded(int frame,int loopId)419 void Scene::loopEnded(int frame, int loopId) {
420 if (_specialLoopMode == kSceneLoopModeLoseControl || _specialLoopMode == kSceneLoopModeOnce || _specialLoopMode == kSceneLoopModeSpinner) {
421 if (_defaultLoopPreloadedSet) {
422 _vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeEnqueue, &Scene::loopEndedStatic, this);
423 _defaultLoopSet = true;
424 _defaultLoopPreloadedSet = false;
425 if (_specialLoopMode == kSceneLoopModeLoseControl) {
426 _vm->playerLosesControl();
427 }
428 } else {
429 if (_specialLoopMode == kSceneLoopModeLoseControl) {
430 _vm->playerGainsControl();
431 _playerWalkedIn = true;
432 }
433 if (_specialLoopMode == kSceneLoopModeSpinner) {
434 _vm->_spinner->open();
435 }
436 _specialLoopMode = kSceneLoopModeNone;
437 _specialLoop = -1;
438 _vqaPlayer->setLoop(_defaultLoop + 1, -1, kLoopSetModeJustStart, nullptr, nullptr);
439 _defaultLoopPreloadedSet = true;
440 }
441 } else if (_specialLoopMode == kSceneLoopModeChangeSet) {
442 _defaultLoopSet = true;
443 _defaultLoopPreloadedSet = false;
444 _vm->playerLosesControl();
445 }
446 }
447
loopEndedStatic(void * data,int frame,int loopId)448 void Scene::loopEndedStatic(void *data, int frame, int loopId) {
449 ((Scene *)data)->loopEnded(frame, loopId);
450 }
451
save(SaveFileWriteStream & f)452 void Scene::save(SaveFileWriteStream &f) {
453 f.writeInt(_setId);
454 f.writeInt(_sceneId);
455 f.writeInt(_defaultLoop);
456 f.writeBool(_defaultLoopSet);
457 f.writeBool(_defaultLoopPreloadedSet);
458 f.writeInt(_specialLoopMode);
459 f.writeInt(_specialLoop);
460 f.writeInt(_nextSetId);
461 f.writeInt(_nextSceneId);
462 f.writeInt(_frame);
463 f.writeVector3(_actorStartPosition);
464 f.writeInt(_actorStartFacing);
465 f.writeBool(_playerWalkedIn);
466 }
467
load(SaveFileReadStream & f)468 void Scene::load(SaveFileReadStream &f) {
469 _setId = f.readInt();
470 _sceneId = f.readInt();
471 _defaultLoop = f.readInt();
472 _defaultLoopSet = f.readBool();
473 _defaultLoopPreloadedSet = f.readBool();
474 _specialLoopMode = f.readInt();
475 _specialLoop = f.readInt();
476 _nextSetId = f.readInt();
477 _nextSceneId = f.readInt();
478 _frame = f.readInt();
479 _actorStartPosition = f.readVector3();
480 _actorStartFacing = f.readInt();
481 _playerWalkedIn = f.readBool();
482 }
483
484 } // End of namespace BladeRunner
485