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