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