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/modules/module2800.h"
24 #include "neverhood/modules/module2800_sprites.h"
25
26 namespace Neverhood {
27
AsScene2803LightCord(NeverhoodEngine * vm,Scene * parentScene,uint32 fileHash1,uint32 fileHash2,int16 x,int16 y)28 AsScene2803LightCord::AsScene2803LightCord(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int16 x, int16 y)
29 : AnimatedSprite(vm, 1100), _parentScene(parentScene), _fileHash1(fileHash1), _fileHash2(fileHash2),
30 _isPulled(false), _isBusy(false) {
31
32 createSurface(1010, 28, 379);
33 SetUpdateHandler(&AnimatedSprite::update);
34 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
35 _x = x;
36 _y = y;
37 stIdle();
38 }
39
handleMessage(int messageNum,const MessageParam & param,Entity * sender)40 uint32 AsScene2803LightCord::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
41 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
42 switch (messageNum) {
43 case NM_ANIMATION_START:
44 if (!_isBusy && param.asInteger() == calcHash("ClickSwitch")) {
45 sendMessage(_parentScene, NM_KLAYMEN_LOWER_LEVER, 0);
46 playSound(0, 0x4E1CA4A0);
47 }
48 break;
49 case NM_KLAYMEN_LOWER_LEVER:
50 stPulled();
51 break;
52 case NM_MOVE_TO_BACK:
53 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 990);
54 break;
55 case NM_MOVE_TO_FRONT:
56 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 1010);
57 break;
58 default:
59 break;
60 }
61 return messageResult;
62 }
63
hmPulled(int messageNum,const MessageParam & param,Entity * sender)64 uint32 AsScene2803LightCord::hmPulled(int messageNum, const MessageParam ¶m, Entity *sender) {
65 uint32 messageResult = handleMessage(messageNum, param, sender);
66 switch (messageNum) {
67 case NM_ANIMATION_STOP:
68 gotoNextState();
69 break;
70 default:
71 break;
72 }
73 return messageResult;
74 }
75
stPulled()76 void AsScene2803LightCord::stPulled() {
77 _isBusy = false;
78 _isPulled = true;
79 startAnimation(_fileHash2, 0, -1);
80 SetMessageHandler(&AsScene2803LightCord::hmPulled);
81 NextState(&AsScene2803LightCord::stIdle);
82 }
83
stIdle()84 void AsScene2803LightCord::stIdle() {
85 _isPulled = false;
86 startAnimation(_fileHash1, 0, -1);
87 SetMessageHandler(&AsScene2803LightCord::handleMessage);
88 }
89
setFileHashes(uint32 fileHash1,uint32 fileHash2)90 void AsScene2803LightCord::setFileHashes(uint32 fileHash1, uint32 fileHash2) {
91 _fileHash1 = fileHash1;
92 _fileHash2 = fileHash2;
93 if (_isPulled) {
94 startAnimation(_fileHash2, _currFrameIndex, -1);
95 _isBusy = true;
96 } else {
97 startAnimation(_fileHash1, 0, -1);
98 }
99 }
100
AsScene2803TestTubeOne(NeverhoodEngine * vm,uint32 fileHash1,uint32 fileHash2)101 AsScene2803TestTubeOne::AsScene2803TestTubeOne(NeverhoodEngine *vm, uint32 fileHash1, uint32 fileHash2)
102 : AnimatedSprite(vm, 1200), _fileHash1(fileHash1), _fileHash2(fileHash2) {
103
104 createSurface1(fileHash1, 100);
105 SetUpdateHandler(&AnimatedSprite::update);
106 SetMessageHandler(&AsScene2803TestTubeOne::handleMessage);
107 _x = 529;
108 _y = 326;
109 }
110
handleMessage(int messageNum,const MessageParam & param,Entity * sender)111 uint32 AsScene2803TestTubeOne::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
112 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
113 switch (messageNum) {
114 case NM_ANIMATION_UPDATE:
115 if (param.asInteger())
116 startAnimation(_fileHash2, 0, -1);
117 else
118 startAnimation(_fileHash1, 0, -1);
119 break;
120 default:
121 break;
122 }
123 return messageResult;
124 }
125
AsScene2803Rope(NeverhoodEngine * vm,Scene * parentScene,int16 x)126 AsScene2803Rope::AsScene2803Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x)
127 : AnimatedSprite(vm, 1100), _parentScene(parentScene) {
128
129 createSurface(990, 68, 476);
130 SetUpdateHandler(&AnimatedSprite::update);
131 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
132 SetMessageHandler(&AsScene2803Rope::handleMessage);
133 startAnimation(0x9D098C23, 35, 53);
134 NextState(&AsScene2803Rope::stReleased);
135 _x = x;
136 _y = -276;
137 }
138
handleMessage(int messageNum,const MessageParam & param,Entity * sender)139 uint32 AsScene2803Rope::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
140 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
141 switch (messageNum) {
142 case NM_ANIMATION_STOP:
143 startAnimation(0x9D098C23, 50, -1);
144 SetMessageHandler(&AsScene2803Rope::hmReleased);
145 break;
146 case NM_MOVE_TO_BACK:
147 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 990);
148 break;
149 case NM_MOVE_TO_FRONT:
150 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 1010);
151 break;
152 default:
153 break;
154 }
155 return messageResult;
156 }
157
hmReleased(int messageNum,const MessageParam & param,Entity * sender)158 uint32 AsScene2803Rope::hmReleased(int messageNum, const MessageParam ¶m, Entity *sender) {
159 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
160 switch (messageNum) {
161 case NM_ANIMATION_STOP:
162 gotoNextState();
163 break;
164 case NM_MOVE_TO_BACK:
165 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 990);
166 break;
167 case NM_MOVE_TO_FRONT:
168 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 1010);
169 break;
170 default:
171 break;
172 }
173 return messageResult;
174 }
175
stReleased()176 void AsScene2803Rope::stReleased() {
177 startAnimation(0x8258A030, 0, 1);
178 NextState(&AsScene2803Rope::stHide);
179 }
180
stHide()181 void AsScene2803Rope::stHide() {
182 stopAnimation();
183 setVisible(false);
184 }
185
SsScene2804RedButton(NeverhoodEngine * vm,Scene2804 * parentScene)186 SsScene2804RedButton::SsScene2804RedButton(NeverhoodEngine *vm, Scene2804 *parentScene)
187 : StaticSprite(vm, 900), _countdown(0), _parentScene(parentScene) {
188
189 loadSprite(getGlobalVar(V_SHRINK_LIGHTS_ON) ? 0x51A10202 : 0x11814A21, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
190 setVisible(false);
191 SetUpdateHandler(&SsScene2804RedButton::update);
192 SetMessageHandler(&SsScene2804RedButton::handleMessage);
193 loadSound(0, 0x44241240);
194 }
195
update()196 void SsScene2804RedButton::update() {
197 updatePosition();
198 if (_countdown != 0 && (--_countdown) == 0) {
199 setVisible(false);
200 }
201 }
202
handleMessage(int messageNum,const MessageParam & param,Entity * sender)203 uint32 SsScene2804RedButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
204 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
205 switch (messageNum) {
206 case 0x1011:
207 if (_countdown == 0 && !_parentScene->isWorking()) {
208 playSound(0);
209 setVisible(true);
210 _countdown = 4;
211 sendMessage(_parentScene, 0x2000, 0);
212 }
213 messageResult = 1;
214 break;
215 default:
216 break;
217 }
218 return messageResult;
219 }
220
SsScene2804LightCoil(NeverhoodEngine * vm)221 SsScene2804LightCoil::SsScene2804LightCoil(NeverhoodEngine *vm)
222 : StaticSprite(vm, 900) {
223
224 loadSprite(0x8889B008, kSLFDefDrawOffset | kSLFDefPosition, 400);
225 setVisible(false);
226 SetMessageHandler(&SsScene2804LightCoil::handleMessage);
227 }
228
handleMessage(int messageNum,const MessageParam & param,Entity * sender)229 uint32 SsScene2804LightCoil::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
230 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
231 switch (messageNum) {
232 case NM_POSITION_CHANGE:
233 setVisible(true);
234 updatePosition();
235 messageResult = 1;
236 break;
237 case 0x2003:
238 setVisible(false);
239 updatePosition();
240 messageResult = 1;
241 break;
242 default:
243 break;
244 }
245 return messageResult;
246 }
247
SsScene2804LightTarget(NeverhoodEngine * vm)248 SsScene2804LightTarget::SsScene2804LightTarget(NeverhoodEngine *vm)
249 : StaticSprite(vm, 900) {
250
251 loadSprite(0x06092132, kSLFDefDrawOffset | kSLFDefPosition, 400);
252 setVisible(false);
253 SetMessageHandler(&SsScene2804LightTarget::handleMessage);
254 }
255
handleMessage(int messageNum,const MessageParam & param,Entity * sender)256 uint32 SsScene2804LightTarget::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
257 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
258 switch (messageNum) {
259 case 0x2004:
260 setVisible(true);
261 updatePosition();
262 messageResult = 1;
263 break;
264 case NM_KLAYMEN_CLIMB_LADDER:
265 setVisible(false);
266 updatePosition();
267 messageResult = 1;
268 break;
269 default:
270 break;
271 }
272 return messageResult;
273 }
274
SsScene2804Flash(NeverhoodEngine * vm)275 SsScene2804Flash::SsScene2804Flash(NeverhoodEngine *vm)
276 : StaticSprite(vm, 900) {
277
278 loadSprite(0x211003A0, kSLFDefDrawOffset | kSLFDefPosition, 400);
279 setVisible(false);
280 loadSound(0, 0xCB36BA54);
281 }
282
show()283 void SsScene2804Flash::show() {
284 setVisible(true);
285 updatePosition();
286 playSound(0);
287 }
288
SsScene2804BeamCoilBody(NeverhoodEngine * vm)289 SsScene2804BeamCoilBody::SsScene2804BeamCoilBody(NeverhoodEngine *vm)
290 : StaticSprite(vm, 900) {
291
292 loadSprite(0x9A816000, kSLFDefDrawOffset | kSLFDefPosition, 400);
293 setVisible(false);
294 }
295
AsScene2804CrystalWaves(NeverhoodEngine * vm,uint crystalIndex)296 AsScene2804CrystalWaves::AsScene2804CrystalWaves(NeverhoodEngine *vm, uint crystalIndex)
297 : AnimatedSprite(vm, 1100), _crystalIndex(crystalIndex) {
298
299 static const NPoint kAsScene2804CrystalWavesPoints[] = {
300 {323, 245},
301 {387, 76},
302 {454, 260},
303 {527, 70}
304 };
305
306 _x = kAsScene2804CrystalWavesPoints[crystalIndex].x;
307 _y = kAsScene2804CrystalWavesPoints[crystalIndex].y;
308 createSurface1(0x840C41F0, 1200);
309 if (crystalIndex & 1)
310 setDoDeltaY(1);
311 setVisible(false);
312 _needRefresh = true;
313 SetUpdateHandler(&AnimatedSprite::update);
314 SetMessageHandler(&Sprite::handleMessage);
315 }
316
show()317 void AsScene2804CrystalWaves::show() {
318 setVisible(true);
319 startAnimation(0x840C41F0, 0, -1);
320 }
321
hide()322 void AsScene2804CrystalWaves::hide() {
323 setVisible(false);
324 stopAnimation();
325 }
326
327 static const int16 kAsScene2804CrystalFrameNums[] = {
328 0, 6, 2, 8, 1, 10, 0, 0
329 };
330
331 static const uint32 kAsScene2804CrystalFileHashes[] = {
332 0x000540B0,
333 0x001280D0,
334 0x003D0010,
335 0x00620190,
336 0x00DC0290
337 };
338
AsScene2804Crystal(NeverhoodEngine * vm,AsScene2804CrystalWaves * asCrystalWaves,uint crystalIndex)339 AsScene2804Crystal::AsScene2804Crystal(NeverhoodEngine *vm, AsScene2804CrystalWaves *asCrystalWaves, uint crystalIndex)
340 : AnimatedSprite(vm, 1100), _asCrystalWaves(asCrystalWaves), _crystalIndex(crystalIndex), _isShowing(false) {
341
342 static const NPoint kAsScene2804CrystalPoints[] = {
343 {204, 196},
344 {272, 316},
345 {334, 206},
346 {410, 334},
347 {470, 180}
348 };
349
350 _colorNum = (int16)getSubVar(VA_CURR_CRYSTAL_COLORS, crystalIndex);
351 _isLightOn = getGlobalVar(V_SHRINK_LIGHTS_ON) != 0;
352 if (_isLightOn) {
353 _x = kAsScene2804CrystalPoints[crystalIndex].x;
354 _y = kAsScene2804CrystalPoints[crystalIndex].y;
355 createSurface1(0x108DFB12, 1200);
356 startAnimation(0x108DFB12, kAsScene2804CrystalFrameNums[_colorNum], -1);
357 _needRefresh = true;
358 _newStickFrameIndex = kAsScene2804CrystalFrameNums[_colorNum];
359 } else {
360 _x = 320;
361 _y = 240;
362 createSurface1(kAsScene2804CrystalFileHashes[crystalIndex], 1200);
363 startAnimation(kAsScene2804CrystalFileHashes[crystalIndex], _colorNum, -1);
364 setVisible(false);
365 _needRefresh = true;
366 _newStickFrameIndex = _colorNum;
367 }
368 loadSound(0, 0x725294D4);
369 SetUpdateHandler(&AnimatedSprite::update);
370 }
371
show()372 void AsScene2804Crystal::show() {
373 if (!_isLightOn) {
374 setVisible(true);
375 _isShowing = true;
376 if (_asCrystalWaves)
377 _asCrystalWaves->show();
378 playSound(0);
379 }
380 }
381
hide()382 void AsScene2804Crystal::hide() {
383 if (!_isLightOn) {
384 setVisible(false);
385 _isShowing = false;
386 if (_asCrystalWaves)
387 _asCrystalWaves->hide();
388 }
389 }
390
activate()391 void AsScene2804Crystal::activate() {
392 if (!_isShowing) {
393 int16 frameNum = kAsScene2804CrystalFrameNums[_colorNum];
394 _colorNum++;
395 if (_colorNum >= 6)
396 _colorNum = 0;
397 if (_isLightOn) {
398 startAnimation(0x108DFB12, frameNum, kAsScene2804CrystalFrameNums[_colorNum]);
399 _playBackwards = kAsScene2804CrystalFrameNums[_colorNum] < _colorNum;
400 _newStickFrameIndex = kAsScene2804CrystalFrameNums[_colorNum];
401 } else {
402 startAnimation(kAsScene2804CrystalFileHashes[_crystalIndex], _colorNum, -1);
403 _newStickFrameIndex = _colorNum;
404 }
405 setSubVar(VA_CURR_CRYSTAL_COLORS, _crystalIndex, _colorNum);
406 }
407 }
408
SsScene2804CrystalButton(NeverhoodEngine * vm,Scene2804 * parentScene,AsScene2804Crystal * asCrystal,uint crystalIndex)409 SsScene2804CrystalButton::SsScene2804CrystalButton(NeverhoodEngine *vm, Scene2804 *parentScene, AsScene2804Crystal *asCrystal, uint crystalIndex)
410 : StaticSprite(vm, 900), _countdown(0), _parentScene(parentScene), _asCrystal(asCrystal), _crystalIndex(crystalIndex) {
411
412 static const uint32 kSsScene2804CrystalButtonFileHashes1[] = {
413 0x911101B0,
414 0x22226001,
415 0x4444A362,
416 0x888925A4,
417 0x11122829
418 };
419
420 static const uint32 kSsScene2804CrystalButtonFileHashes2[] = {
421 0xB500A1A0,
422 0x6A012021,
423 0xD4022322,
424 0xA8042525,
425 0x5008292B
426 };
427
428 loadSprite(getGlobalVar(V_SHRINK_LIGHTS_ON) ? kSsScene2804CrystalButtonFileHashes1[crystalIndex] : kSsScene2804CrystalButtonFileHashes2[crystalIndex],
429 kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
430 setVisible(false);
431 loadSound(0, 0x44045140);
432 SetUpdateHandler(&SsScene2804CrystalButton::update);
433 SetMessageHandler(&SsScene2804CrystalButton::handleMessage);
434 }
435
update()436 void SsScene2804CrystalButton::update() {
437 updatePosition();
438 if (_countdown != 0 && (--_countdown) == 0) {
439 setVisible(false);
440 }
441 }
442
handleMessage(int messageNum,const MessageParam & param,Entity * sender)443 uint32 SsScene2804CrystalButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
444 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
445 switch (messageNum) {
446 case 0x1011:
447 if (_countdown == 0 && !_parentScene->isWorking()) {
448 playSound(0);
449 setVisible(true);
450 _countdown = 4;
451 _asCrystal->activate();
452 }
453 messageResult = 1;
454 break;
455 default:
456 break;
457 }
458 return messageResult;
459 }
460
AsScene2804BeamCoil(NeverhoodEngine * vm,Scene * parentScene,SsScene2804BeamCoilBody * ssBeamCoilBody)461 AsScene2804BeamCoil::AsScene2804BeamCoil(NeverhoodEngine *vm, Scene *parentScene, SsScene2804BeamCoilBody *ssBeamCoilBody)
462 : AnimatedSprite(vm, 1400), _parentScene(parentScene), _ssBeamCoilBody(ssBeamCoilBody), _countdown(0) {
463
464 createSurface1(0x00494891, 1000);
465 _x = 125;
466 _y = 184;
467 setVisible(false);
468 _needRefresh = true;
469 AnimatedSprite::updatePosition();
470 loadSound(0, 0x6352F051);
471 _vm->_soundMan->addSound(0xC5EA0B28, 0xEF56B094);
472 SetUpdateHandler(&AsScene2804BeamCoil::update);
473 SetMessageHandler(&AsScene2804BeamCoil::handleMessage);
474 }
475
~AsScene2804BeamCoil()476 AsScene2804BeamCoil::~AsScene2804BeamCoil() {
477 _vm->_soundMan->deleteSoundGroup(0xC5EA0B28);
478 }
479
update()480 void AsScene2804BeamCoil::update() {
481 updateAnim();
482 updatePosition();
483 if (_countdown != 0 && (--_countdown) == 0) {
484 sendMessage(_parentScene, 0x2001, 0);
485 }
486 }
487
handleMessage(int messageNum,const MessageParam & param,Entity * sender)488 uint32 AsScene2804BeamCoil::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
489 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
490 switch (messageNum) {
491 case NM_POSITION_CHANGE:
492 show();
493 _countdown = 92;
494 messageResult = 1;
495 break;
496 case 0x2003:
497 hide();
498 messageResult = 1;
499 break;
500 default:
501 break;
502 }
503 return messageResult;
504 }
505
show()506 void AsScene2804BeamCoil::show() {
507 _ssBeamCoilBody->setVisible(true);
508 setVisible(true);
509 startAnimation(0x00494891, 0, -1);
510 playSound(0);
511 SetMessageHandler(&AsScene2804BeamCoil::hmBeaming);
512 NextState(&AsScene2804BeamCoil::stBeaming);
513 }
514
hide()515 void AsScene2804BeamCoil::hide() {
516 stopAnimation();
517 SetMessageHandler(&AsScene2804BeamCoil::handleMessage);
518 setVisible(false);
519 _ssBeamCoilBody->setVisible(false);
520 _vm->_soundMan->stopSound(0xEF56B094);
521 }
522
stBeaming()523 void AsScene2804BeamCoil::stBeaming() {
524 startAnimation(0x00494891, 93, -1);
525 NextState(&AsScene2804BeamCoil::stBeaming);
526 _vm->_soundMan->playSoundLooping(0xEF56B094);
527 }
528
hmBeaming(int messageNum,const MessageParam & param,Entity * sender)529 uint32 AsScene2804BeamCoil::hmBeaming(int messageNum, const MessageParam ¶m, Entity *sender) {
530 uint32 messageResult = handleMessage(messageNum, param, sender);
531 switch (messageNum) {
532 case NM_ANIMATION_STOP:
533 gotoNextState();
534 break;
535 default:
536 break;
537 }
538 return messageResult;
539 }
540
AsScene2804BeamTarget(NeverhoodEngine * vm)541 AsScene2804BeamTarget::AsScene2804BeamTarget(NeverhoodEngine *vm)
542 : AnimatedSprite(vm, 1400) {
543
544 createSurface1(0x03842000, 1000);
545 _x = 475;
546 _y = 278;
547 setVisible(false);
548 _needRefresh = true;
549 updatePosition();
550 SetUpdateHandler(&AnimatedSprite::update);
551 SetMessageHandler(&AsScene2804BeamTarget::handleMessage);
552 }
553
handleMessage(int messageNum,const MessageParam & param,Entity * sender)554 uint32 AsScene2804BeamTarget::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
555 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
556 switch (messageNum) {
557 case 0x2004:
558 setVisible(true);
559 startAnimation(0x03842000, 0, -1);
560 messageResult = 1;
561 break;
562 case NM_KLAYMEN_CLIMB_LADDER:
563 setVisible(false);
564 stopAnimation();
565 messageResult = 1;
566 break;
567 default:
568 break;
569 }
570 return messageResult;
571 }
572
AsScene2806Spew(NeverhoodEngine * vm)573 AsScene2806Spew::AsScene2806Spew(NeverhoodEngine *vm)
574 : AnimatedSprite(vm, 1200) {
575
576 createSurface1(0x04211490, 1200);
577 _x = 378;
578 _y = 423;
579 SetUpdateHandler(&AnimatedSprite::update);
580 SetMessageHandler(&AsScene2806Spew::handleMessage);
581 setDoDeltaX(1);
582 setVisible(false);
583 }
584
handleMessage(int messageNum,const MessageParam & param,Entity * sender)585 uint32 AsScene2806Spew::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
586 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
587 switch (messageNum) {
588 case NM_ANIMATION_UPDATE:
589 playSound(0, 0x48640244);
590 startAnimation(0x04211490, 0, -1);
591 setVisible(true);
592 break;
593 case NM_ANIMATION_STOP:
594 stopAnimation();
595 setVisible(false);
596 break;
597 default:
598 break;
599 }
600 return messageResult;
601 }
602
603 static const uint32 kClass428FileHashes[] = {
604 0x140022CA,
605 0x4C30A602,
606 0xB1633402,
607 0x12982135,
608 0x0540B728,
609 0x002A81E3,
610 0x08982841,
611 0x10982841,
612 0x20982841,
613 0x40982841,
614 0x80982841,
615 0x40800711
616 };
617
618 static const int kClass428Countdowns1[] = {
619 18, 16, 10, 0
620 };
621
622 static const int kClass428Countdowns2[] = {
623 9, 9, 8, 8, 5, 5, 0, 0
624 };
625
626 static const uint32 kClass490FileHashes[] = {
627 0x08100071,
628 0x24084215,
629 0x18980A10
630 };
631
632 static const int16 kClass490FrameIndices1[] = {
633 0, 8, 15, 19
634 };
635
636 static const int16 kClass490FrameIndices2[] = {
637 0, 4, 8, 11, 15, 17, 19, 0
638 };
639
SsScene2808Dispenser(NeverhoodEngine * vm,Scene * parentScene,int testTubeSetNum,int testTubeIndex)640 SsScene2808Dispenser::SsScene2808Dispenser(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum, int testTubeIndex)
641 : StaticSprite(vm, 900), _parentScene(parentScene), _countdown(0), _testTubeSetNum(testTubeSetNum),
642 _testTubeIndex(testTubeIndex) {
643
644 loadSprite(kClass428FileHashes[testTubeSetNum * 3 + testTubeIndex], kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 1500);
645 setVisible(false);
646 SetUpdateHandler(&SsScene2808Dispenser::update);
647 SetMessageHandler(&SsScene2808Dispenser::handleMessage);
648 }
649
update()650 void SsScene2808Dispenser::update() {
651 updatePosition();
652 if (_countdown != 0 && (--_countdown) == 0) {
653 setVisible(false);
654 }
655 }
656
handleMessage(int messageNum,const MessageParam & param,Entity * sender)657 uint32 SsScene2808Dispenser::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
658 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
659 switch (messageNum) {
660 case 0x1011:
661 sendMessage(_parentScene, 0x2000, _testTubeIndex);
662 messageResult = 1;
663 break;
664 default:
665 break;
666 }
667 return messageResult;
668 }
669
startCountdown(int index)670 void SsScene2808Dispenser::startCountdown(int index) {
671 setVisible(true);
672 updatePosition();
673 if (_testTubeSetNum == 0) {
674 _countdown = kClass428Countdowns1[index];
675 } else {
676 _countdown = kClass428Countdowns2[index];
677 }
678 }
679
AsScene2808TestTube(NeverhoodEngine * vm,int testTubeSetNum,int testTubeIndex,SsScene2808Dispenser * ssDispenser)680 AsScene2808TestTube::AsScene2808TestTube(NeverhoodEngine *vm, int testTubeSetNum, int testTubeIndex, SsScene2808Dispenser *ssDispenser)
681 : AnimatedSprite(vm, 1100), _testTubeSetNum(testTubeSetNum), _testTubeIndex(testTubeIndex), _ssDispenser(ssDispenser), _fillLevel(0) {
682
683 if (testTubeSetNum == 0) {
684 _x = 504;
685 _y = 278;
686 } else {
687 setDoDeltaX(1);
688 _x = 136;
689 _y = 278;
690 }
691
692 createSurface1(kClass490FileHashes[testTubeIndex], 1100);
693
694 if (testTubeSetNum == 0) {
695 loadSound(0, 0x30809E2D);
696 loadSound(1, 0x72811E2D);
697 loadSound(2, 0x78B01625);
698 } else {
699 loadSound(3, 0x70A41E0C);
700 loadSound(4, 0x50205E2D);
701 loadSound(5, 0xF8621E2D);
702 loadSound(6, 0xF1A03C2D);
703 loadSound(7, 0x70A43D2D);
704 loadSound(8, 0xF0601E2D);
705 }
706
707 startAnimation(kClass490FileHashes[testTubeIndex], 0, -1);
708 _newStickFrameIndex = 0;
709
710 SetUpdateHandler(&AnimatedSprite::update);
711 SetMessageHandler(&AsScene2808TestTube::handleMessage);
712
713 if (_fillLevel == 0)
714 setVisible(false);
715
716 }
717
handleMessage(int messageNum,const MessageParam & param,Entity * sender)718 uint32 AsScene2808TestTube::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
719 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
720 switch (messageNum) {
721 case 0x1011:
722 fill();
723 messageResult = 1;
724 break;
725 default:
726 break;
727 }
728 return messageResult;
729 }
730
fill()731 void AsScene2808TestTube::fill() {
732 if ((int)_fillLevel < _testTubeSetNum * 3 + 3) {
733 if (_testTubeSetNum == 0) {
734 playSound(_fillLevel);
735 setVisible(true);
736 startAnimation(kClass490FileHashes[_testTubeIndex], kClass490FrameIndices1[_fillLevel], kClass490FrameIndices1[_fillLevel + 1]);
737 _newStickFrameIndex = kClass490FrameIndices1[_fillLevel + 1];
738 } else {
739 playSound(3 + _fillLevel);
740 setVisible(true);
741 startAnimation(kClass490FileHashes[_testTubeIndex], kClass490FrameIndices2[_fillLevel], kClass490FrameIndices2[_fillLevel + 1]);
742 _newStickFrameIndex = kClass490FrameIndices2[_fillLevel + 1];
743 }
744 _ssDispenser->startCountdown(_fillLevel);
745 _fillLevel++;
746 }
747 }
748
flush()749 void AsScene2808TestTube::flush() {
750 if (_fillLevel != 0) {
751 if (_testTubeSetNum == 0) {
752 startAnimation(kClass490FileHashes[_testTubeIndex], kClass490FrameIndices1[_fillLevel], -1);
753 } else {
754 startAnimation(kClass490FileHashes[_testTubeIndex], kClass490FrameIndices2[_fillLevel], -1);
755 }
756 _newStickFrameIndex = 0;
757 _playBackwards = true;
758 setVisible(true);
759 }
760 }
761
AsScene2808Handle(NeverhoodEngine * vm,Scene * parentScene,int testTubeSetNum)762 AsScene2808Handle::AsScene2808Handle(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum)
763 : AnimatedSprite(vm, 1300), _parentScene(parentScene), _testTubeSetNum(testTubeSetNum), _isActivated(false) {
764
765 loadSound(0, 0xE18D1F30);
766 _x = 320;
767 _y = 240;
768 if (_testTubeSetNum == 1)
769 setDoDeltaX(1);
770 createSurface1(0x040900D0, 1300);
771 startAnimation(0x040900D0, 0, -1);
772 _needRefresh = true;
773 _newStickFrameIndex = 0;
774 SetUpdateHandler(&AnimatedSprite::update);
775 SetMessageHandler(&AsScene2808Handle::handleMessage);
776 AnimatedSprite::updatePosition();
777 }
778
handleMessage(int messageNum,const MessageParam & param,Entity * sender)779 uint32 AsScene2808Handle::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
780 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
781 switch (messageNum) {
782 case 0x1011:
783 if (!_isActivated) {
784 sendMessage(_parentScene, 0x2001, 0);
785 playSound(0);
786 activate();
787 }
788 messageResult = 1;
789 break;
790 default:
791 break;
792 }
793 return messageResult;
794 }
795
hmActivating(int messageNum,const MessageParam & param,Entity * sender)796 uint32 AsScene2808Handle::hmActivating(int messageNum, const MessageParam ¶m, Entity *sender) {
797 uint32 messageResult = handleMessage(messageNum, param, sender);
798 switch (messageNum) {
799 case NM_ANIMATION_STOP:
800 gotoNextState();
801 break;
802 default:
803 break;
804 }
805 return messageResult;
806 }
807
activate()808 void AsScene2808Handle::activate() {
809 startAnimation(0x040900D0, 0, -1);
810 SetMessageHandler(&AsScene2808Handle::hmActivating);
811 NextState(&AsScene2808Handle::stActivated);
812 _isActivated = true;
813 _newStickFrameIndex = -1;
814 }
815
stActivated()816 void AsScene2808Handle::stActivated() {
817 stopAnimation();
818 sendMessage(_parentScene, NM_POSITION_CHANGE, 0);
819 }
820
AsScene2808Flow(NeverhoodEngine * vm,Scene * parentScene,int testTubeSetNum)821 AsScene2808Flow::AsScene2808Flow(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum)
822 : AnimatedSprite(vm, 1100), _parentScene(parentScene), _testTubeSetNum(testTubeSetNum) {
823
824 if (testTubeSetNum == 0) {
825 _x = 312;
826 _y = 444;
827 } else {
828 _x = 328;
829 _y = 444;
830 }
831 createSurface1(0xB8414818, 1200);
832 startAnimation(0xB8414818, 0, -1);
833 setVisible(false);
834 _newStickFrameIndex = 0;
835 _needRefresh = true;
836 loadSound(0, 0x6389B652);
837 SetUpdateHandler(&AnimatedSprite::update);
838 AnimatedSprite::updatePosition();
839 }
840
hmFlowing(int messageNum,const MessageParam & param,Entity * sender)841 uint32 AsScene2808Flow::hmFlowing(int messageNum, const MessageParam ¶m, Entity *sender) {
842 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
843 switch (messageNum) {
844 case NM_ANIMATION_STOP:
845 gotoNextState();
846 break;
847 default:
848 break;
849 }
850 return messageResult;
851 }
852
start()853 void AsScene2808Flow::start() {
854 startAnimation(0xB8414818, 0, -1);
855 setVisible(true);
856 SetMessageHandler(&AsScene2808Flow::hmFlowing);
857 NextState(&AsScene2808Flow::stKeepFlowing);
858 playSound(0);
859 }
860
stKeepFlowing()861 void AsScene2808Flow::stKeepFlowing() {
862 startAnimation(0xB8414818, 1, -1);
863 NextState(&AsScene2808Flow::stKeepFlowing);
864 }
865
AsScene2808LightEffect(NeverhoodEngine * vm,int testTubeSetNum)866 AsScene2808LightEffect::AsScene2808LightEffect(NeverhoodEngine *vm, int testTubeSetNum)
867 : AnimatedSprite(vm, 800), _countdown(1) {
868
869 _x = 320;
870 _y = 240;
871 if (testTubeSetNum == 1)
872 setDoDeltaX(1);
873 createSurface1(0x804C2404, 800);
874 SetUpdateHandler(&AsScene2808LightEffect::update);
875 _needRefresh = true;
876 AnimatedSprite::updatePosition();
877 }
878
update()879 void AsScene2808LightEffect::update() {
880 if (_countdown != 0 && (--_countdown) == 0) {
881 int16 frameIndex = _vm->_rnd->getRandomNumber(3 - 1);
882 startAnimation(0x804C2404, frameIndex, frameIndex);
883 updateAnim();
884 updatePosition();
885 _countdown = _vm->_rnd->getRandomNumber(3 - 1) + 1;
886 }
887 }
888
AsScene2809Spew(NeverhoodEngine * vm)889 AsScene2809Spew::AsScene2809Spew(NeverhoodEngine *vm)
890 : AnimatedSprite(vm, 1200) {
891
892 SetUpdateHandler(&AnimatedSprite::update);
893 SetMessageHandler(&AsScene2809Spew::handleMessage);
894 createSurface1(0x04211490, 1200);
895 _x = 262;
896 _y = 423;
897 setDoDeltaX(0);
898 setVisible(false);
899 }
900
handleMessage(int messageNum,const MessageParam & param,Entity * sender)901 uint32 AsScene2809Spew::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
902 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
903 switch (messageNum) {
904 case NM_ANIMATION_UPDATE:
905 playSound(0, 0x48640244);
906 startAnimation(0x04211490, 0, -1);
907 setVisible(true);
908 break;
909 case NM_ANIMATION_STOP:
910 stopAnimation();
911 setVisible(false);
912 break;
913 default:
914 break;
915 }
916 return messageResult;
917 }
918
AsScene2810Rope(NeverhoodEngine * vm,Scene * parentScene,int16 x)919 AsScene2810Rope::AsScene2810Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x)
920 : AnimatedSprite(vm, 1100), _parentScene(parentScene) {
921
922 createSurface(990, 68, 476);
923 SetUpdateHandler(&AnimatedSprite::update);
924 SetMessageHandler(&AsScene2810Rope::handleMessage);
925 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
926 _x = x;
927 _y = -276;
928 startAnimation(0x9D098C23, 35, 53);
929 }
930
handleMessage(int messageNum,const MessageParam & param,Entity * sender)931 uint32 AsScene2810Rope::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
932 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
933 switch (messageNum) {
934 case NM_ANIMATION_STOP:
935 startAnimation(0x9D098C23, 35, 53);
936 break;
937 case NM_MOVE_TO_BACK:
938 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 990);
939 break;
940 case NM_MOVE_TO_FRONT:
941 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 1010);
942 break;
943 default:
944 break;
945 }
946 return messageResult;
947 }
948
AsScene2812Winch(NeverhoodEngine * vm)949 AsScene2812Winch::AsScene2812Winch(NeverhoodEngine *vm)
950 : AnimatedSprite(vm, 1100) {
951
952 createSurface1(0x20DA08A0, 1200);
953 SetUpdateHandler(&AnimatedSprite::update);
954 SetMessageHandler(&AsScene2812Winch::handleMessage);
955 setVisible(false);
956 _x = 280;
957 _y = 184;
958 }
959
~AsScene2812Winch()960 AsScene2812Winch::~AsScene2812Winch() {
961 _vm->_soundMan->deleteSoundGroup(0x00B000E2);
962 }
963
handleMessage(int messageNum,const MessageParam & param,Entity * sender)964 uint32 AsScene2812Winch::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
965 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
966 switch (messageNum) {
967 case NM_ANIMATION_UPDATE:
968 startAnimation(0x20DA08A0, 0, -1);
969 setVisible(true);
970 _vm->_soundMan->addSound(0x00B000E2, 0xC874EE6C);
971 _vm->_soundMan->playSoundLooping(0xC874EE6C);
972 break;
973 case NM_ANIMATION_STOP:
974 startAnimation(0x20DA08A0, 7, -1);
975 break;
976 default:
977 break;
978 }
979 return messageResult;
980 }
981
AsScene2812Rope(NeverhoodEngine * vm,Scene * parentScene)982 AsScene2812Rope::AsScene2812Rope(NeverhoodEngine *vm, Scene *parentScene)
983 : AnimatedSprite(vm, 1100), _parentScene(parentScene) {
984
985 createSurface(990, 68, 476);
986 SetUpdateHandler(&AnimatedSprite::update);
987 SetMessageHandler(&AsScene2812Rope::handleMessage);
988 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
989 startAnimation(0xAE080551, 0, -1);
990 _x = 334;
991 _y = 201;
992 }
993
handleMessage(int messageNum,const MessageParam & param,Entity * sender)994 uint32 AsScene2812Rope::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
995 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
996 switch (messageNum) {
997 case NM_KLAYMEN_USE_OBJECT:
998 setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0);
999 stRopingDown();
1000 break;
1001 case NM_MOVE_TO_BACK:
1002 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 990);
1003 break;
1004 case NM_MOVE_TO_FRONT:
1005 sendMessage(_parentScene, NM_PRIORITY_CHANGE, 1010);
1006 break;
1007 default:
1008 break;
1009 }
1010 return messageResult;
1011 }
1012
hmRopingDown(int messageNum,const MessageParam & param,Entity * sender)1013 uint32 AsScene2812Rope::hmRopingDown(int messageNum, const MessageParam ¶m, Entity *sender) {
1014 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
1015 switch (messageNum) {
1016 case NM_ANIMATION_STOP:
1017 gotoNextState();
1018 break;
1019 default:
1020 break;
1021 }
1022 return messageResult;
1023 }
1024
stRopingDown()1025 void AsScene2812Rope::stRopingDown() {
1026 sendMessage(_parentScene, NM_KLAYMEN_USE_OBJECT, 0);
1027 startAnimation(0x9D098C23, 0, -1);
1028 SetMessageHandler(&AsScene2812Rope::hmRopingDown);
1029 }
1030
AsScene2812TrapDoor(NeverhoodEngine * vm)1031 AsScene2812TrapDoor::AsScene2812TrapDoor(NeverhoodEngine *vm)
1032 : AnimatedSprite(vm, 0x805D0029, 100, 320, 240) {
1033
1034 SetMessageHandler(&AsScene2812TrapDoor::handleMessage);
1035 _newStickFrameIndex = 0;
1036 }
1037
handleMessage(int messageNum,const MessageParam & param,Entity * sender)1038 uint32 AsScene2812TrapDoor::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) {
1039 uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
1040 switch (messageNum) {
1041 case NM_ANIMATION_UPDATE:
1042 startAnimation(0x805D0029, 0, -1);
1043 playSound(0, 0xEA005F40);
1044 _newStickFrameIndex = STICK_LAST_FRAME;
1045 break;
1046 default:
1047 break;
1048 }
1049 return messageResult;
1050 }
1051
KmScene2801(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y)1052 KmScene2801::KmScene2801(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
1053 : Klaymen(vm, parentScene, x, y) {
1054
1055 // Empty
1056 }
1057
xHandleMessage(int messageNum,const MessageParam & param)1058 uint32 KmScene2801::xHandleMessage(int messageNum, const MessageParam ¶m) {
1059 switch (messageNum) {
1060 case 0x4001:
1061 case 0x4800:
1062 startWalkToX(param.asPoint().x, false);
1063 break;
1064 case NM_KLAYMEN_STAND_IDLE:
1065 GotoState(&Klaymen::stTryStandIdle);
1066 break;
1067 case NM_KLAYMEN_PICKUP:
1068 GotoState(&Klaymen::stPickUpGeneric);
1069 break;
1070 case 0x4817:
1071 setDoDeltaX(param.asInteger());
1072 gotoNextStateExt();
1073 break;
1074 case 0x481B:
1075 if (param.asPoint().y != 0)
1076 startWalkToXDistance(param.asPoint().y, param.asPoint().x);
1077 else
1078 startWalkToAttachedSpriteXDistance(param.asPoint().x);
1079 break;
1080 case NM_KLAYMEN_TURN_TO_USE:
1081 GotoState(&Klaymen::stTurnToUse);
1082 break;
1083 case NM_KLAYMEN_RETURN_FROM_USE:
1084 GotoState(&Klaymen::stReturnFromUse);
1085 break;
1086 case 0x481F:
1087 if (param.asInteger() == 1)
1088 GotoState(&Klaymen::stWonderAboutAfter);
1089 else if (param.asInteger() == 0)
1090 GotoState(&Klaymen::stWonderAboutHalf);
1091 else if (param.asInteger() == 4)
1092 GotoState(&Klaymen::stTurnAwayFromUse);
1093 else if (param.asInteger() == 3)
1094 GotoState(&Klaymen::stTurnToUseHalf);
1095 else
1096 GotoState(&Klaymen::stWonderAbout);
1097 break;
1098 case 0x482D:
1099 setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
1100 gotoNextStateExt();
1101 break;
1102 case 0x482E:
1103 if (param.asInteger() == 1)
1104 GotoState(&Klaymen::stWalkToFrontNoStep);
1105 else
1106 GotoState(&Klaymen::stWalkToFront);
1107 break;
1108 case 0x482F:
1109 if (param.asInteger() == 1)
1110 GotoState(&Klaymen::stTurnToFront);
1111 else
1112 GotoState(&Klaymen::stTurnToBack);
1113 break;
1114 case 0x4837:
1115 stopWalking();
1116 break;
1117 default:
1118 break;
1119 }
1120 return 0;
1121 }
1122
KmScene2803(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y,NRect * clipRects,int clipRectsCount)1123 KmScene2803::KmScene2803(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount)
1124 : Klaymen(vm, parentScene, x, y) {
1125
1126 _surface->setClipRects(clipRects, clipRectsCount);
1127 _dataResource.load(0x00900849);
1128 }
1129
xHandleMessage(int messageNum,const MessageParam & param)1130 uint32 KmScene2803::xHandleMessage(int messageNum, const MessageParam ¶m) {
1131 switch (messageNum) {
1132 case 0x4001:
1133 case 0x4800:
1134 startWalkToX(param.asPoint().x, false);
1135 break;
1136 case NM_KLAYMEN_STAND_IDLE:
1137 GotoState(&Klaymen::stTryStandIdle);
1138 break;
1139 case 0x4803:
1140 _destY = param.asInteger();
1141 GotoState(&Klaymen::stJumpToGrab);
1142 break;
1143 case 0x4804:
1144 if (param.asInteger() == 3)
1145 GotoState(&Klaymen::stFinishGrow);
1146 break;
1147 case 0x480D:
1148 GotoState(&Klaymen::stPullCord);
1149 break;
1150 case 0x4817:
1151 setDoDeltaX(param.asInteger());
1152 gotoNextStateExt();
1153 break;
1154 case 0x4818:
1155 startWalkToX(_dataResource.getPoint(param.asInteger()).x, false);
1156 break;
1157 case NM_KLAYMEN_TURN_TO_USE:
1158 GotoState(&Klaymen::stTurnToUse);
1159 break;
1160 case NM_KLAYMEN_RETURN_FROM_USE:
1161 GotoState(&Klaymen::stReturnFromUse);
1162 break;
1163 case 0x481F:
1164 if (param.asInteger() == 1)
1165 GotoState(&Klaymen::stWonderAboutAfter);
1166 else
1167 GotoState(&Klaymen::stWonderAboutHalf);
1168 break;
1169 case 0x482E:
1170 GotoState(&Klaymen::stWalkToFront);
1171 break;
1172 case 0x482F:
1173 GotoState(&Klaymen::stTurnToBack);
1174 break;
1175 case 0x4834:
1176 GotoState(&Klaymen::stStepOver);
1177 break;
1178 case 0x4838:
1179 GotoState(&Klaymen::stJumpToGrabRelease);
1180 break;
1181 default:
1182 break;
1183 }
1184 return 0;
1185 }
1186
KmScene2803Small(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y)1187 KmScene2803Small::KmScene2803Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
1188 : Klaymen(vm, parentScene, x, y) {
1189
1190 _dataResource.load(0x81120132);
1191 }
1192
xHandleMessage(int messageNum,const MessageParam & param)1193 uint32 KmScene2803Small::xHandleMessage(int messageNum, const MessageParam ¶m) {
1194 switch (messageNum) {
1195 case 0x4001:
1196 case 0x4800:
1197 startWalkToXSmall(param.asPoint().x);
1198 break;
1199 case NM_KLAYMEN_STAND_IDLE:
1200 GotoState(&Klaymen::stStandIdleSmall);
1201 break;
1202 case 0x4817:
1203 setDoDeltaX(param.asInteger());
1204 gotoNextStateExt();
1205 break;
1206 case 0x4818:
1207 startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x);
1208 break;
1209 case 0x481F:
1210 if (param.asInteger() == 1)
1211 GotoState(&Klaymen::stWonderAboutAfterSmall);
1212 else if (param.asInteger() == 0)
1213 GotoState(&Klaymen::stWonderAboutHalfSmall);
1214 else
1215 GotoState(&Klaymen::stWonderAboutSmall);
1216 break;
1217 case 0x482E:
1218 if (param.asInteger() == 1)
1219 GotoState(&Klaymen::stWalkToFrontNoStepSmall);
1220 else if (param.asInteger() == 2)
1221 GotoState(&Klaymen::stWalkToFront2Small);
1222 else
1223 GotoState(&Klaymen::stWalkToFrontSmall);
1224 break;
1225 case 0x482F:
1226 if (param.asInteger() == 1)
1227 GotoState(&Klaymen::stTurnToBackHalfSmall);
1228 else if (param.asInteger() == 2)
1229 GotoState(&Klaymen::stTurnToBackWalkSmall);
1230 else
1231 GotoState(&Klaymen::stTurnToBackSmall);
1232 break;
1233 case 0x4830:
1234 GotoState(&KmScene2803Small::stShrink);
1235 break;
1236 default:
1237 break;
1238 }
1239 return 0;
1240 }
1241
hmShrink(int messageNum,const MessageParam & param,Entity * sender)1242 uint32 KmScene2803Small::hmShrink(int messageNum, const MessageParam ¶m, Entity *sender) {
1243 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1244 switch (messageNum) {
1245 case NM_ANIMATION_START:
1246 if (param.asInteger() == 0x80C110B5)
1247 sendMessage(_parentScene, NM_MOVE_TO_BACK, 0);
1248 else if (param.asInteger() == 0x33288344)
1249 playSound(2, 0x10688664);
1250 break;
1251 default:
1252 break;
1253 }
1254 return messageResult;
1255 }
1256
stShrink()1257 void KmScene2803Small::stShrink() {
1258 _busyStatus = 0;
1259 _acceptInput = false;
1260 playSound(0, 0x4C69EA53);
1261 startAnimation(0x1AE88904, 0, -1);
1262 SetUpdateHandler(&Klaymen::update);
1263 SetMessageHandler(&KmScene2803Small::hmShrink);
1264 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
1265 }
1266
KmScene2805(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y)1267 KmScene2805::KmScene2805(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
1268 : Klaymen(vm, parentScene, x, y) {
1269
1270 // Empty
1271 }
1272
xHandleMessage(int messageNum,const MessageParam & param)1273 uint32 KmScene2805::xHandleMessage(int messageNum, const MessageParam ¶m) {
1274 uint32 messageResult = 0;
1275 switch (messageNum) {
1276 case NM_ANIMATION_UPDATE:
1277 _isSittingInTeleporter = param.asInteger() != 0;
1278 messageResult = 1;
1279 break;
1280 case 0x4001:
1281 case 0x4800:
1282 startWalkToX(param.asPoint().x, false);
1283 break;
1284 case NM_KLAYMEN_STAND_IDLE:
1285 if (_isSittingInTeleporter)
1286 GotoState(&Klaymen::stSitIdleTeleporter);
1287 else
1288 GotoState(&Klaymen::stTryStandIdle);
1289 break;
1290 case 0x4817:
1291 setDoDeltaX(param.asInteger());
1292 gotoNextStateExt();
1293 break;
1294 case NM_KLAYMEN_TURN_TO_USE:
1295 if (_isSittingInTeleporter)
1296 GotoState(&Klaymen::stTurnToUseInTeleporter);
1297 break;
1298 case NM_KLAYMEN_RETURN_FROM_USE:
1299 if (_isSittingInTeleporter)
1300 GotoState(&Klaymen::stReturnFromUseInTeleporter);
1301 break;
1302 case 0x4834:
1303 GotoState(&Klaymen::stStepOver);
1304 break;
1305 case 0x4835:
1306 sendMessage(_parentScene, 0x2000, 1);
1307 _isSittingInTeleporter = true;
1308 GotoState(&Klaymen::stSitInTeleporter);
1309 break;
1310 case 0x4836:
1311 sendMessage(_parentScene, 0x2000, 0);
1312 _isSittingInTeleporter = false;
1313 GotoState(&Klaymen::stGetUpFromTeleporter);
1314 break;
1315 case 0x483D:
1316 teleporterAppear(0xDE284B74);
1317 break;
1318 case 0x483E:
1319 teleporterDisappear(0xD82A4094);
1320 break;
1321 default:
1322 break;
1323 }
1324 return messageResult;
1325 }
1326
KmScene2806(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y,bool needsLargeSurface,NRect * clipRects,uint clipRectsCount)1327 KmScene2806::KmScene2806(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y,
1328 bool needsLargeSurface, NRect *clipRects, uint clipRectsCount)
1329 : Klaymen(vm, parentScene, x, y) {
1330
1331 if (needsLargeSurface) {
1332 NDimensions dimensions = _animResource.loadSpriteDimensions(0x2838C010);
1333 delete _surface;
1334 createSurface(1000, dimensions.width, dimensions.height);
1335 loadSound(3, 0x58E0C341);
1336 loadSound(4, 0x40A00342);
1337 loadSound(5, 0xD0A1C348);
1338 loadSound(6, 0x166FC6E0);
1339 loadSound(7, 0x00018040);
1340 }
1341
1342 _dataResource.load(0x98182003);
1343 _surface->setClipRects(clipRects, clipRectsCount);
1344 }
1345
xHandleMessage(int messageNum,const MessageParam & param)1346 uint32 KmScene2806::xHandleMessage(int messageNum, const MessageParam ¶m) {
1347 switch (messageNum) {
1348 case 0x4001:
1349 case 0x4800:
1350 startWalkToX(param.asPoint().x, false);
1351 break;
1352 case NM_KLAYMEN_STAND_IDLE:
1353 GotoState(&Klaymen::stTryStandIdle);
1354 break;
1355 case 0x4804:
1356 startWalkToX(440, true);
1357 break;
1358 case 0x480D:
1359 GotoState(&Klaymen::stPullCord);
1360 break;
1361 case NM_KLAYMEN_PRESS_BUTTON:
1362 if (param.asInteger() == 0)
1363 GotoState(&Klaymen::stPressButtonSide);
1364 break;
1365 case 0x4817:
1366 setDoDeltaX(param.asInteger());
1367 gotoNextStateExt();
1368 break;
1369 case 0x4818:
1370 startWalkToX(_dataResource.getPoint(param.asInteger()).x, false);
1371 break;
1372 case 0x4831:
1373 GotoState(&Klaymen::stGrow);
1374 break;
1375 case 0x4832:
1376 if (param.asInteger() == 1)
1377 GotoState(&Klaymen::stDrinkPotion);
1378 else
1379 GotoState(&Klaymen::stUseTube);
1380 break;
1381 default:
1382 break;
1383 }
1384 return 0;
1385 }
1386
KmScene2809(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y,bool needsLargeSurface,NRect * clipRects,uint clipRectsCount)1387 KmScene2809::KmScene2809(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y,
1388 bool needsLargeSurface, NRect *clipRects, uint clipRectsCount)
1389 : Klaymen(vm, parentScene, x, y) {
1390
1391 if (needsLargeSurface) {
1392 NDimensions dimensions = _animResource.loadSpriteDimensions(0x2838C010);
1393 delete _surface;
1394 createSurface(1000, dimensions.width, dimensions.height);
1395 loadSound(3, 0x58E0C341);
1396 loadSound(4, 0x40A00342);
1397 loadSound(5, 0xD0A1C348);
1398 loadSound(6, 0x166FC6E0);
1399 loadSound(7, 0x00018040);
1400 }
1401
1402 _dataResource.load(0x1830009A);
1403 _surface->setClipRects(clipRects, clipRectsCount);
1404 }
1405
xHandleMessage(int messageNum,const MessageParam & param)1406 uint32 KmScene2809::xHandleMessage(int messageNum, const MessageParam ¶m) {
1407 switch (messageNum) {
1408 case 0x4001:
1409 case 0x4800:
1410 startWalkToX(param.asPoint().x, false);
1411 break;
1412 case NM_KLAYMEN_STAND_IDLE:
1413 GotoState(&Klaymen::stTryStandIdle);
1414 break;
1415 case 0x4804:
1416 startWalkToX(226, true);
1417 break;
1418 case 0x480D:
1419 GotoState(&Klaymen::stPullCord);
1420 break;
1421 case NM_KLAYMEN_PRESS_BUTTON:
1422 if (param.asInteger() == 0)
1423 GotoState(&Klaymen::stPressButtonSide);
1424 break;
1425 case 0x4817:
1426 setDoDeltaX(param.asInteger());
1427 gotoNextStateExt();
1428 break;
1429 case 0x4818:
1430 startWalkToX(_dataResource.getPoint(param.asInteger()).x, false);
1431 break;
1432 case 0x4831:
1433 GotoState(&Klaymen::stGrow);
1434 break;
1435 case 0x4832:
1436 if (param.asInteger() == 1)
1437 GotoState(&Klaymen::stDrinkPotion);
1438 else
1439 GotoState(&Klaymen::stUseTube);
1440 break;
1441 default:
1442 break;
1443 }
1444 return 0;
1445 }
1446
KmScene2810Small(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y)1447 KmScene2810Small::KmScene2810Small(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
1448 : Klaymen(vm, parentScene, x, y) {
1449
1450 // Empty
1451 }
1452
xHandleMessage(int messageNum,const MessageParam & param)1453 uint32 KmScene2810Small::xHandleMessage(int messageNum, const MessageParam ¶m) {
1454 switch (messageNum) {
1455 case 0x4001:
1456 case 0x4800:
1457 startWalkToXSmall(param.asPoint().x);
1458 break;
1459 case NM_KLAYMEN_STAND_IDLE:
1460 GotoState(&Klaymen::stStandIdleSmall);
1461 break;
1462 case 0x4817:
1463 setDoDeltaX(param.asInteger());
1464 gotoNextStateExt();
1465 break;
1466 case 0x4818:
1467 startWalkToXSmall(_dataResource.getPoint(param.asInteger()).x);
1468 break;
1469 case 0x481F:
1470 if (param.asInteger() == 1)
1471 GotoState(&Klaymen::stWonderAboutAfterSmall);
1472 else if (param.asInteger() == 0)
1473 GotoState(&Klaymen::stWonderAboutHalfSmall);
1474 else
1475 GotoState(&Klaymen::stWonderAboutSmall);
1476 break;
1477 case 0x482E:
1478 if (param.asInteger() == 1)
1479 GotoState(&Klaymen::stWalkToFrontNoStepSmall);
1480 else
1481 GotoState(&Klaymen::stWalkToFrontSmall);
1482 break;
1483 case 0x482F:
1484 if (param.asInteger() == 1)
1485 GotoState(&Klaymen::stTurnToBackHalfSmall);
1486 else
1487 GotoState(&Klaymen::stTurnToBackSmall);
1488 break;
1489 case 0x4837:
1490 stopWalking();
1491 break;
1492 default:
1493 break;
1494 }
1495 return 0;
1496 }
1497
KmScene2810(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y,NRect * clipRects,uint clipRectsCount)1498 KmScene2810::KmScene2810(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRect *clipRects, uint clipRectsCount)
1499 : Klaymen(vm, parentScene, x, y) {
1500
1501 _surface->setClipRects(clipRects, clipRectsCount);
1502 }
1503
xHandleMessage(int messageNum,const MessageParam & param)1504 uint32 KmScene2810::xHandleMessage(int messageNum, const MessageParam ¶m) {
1505 switch (messageNum) {
1506 case 0x4001:
1507 case 0x4800:
1508 startWalkToX(param.asPoint().x, false);
1509 break;
1510 case NM_KLAYMEN_STAND_IDLE:
1511 GotoState(&Klaymen::stTryStandIdle);
1512 break;
1513 case 0x4803:
1514 _destY = param.asInteger();
1515 GotoState(&Klaymen::stJumpToGrab);
1516 break;
1517 case 0x4804:
1518 if (param.asInteger() == 3)
1519 GotoState(&Klaymen::stFinishGrow);
1520 break;
1521 case NM_KLAYMEN_PICKUP:
1522 GotoState(&Klaymen::stPickUpGeneric);
1523 break;
1524 case 0x4817:
1525 setDoDeltaX(param.asInteger());
1526 gotoNextStateExt();
1527 break;
1528 case 0x4818:
1529 startWalkToX(_dataResource.getPoint(param.asInteger()).x, false);
1530 break;
1531 case 0x481B:
1532 if (param.asPoint().y != 0)
1533 startWalkToXDistance(param.asPoint().y, param.asPoint().x);
1534 else
1535 startWalkToAttachedSpriteXDistance(param.asPoint().x);
1536 break;
1537 case 0x481F:
1538 if (param.asInteger() == 0)
1539 GotoState(&Klaymen::stWonderAboutHalf);
1540 else if (param.asInteger() == 1)
1541 GotoState(&Klaymen::stWonderAboutAfter);
1542 else if (param.asInteger() == 3)
1543 GotoState(&Klaymen::stTurnToUseHalf);
1544 else if (param.asInteger() == 4)
1545 GotoState(&Klaymen::stTurnAwayFromUse);
1546 else if (param.asInteger() == 5)
1547 GotoState(&Klaymen::stTurnToUseExt);
1548 else
1549 GotoState(&Klaymen::stWonderAbout);
1550 break;
1551 case 0x4820:
1552 sendMessage(_parentScene, 0x2000, 0);
1553 GotoState(&Klaymen::stContinueClimbLadderUp);
1554 break;
1555 case 0x4821:
1556 sendMessage(_parentScene, 0x2000, 0);
1557 _destY = param.asInteger();
1558 GotoState(&Klaymen::stStartClimbLadderDown);
1559 break;
1560 case 0x4822:
1561 sendMessage(_parentScene, 0x2000, 0);
1562 _destY = param.asInteger();
1563 GotoState(&Klaymen::stStartClimbLadderUp);
1564 break;
1565 case 0x4823:
1566 sendMessage(_parentScene, 0x2001, 0);
1567 GotoState(&Klaymen::stClimbLadderHalf);
1568 break;
1569 case 0x4824:
1570 sendMessage(_parentScene, 0x2000, 0);
1571 _destY = _dataResource.getPoint(param.asInteger()).y;
1572 GotoState(&Klaymen::stStartClimbLadderDown);
1573 break;
1574 case 0x4825:
1575 sendMessage(_parentScene, 0x2000, 0);
1576 _destY = _dataResource.getPoint(param.asInteger()).y;
1577 GotoState(&Klaymen::stStartClimbLadderUp);
1578 break;
1579 case 0x482D:
1580 setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
1581 gotoNextStateExt();
1582 break;
1583 case 0x4837:
1584 stopWalking();
1585 break;
1586 default:
1587 break;
1588 }
1589 return 0;
1590 }
1591
KmScene2812(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y)1592 KmScene2812::KmScene2812(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
1593 : Klaymen(vm, parentScene, x, y) {
1594
1595 // Empty
1596 }
1597
xHandleMessage(int messageNum,const MessageParam & param)1598 uint32 KmScene2812::xHandleMessage(int messageNum, const MessageParam ¶m) {
1599 switch (messageNum) {
1600 case 0x4001:
1601 case 0x4800:
1602 startWalkToX(param.asPoint().x, false);
1603 break;
1604 case NM_KLAYMEN_STAND_IDLE:
1605 GotoState(&Klaymen::stTryStandIdle);
1606 break;
1607 case 0x4805:
1608 _destY = param.asInteger();
1609 GotoState(&Klaymen::stJumpToGrabFall);
1610 break;
1611 case NM_KLAYMEN_PICKUP:
1612 if (param.asInteger() == 2)
1613 GotoState(&Klaymen::stPickUpNeedle);
1614 else if (param.asInteger() == 1)
1615 GotoState(&Klaymen::stPickUpTube);
1616 else
1617 GotoState(&Klaymen::stPickUpGeneric);
1618 break;
1619 case 0x4817:
1620 setDoDeltaX(param.asInteger());
1621 gotoNextStateExt();
1622 break;
1623 case NM_KLAYMEN_INSERT_DISK:
1624 GotoState(&Klaymen::stInsertDisk);
1625 break;
1626 case 0x481B:
1627 if (param.asPoint().y != 0)
1628 startWalkToXDistance(param.asPoint().y, param.asPoint().x);
1629 else
1630 startWalkToAttachedSpriteXDistance(param.asPoint().x);
1631 break;
1632 case NM_KLAYMEN_TURN_TO_USE:
1633 GotoState(&Klaymen::stTurnToUse);
1634 break;
1635 case NM_KLAYMEN_RETURN_FROM_USE:
1636 GotoState(&Klaymen::stReturnFromUse);
1637 break;
1638 case 0x4820:
1639 sendMessage(_parentScene, 0x2001, 0);
1640 GotoState(&Klaymen::stContinueClimbLadderUp);
1641 break;
1642 case 0x4821:
1643 sendMessage(_parentScene, 0x2001, 0);
1644 _destY = param.asInteger();
1645 GotoState(&Klaymen::stStartClimbLadderDown);
1646 break;
1647 case 0x4822:
1648 sendMessage(_parentScene, 0x2001, 0);
1649 _destY = param.asInteger();
1650 GotoState(&Klaymen::stStartClimbLadderUp);
1651 break;
1652 case 0x4823:
1653 sendMessage(_parentScene, NM_POSITION_CHANGE, 0);
1654 GotoState(&Klaymen::stClimbLadderHalf);
1655 break;
1656 case 0x482D:
1657 setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
1658 gotoNextStateExt();
1659 break;
1660 case 0x482E:
1661 if (param.asInteger() == 1)
1662 GotoState(&Klaymen::stWalkToFrontNoStep);
1663 else
1664 GotoState(&Klaymen::stWalkToFront);
1665 break;
1666 case 0x482F:
1667 if (param.asInteger() == 1)
1668 GotoState(&Klaymen::stTurnToFront);
1669 else
1670 GotoState(&Klaymen::stTurnToBack);
1671 break;
1672 case 0x483F:
1673 startSpecialWalkRight(param.asInteger());
1674 break;
1675 case 0x4840:
1676 startSpecialWalkLeft(param.asInteger());
1677 break;
1678 default:
1679 break;
1680 }
1681 return 0;
1682 }
1683
1684 } // End of namespace Neverhood
1685