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 #include "dragons/scene.h"
23 #include "dragons/dragons.h"
24 #include "dragons/actor.h"
25 #include "dragons/background.h"
26 #include "dragons/cursor.h"
27 #include "dragons/credits.h"
28 #include "dragons/dragonini.h"
29 #include "dragons/dragonimg.h"
30 #include "dragons/font.h"
31 #include "dragons/inventory.h"
32 #include "dragons/screen.h"
33 #include "dragons/actorresource.h"
34 #include "dragons/scriptopcodes.h"
35 
36 namespace Dragons {
37 
38 
Scene(DragonsEngine * vm,Screen * screen,ScriptOpcodes * scriptOpcodes,ActorManager * actorManager,DragonRMS * dragonRMS,DragonINIResource * dragonINIResource,BackgroundResourceLoader * backgroundResourceLoader)39 Scene::Scene(DragonsEngine *vm, Screen *screen, ScriptOpcodes *scriptOpcodes, ActorManager *actorManager, DragonRMS *dragonRMS, DragonINIResource *dragonINIResource, BackgroundResourceLoader *backgroundResourceLoader)
40 		: _vm(vm), _screen(screen), _scriptOpcodes(scriptOpcodes), _stage(0), _actorManager(actorManager), _dragonRMS(dragonRMS), _dragonINIResource(dragonINIResource), _backgroundLoader(backgroundResourceLoader) {
41 	_mapTransitionEffectSceneID = 2;
42 	_data_800633ee = 0;
43 
44 	_currentSceneId = -1;
45 }
loadScene(uint32 sceneId,uint32 cameraPointId)46 void Scene::loadScene(uint32 sceneId, uint32 cameraPointId) {
47 	if (!_vm->isFlagSet(ENGINE_FLAG_40)) {
48 		_vm->fadeToBlack();
49 	}
50 	bool unkFlag2Set = _vm->isUnkFlagSet(ENGINE_UNK1_FLAG_2);
51 	bool flag8set = _vm->isFlagSet(ENGINE_FLAG_8);
52 	_vm->clearFlags(ENGINE_FLAG_8);
53 	_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
54 
55 	for (int i = 0; i < 8; i++) {
56 		_vm->_paletteCyclingTbl[i].updateInterval = 0;
57 	}
58 
59 	// TODO
60 	_vm->reset_screen_maybe();
61 
62 	loadSceneData(sceneId, cameraPointId);
63 
64 	if (flag8set) {
65 		_vm->setFlags(ENGINE_FLAG_8);
66 	}
67 
68 	if (!_vm->isFlagSet(ENGINE_FLAG_8000000) && sceneId != 4) {
69 		_vm->_cursor->updateSequenceID((int16)_vm->_cursor->_sequenceID);
70 	}
71 	_vm->waitForFrames(2);
72 	_vm->fadeFromBlack();
73 	if (!unkFlag2Set) {
74 		_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
75 	}
76 	_data_800633ee = 0;
77 
78 	if (!(sceneId & 0x8000)) {
79 		byte *obd = _dragonRMS->getAfterSceneLoadedScript(sceneId);
80 		ScriptOpCall scriptOpCall(obd + 4, READ_LE_UINT32(obd));
81 		_scriptOpcodes->runScript(scriptOpCall);
82 	}
83 	DragonINI *ini = _dragonINIResource->getRecord(0xc4);
84 	ini->objectState = 0;
85 }
86 
loadSceneData(uint32 sceneId,uint32 cameraPointId)87 void Scene::loadSceneData(uint32 sceneId, uint32 cameraPointId) {
88 	bool isUnkFlag2Set = _vm->isUnkFlagSet(ENGINE_UNK1_FLAG_2);
89 
90 	_vm->setUnkFlags(ENGINE_UNK1_FLAG_2 | Dragons::ENGINE_UNK1_FLAG_8);
91 
92 	for (int i = 0; i < _dragonINIResource->totalRecords(); i++) {
93 		DragonINI *ini = _dragonINIResource->getRecord(i);
94 		ini->counter = -1;
95 		ini->flags &= ~INI_FLAG_10;
96 	}
97 
98 	uint16 sceneIdStripped = (uint16)sceneId & ~0x8000;
99 	if (sceneIdStripped == 0x18 || sceneIdStripped == 0x26 || sceneIdStripped == 0x7 ||
100 			sceneIdStripped == 0x17 || sceneIdStripped == 0x5 || sceneIdStripped == 0x19 ||
101 			sceneIdStripped == 0x34 || sceneIdStripped == 0x1d || sceneIdStripped == 0x6) {
102 //		buf2048bytes = buf2048bytes + 0x1800;
103 		// error("0x8002f404"); //TODO do we need this logic?
104 	}
105 
106 	_screen->setScreenShakeOffset(0, 0);
107 
108 	if (!(sceneId & 0x8000)) {
109 		byte *obd = _dragonRMS->getBeforeSceneDataLoadedScript(sceneId);
110 		ScriptOpCall scriptOpCall(obd + 4, READ_LE_UINT32(obd));
111 		uint16 oldSceneId = _currentSceneId;
112 		_currentSceneId = -1;
113 		_scriptOpcodes->runScript(scriptOpCall);
114 		_currentSceneId = oldSceneId;
115 	}
116 
117 	_actorManager->clearActorFlags(2);
118 	//TODO stopAndCloseSceneVab()
119 
120 	_vm->_cursor->setActorFlag400();
121 	_vm->_inventory->setActorFlag400();
122 	_vm->clearFlags(ENGINE_FLAG_200);
123 
124 	resetActorFrameFlags();
125 
126 	// Loading animation logic would go here. 0x8002f538
127 
128 	_vm->clearFlags(ENGINE_FLAG_20);
129 	_vm->setUnkFlags(ENGINE_UNK1_FLAG_10);
130 
131 	_vm->fadeFromBlack();
132 	// TODO 0x8002f7c4
133 
134 	_vm->_cursor->updatePosition(160, 100);
135 
136 	_vm->clearFlags(ENGINE_FLAG_100000);
137 	_vm->clearFlags(ENGINE_FLAG_200000);
138 
139 	DragonINI *flicker = _vm->_dragonINIResource->getFlickerRecord();
140 
141 	if (flicker == nullptr || flicker->sceneId == 0) {
142 		_vm->getINI(1)->sceneId = 0;
143 	} else {
144 		_currentSceneId = (uint16)(sceneId & 0x7fff);
145 		flicker->sceneId = _currentSceneId;
146 		_vm->getINI(1)->sceneId = _currentSceneId;
147 	}
148 
149 	_vm->loadCurrentSceneMsf();
150 
151 	_stage = _backgroundLoader->load(sceneId);
152 	if (!_vm->isFlagSet(ENGINE_FLAG_800)) {
153 		byte *cursorPalette = _vm->_cursor->getPalette();
154 		byte *stagePalette = _stage->getPalette();
155 		for (int i = 0xc0; i < 0x100; i++) {
156 			stagePalette[i * 2] = cursorPalette[(i-0xc0) * 2];
157 			stagePalette[i * 2 + 1] = cursorPalette[(i-0xc0) * 2 + 1];
158 		}
159 	}
160 	for (int i = 1; i < 0x100; i ++) {
161 		byte *stagePalette = _stage->getPalette();
162 		uint16 c = READ_LE_INT16(stagePalette + i * 2);
163 		if ((c & 0x7fff) == 0) {
164 			stagePalette[i * 2 + 1] |= 0x80;
165 		}
166 	}
167 	_screen->loadPalette(0, _stage->getPalette());
168 
169 	for (int i = 1; i < 0x100; i ++) {
170 		byte *stagePalette = _stage->getPalette();
171 		uint16 c = READ_LE_INT16(stagePalette + i * 2);
172 		if ((c & 0x7fff) == 0) {
173 			stagePalette[i * 2] = 1;
174 			stagePalette[i * 2 + 1] = 0;
175 		}
176 	}
177 
178 	_camera = _stage->getPoint2(cameraPointId);
179 
180 	if (flicker && !(sceneId & 0x8000)) {
181 		flicker->x = _camera.x;
182 		flicker->y = _camera.y;
183 		_vm->getINI(1)->x = _camera.x;
184 		_vm->getINI(1)->y = _camera.y;
185 	}
186 
187 	debug(3, "Flicker: (%X, %X)", _camera.x, _camera.y);
188 
189 	if (_camera.x > 160) {
190 		_camera.x -= 160;
191 	} else {
192 		_camera.x = 0;
193 	}
194 
195 	if (_camera.y > 100) {
196 		_camera.y -= 100;
197 	} else {
198 		_camera.y = 0;
199 	}
200 
201 	if (_camera.x + 320 >= _stage->getWidth()) {
202 		_camera.x = _stage->getWidth() - 320;
203 	}
204 
205 	if (_camera.y + 200 >= _stage->getHeight()) {
206 		_camera.y = _stage->getHeight() - 200;
207 	}
208 
209 	debug(3, "Camera: (%d, %d)", _camera.x, _camera.y);
210 
211 	// 0x8002ff80
212 	_vm->fadeToBlack();
213 	_vm->clearUnkFlags(ENGINE_UNK1_FLAG_10);
214 	_vm->setFlags(ENGINE_FLAG_20);
215 	// TODO reset vsync_updater_function
216 
217 	_vm->setFlags(ENGINE_FLAG_200);
218 	_actorManager->clearActorFlags(2);
219 	_vm->_isLoadingDialogAudio = false;
220 	// TODO 0x8002fff0
221 
222 	for (int i = 0; i < _dragonINIResource->totalRecords(); i++) {
223 		DragonINI *ini = _dragonINIResource->getRecord(i);
224 		if (ini->sceneId == sceneIdStripped) {
225 			if (ini->flags & 1) {
226 				Actor *actor = _actorManager->loadActor(ini->actorResourceId, ini->sequenceId, ini->x, ini->y, 0);
227 
228 				if (actor) {
229 					ini->actor = actor;
230 					if (ini->flags & 0x1000) {
231 						actor->_frame_flags |= 0x10;
232 					} else {
233 						if (ini->flags & 0x2000) {
234 							actor->_frame_flags |= 0x20;
235 						} else {
236 							actor->_frame_flags &= ~0x10;
237 						}
238 					}
239 
240 					actor->_direction = ini->direction2;
241 
242 					if (ini->flags & 2) {
243 						actor->_flags |= ACTOR_FLAG_80;
244 					} else {
245 						actor->_flags &= 0xfeff;
246 					}
247 
248 					if (ini->flags & 0x20) {
249 						actor->_flags |= ACTOR_FLAG_100;
250 					} else {
251 						actor->_flags &= 0xfeff;
252 					}
253 
254 					if (ini->flags & 4) {
255 						actor->_flags |= ACTOR_FLAG_8000;
256 					} else {
257 						actor->_flags &= 0x7fff;
258 					}
259 
260 					if (ini->flags & 0x100) {
261 						actor->_flags |= ACTOR_FLAG_4000;
262 					} else {
263 						actor->_flags &= 0xbfff;
264 					}
265 //
266 //				Graphics::Surface *s = actor->getCurrentFrame();
267 //				int x = ini->x - actor->_frame_vram_x;
268 //				int y = ini->y - actor->_frame_vram_y;
269 //				if (x >= 0 && y >= 0 && x + s->w < 320 && y + s->h < 200) {
270 //					debug("Actor %d, %d %d (%d, %d)", actor->_actorID, ini->actorResourceId, ini->flags, ini->x, ini->y);
271 //					_stage->getFgLayer()->copyRectToSurface(*s, x, y, Common::Rect(s->w, s->h));
272 //				}
273 				}
274 				// _stage->getFgLayer()->drawLine(ini->x, ini->y, ini->x + 8, ini->y + 8, 0x7c00);
275 				//break;
276 			} else {
277 				if (ini->iptIndex_maybe != -1) {
278 					loadImageOverlay(ini->iptIndex_maybe);
279 				}
280 			}
281 		}
282 	}
283 
284 	// 0x80030458
285 	DragonINI *ini = _vm->getINI(1);
286 	if (ini->actor && _vm->_dragonINIResource->getFlickerRecord() && _vm->_dragonINIResource->getFlickerRecord()->sceneId == _currentSceneId) {
287 		ini->actor->setFlag(ACTOR_FLAG_100);
288 		ini->actor->_priorityLayer = 0;
289 	}
290 
291 
292 	if (flicker && flicker->sceneId != 0) {
293 		flicker->direction2 = _vm->_flickerInitialSceneDirection;
294 		if (flicker->actor) {
295 			flicker->actor->_direction = _vm->_flickerInitialSceneDirection;
296 			flicker->actor->setFlag(ACTOR_FLAG_4);
297 		}
298 	}
299 
300 	// 0x800305bc
301 	_vm->_inventory->loadScene(_currentSceneId);
302 
303 	// 0x8003070c
304 	// TODO sub_80013b3c(); // palette related.
305 
306 	if (_vm->_inventory->isOpen()) {
307 		_vm->_inventory->close();
308 	}
309 
310 	if (!_vm->isFlagSet(ENGINE_FLAG_10000)) {
311 		_vm->setFlags(ENGINE_FLAG_10);
312 	}
313 
314 	_vm->setFlags(ENGINE_FLAG_1);
315 	_vm->setFlags(ENGINE_FLAG_200);
316 	_vm->setFlags(ENGINE_FLAG_4000000);
317 
318 	if (flicker && flicker->sceneId == _currentSceneId) {
319 
320 		flicker->actor->updateSequence((uint16)flicker->actor->_direction);
321 	}
322 
323 	_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
324 	_vm->clearUnkFlags(ENGINE_UNK1_FLAG_8);
325 
326 	if (isUnkFlag2Set) {
327 		_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
328 	}
329 
330 	if (!(sceneId & 0x8000)) {
331 		byte *obd = _dragonRMS->getAfterSceneDataLoadedScript(sceneId);
332 		ScriptOpCall scriptOpCall(obd + 4, READ_LE_UINT32(obd));
333 		_scriptOpcodes->runScript(scriptOpCall);
334 	}
335 
336 }
337 
draw()338 void Scene::draw() {
339 	Common::Rect rect(_camera.x, _camera.y, _camera.x + 320, _camera.y + 200);
340 	_vm->_screen->clearScreen();
341 
342 	for (uint16 priority = 1; priority < 16; priority++) {
343 		if (_vm->isInMenu() || (priority == 7 && _vm->isFlagSet(ENGINE_FLAG_200))) {
344 			_vm->_fontManager->updatePalette();
345 			_vm->_fontManager->draw();
346 		}
347 
348 		if (_vm->isFlagSet(ENGINE_FLAG_200)) {
349 			if (priority == 5) {
350 				if (_vm->isFlagSet(ENGINE_FLAG_80)) {
351 					_vm->_inventory->draw();
352 				}
353 			}
354 
355 			if (priority == _stage->getFgLayerPriority()) {
356 				drawBgLayer(2, rect, _stage->getFgLayer());
357 			}
358 			if (priority == _stage->getMgLayerPriority()) {
359 				drawBgLayer(1, rect, _stage->getMgLayer());
360 			}
361 			if (priority == _stage->getBgLayerPriority()) {
362 				drawBgLayer(0, rect, _stage->getBgLayer());
363 			}
364 		}
365 
366 		_screen->drawFlatQuads(priority);
367 
368 		for (int16 i = 0; i < DRAGONS_ENGINE_NUM_ACTORS; i++) {
369 			Actor *actor = _actorManager->getActorByDisplayOrder(i);
370 			if (actor->_x_pos == -100 && actor->_y_pos == 100) {
371 				actor->_priorityLayer = 0;
372 				continue;
373 			}
374 
375 			if (actor->_flags & ACTOR_FLAG_40 &&
376 					!(actor->_flags & ACTOR_FLAG_400) &&
377 					actor->_surface &&
378 					actor->_frame->width != 0 &&
379 					actor->_frame->height != 0) {
380 				Graphics::Surface *s = actor->_surface;
381 				if (actor->_priorityLayer == priority) { //} && x + s->w < 320 && y + s->h < 200) {
382 					if (!actor->isFlagSet(ACTOR_FLAG_80)) {
383 						actor->_scale = _stage->getScaleLayer()->getScale(actor->_y_pos);
384 					}
385 					int x = actor->_x_pos - (actor->_frame->xOffset * actor->_scale / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) - (actor->isFlagSet(ACTOR_FLAG_200) ? 0 : _camera.x);
386 					int y = actor->_y_pos - (actor->_frame->yOffset * actor->_scale / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) - (actor->isFlagSet(ACTOR_FLAG_200) ? 0 : _camera.y);
387 
388 					debug(5, "Actor %d %s (%d, %d) w:%d h:%d Priority: %d Scale: %d", actor->_actorID, actor->_actorResource->getFilename(), x,
389 						  y,
390 						  s->w, s->h, actor->_priorityLayer, actor->_scale);
391 					_screen->copyRectToSurface8bpp(*s, actor->getPalette(), x, y, Common::Rect(s->w, s->h), (bool)(actor->_frame->flags & FRAME_FLAG_FLIP_X), actor->isFlagSet(ACTOR_FLAG_8000) ? NONE : NORMAL, actor->_scale);
392 					if (_vm->isDebugMode()) {
393 						_screen->drawRect(0x7fff, Common::Rect(x, y, x + s->w, y + s->h), actor->_actorID);
394 						drawActorNumber(x + s->w, y + 8, actor->_actorID);
395 					}
396 				}
397 			}
398 		}
399 	}
400 	if (_vm->_credits->isRunning()) {
401 		_vm->_credits->draw();
402 	}
403 
404 	if (_vm->isDebugMode()) {
405 		_vm->_fontManager->clearText();
406 	}
407 }
408 
getPriorityAtPosition(Common::Point pos)409 int16 Scene::getPriorityAtPosition(Common::Point pos) {
410 	return _stage->getPriorityAtPoint(pos);
411 }
412 
contains(DragonINI * ini)413 bool Scene::contains(DragonINI *ini) {
414 	assert(ini);
415 	return ini->sceneId == _currentSceneId;
416 }
417 
getPalette()418 byte *Scene::getPalette() {
419 	assert(_stage);
420 	return _stage->getPalette();
421 }
422 
getSceneId()423 uint16 Scene::getSceneId() {
424 	return (uint16)_currentSceneId;
425 }
426 
getPoint(uint32 pointIndex)427 Common::Point Scene::getPoint(uint32 pointIndex) {
428 	return _stage->getPoint2(pointIndex);
429 }
430 
getStageWidth()431 uint16 Scene::getStageWidth() {
432 	return _stage->getWidth();
433 }
434 
getStageHeight()435 uint16 Scene::getStageHeight() {
436 	return _stage->getHeight();
437 }
438 
loadImageOverlay(uint16 iptId)439 void Scene::loadImageOverlay(uint16 iptId) {
440 	Img *img =_vm->_dragonImg->getImg(iptId);
441 	if (img->h != 0) {
442 		if (img->field_e <= 2) {
443 			_stage->overlayImage(img->layerNum - 1, img->data, img->x, img->y, img->w, img->h);
444 		}
445 
446 		if (img->field_e == 2 || img->field_e == 0) {
447 			_stage->overlayPriorityTileMap(img->data + img->w * img->h * 2, img->x, img->y, img->w, img->h);
448 		}
449 	}
450 }
451 
removeImageOverlay(uint16 iptId)452 void Scene::removeImageOverlay(uint16 iptId) {
453 	Img *img =_vm->_dragonImg->getImg(iptId);
454 	_stage->restoreTiles(img->layerNum - 1, img->x, img->y, img->w, img->h);
455 	_stage->restorePriorityTileMap(img->x, img->y, img->w, img->h);
456 }
457 
setSceneId(int16 newSceneId)458 void Scene::setSceneId(int16 newSceneId) {
459 	_currentSceneId = newSceneId;
460 }
461 
resetActorFrameFlags()462 void Scene::resetActorFrameFlags() {
463 	for (int i = 0; i < 0x17; i++) {
464 		Actor *actor = _vm->_actorManager->getActor(i);
465 		actor->_frame_flags &= ~ACTOR_FRAME_FLAG_10;
466 		actor->_frame_flags &= ~ACTOR_FRAME_FLAG_20;
467 	}
468 }
469 
setBgLayerPriority(uint8 newPriority)470 void Scene::setBgLayerPriority(uint8 newPriority) {
471 	_stage->setBgLayerPriority(newPriority);
472 }
473 
setMgLayerPriority(uint8 newPriority)474 void Scene::setMgLayerPriority(uint8 newPriority) {
475 	_stage->setMgLayerPriority(newPriority);
476 }
477 
setFgLayerPriority(uint8 newPriority)478 void Scene::setFgLayerPriority(uint8 newPriority) {
479 	_stage->setFgLayerPriority(newPriority);
480 }
481 
setStagePalette(byte * newPalette)482 void Scene::setStagePalette(byte *newPalette) {
483 	_stage->setPalette(newPalette);
484 }
485 
486 
drawActorNumber(int16 x,int16 y,uint16 actorId)487 void Scene::drawActorNumber(int16 x, int16 y, uint16 actorId) {
488 	uint16 text[30];
489 	char text8[15];
490 
491 	sprintf(text8, "%d", actorId);
492 
493 	for (uint i = 0; i < strlen(text8); i++) {
494 		text[i] = text8[i];
495 	}
496 	_vm->_fontManager->addText(x, y, text, strlen(text8), 1);
497 }
498 
setLayerOffset(uint8 layerNumber,Common::Point offset)499 void Scene::setLayerOffset(uint8 layerNumber, Common::Point offset) {
500 	_stage->setLayerOffset(layerNumber, offset);
501 }
502 
getLayerOffset(uint8 layerNumber)503 Common::Point Scene::getLayerOffset(uint8 layerNumber) {
504 	return _stage->getLayerOffset(layerNumber);
505 }
506 
drawBgLayer(uint8 layerNumber,Common::Rect rect,Graphics::Surface * surface)507 void Scene::drawBgLayer(uint8 layerNumber, Common::Rect rect, Graphics::Surface *surface) {
508 	Common::Point offset = _stage->getLayerOffset(layerNumber);
509 //	Common::Rect clippedRect = _screen->clipRectToRect(offset.x, offset.y, rect, Common::Rect(_stage->getBgLayer()->w, _stage->getBgLayer()->h));
510 	rect.left += rect.left + offset.x < 0 ? -(rect.left + offset.x) : offset.x;
511 	if (rect.right + offset.x > surface->w) {
512 		rect.right = surface->w - 1;
513 	} else {
514 		rect.right += offset.x;
515 	}
516 //	clippedRect.right += offset.x < 0 ? -offset.x : 0;
517 	rect.top += rect.top + offset.y < 0 ? -(rect.top + offset.y) : offset.y;
518 	if (rect.bottom + offset.y > surface->h) {
519 		rect.bottom = surface->h - 1;
520 	} else {
521 		rect.bottom += offset.y;
522 	}
523 //	clippedRect.bottom += offset.y < 0 ? -offset.y : 0;
524 	_screen->copyRectToSurface8bppWrappedX(*surface, _screen->getPalette(0), rect, _stage->getLayerAlphaMode(layerNumber));
525 }
526 
getScaleLayer()527 ScaleLayer *Scene::getScaleLayer() {
528 	return _stage->getScaleLayer();
529 }
530 
setLayerAlphaMode(uint8 layerNumber,AlphaBlendMode mode)531 void Scene::setLayerAlphaMode(uint8 layerNumber, AlphaBlendMode mode) {
532 	_stage->setLayerAlphaMode(layerNumber, mode);
533 }
534 
535 } // End of namespace Dragons
536