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 "neverhood/console.h"
24 #include "neverhood/scene.h"
25 #include "neverhood/smackerplayer.h"
26
27 namespace Neverhood {
28
Scene(NeverhoodEngine * vm,Module * parentModule)29 Scene::Scene(NeverhoodEngine *vm, Module *parentModule)
30 : Entity(vm, 0), _parentModule(parentModule), _dataResource(vm), _hitRects(NULL),
31 _mouseCursorWasVisible(true) {
32
33 _isKlaymenBusy = false;
34 _doConvertMessages = false;
35 _messageList = NULL;
36 _rectType = 0;
37 _mouseClickPos.x = 0;
38 _mouseClickPos.y = 0;
39 _mouseClicked = false;
40 _rectList = NULL;
41 _klaymen = NULL;
42 _mouseCursor = NULL;
43 _palette = NULL;
44 _background = NULL;
45 clearHitRects();
46 clearCollisionSprites();
47 _vm->_screen->setFps(24);
48 _vm->_screen->setSmackerDecoder(NULL);
49 _canAcceptInput = true;
50 _messageList2 = NULL;
51 _smackerPlayer = NULL;
52 _isMessageListBusy = false;
53 _messageValue = -1;
54 _messageListStatus = 0;
55 _messageListCount = 0;
56 _messageListIndex = 0;
57
58 _backgroundFileHash = _cursorFileHash = 0;
59
60 SetUpdateHandler(&Scene::update);
61 SetMessageHandler(&Scene::handleMessage);
62
63 _vm->_screen->clearRenderQueue();
64 }
65
~Scene()66 Scene::~Scene() {
67
68 _vm->_screen->setSmackerDecoder(NULL);
69
70 if (_palette) {
71 removeEntity(_palette);
72 delete _palette;
73 }
74
75 // Delete all entities
76 for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++)
77 delete *iter;
78
79 // Don't delete surfaces since they always belong to an entity
80
81 // Purge the resources after each scene
82 _vm->_res->purgeResources();
83
84 }
85
draw()86 void Scene::draw() {
87 if (_smackerPlayer) {
88 if (_smackerPlayer->getSurface())
89 _smackerPlayer->getSurface()->draw();
90 } else {
91 for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++)
92 (*iter)->draw();
93 }
94 }
95
addEntity(Entity * entity)96 void Scene::addEntity(Entity *entity) {
97 int index = 0, insertIndex = -1;
98 for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++) {
99 if ((*iter)->getPriority() > entity->getPriority()) {
100 insertIndex = index;
101 break;
102 }
103 index++;
104 }
105 if (insertIndex >= 0)
106 _entities.insert_at(insertIndex, entity);
107 else
108 _entities.push_back(entity);
109 }
110
removeEntity(Entity * entity)111 bool Scene::removeEntity(Entity *entity) {
112 for (uint index = 0; index < _entities.size(); index++)
113 if (_entities[index] == entity) {
114 _entities.remove_at(index);
115 return true;
116 }
117 return false;
118 }
119
addSurface(BaseSurface * surface)120 void Scene::addSurface(BaseSurface *surface) {
121 if (surface) {
122 int index = 0, insertIndex = -1;
123 for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++) {
124 if ((*iter)->getPriority() > surface->getPriority()) {
125 insertIndex = index;
126 break;
127 }
128 index++;
129 }
130 if (insertIndex >= 0)
131 _surfaces.insert_at(insertIndex, surface);
132 else
133 _surfaces.push_back(surface);
134 }
135 }
136
removeSurface(BaseSurface * surface)137 bool Scene::removeSurface(BaseSurface *surface) {
138 for (uint index = 0; index < _surfaces.size(); index++) {
139 if (_surfaces[index] == surface) {
140 _surfaces.remove_at(index);
141 return true;
142 }
143 }
144 return false;
145 }
146
printSurfaces(Console * con)147 void Scene::printSurfaces(Console *con) {
148 for (uint index = 0; index < _surfaces.size(); index++) {
149 NDrawRect drawRect = _surfaces[index]->getDrawRect();
150 NRect clipRect = _surfaces[index]->getClipRect();
151 int priority = _surfaces[index]->getPriority();
152 con->debugPrintf("%d ('%s'): Priority %d, draw rect (%d, %d, %d, %d), clip rect (%d, %d, %d, %d)\n",
153 index, _surfaces[index]->getName().c_str(), priority,
154 drawRect.x, drawRect.y, drawRect.x2(), drawRect.y2(),
155 clipRect.x1, clipRect.y1, clipRect.x2, clipRect.y2);
156 }
157 }
158
addSprite(Sprite * sprite)159 Sprite *Scene::addSprite(Sprite *sprite) {
160 addEntity(sprite);
161 addSurface(sprite->getSurface());
162 return sprite;
163 }
164
removeSprite(Sprite * sprite)165 void Scene::removeSprite(Sprite *sprite) {
166 removeSurface(sprite->getSurface());
167 removeEntity(sprite);
168 }
169
setSurfacePriority(BaseSurface * surface,int priority)170 void Scene::setSurfacePriority(BaseSurface *surface, int priority) {
171 surface->setPriority(priority);
172 if (removeSurface(surface))
173 addSurface(surface);
174 }
175
setSpriteSurfacePriority(Sprite * sprite,int priority)176 void Scene::setSpriteSurfacePriority(Sprite *sprite, int priority) {
177 if (sprite)
178 setSurfacePriority(sprite->getSurface(), priority);
179 }
180
deleteSprite(Sprite ** sprite)181 void Scene::deleteSprite(Sprite **sprite) {
182 removeCollisionSprite(*sprite);
183 removeSurface((*sprite)->getSurface());
184 removeEntity(*sprite);
185 delete *sprite;
186 *sprite = NULL;
187 }
188
addBackground(Background * background)189 Background *Scene::addBackground(Background *background) {
190 addEntity(background);
191 addSurface(background->getSurface());
192 return background;
193 }
194
setBackground(uint32 fileHash)195 void Scene::setBackground(uint32 fileHash) {
196 _background = addBackground(new Background(_vm, fileHash, 0, 0));
197 _backgroundFileHash = fileHash;
198 }
199
changeBackground(uint32 fileHash)200 void Scene::changeBackground(uint32 fileHash) {
201 _background->load(fileHash);
202 }
203
setPalette(uint32 fileHash)204 void Scene::setPalette(uint32 fileHash) {
205 _palette = fileHash ? new Palette(_vm, fileHash) : new Palette(_vm);
206 _palette->usePalette();
207 }
208
setHitRects(uint32 id)209 void Scene::setHitRects(uint32 id) {
210 setHitRects(_vm->_staticData->getHitRectList(id));
211 }
212
setHitRects(HitRectList * hitRects)213 void Scene::setHitRects(HitRectList *hitRects) {
214 _hitRects = hitRects;
215 }
216
insertStaticSprite(uint32 fileHash,int surfacePriority)217 Sprite *Scene::insertStaticSprite(uint32 fileHash, int surfacePriority) {
218 return addSprite(new StaticSprite(_vm, fileHash, surfacePriority));
219 }
220
insertScreenMouse(uint32 fileHash,const NRect * mouseRect)221 void Scene::insertScreenMouse(uint32 fileHash, const NRect *mouseRect) {
222 NRect rect = NRect::make(-1, -1, -1, -1);
223 if (mouseRect)
224 rect = *mouseRect;
225 insertMouse(new Mouse(_vm, fileHash, rect));
226 _cursorFileHash = fileHash;
227 }
228
insertPuzzleMouse(uint32 fileHash,int16 x1,int16 x2)229 void Scene::insertPuzzleMouse(uint32 fileHash, int16 x1, int16 x2) {
230 insertMouse(new Mouse(_vm, fileHash, x1, x2));
231 _cursorFileHash = fileHash;
232 }
233
insertNavigationMouse(uint32 fileHash,int type)234 void Scene::insertNavigationMouse(uint32 fileHash, int type) {
235 insertMouse(new Mouse(_vm, fileHash, type));
236 _cursorFileHash = fileHash;
237 }
238
showMouse(bool visible)239 void Scene::showMouse(bool visible) {
240 _mouseCursor->getSurface()->setVisible(visible);
241 }
242
changeMouseCursor(uint32 fileHash)243 void Scene::changeMouseCursor(uint32 fileHash) {
244 _mouseCursor->load(fileHash);
245 _mouseCursor->updateCursor();
246 }
247
addSmackerPlayer(SmackerPlayer * smackerPlayer)248 SmackerPlayer *Scene::addSmackerPlayer(SmackerPlayer *smackerPlayer) {
249 addEntity(smackerPlayer);
250 addSurface(smackerPlayer->getSurface());
251 return smackerPlayer;
252 }
253
update()254 void Scene::update() {
255
256 if (_mouseClicked) {
257 if (_klaymen) {
258 if (_canAcceptInput &&
259 _klaymen->hasMessageHandler() &&
260 sendMessage(_klaymen, 0x1008, 0) != 0 &&
261 queryPositionSprite(_mouseClickPos.x, _mouseClickPos.y)) {
262 _mouseClicked = false;
263 } else if (_canAcceptInput &&
264 _klaymen->hasMessageHandler() &&
265 sendMessage(_klaymen, 0x1008, 0) != 0) {
266 _mouseClicked = !queryPositionRectList(_mouseClickPos.x, _mouseClickPos.y);
267 }
268 } else if (queryPositionSprite(_mouseClickPos.x, _mouseClickPos.y)) {
269 _mouseClicked = false;
270 }
271 }
272
273 processMessageList();
274
275 // Update all entities
276 for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++)
277 (*iter)->handleUpdate();
278
279 }
280
leaveScene(uint32 result)281 void Scene::leaveScene(uint32 result) {
282 sendMessage(_parentModule, 0x1009, result);
283 }
284
handleMessage(int messageNum,const MessageParam & param,Entity * sender)285 uint32 Scene::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
286 switch (messageNum) {
287 case NM_MOUSE_MOVE:
288 if (_mouseCursor && _mouseCursor->hasMessageHandler())
289 sendMessage(_mouseCursor, 0x4002, param);
290 break;
291 case NM_MOUSE_CLICK:
292 _mouseClicked = true;
293 _mouseClickPos = param.asPoint();
294 break;
295 case 0x0006:
296 sendMessage(_parentModule, 0x1009, param);
297 break;
298 case 0x1006:
299 // Sent by Klaymen when its animation sequence has finished
300 if (_isKlaymenBusy) {
301 _isKlaymenBusy = false;
302 if (_messageListIndex == _messageListCount) {
303 // If the current message list was processed completely,
304 // sent Klaymen into the idle state.
305 sendMessage(_klaymen, NM_KLAYMEN_STAND_IDLE, 0);
306 } else {
307 // Else continue with the next message in the current message list
308 processMessageList();
309 }
310 }
311 break;
312 case 0x1007:
313 // This isn't sent by any code, check if it's in a message list
314 // This cancels the current message list and sets Klaymen into the idle state.
315 if (_isKlaymenBusy) {
316 _isKlaymenBusy = false;
317 _messageList = NULL;
318 sendMessage(_klaymen, NM_KLAYMEN_STAND_IDLE, 0);
319 }
320 break;
321 case NM_MOUSE_HIDE:
322 if (_mouseCursor) {
323 _mouseCursorWasVisible = _mouseCursor->getSurface()->getVisible();
324 _mouseCursor->getSurface()->setVisible(false);
325 }
326 break;
327 case NM_MOUSE_SHOW:
328 if (_mouseCursorWasVisible && _mouseCursor) {
329 _mouseCursor->getSurface()->setVisible(true);
330 }
331 break;
332 case NM_PRIORITY_CHANGE:
333 // Set the sender's surface priority
334 setSurfacePriority(((Sprite*)sender)->getSurface(), param.asInteger());
335 break;
336 default:
337 break;
338 }
339 return 0;
340 }
341
queryPositionSprite(int16 mouseX,int16 mouseY)342 bool Scene::queryPositionSprite(int16 mouseX, int16 mouseY) {
343 for (uint i = 0; i < _collisionSprites.size(); i++) {
344 Sprite *sprite = _collisionSprites[i];
345 if (sprite->hasMessageHandler() && sprite->isPointInside(mouseX, mouseY) &&
346 sendPointMessage(sprite, 0x1011, _mouseClickPos) != 0) {
347 return true;
348 }
349 }
350 return false;
351 }
352
queryPositionRectList(int16 mouseX,int16 mouseY)353 bool Scene::queryPositionRectList(int16 mouseX, int16 mouseY) {
354 int16 klaymenX = _klaymen->getX();
355 int16 klaymenY = _klaymen->getY();
356 if (_rectType == 1) {
357 RectList &rectList = *_rectList;
358 for (uint i = 0; i < rectList.size(); i++) {
359 debug(2, "(%d, %d) ? (%d, %d, %d, %d)", klaymenX, klaymenY, rectList[i].rect.x1, rectList[i].rect.y1, rectList[i].rect.x2, rectList[i].rect.y2);
360 if (rectList[i].rect.contains(klaymenX, klaymenY)) {
361 for (uint j = 0; j < rectList[i].subRects.size(); j++) {
362 debug(2, " (%d, %d) ? (%d, %d, %d, %d)", mouseX, mouseY, rectList[i].subRects[j].rect.x1, rectList[i].subRects[j].rect.y1, rectList[i].subRects[j].rect.x2, rectList[i].subRects[j].rect.y2);
363 if (rectList[i].subRects[j].rect.contains(mouseX, mouseY)) {
364 return setMessageList2(rectList[i].subRects[j].messageListId);
365 }
366 }
367 }
368 }
369 } else if (_rectType == 2) {
370 MessageList *messageList = _dataResource.getMessageListAtPos(klaymenX, klaymenY, mouseX, mouseY);
371 if (messageList && messageList->size())
372 setMessageList2(messageList, true, true);
373 }
374 return true;
375 }
376
setMessageList(uint32 id,bool canAcceptInput,bool doConvertMessages)377 void Scene::setMessageList(uint32 id, bool canAcceptInput, bool doConvertMessages) {
378 setMessageList(_vm->_staticData->getMessageList(id), canAcceptInput, doConvertMessages);
379 }
380
setMessageList(MessageList * messageList,bool canAcceptInput,bool doConvertMessages)381 void Scene::setMessageList(MessageList *messageList, bool canAcceptInput, bool doConvertMessages) {
382 _messageList = messageList;
383 _messageListCount = _messageList ? _messageList->size() : 0;
384 _messageListIndex = 0;
385 _isKlaymenBusy = false;
386 _canAcceptInput = canAcceptInput;
387 _doConvertMessages = doConvertMessages;
388 _messageListStatus = 1;
389 sendMessage(_klaymen, 0x101C, 0);
390 }
391
setMessageList2(uint32 id,bool canAcceptInput,bool doConvertMessages)392 bool Scene::setMessageList2(uint32 id, bool canAcceptInput, bool doConvertMessages) {
393 return setMessageList2(_vm->_staticData->getMessageList(id), canAcceptInput, doConvertMessages);
394 }
395
setMessageList2(MessageList * messageList,bool canAcceptInput,bool doConvertMessages)396 bool Scene::setMessageList2(MessageList *messageList, bool canAcceptInput, bool doConvertMessages) {
397 if (_messageListStatus == 0 ||
398 (_messageListStatus == 1 && messageList != _messageList2) ||
399 (_messageListStatus == 2 && messageList == _messageList2)) {
400 // NOTE Skipped unneeded resource preloading code
401 _messageValue = -1;
402 _messageList2 = messageList;
403 setMessageList(messageList, canAcceptInput, doConvertMessages);
404 return true;
405 }
406 return false;
407 }
408
isMessageList2(uint32 id)409 bool Scene::isMessageList2(uint32 id) {
410 return _messageList2 == _vm->_staticData->getMessageList(id);
411 }
412
processMessageList()413 void Scene::processMessageList() {
414 debug(7, "Scene::processMessageList() _isMessageListBusy = %d; _isKlaymenBusy = %d", _isMessageListBusy, _isKlaymenBusy);
415
416 if (_isMessageListBusy || _isKlaymenBusy)
417 return;
418
419 _isMessageListBusy = true;
420
421 if (!_messageList) {
422 _messageList2 = NULL;
423 _messageListStatus = 0;
424 }
425
426 if (_messageList && _klaymen) {
427
428 #if 0
429 debug("MessageList: %p, %d", (void*)_messageList, _messageList->size());
430 for (uint i = 0; i < _messageList->size(); ++i) {
431 if (i == _messageListIndex) debugN("**"); else debugN(" ");
432 debug("(%08X, %08X)", (*_messageList)[i].messageNum, (*_messageList)[i].messageValue);
433 }
434 debug("--------------------------------");
435 #endif
436
437 while (_messageList && _messageListIndex < _messageListCount && !_isKlaymenBusy) {
438 uint32 messageNum = (*_messageList)[_messageListIndex].messageNum;
439 uint32 messageParam = (*_messageList)[_messageListIndex].messageValue;
440
441 ++_messageListIndex;
442 if (_messageListIndex == _messageListCount)
443 sendMessage(_klaymen, 0x1021, 0);
444 if (_doConvertMessages)
445 messageNum = convertMessageNum(messageNum);
446 if (messageNum == 0x1009 || messageNum == 0x1024) {
447 sendMessage(_parentModule, messageNum, messageParam);
448 } else if (messageNum == 0x100A) {
449 _messageValue = messageParam;
450 sendMessage(_parentModule, messageNum, messageParam);
451 } else if (messageNum == 0x4001) {
452 _isKlaymenBusy = true;
453 sendPointMessage(_klaymen, 0x4001, _mouseClickPos);
454 } else if (messageNum == 0x100D) {
455 if (this->hasMessageHandler() && sendMessage(this, NM_ANIMATION_START, messageParam) != 0)
456 continue;
457 } else if (messageNum == 0x101A) {
458 _messageListStatus = 0;
459 } else if (messageNum == 0x101B) {
460 _messageListStatus = 2;
461 } else if (messageNum == 0x1020) {
462 _canAcceptInput = false;
463 } else if (messageNum >= 0x2000 && messageNum <= 0x2FFF) {
464 if (this->hasMessageHandler() && sendMessage(this, messageNum, messageParam) != 0) {
465 _isMessageListBusy = false;
466 return;
467 }
468 } else if (messageNum != 0x4003) {
469 _isKlaymenBusy = true;
470 if (_klaymen->hasMessageHandler() && sendMessage(_klaymen, messageNum, messageParam) != 0) {
471 _isKlaymenBusy = false;
472 }
473 }
474 if (_messageListIndex == _messageListCount) {
475 _canAcceptInput = true;
476 _messageList = NULL;
477 }
478 }
479 }
480
481 _isMessageListBusy = false;
482
483 }
484
cancelMessageList()485 void Scene::cancelMessageList() {
486 _isKlaymenBusy = false;
487 _messageList = NULL;
488 _canAcceptInput = true;
489 sendMessage(_klaymen, NM_KLAYMEN_STAND_IDLE, 0);
490 }
491
setRectList(uint32 id)492 void Scene::setRectList(uint32 id) {
493 setRectList(_vm->_staticData->getRectList(id));
494 }
495
setRectList(RectList * rectList)496 void Scene::setRectList(RectList *rectList) {
497 _rectList = rectList;
498 _rectType = 1;
499 }
500
clearRectList()501 void Scene::clearRectList() {
502 _rectList = NULL;
503 _rectType = 0;
504 }
505
loadHitRectList()506 void Scene::loadHitRectList() {
507 HitRectList *hitRectList = _dataResource.getHitRectList();
508 if (hitRectList) {
509 _hitRectList = *hitRectList;
510 setHitRects(&_hitRectList);
511 }
512 }
513
loadDataResource(uint32 fileHash)514 void Scene::loadDataResource(uint32 fileHash) {
515 _dataResource.load(fileHash);
516 _rectType = 2;
517 if (_klaymen)
518 _klaymen->loadDataResource(fileHash);
519 }
520
convertMessageNum(uint32 messageNum)521 uint16 Scene::convertMessageNum(uint32 messageNum) {
522 switch (messageNum) {
523 case 0x00004004:
524 return 0x4001;
525 case 0x00000083:
526 return 0x100A;
527 case 0x044001C8:
528 return 0x481C;
529 case 0x02420480:
530 return 0x4818;
531 case 0x08004025:
532 return 0x100D;
533 case 0x04404281:
534 return 0x4824;
535 case 0x08400880:
536 return 0x4825;
537 case 0x08209081:
538 return 0x4823;
539 case 0x24000060:
540 return 0x1009;
541 case 0x42002200:
542 return 0x4004;
543 case 0x428D4894:
544 return 0x101A;
545 default:
546 break;
547 }
548 return 0x1000;
549 }
550
clearHitRects()551 void Scene::clearHitRects() {
552 _hitRects = NULL;
553 }
554
findHitRectAtPos(int16 x,int16 y)555 HitRect *Scene::findHitRectAtPos(int16 x, int16 y) {
556 static HitRect kDefaultHitRect = {NRect(), 0x5000};
557 if (_hitRects)
558 for (HitRectList::iterator it = _hitRects->begin(); it != _hitRects->end(); it++)
559 if ((*it).rect.contains(x, y))
560 return &(*it);
561 return &kDefaultHitRect;
562 }
563
addCollisionSprite(Sprite * sprite)564 void Scene::addCollisionSprite(Sprite *sprite) {
565 int index = 0, insertIndex = -1;
566 for (Common::Array<Sprite*>::iterator iter = _collisionSprites.begin(); iter != _collisionSprites.end(); iter++) {
567 if ((*iter)->getPriority() > sprite->getPriority()) {
568 insertIndex = index;
569 break;
570 }
571 index++;
572 }
573 if (insertIndex >= 0)
574 _collisionSprites.insert_at(insertIndex, sprite);
575 else
576 _collisionSprites.push_back(sprite);
577 }
578
removeCollisionSprite(Sprite * sprite)579 void Scene::removeCollisionSprite(Sprite *sprite) {
580 for (uint index = 0; index < _collisionSprites.size(); index++) {
581 if (_collisionSprites[index] == sprite) {
582 _collisionSprites.remove_at(index);
583 break;
584 }
585 }
586 }
587
clearCollisionSprites()588 void Scene::clearCollisionSprites() {
589 _collisionSprites.clear();
590 }
591
checkCollision(Sprite * sprite,uint16 flags,int messageNum,uint32 messageParam)592 void Scene::checkCollision(Sprite *sprite, uint16 flags, int messageNum, uint32 messageParam) {
593 for (Common::Array<Sprite*>::iterator iter = _collisionSprites.begin(); iter != _collisionSprites.end(); iter++) {
594 Sprite *collSprite = *iter;
595 if ((sprite->getFlags() & flags) && collSprite->checkCollision(sprite->getCollisionBounds())) {
596 sprite->sendMessage(collSprite, messageNum, messageParam);
597 }
598 }
599 }
600
insertMouse(Mouse * mouseCursor)601 void Scene::insertMouse(Mouse *mouseCursor) {
602 if (_mouseCursor)
603 deleteSprite((Sprite**)&_mouseCursor);
604 _mouseCursor = mouseCursor;
605 addEntity(_mouseCursor);
606 }
607
608 // StaticScene
609
StaticScene(NeverhoodEngine * vm,Module * parentModule,uint32 backgroundFileHash,uint32 cursorFileHash)610 StaticScene::StaticScene(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash)
611 : Scene(vm, parentModule) {
612
613 SetMessageHandler(&StaticScene::handleMessage);
614
615 setBackground(backgroundFileHash);
616 setPalette(backgroundFileHash);
617 insertPuzzleMouse(cursorFileHash, 20, 620);
618 }
619
handleMessage(int messageNum,const MessageParam & param,Entity * sender)620 uint32 StaticScene::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
621 Scene::handleMessage(messageNum, param, sender);
622 switch (messageNum) {
623 case NM_MOUSE_CLICK:
624 if (param.asPoint().x <= 20 || param.asPoint().x >= 620)
625 leaveScene(0);
626 break;
627 default:
628 break;
629 }
630 return 0;
631 }
632
633 } // End of namespace Neverhood
634