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/klaymen.h"
24 #include "neverhood/resourceman.h"
25 #include "neverhood/scene.h"
26 #include "neverhood/staticdata.h"
27
28 namespace Neverhood {
29
30 static const KlaymenIdleTableItem klaymenIdleTable1[] = {
31 {1, kIdlePickEar},
32 {1, kIdleSpinHead},
33 {1, kIdleArms},
34 {1, kIdleChest},
35 {1, kIdleHeadOff}
36 };
37
38 static const KlaymenIdleTableItem klaymenIdleTable2[] = {
39 {1, kIdlePickEar},
40 {1, kIdleSpinHead},
41 {1, kIdleChest},
42 {1, kIdleHeadOff}
43 };
44
45 static const KlaymenIdleTableItem klaymenIdleTable3[] = {
46 {1, kIdleTeleporterHands},
47 {1, kIdleTeleporterHands2}
48 };
49
50 // Klaymen
51
Klaymen(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y,NRectArray * clipRects)52 Klaymen::Klaymen(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, NRectArray *clipRects)
53 : AnimatedSprite(vm, 1000), _idleCounterMax(0), _idleCounter(0), _isMoveObjectRequested(false), _blinkCounterMax(0),
54 _isWalkingOpenDoorNotified(false), _spitOutCountdown(0), _tapesToInsert(0), _keysToInsert(0), _busyStatus(0), _acceptInput(true),
55 _attachedSprite(NULL), _isWalking(false), _actionStatus(1), _parentScene(parentScene), _isSneaking(false), _isLargeStep(false),
56 _doYHitIncr(false), _isLeverDown(false), _isSittingInTeleporter(false), _actionStatusChanged(false), _ladderStatus(0), _pathPoints(NULL), _soundFlag(false),
57 _idleTableNum(0), _otherSprite(NULL), _moveObjectCountdown(0), _walkResumeFrameIncr(0) {
58
59 createSurface(1000, 320, 200);
60 _x = x;
61 _y = y;
62 _destX = x;
63 _destY = y;
64 _flags = 2;
65 setKlaymenIdleTable1();
66 stTryStandIdle();
67 SetUpdateHandler(&Klaymen::update);
68 }
69
xUpdate()70 void Klaymen::xUpdate() {
71 // Empty
72 }
73
xHandleMessage(int messageNum,const MessageParam & param)74 uint32 Klaymen::xHandleMessage(int messageNum, const MessageParam ¶m) {
75 switch (messageNum) {
76 case 0x4001:
77 case 0x4800:
78 startWalkToX(param.asPoint().x, false);
79 break;
80 case NM_KLAYMEN_STAND_IDLE:
81 GotoState(&Klaymen::stTryStandIdle);
82 break;
83 case 0x4818:
84 startWalkToX(_dataResource.getPoint(param.asInteger()).x, false);
85 break;
86 default:
87 break;
88 }
89 return 0;
90 }
91
update()92 void Klaymen::update() {
93 AnimatedSprite::update();
94 xUpdate();
95 }
96
setKlaymenIdleTable(const KlaymenIdleTableItem * table,uint tableCount)97 void Klaymen::setKlaymenIdleTable(const KlaymenIdleTableItem *table, uint tableCount) {
98 _idleTable = table;
99 _idleTableCount = tableCount;
100 _idleTableTotalWeight = 0;
101 for (uint i = 0; i < tableCount; i++)
102 _idleTableTotalWeight += table[i].weight;
103 }
104
setKlaymenIdleTable1()105 void Klaymen::setKlaymenIdleTable1() {
106 setKlaymenIdleTable(klaymenIdleTable1, ARRAYSIZE(klaymenIdleTable1));
107 }
108
setKlaymenIdleTable2()109 void Klaymen::setKlaymenIdleTable2() {
110 setKlaymenIdleTable(klaymenIdleTable2, ARRAYSIZE(klaymenIdleTable2));
111 }
112
setKlaymenIdleTable3()113 void Klaymen::setKlaymenIdleTable3() {
114 setKlaymenIdleTable(klaymenIdleTable3, ARRAYSIZE(klaymenIdleTable3));
115 }
116
stIdlePickEar()117 void Klaymen::stIdlePickEar() {
118 _busyStatus = 1;
119 _acceptInput = true;
120 startAnimation(0x5B20C814, 0, -1);
121 SetUpdateHandler(&Klaymen::update);
122 SetMessageHandler(&Klaymen::hmIdlePickEar);
123 SetSpriteUpdate(NULL);
124 NextState(&Klaymen::stStandAround);
125 FinalizeState(&Klaymen::evIdlePickEarDone);
126 }
127
hmIdlePickEar(int messageNum,const MessageParam & param,Entity * sender)128 uint32 Klaymen::hmIdlePickEar(int messageNum, const MessageParam ¶m, Entity *sender) {
129 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
130 switch (messageNum) {
131 case NM_ANIMATION_START:
132 if (param.asInteger() == 0x04DBC02C) {
133 playSound(0, 0x44528AA1);
134 }
135 break;
136 default:
137 break;
138 }
139 return messageResult;
140 }
141
evIdlePickEarDone()142 void Klaymen::evIdlePickEarDone() {
143 stopSound(0);
144 }
145
stIdleSpinHead()146 void Klaymen::stIdleSpinHead() {
147 _busyStatus = 1;
148 _acceptInput = true;
149 startAnimation(0xD122C137, 0, -1);
150 SetUpdateHandler(&Klaymen::update);
151 SetMessageHandler(&Klaymen::hmIdleSpinHead);
152 SetSpriteUpdate(NULL);
153 NextState(&Klaymen::stStandAround);
154 }
155
hmIdleSpinHead(int messageNum,const MessageParam & param,Entity * sender)156 uint32 Klaymen::hmIdleSpinHead(int messageNum, const MessageParam ¶m, Entity *sender) {
157 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
158 switch (messageNum) {
159 case NM_ANIMATION_START:
160 if (param.asInteger() == 0x808A0008) {
161 playSound(0, 0xD948A340);
162 }
163 break;
164 default:
165 break;
166 }
167 return messageResult;
168 }
169
stIdleArms()170 void Klaymen::stIdleArms() {
171 _busyStatus = 1;
172 _acceptInput = true;
173 startAnimation(0x543CD054, 0, -1);
174 SetUpdateHandler(&Klaymen::update);
175 SetMessageHandler(&Klaymen::hmIdleArms);
176 SetSpriteUpdate(NULL);
177 NextState(&Klaymen::stStandAround);
178 FinalizeState(&Klaymen::evIdleArmsDone);
179 }
180
evIdleArmsDone()181 void Klaymen::evIdleArmsDone() {
182 stopSound(0);
183 }
184
hmIdleArms(int messageNum,const MessageParam & param,Entity * sender)185 uint32 Klaymen::hmIdleArms(int messageNum, const MessageParam ¶m, Entity *sender) {
186 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
187 switch (messageNum) {
188 case NM_ANIMATION_START:
189 if (param.asInteger() == 0x5A0F0104) {
190 playSound(0, 0x7970A100);
191 } else if (param.asInteger() == 0x9A9A0109) {
192 playSound(0, 0xD170CF04);
193 } else if (param.asInteger() == 0x989A2169) {
194 playSound(0, 0xD073CF14);
195 }
196 break;
197 default:
198 break;
199 }
200 return messageResult;
201 }
202
stIdleChest()203 void Klaymen::stIdleChest() {
204 _busyStatus = 1;
205 _acceptInput = true;
206 startAnimation(0x40A0C034, 0, -1);
207 SetUpdateHandler(&Klaymen::update);
208 SetMessageHandler(&Klaymen::hmIdleChest);
209 SetSpriteUpdate(NULL);
210 NextState(&Klaymen::stStandAround);
211 }
212
hmIdleChest(int messageNum,const MessageParam & param,Entity * sender)213 uint32 Klaymen::hmIdleChest(int messageNum, const MessageParam ¶m, Entity *sender) {
214 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
215 switch (messageNum) {
216 case NM_ANIMATION_START:
217 if (param.asInteger() == 0x0D2A0288) {
218 playSound(0, 0xD192A368);
219 }
220 break;
221 default:
222 break;
223 }
224 return messageResult;
225 }
226
stIdleHeadOff()227 void Klaymen::stIdleHeadOff() {
228 _busyStatus = 1;
229 _acceptInput = true;
230 startAnimation(0x5120E137, 0, -1);
231 SetUpdateHandler(&Klaymen::update);
232 SetMessageHandler(&Klaymen::hmIdleHeadOff);
233 SetSpriteUpdate(NULL);
234 NextState(&Klaymen::stStandAround);
235 }
236
hmIdleHeadOff(int messageNum,const MessageParam & param,Entity * sender)237 uint32 Klaymen::hmIdleHeadOff(int messageNum, const MessageParam ¶m, Entity *sender) {
238 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
239 switch (messageNum) {
240 case NM_ANIMATION_START:
241 if (param.asInteger() == 0xC006000C) {
242 playSound(0, 0x9D406340);
243 } else if (param.asInteger() == 0x2E4A2940) {
244 playSound(0, 0x53A4A1D4);
245 } else if (param.asInteger() == 0xAA0A0860) {
246 playSound(0, 0x5BE0A3C6);
247 } else if (param.asInteger() == 0xC0180260) {
248 playSound(0, 0x5D418366);
249 }
250 break;
251 default:
252 break;
253 }
254 return messageResult;
255 }
256
stIdleWonderAbout()257 void Klaymen::stIdleWonderAbout() {
258 _busyStatus = 1;
259 _acceptInput = true;
260 startAnimation(0xD820A114, 0, -1);
261 SetUpdateHandler(&Klaymen::update);
262 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
263 SetSpriteUpdate(NULL);
264 NextState(&Klaymen::stStandAround);
265 }
266
stSitIdleTeleporter()267 void Klaymen::stSitIdleTeleporter() {
268 _busyStatus = 0;
269 _acceptInput = true;
270 startAnimation(0x582EC138, 0, -1);
271 SetUpdateHandler(&Klaymen::upSitIdleTeleporter);
272 SetMessageHandler(&Klaymen::hmLowLevel);
273 SetSpriteUpdate(NULL);
274 _idleCounter = 0;
275 _blinkCounter = 0;
276 _idleCounterMax = 8;
277 _blinkCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
278 }
279
upSitIdleTeleporter()280 void Klaymen::upSitIdleTeleporter() {
281 update();
282 if (++_idleCounter >= _idleCounterMax) {
283 _idleCounter = 0;
284 if (_idleTable) {
285 int idleWeight = _vm->_rnd->getRandomNumber(_idleTableTotalWeight - 1);
286 for (uint i = 0; i < _idleTableCount; i++) {
287 if (idleWeight < _idleTable[i].weight) {
288 enterIdleAnimation(_idleTable[i].idleAnimation);
289 _idleCounterMax = _vm->_rnd->getRandomNumber(128 - 1) + 24;
290 break;
291 }
292 idleWeight -= _idleTable[i].weight;
293 }
294 }
295 } else if (++_blinkCounter >= _blinkCounterMax) {
296 _blinkCounter = 0;
297 _blinkCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
298 stSitIdleTeleporterBlink();
299 }
300 }
301
stSitIdleTeleporterBlink()302 void Klaymen::stSitIdleTeleporterBlink() {
303 _busyStatus = 0;
304 _acceptInput = true;
305 startAnimation(0x5C24C018, 0, -1);
306 SetUpdateHandler(&Klaymen::update);
307 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
308 SetSpriteUpdate(NULL);
309 NextState(&Klaymen::stSitIdleTeleporterBlinkSecond);
310 }
311
stSitIdleTeleporterBlinkSecond()312 void Klaymen::stSitIdleTeleporterBlinkSecond() {
313 _busyStatus = 0;
314 _acceptInput = true;
315 startAnimation(0x582EC138, 0, -1);
316 SetUpdateHandler(&Klaymen::upSitIdleTeleporter);
317 SetMessageHandler(&Klaymen::hmLowLevel);
318 SetSpriteUpdate(NULL);
319 }
320
stPickUpNeedle()321 void Klaymen::stPickUpNeedle() {
322 setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
323 if (!stStartAction(AnimationCallback(&Klaymen::stPickUpNeedle))) {
324 _busyStatus = 1;
325 _acceptInput = false;
326 startAnimation(0x1449C169, 0, -1);
327 SetUpdateHandler(&Klaymen::update);
328 SetMessageHandler(&Klaymen::hmPickUpObject);
329 SetSpriteUpdate(NULL);
330 }
331 }
332
stPickUpTube()333 void Klaymen::stPickUpTube() {
334 setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
335 if (!stStartAction(AnimationCallback(&Klaymen::stPickUpTube))) {
336 _busyStatus = 1;
337 _acceptInput = false;
338 startAnimation(0x0018C032, 0, -1);
339 SetUpdateHandler(&Klaymen::update);
340 SetMessageHandler(&Klaymen::hmPickUpTube);
341 SetSpriteUpdate(NULL);
342 }
343 }
344
hmPickUpTube(int messageNum,const MessageParam & param,Entity * sender)345 uint32 Klaymen::hmPickUpTube(int messageNum, const MessageParam ¶m, Entity *sender) {
346 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
347 switch (messageNum) {
348 case NM_ANIMATION_START:
349 if (param.asInteger() == 0xC1380080) {
350 sendMessage(_attachedSprite, NM_KLAYMEN_USE_OBJECT, 0);
351 playSound(0, 0xC8004340);
352 } else if (param.asInteger() == 0x02B20220) {
353 playSound(0, 0xC5408620);
354 } else if (param.asInteger() == 0x03020231) {
355 playSound(0, 0xD4C08010);
356 } else if (param.asInteger() == 0x67221A03) {
357 playSound(0, 0x44051000);
358 } else if (param.asInteger() == 0x925A0C1E) {
359 playSound(0, 0x40E5884D);
360 }
361 break;
362 default:
363 break;
364 }
365 return messageResult;
366 }
367
stTurnToUseInTeleporter()368 void Klaymen::stTurnToUseInTeleporter() {
369 _busyStatus = 0;
370 _acceptInput = false;
371 startAnimation(0xD229823D, 0, -1);
372 SetUpdateHandler(&Klaymen::update);
373 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
374 SetSpriteUpdate(NULL);
375 }
376
stReturnFromUseInTeleporter()377 void Klaymen::stReturnFromUseInTeleporter() {
378 _busyStatus = 0;
379 _acceptInput = false;
380 startAnimation(0x9A2801E0, 0, -1);
381 SetUpdateHandler(&Klaymen::update);
382 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
383 SetSpriteUpdate(NULL);
384 }
385
stStepOver()386 void Klaymen::stStepOver() {
387 if (!stStartAction(AnimationCallback(&Klaymen::stStepOver))) {
388 _busyStatus = 2;
389 _acceptInput = false;
390 startAnimation(0x004AA310, 0, -1);
391 SetUpdateHandler(&Klaymen::update);
392 SetMessageHandler(&Klaymen::hmStartWalking);
393 SetSpriteUpdate(&Klaymen::suUpdateDestX);
394 }
395 }
396
stSitInTeleporter()397 void Klaymen::stSitInTeleporter() {
398 if (!stStartAction(AnimationCallback(&Klaymen::stSitInTeleporter))) {
399 _busyStatus = 0;
400 _acceptInput = false;
401 startAnimation(0x392A0330, 0, -1);
402 SetUpdateHandler(&Klaymen::update);
403 SetMessageHandler(&Klaymen::hmSitInTeleporter);
404 SetSpriteUpdate(&Klaymen::suUpdateDestX);
405 }
406 }
407
hmSitInTeleporter(int messageNum,const MessageParam & param,Entity * sender)408 uint32 Klaymen::hmSitInTeleporter(int messageNum, const MessageParam ¶m, Entity *sender) {
409 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
410 switch (messageNum) {
411 case NM_ANIMATION_START:
412 if (param.asInteger() == 0x001A2832) {
413 playSound(0, 0xC0E4884C);
414 }
415 break;
416 default:
417 break;
418 }
419 return messageResult;
420 }
421
stGetUpFromTeleporter()422 void Klaymen::stGetUpFromTeleporter() {
423 _busyStatus = 0;
424 _acceptInput = false;
425 startAnimation(0x913AB120, 0, -1);
426 SetUpdateHandler(&Klaymen::update);
427 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
428 SetSpriteUpdate(&Klaymen::suUpdateDestX);
429 }
430
431 /////////////////////////////////////////////////////////////////
432
stopWalking()433 void Klaymen::stopWalking() {
434 _destX = _x;
435 if (!_isWalking && !_isSneaking && !_isLargeStep) {
436 gotoState(NULL);
437 gotoNextStateExt();
438 }
439 }
440
startIdleAnimation(uint32 fileHash,AnimationCb callback)441 void Klaymen::startIdleAnimation(uint32 fileHash, AnimationCb callback) {
442 debug(1, "startIdleAnimation(%08X)", fileHash);
443 NextState(callback);
444 SetUpdateHandler(&Klaymen::upIdleAnimation);
445 }
446
upIdleAnimation()447 void Klaymen::upIdleAnimation() {
448 gotoNextStateExt();
449 update();
450 }
451
stStartActionFromIdle(AnimationCb callback)452 bool Klaymen::stStartActionFromIdle(AnimationCb callback) {
453 if (_busyStatus == 2) {
454 _busyStatus = 1;
455 _acceptInput = false;
456 startAnimation(0x9A7020B8, 0, -1);
457 SetUpdateHandler(&Klaymen::update);
458 SetMessageHandler(&Klaymen::hmStartAction);
459 SetSpriteUpdate(NULL);
460 NextState(callback);
461 return true;
462 }
463 return false;
464 }
465
gotoNextStateExt()466 void Klaymen::gotoNextStateExt() {
467 if (_finalizeStateCb) {
468 AnimationCb cb = _finalizeStateCb;
469 _finalizeStateCb = NULL;
470 (this->*cb)();
471 }
472 if (_nextStateCb) {
473 AnimationCb cb = _nextStateCb;
474 _nextStateCb = NULL;
475 (this->*cb)();
476 } else {
477 // Inform the scene that the current Klaymen animation sequence has finished
478 sendMessage(_parentScene, 0x1006, 0);
479 }
480 }
481
beginAction()482 void Klaymen::beginAction() {
483 _actionStatusChanged = false;
484 _actionStatus = 1;
485 }
486
endAction()487 void Klaymen::endAction() {
488 if (_actionStatusChanged)
489 _actionStatus = 0;
490 }
491
stTryStandIdle()492 void Klaymen::stTryStandIdle() {
493 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stTryStandIdle))) {
494 _busyStatus = 1;
495 _acceptInput = true;
496 startAnimation(0x5420E254, 0, -1);
497 SetUpdateHandler(&Klaymen::upStandIdle);
498 SetMessageHandler(&Klaymen::hmLowLevel);
499 SetSpriteUpdate(NULL);
500 _idleCounter = 0;
501 _blinkCounter = 0;
502 _blinkCounterMax = _vm->_rnd->getRandomNumber(64) + 24;
503 }
504 }
505
upStandIdle()506 void Klaymen::upStandIdle() {
507 update();
508 if (++_idleCounter >= 720) {
509 _idleCounter = 0;
510 if (_idleTable) {
511 int idleWeight = _vm->_rnd->getRandomNumber(_idleTableTotalWeight - 1);
512 for (uint i = 0; i < _idleTableCount; i++) {
513 if (idleWeight < _idleTable[i].weight) {
514 enterIdleAnimation(_idleTable[i].idleAnimation);
515 break;
516 }
517 idleWeight -= _idleTable[i].weight;
518 }
519 }
520 } else if (++_blinkCounter >= _blinkCounterMax) {
521 _blinkCounter = 0;
522 _blinkCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
523 stIdleBlink();
524 }
525 }
526
hmLowLevel(int messageNum,const MessageParam & param,Entity * sender)527 uint32 Klaymen::hmLowLevel(int messageNum, const MessageParam ¶m, Entity *sender) {
528 Sprite::handleMessage(messageNum, param, sender);
529 uint32 messageResult = xHandleMessage(messageNum, param);
530 switch (messageNum) {
531 case 0x1008:
532 messageResult = _acceptInput;
533 break;
534 case 0x1014:
535 _attachedSprite = (Sprite*)(param.asEntity());
536 break;
537 case NM_SCENE_LEAVE:
538 gotoNextStateExt();
539 break;
540 case 0x101C:
541 beginAction();
542 break;
543 case 0x1021:
544 endAction();
545 break;
546 case 0x481C:
547 _actionStatus = param.asInteger();
548 _actionStatusChanged = true;
549 messageResult = 1;
550 break;
551 case 0x482C:
552 if (param.asInteger() != 0) {
553 _pathPoints = _dataResource.getPointArray(param.asInteger());
554 } else {
555 _pathPoints = NULL;
556 }
557 break;
558 default:
559 break;
560 }
561 return messageResult;
562 }
563
stIdleBlink()564 void Klaymen::stIdleBlink() {
565 _busyStatus = 1;
566 _acceptInput = true;
567 startAnimation(0x5900C41E, 0, -1);
568 SetUpdateHandler(&Klaymen::update);
569 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
570 SetSpriteUpdate(NULL);
571 NextState(&Klaymen::stStandAround);
572 }
573
hmLowLevelAnimation(int messageNum,const MessageParam & param,Entity * sender)574 uint32 Klaymen::hmLowLevelAnimation(int messageNum, const MessageParam ¶m, Entity *sender) {
575 uint32 messageResult = hmLowLevel(messageNum, param, sender);
576 switch (messageNum) {
577 case NM_ANIMATION_STOP:
578 gotoNextStateExt();
579 break;
580 default:
581 break;
582 }
583 return messageResult;
584 }
585
stStandAround()586 void Klaymen::stStandAround() {
587 _busyStatus = 1;
588 _acceptInput = true;
589 startAnimation(0x5420E254, 0, -1);
590 SetUpdateHandler(&Klaymen::upStandIdle);
591 SetMessageHandler(&Klaymen::hmLowLevel);
592 SetSpriteUpdate(NULL);
593 }
594
hmStartAction(int messageNum,const MessageParam & param,Entity * sender)595 uint32 Klaymen::hmStartAction(int messageNum, const MessageParam ¶m, Entity *sender) {
596 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
597 switch (messageNum) {
598 case NM_ANIMATION_START:
599 if (param.asInteger() == 0x271AA210) {
600 playSound(0, 0x4924AAC4);
601 } else if (param.asInteger() == 0x2B22AA81) {
602 playSound(0, 0x0A2AA8E0);
603 }
604 break;
605 default:
606 break;
607 }
608 return messageResult;
609 }
610
611
startWalkToX(int16 x,bool walkExt)612 void Klaymen::startWalkToX(int16 x, bool walkExt) {
613 int16 xdiff = ABS(x - _x);
614 if (x == _x) {
615 _destX = x;
616 if (!_isWalking && !_isSneaking && !_isLargeStep) {
617 gotoState(NULL);
618 gotoNextStateExt();
619 }
620 } else if (xdiff <= 36 && !_isWalking && !_isSneaking && !_isLargeStep) {
621 _destX = x;
622 gotoState(NULL);
623 gotoNextStateExt();
624 } else if (xdiff <= 42 && _actionStatus != 3) {
625 if (_isSneaking && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0)) && ABS(_destX - _x) > xdiff) {
626 _destX = x;
627 } else {
628 _destX = x;
629 GotoState(&Klaymen::stSneak);
630 }
631 } else if (_isWalking && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0))) {
632 _destX = x;
633 } else if (walkExt) {
634 _destX = x;
635 GotoState(&Klaymen::stStartWalkingExt);
636 } else {
637 _destX = x;
638 GotoState(&Klaymen::stStartWalking);
639 }
640 }
641
stStartAction(AnimationCb callback3)642 bool Klaymen::stStartAction(AnimationCb callback3) {
643 if (_busyStatus == 1) {
644 _busyStatus = 2;
645 _acceptInput = false;
646 startAnimation(0x5C7080D4, 0, -1);
647 SetUpdateHandler(&Klaymen::update);
648 SetMessageHandler(&Klaymen::hmStartAction);
649 SetSpriteUpdate(&Klaymen::suAction);
650 NextState(callback3);
651 return true;
652 } else {
653 _x = _destX;
654 return false;
655 }
656 }
657
suAction()658 void Klaymen::suAction() {
659
660 int16 xdiff = _destX - _x;
661
662 if (_doDeltaX) {
663 _x -= _deltaX;
664 } else {
665 _x += _deltaX;
666 }
667 _deltaX = 0;
668
669 if (_doDeltaY) {
670 _y -= _deltaY;
671 } else {
672 _y += _deltaY;
673 }
674 _deltaY = 0;
675
676 if (_frameChanged) {
677 if (xdiff > 6)
678 _x += 6;
679 else if (xdiff < -6)
680 _x -= 6;
681 else
682 _x = _destX;
683 }
684
685 updateBounds();
686
687 }
688
suSneaking()689 void Klaymen::suSneaking() {
690
691 int16 xdiff = _destX - _x;
692
693 if (_currFrameIndex == 9) {
694 if (xdiff > 26)
695 _deltaX += xdiff - 26;
696 else if (xdiff < -26)
697 _deltaX -= xdiff + 26;
698 }
699
700 if (xdiff > _deltaX)
701 xdiff = _deltaX;
702 else if (xdiff < -_deltaX)
703 xdiff = -_deltaX;
704 _deltaX = 0;
705
706 if (_destX != _x) {
707 HitRect *hitRectPrev = _parentScene->findHitRectAtPos(_x, _y);
708 _x += xdiff;
709 if (_pathPoints) {
710 walkAlongPathPoints();
711 } else {
712 HitRect *hitRectNext = _parentScene->findHitRectAtPos(_x, _y);
713 if (hitRectNext->type == 0x5002) {
714 _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (hitRectNext->rect.x2 - _x) / 2);
715 } else if (hitRectNext->type == 0x5003) {
716 _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (_x - hitRectNext->rect.x1) / 2);
717 } else if (hitRectPrev->type == 0x5002) {
718 if (xdiff > 0) {
719 _y = hitRectPrev->rect.y2;
720 } else {
721 _y = hitRectPrev->rect.y1;
722 }
723 } else if (hitRectPrev->type == 0x5003) {
724 if (xdiff < 0) {
725 _y = hitRectPrev->rect.y2;
726 } else {
727 _y = hitRectPrev->rect.y1;
728 }
729 }
730 }
731 updateBounds();
732 }
733
734 }
735
stSneak()736 void Klaymen::stSneak() {
737 _busyStatus = 1;
738 _isSneaking = true;
739 _acceptInput = true;
740 setDoDeltaX(_destX < _x ? 1 : 0);
741 startAnimation(0x5C48C506, 0, -1);
742 SetUpdateHandler(&Klaymen::update);
743 SetMessageHandler(&Klaymen::hmSneaking);
744 SetSpriteUpdate(&Klaymen::suSneaking);
745 FinalizeState(&Klaymen::evSneakingDone);
746 }
747
evSneakingDone()748 void Klaymen::evSneakingDone() {
749 _isSneaking = false;
750 }
751
hmSneaking(int messageNum,const MessageParam & param,Entity * sender)752 uint32 Klaymen::hmSneaking(int messageNum, const MessageParam ¶m, Entity *sender) {
753 uint32 messageResult = hmLowLevel(messageNum, param, sender);
754 switch (messageNum) {
755 case NM_ANIMATION_START:
756 if (param.asInteger() == 0x32180101) {
757 playSound(0, 0x4924AAC4);
758 } else if (param.asInteger() == 0x0A2A9098) {
759 playSound(0, 0x0A2AA8E0);
760 } else if (param.asInteger() == 0x32188010) {
761 playSound(0, _soundFlag ? 0x48498E46 : 0x405002D8);
762 } else if (param.asInteger() == 0x02A2909C) {
763 playSound(0, _soundFlag ? 0x50399F64 : 0x0460E2FA);
764 }
765 break;
766 case NM_ANIMATION_STOP:
767 _x = _destX;
768 gotoNextStateExt();
769 break;
770 default:
771 break;
772 }
773 return messageResult;
774 }
775
stStartWalking()776 void Klaymen::stStartWalking() {
777 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stStartWalking))) {
778 _busyStatus = 0;
779 _isWalking = true;
780 _acceptInput = true;
781 setDoDeltaX(_destX < _x ? 1 : 0);
782 startAnimation(0x242C0198, 0, -1);
783 SetUpdateHandler(&Klaymen::update);
784 SetMessageHandler(&Klaymen::hmStartWalking);
785 SetSpriteUpdate(&Klaymen::suWalkingTestExit);
786 NextState(&Klaymen::stWalkingFirst);
787 FinalizeState(&Klaymen::evStartWalkingDone);
788 }
789 }
790
evStartWalkingDone()791 void Klaymen::evStartWalkingDone() {
792 _isWalking = false;
793 }
794
hmStartWalking(int messageNum,const MessageParam & param,Entity * sender)795 uint32 Klaymen::hmStartWalking(int messageNum, const MessageParam ¶m, Entity *sender) {
796 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
797 switch (messageNum) {
798 case NM_ANIMATION_START:
799 if (param.asInteger() == 0x32180101) {
800 playSound(0, _soundFlag ? 0x48498E46 : 0x405002D8);
801 } else if (param.asInteger() == 0x0A2A9098) {
802 playSound(0, _soundFlag ? 0x50399F64 : 0x0460E2FA);
803 }
804 break;
805 default:
806 break;
807 }
808 return messageResult;
809 }
810
stWalkingFirst()811 void Klaymen::stWalkingFirst() {
812 _busyStatus = 0;
813 _isWalking = true;
814 _acceptInput = true;
815 startAnimation(0x1A249001, 0, -1);
816 SetUpdateHandler(&Klaymen::update);
817 SetMessageHandler(&Klaymen::hmWalking);
818 SetSpriteUpdate(&Klaymen::suWalkingFirst);
819 NextState(&Klaymen::stUpdateWalkingFirst);
820 FinalizeState(&Klaymen::evStartWalkingDone);
821 }
822
suWalkingFirst()823 void Klaymen::suWalkingFirst() {
824 SetSpriteUpdate(&Klaymen::suWalkingTestExit);
825 _deltaX = 0;
826 }
827
hmWalking(int messageNum,const MessageParam & param,Entity * sender)828 uint32 Klaymen::hmWalking(int messageNum, const MessageParam ¶m, Entity *sender) {
829 uint32 messageResult = hmLowLevel(messageNum, param, sender);
830 switch (messageNum) {
831 case NM_ANIMATION_START:
832 if (param.asInteger() == 0x32180101) {
833 playSound(0, _soundFlag ? 0x48498E46 : 0x405002D8);
834 } else if (param.asInteger() == 0x0A2A9098) {
835 playSound(0, _soundFlag ? 0x50399F64 : 0x0460E2FA);
836 }
837 break;
838 default:
839 break;
840 }
841 return messageResult;
842 }
843
stUpdateWalkingFirst()844 void Klaymen::stUpdateWalkingFirst() {
845 if (_actionStatus == 2) {
846 gotoNextStateExt();
847 } else if (_actionStatus == 3) {
848 stWalkingOpenDoor();
849 } else {
850 _isSneaking = true;
851 _acceptInput = true;
852 if (ABS(_destX - _x) <= 42 && _currFrameIndex >= 5 && _currFrameIndex <= 11) {
853 if (_actionStatus == 0) {
854 _busyStatus = 1;
855 startAnimation(0xF234EE31, 0, -1);
856 } else {
857 _busyStatus = 2;
858 startAnimation(0xF135CC21, 0, -1);
859 }
860 } else if (ABS(_destX - _x) <= 10 && (_currFrameIndex >= 12 || _currFrameIndex <= 4)) {
861 if (_actionStatus == 0) {
862 _busyStatus = 1;
863 startAnimation(0x8604A152, 0, -1);
864 } else {
865 _busyStatus = 2;
866 startAnimation(0xA246A132, 0, -1);
867 }
868 }
869 SetUpdateHandler(&Klaymen::update);
870 SetMessageHandler(&Klaymen::hmSneaking);
871 SetSpriteUpdate(&Klaymen::suSneaking);
872 FinalizeState(&Klaymen::evSneakingDone);
873 }
874 }
875
suWalkingTestExit()876 void Klaymen::suWalkingTestExit() {
877 int16 xdiff = ABS(_destX - _x);
878 int16 xdelta = _destX - _x;
879
880 if (xdelta > _deltaX)
881 xdelta = _deltaX;
882 else if (xdelta < -_deltaX)
883 xdelta = -_deltaX;
884
885 _deltaX = 0;
886
887 if (xdiff == 0 ||
888 (_actionStatus != 2 && _actionStatus != 3 && xdiff <= 42 && _currFrameIndex >= 5 && _currFrameIndex <= 11) ||
889 (_actionStatus != 2 && _actionStatus != 3 && xdiff <= 10 && (_currFrameIndex >= 12 || _currFrameIndex <= 4)) ||
890 (_actionStatus == 3 && xdiff < 30) ||
891 (_actionStatus == 3 && xdiff < 150 && _currFrameIndex >= 6)) {
892 sendMessage(this, NM_SCENE_LEAVE, 0);
893 } else {
894 HitRect *hitRectPrev = _parentScene->findHitRectAtPos(_x, _y);
895 _x += xdelta;
896 if (_pathPoints) {
897 walkAlongPathPoints();
898 } else {
899 HitRect *hitRectNext = _parentScene->findHitRectAtPos(_x, _y);
900 if (hitRectNext->type == 0x5002) {
901 _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (hitRectNext->rect.x2 - _x) / 2);
902 } else if (hitRectNext->type == 0x5003) {
903 _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (_x - hitRectNext->rect.x1) / 2);
904 } else if (hitRectPrev->type == 0x5002) {
905 _y = xdelta > 0 ? hitRectPrev->rect.y2 : hitRectPrev->rect.y1;
906 } else if (hitRectPrev->type == 0x5003) {
907 _y = xdelta < 0 ? hitRectPrev->rect.y2 : hitRectPrev->rect.y1;
908 } else if (_doYHitIncr && xdelta != 0) {
909 if (hitRectNext->type == 0x5000) {
910 _y++;
911 } else if (hitRectNext->type == 0x5001 && _y > hitRectNext->rect.y1) {
912 _y--;
913 }
914 }
915 }
916 updateBounds();
917 }
918
919 }
920
hmLever(int messageNum,const MessageParam & param,Entity * sender)921 uint32 Klaymen::hmLever(int messageNum, const MessageParam ¶m, Entity *sender) {
922 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
923 switch (messageNum) {
924 case NM_ANIMATION_START:
925 if (param.asInteger() == 0x4AB28209) {
926 sendMessage(_attachedSprite, NM_MOVE_TO_BACK, 0);
927 } else if (param.asInteger() == 0x88001184) {
928 sendMessage(_attachedSprite, NM_MOVE_TO_FRONT, 0);
929 }
930 break;
931 default:
932 break;
933 }
934 return messageResult;
935 }
936
stPickUpGeneric()937 void Klaymen::stPickUpGeneric() {
938 setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
939 if (!stStartAction(AnimationCallback(&Klaymen::stPickUpGeneric))) {
940 _busyStatus = 1;
941 _acceptInput = false;
942 startAnimation(0x1C28C178, 0, -1);
943 SetUpdateHandler(&Klaymen::update);
944 SetMessageHandler(&Klaymen::hmPickUpObject);
945 SetSpriteUpdate(NULL);
946 }
947 }
948
hmPickUpObject(int messageNum,const MessageParam & param,Entity * sender)949 uint32 Klaymen::hmPickUpObject(int messageNum, const MessageParam ¶m, Entity *sender) {
950 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
951 switch (messageNum) {
952 case NM_ANIMATION_START:
953 if (param.asInteger() == 0xC1380080) {
954 sendMessage(_attachedSprite, NM_KLAYMEN_USE_OBJECT, 0);
955 playSound(0, 0x40208200);
956 } else if (param.asInteger() == 0x02B20220) {
957 playSound(0, 0xC5408620);
958 } else if (param.asInteger() == 0x03020231) {
959 playSound(0, 0xD4C08010);
960 } else if (param.asInteger() == 0x67221A03) {
961 playSound(0, 0x44051000);
962 } else if (param.asInteger() == 0x2EAE0303) {
963 playSound(0, 0x03630300);
964 } else if (param.asInteger() == 0x61CE4467) {
965 playSound(0, 0x03630300);
966 }
967 break;
968 default:
969 break;
970 }
971 return messageResult;
972
973 }
974
stPressButton()975 void Klaymen::stPressButton() {
976 if (!stStartAction(AnimationCallback(&Klaymen::stPressButton))) {
977 _busyStatus = 2;
978 _acceptInput = true;
979 startAnimation(0x1C02B03D, 0, -1);
980 SetUpdateHandler(&Klaymen::update);
981 SetMessageHandler(&Klaymen::hmPressButton);
982 SetSpriteUpdate(NULL);
983 }
984 }
985
hmPressButton(int messageNum,const MessageParam & param,Entity * sender)986 uint32 Klaymen::hmPressButton(int messageNum, const MessageParam ¶m, Entity *sender) {
987 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
988 switch (messageNum) {
989 case NM_ANIMATION_START:
990 if (param.asInteger() == 0x0D01B294) {
991 sendMessage(_attachedSprite, 0x480B, 0);
992 } else if (param.asInteger() == 0x32180101) {
993 playSound(0, 0x4924AAC4);
994 } else if (param.asInteger() == 0x0A2A9098) {
995 playSound(0, 0x0A2AA8E0);
996 }
997 break;
998 default:
999 break;
1000 }
1001 return messageResult;
1002 }
1003
stPressFloorButton()1004 void Klaymen::stPressFloorButton() {
1005 if (!stStartAction(AnimationCallback(&Klaymen::stPressFloorButton))) {
1006 _busyStatus = 2;
1007 _acceptInput = true;
1008 startAnimation(0x1C16B033, 0, -1);
1009 SetUpdateHandler(&Klaymen::update);
1010 SetMessageHandler(&Klaymen::hmPressButton);
1011 SetSpriteUpdate(NULL);
1012 }
1013 }
1014
stPressButtonSide()1015 void Klaymen::stPressButtonSide() {
1016 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stPressButtonSide))) {
1017 _busyStatus = 1;
1018 _acceptInput = true;
1019 startAnimation(0x1CD89029, 0, -1);
1020 SetUpdateHandler(&Klaymen::update);
1021 SetMessageHandler(&Klaymen::hmPressButton);
1022 SetSpriteUpdate(&Klaymen::suAction);
1023 }
1024 }
1025
startSpecialWalkRight(int16 x)1026 void Klaymen::startSpecialWalkRight(int16 x) {
1027 if (_x == x) {
1028 _destX = x;
1029 gotoState(NULL);
1030 gotoNextStateExt();
1031 } else if (_x < x) {
1032 startWalkToX(x, false);
1033 } else if (_x - x <= 105) {
1034 startWalkToXExt(x);
1035 } else {
1036 startWalkToX(x, false);
1037 }
1038 }
1039
startSpecialWalkLeft(int16 x)1040 void Klaymen::startSpecialWalkLeft(int16 x) {
1041 if (x == _x) {
1042 _destX = x;
1043 gotoState(NULL);
1044 gotoNextStateExt();
1045 } else if (x < _x) {
1046 startWalkToX(x, false);
1047 } else if (x - _x <= 105) {
1048 startWalkToXExt(x);
1049 } else {
1050 startWalkToX(x, false);
1051 }
1052 }
1053
startWalkToXSmall(int16 x)1054 void Klaymen::startWalkToXSmall(int16 x) {
1055 _actionStatus = 2;
1056 if (_x == x) {
1057 _destX = x;
1058 if (_isWalking) {
1059 GotoState(NULL);
1060 gotoNextStateExt();
1061 }
1062 } else if (_isWalking && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0))) {
1063 _destX = x;
1064 } else {
1065 _destX = x;
1066 GotoState(&Klaymen::stStartWalkingSmall);
1067 }
1068 }
1069
stStartWalkingSmall()1070 void Klaymen::stStartWalkingSmall() {
1071 _isWalking = true;
1072 _acceptInput = true;
1073 _actionStatus = 2;
1074 setDoDeltaX(_destX < _x ? 1 : 0);
1075 startAnimation(0x3A4CD934, 0, -1);
1076 SetUpdateHandler(&Klaymen::update);
1077 SetMessageHandler(&Klaymen::hmWalkingSmall);
1078 SetSpriteUpdate(&Klaymen::suWalkingTestExit);
1079 FinalizeState(&Klaymen::evStartWalkingDone);
1080 }
1081
hmWalkingSmall(int messageNum,const MessageParam & param,Entity * sender)1082 uint32 Klaymen::hmWalkingSmall(int messageNum, const MessageParam ¶m, Entity *sender) {
1083 uint32 messageResult = hmLowLevel(messageNum, param, sender);
1084 switch (messageNum) {
1085 case NM_ANIMATION_START:
1086 if (param.asInteger() == 0x32180101)
1087 playSound(0, 0x4924AAC4);
1088 else if (param.asInteger() == 0x0A2A9098)
1089 playSound(0, 0x0A2AA8E0);
1090 break;
1091 default:
1092 break;
1093 }
1094 return messageResult;
1095 }
1096
stStandIdleSmall()1097 void Klaymen::stStandIdleSmall() {
1098 _busyStatus = 0;
1099 _acceptInput = true;
1100 startAnimation(0x90D0D1D0, 0, -1);
1101 SetUpdateHandler(&Klaymen::update);
1102 SetMessageHandler(&Klaymen::hmLowLevel);
1103 SetSpriteUpdate(NULL);
1104 }
1105
stWonderAboutAfterSmall()1106 void Klaymen::stWonderAboutAfterSmall() {
1107 _busyStatus = 0;
1108 _acceptInput = true;
1109 startAnimation(0x11C8D156, 30, -1);
1110 SetUpdateHandler(&Klaymen::update);
1111 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1112 SetSpriteUpdate(NULL);
1113 }
1114
stWonderAboutHalfSmall()1115 void Klaymen::stWonderAboutHalfSmall() {
1116 _busyStatus = 0;
1117 _acceptInput = true;
1118 startAnimation(0x11C8D156, 0, 10);
1119 SetUpdateHandler(&Klaymen::update);
1120 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1121 SetSpriteUpdate(NULL);
1122 }
1123
stWonderAboutSmall()1124 void Klaymen::stWonderAboutSmall() {
1125 _busyStatus = 0;
1126 _acceptInput = true;
1127 startAnimation(0x11C8D156, 0, -1);
1128 SetUpdateHandler(&Klaymen::update);
1129 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1130 SetSpriteUpdate(NULL);
1131 }
1132
stWalkToFrontNoStepSmall()1133 void Klaymen::stWalkToFrontNoStepSmall() {
1134 _busyStatus = 0;
1135 _acceptInput = false;
1136 startAnimationByHash(0x3F9CC394, 0x14884392, 0);
1137 SetUpdateHandler(&Klaymen::update);
1138 SetMessageHandler(&Klaymen::hmWalkFrontBackSmall);
1139 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1140 }
1141
hmWalkFrontBackSmall(int messageNum,const MessageParam & param,Entity * sender)1142 uint32 Klaymen::hmWalkFrontBackSmall(int messageNum, const MessageParam ¶m, Entity *sender) {
1143 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1144 switch (messageNum) {
1145 case NM_ANIMATION_START:
1146 if (param.asInteger() == 0x80C110B5)
1147 sendMessage(_parentScene, NM_MOVE_TO_BACK, 0);
1148 else if (param.asInteger() == 0x110010D1)
1149 sendMessage(_parentScene, NM_MOVE_TO_FRONT, 0);
1150 else if (param.asInteger() == 0x32180101)
1151 playSound(0, 0x4924AAC4);
1152 else if (param.asInteger() == 0x0A2A9098)
1153 playSound(0, 0x0A2AA8E0);
1154 break;
1155 default:
1156 break;
1157 }
1158 return messageResult;
1159 }
1160
stWalkToFront2Small()1161 void Klaymen::stWalkToFront2Small() {
1162 _busyStatus = 0;
1163 _acceptInput = false;
1164 startAnimation(0x2F1C4694, 0, -1);
1165 SetUpdateHandler(&Klaymen::update);
1166 SetMessageHandler(&Klaymen::hmWalkFrontBackSmall);
1167 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1168 }
1169
stWalkToFrontSmall()1170 void Klaymen::stWalkToFrontSmall() {
1171 _busyStatus = 0;
1172 _acceptInput = false;
1173 startAnimation(0x3F9CC394, 0, -1);
1174 SetUpdateHandler(&Klaymen::update);
1175 SetMessageHandler(&Klaymen::hmWalkFrontBackSmall);
1176 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1177 }
1178
stTurnToBackHalfSmall()1179 void Klaymen::stTurnToBackHalfSmall() {
1180 _busyStatus = 0;
1181 _acceptInput = false;
1182 startAnimationByHash(0x37ECD436, 0, 0x8520108C);
1183 SetUpdateHandler(&Klaymen::update);
1184 SetMessageHandler(&Klaymen::hmWalkFrontBackSmall);
1185 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1186 }
1187
stTurnToBackWalkSmall()1188 void Klaymen::stTurnToBackWalkSmall() {
1189 _busyStatus = 0;
1190 _acceptInput = false;
1191 startAnimation(0x16EDDE36, 0, -1);
1192 SetUpdateHandler(&Klaymen::update);
1193 SetMessageHandler(&Klaymen::hmWalkFrontBackSmall);
1194 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1195 }
1196
stTurnToBackSmall()1197 void Klaymen::stTurnToBackSmall() {
1198 _busyStatus = 0;
1199 _acceptInput = false;
1200 startAnimation(0x37ECD436, 0, -1);
1201 SetUpdateHandler(&Klaymen::update);
1202 SetMessageHandler(&Klaymen::hmWalkFrontBackSmall);
1203 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1204 }
1205
stPullCord()1206 void Klaymen::stPullCord() {
1207 if (!stStartAction(AnimationCallback(&Klaymen::stPullCord))) {
1208 _busyStatus = 2;
1209 _acceptInput = false;
1210 startAnimation(0x3F28E094, 0, -1);
1211 SetUpdateHandler(&Klaymen::update);
1212 SetMessageHandler(&Klaymen::hmPullReleaseCord);
1213 SetSpriteUpdate(NULL);
1214 NextState(&Klaymen::stReleaseCord);
1215 }
1216 }
1217
stReleaseCord()1218 void Klaymen::stReleaseCord() {
1219 _acceptInput = false;
1220 startAnimation(0x3A28C094, 0, -1);
1221 SetUpdateHandler(&Klaymen::update);
1222 SetMessageHandler(&Klaymen::hmPullReleaseCord);
1223 SetSpriteUpdate(NULL);
1224 }
1225
hmPullReleaseCord(int messageNum,const MessageParam & param,Entity * sender)1226 uint32 Klaymen::hmPullReleaseCord(int messageNum, const MessageParam ¶m, Entity *sender) {
1227 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1228 switch (messageNum) {
1229 case NM_ANIMATION_START:
1230 if (param.asInteger() == 0x4AB28209) {
1231 sendMessage(_attachedSprite, NM_MOVE_TO_BACK, 0);
1232 sendMessage(_attachedSprite, NM_KLAYMEN_LOWER_LEVER, 0);
1233 } else if (param.asInteger() == 0x88001184) {
1234 sendMessage(_attachedSprite, NM_MOVE_TO_FRONT, 0);
1235 }
1236 break;
1237 default:
1238 break;
1239 }
1240 return messageResult;
1241 }
1242
stUseTube()1243 void Klaymen::stUseTube() {
1244 if (!stStartAction(AnimationCallback(&Klaymen::stUseTube))) {
1245 _busyStatus = 1;
1246 _acceptInput = false;
1247 startAnimation(0x1A38A814, 0, -1);
1248 SetUpdateHandler(&Klaymen::update);
1249 SetMessageHandler(&Klaymen::hmUseTube);
1250 SetSpriteUpdate(NULL);
1251 }
1252 }
1253
hmUseTube(int messageNum,const MessageParam & param,Entity * sender)1254 uint32 Klaymen::hmUseTube(int messageNum, const MessageParam ¶m, Entity *sender) {
1255 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1256 switch (messageNum) {
1257 case NM_ANIMATION_START:
1258 if (param.asInteger() == 0x02B20220)
1259 playSound(0, 0xC5408620);
1260 else if (param.asInteger() == 0x0A720138)
1261 playSound(0, 0xD4C08010);
1262 else if (param.asInteger() == 0x03020231)
1263 playSound(0, 0xD4C08010);
1264 else if (param.asInteger() == 0xB613A180)
1265 playSound(0, 0x44051000);
1266 else if (param.asInteger() == 0x67221A03)
1267 playSound(0, 0x44051000);
1268 else if (param.asInteger() == 0x038A010B)
1269 playSound(0, 0x00018040);
1270 else if (param.asInteger() == 0x422B0280)
1271 playSound(0, 0x166FC6E0);
1272 else if (param.asInteger() == 0x925A0C1E)
1273 playSound(0, 0x40E5884D);
1274 break;
1275 default:
1276 break;
1277 }
1278 return messageResult;
1279 }
1280
stWalkingFirstExt()1281 void Klaymen::stWalkingFirstExt() {
1282 _busyStatus = 0;
1283 _isWalking = true;
1284 _acceptInput = true;
1285 startAnimation(0x5A2CBC00, 0, -1);
1286 SetUpdateHandler(&Klaymen::update);
1287 SetMessageHandler(&Klaymen::hmWalking);
1288 SetSpriteUpdate(&Klaymen::suWalkingFirst);
1289 NextState(&Klaymen::stUpdateWalkingFirst);
1290 FinalizeState(&Klaymen::evStartWalkingDone);
1291 }
1292
stStartWalkingExt()1293 void Klaymen::stStartWalkingExt() {
1294 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stStartWalkingExt))) {
1295 _busyStatus = 0;
1296 _isWalking = true;
1297 _acceptInput = true;
1298 setDoDeltaX(_destX < _x ? 1 : 0);
1299 startAnimation(0x272C1199, 0, -1);
1300 SetUpdateHandler(&Klaymen::update);
1301 SetMessageHandler(&Klaymen::hmStartWalking);
1302 SetSpriteUpdate(&Klaymen::suWalkingTestExit);
1303 NextState(&Klaymen::stWalkingFirstExt);
1304 FinalizeState(&Klaymen::evStartWalkingDone);
1305 }
1306 }
1307
startWalkToXDistance(int16 destX,int16 distance)1308 void Klaymen::startWalkToXDistance(int16 destX, int16 distance) {
1309 if (_x > destX) {
1310 if (_x == destX + distance) {
1311 _destX = destX + distance;
1312 gotoState(NULL);
1313 gotoNextStateExt();
1314 } else if (_x < destX + distance) {
1315 startWalkToXExt(destX + distance);
1316 } else {
1317 startWalkToX(destX + distance, false);
1318 }
1319 } else {
1320 if (_x == destX - distance) {
1321 _destX = destX - distance;
1322 gotoState(NULL);
1323 gotoNextStateExt();
1324 } else if (_x > destX - distance) {
1325 startWalkToXExt(destX - distance);
1326 } else {
1327 startWalkToX(destX - distance, false);
1328 }
1329 }
1330 }
1331
startWalkToXExt(int16 x)1332 void Klaymen::startWalkToXExt(int16 x) {
1333 int16 xdiff = ABS(x - _x);
1334 if (x == _x) {
1335 _destX = x;
1336 if (!_isWalking && !_isSneaking && !_isLargeStep) {
1337 gotoState(NULL);
1338 gotoNextStateExt();
1339 }
1340 } else if (xdiff <= 36 && !_isWalking && !_isSneaking && !_isLargeStep) {
1341 _destX = x;
1342 gotoState(NULL);
1343 gotoNextStateExt();
1344 } else if (xdiff <= 42 && _actionStatus != 3) {
1345 if (_isSneaking && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0)) && ABS(_destX - _x) > xdiff) {
1346 _destX = x;
1347 } else {
1348 _destX = x;
1349 GotoState(&Klaymen::stSneak);
1350 }
1351 } else if (_isLargeStep && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0))) {
1352 _destX = x;
1353 } else {
1354 _destX = x;
1355 GotoState(&Klaymen::stLargeStep);
1356 }
1357 }
1358
stLargeStep()1359 void Klaymen::stLargeStep() {
1360 _busyStatus = 2;
1361 _isLargeStep = true;
1362 _acceptInput = true;
1363 setDoDeltaX(_destX >= _x ? 1 : 0);
1364 startAnimation(0x08B28116, 0, -1);
1365 SetUpdateHandler(&Klaymen::update);
1366 SetMessageHandler(&Klaymen::hmLargeStep);
1367 SetSpriteUpdate(&Klaymen::suLargeStep);
1368 FinalizeState(&Klaymen::evLargeStepDone);
1369 }
1370
evLargeStepDone()1371 void Klaymen::evLargeStepDone() {
1372 _isLargeStep = false;
1373 }
1374
suLargeStep()1375 void Klaymen::suLargeStep() {
1376 int16 xdiff = _destX - _x;
1377
1378 if (_doDeltaX) {
1379 _deltaX = -_deltaX;
1380 }
1381
1382 if (_currFrameIndex == 7) {
1383 _deltaX = xdiff;
1384 }
1385
1386 if ((xdiff > 0 && xdiff > _deltaX) || (xdiff < 0 && xdiff < _deltaX))
1387 xdiff = _deltaX;
1388
1389 _deltaX = 0;
1390
1391 if (_x != _destX) {
1392 HitRect *hitRectPrev = _parentScene->findHitRectAtPos(_x, _y);
1393 _x += xdiff;
1394 if (_pathPoints) {
1395 walkAlongPathPoints();
1396 } else {
1397 HitRect *hitRectNext = _parentScene->findHitRectAtPos(_x, _y);
1398 if (hitRectNext->type == 0x5002) {
1399 _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (hitRectNext->rect.x2 - _x) / 2);
1400 } else if (hitRectNext->type == 0x5003) {
1401 _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (_x - hitRectNext->rect.x1) / 2);
1402 } else if (hitRectPrev->type == 0x5002) {
1403 _y = xdiff > 0 ? hitRectPrev->rect.y2 : hitRectPrev->rect.y1;
1404 } else if (hitRectPrev->type == 0x5003) {
1405 _y = xdiff < 0 ? hitRectPrev->rect.y2 : hitRectPrev->rect.y1;
1406 }
1407 }
1408 updateBounds();
1409 }
1410 }
1411
hmLargeStep(int messageNum,const MessageParam & param,Entity * sender)1412 uint32 Klaymen::hmLargeStep(int messageNum, const MessageParam ¶m, Entity *sender) {
1413 uint32 messageResult = hmLowLevel(messageNum, param, sender);
1414 switch (messageNum) {
1415 case NM_ANIMATION_START:
1416 if (param.asInteger() == 0x32180101) {
1417 playSound(0, 0x4924AAC4);
1418 } else if (param.asInteger() == 0x0A2A9098) {
1419 playSound(0, 0x0A2AA8E0);
1420 }
1421 break;
1422 case NM_ANIMATION_STOP:
1423 _x = _destX;
1424 gotoNextStateExt();
1425 break;
1426 default:
1427 break;
1428 }
1429 return messageResult;
1430 }
1431
stWonderAboutHalf()1432 void Klaymen::stWonderAboutHalf() {
1433 _busyStatus = 0;
1434 _acceptInput = true;
1435 startAnimation(0xD820A114, 0, 10);
1436 SetUpdateHandler(&Klaymen::update);
1437 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1438 SetSpriteUpdate(NULL);
1439 }
1440
stWonderAboutAfter()1441 void Klaymen::stWonderAboutAfter() {
1442 _busyStatus = 1;
1443 _acceptInput = true;
1444 startAnimation(0xD820A114, 30, -1);
1445 SetUpdateHandler(&Klaymen::update);
1446 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1447 SetSpriteUpdate(NULL);
1448 }
1449
stTurnToUseHalf()1450 void Klaymen::stTurnToUseHalf() {
1451 _busyStatus = 0;
1452 _acceptInput = true;
1453 startAnimation(0x9B250AD2, 0, 7);
1454 SetUpdateHandler(&Klaymen::update);
1455 SetMessageHandler(&Klaymen::hmTurnToUse);
1456 SetSpriteUpdate(NULL);
1457 }
1458
hmTurnToUse(int messageNum,const MessageParam & param,Entity * sender)1459 uint32 Klaymen::hmTurnToUse(int messageNum, const MessageParam ¶m, Entity *sender) {
1460 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1461 switch (messageNum) {
1462 case NM_ANIMATION_START:
1463 if (param.asInteger() == 0x32180101) {
1464 playSound(0, 0x4924AAC4);
1465 } else if (param.asInteger() == 0x0A2A9098) {
1466 playSound(0, 0x0A2AA8E0);
1467 }
1468 break;
1469 default:
1470 break;
1471 }
1472 return messageResult;
1473 }
1474
stTurnAwayFromUse()1475 void Klaymen::stTurnAwayFromUse() {
1476 _busyStatus = 1;
1477 _acceptInput = true;
1478 startAnimation(0x98F88391, 4, -1);
1479 SetUpdateHandler(&Klaymen::update);
1480 SetMessageHandler(&Klaymen::hmTurnToUse);
1481 SetSpriteUpdate(NULL);
1482 }
1483
stWonderAbout()1484 void Klaymen::stWonderAbout() {
1485 _busyStatus = 1;
1486 _acceptInput = true;
1487 startAnimation(0xD820A114, 0, -1);
1488 SetUpdateHandler(&Klaymen::update);
1489 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1490 SetSpriteUpdate(NULL);
1491 }
1492
stPeekWall()1493 void Klaymen::stPeekWall() {
1494 _busyStatus = 1;
1495 _acceptInput = true;
1496 startAnimation(0xAC20C012, 0, -1);
1497 SetUpdateHandler(&Klaymen::update);
1498 SetMessageHandler(&Klaymen::hmPeekWall);
1499 SetSpriteUpdate(NULL);
1500 }
1501
hmPeekWall(int messageNum,const MessageParam & param,Entity * sender)1502 uint32 Klaymen::hmPeekWall(int messageNum, const MessageParam ¶m, Entity *sender) {
1503 int16 speedUpFrameIndex;
1504 switch (messageNum) {
1505 case 0x1008:
1506 speedUpFrameIndex = getFrameIndex(kKlaymenSpeedUpHash);
1507 if (_currFrameIndex < speedUpFrameIndex)
1508 startAnimation(0xAC20C012, speedUpFrameIndex, -1);
1509 return 0;
1510 case NM_ANIMATION_START:
1511 if (param.asInteger() == 0x32180101) {
1512 playSound(0, 0x405002D8);
1513 } else if (param.asInteger() == 0x0A2A9098) {
1514 playSound(0, 0x0460E2FA);
1515 }
1516 break;
1517 default:
1518 break;
1519 }
1520 return hmLowLevelAnimation(messageNum, param, sender);
1521 }
1522
suUpdateDestX()1523 void Klaymen::suUpdateDestX() {
1524 AnimatedSprite::updateDeltaXY();
1525 _destX = _x;
1526 }
1527
stReleaseRing()1528 void Klaymen::stReleaseRing() {
1529 _busyStatus = 1;
1530 _acceptInput = false;
1531 sendMessage(_attachedSprite, NM_KLAYMEN_RAISE_LEVER, 0);
1532 _attachedSprite = NULL;
1533 startAnimation(0xB869A4B9, 0, -1);
1534 SetUpdateHandler(&Klaymen::update);
1535 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1536 SetSpriteUpdate(NULL);
1537 }
1538
startWalkToAttachedSpriteXDistance(int16 distance)1539 void Klaymen::startWalkToAttachedSpriteXDistance(int16 distance) {
1540 startWalkToXDistance(_attachedSprite->getX(), distance);
1541 }
1542
stContinueClimbLadderUp()1543 void Klaymen::stContinueClimbLadderUp() {
1544 _busyStatus = 0;
1545 _acceptInput = true;
1546 _ladderStatus = 3;
1547 startAnimationByHash(0x3A292504, 0x01084280, 0);
1548 _newStickFrameHash = 0x01084280;
1549 SetUpdateHandler(&Klaymen::update);
1550 SetMessageHandler(&Klaymen::hmLowLevel);
1551 SetSpriteUpdate(NULL);
1552 gotoNextStateExt();
1553 }
1554
stStartClimbLadderDown()1555 void Klaymen::stStartClimbLadderDown() {
1556 if (!stStartAction(AnimationCallback(&Klaymen::stStartClimbLadderDown))) {
1557 _busyStatus = 0;
1558 if (_destY < _y) {
1559 if (_ladderStatus == 1) {
1560 _ladderStatus = 2;
1561 stClimbLadderHalf();
1562 } else {
1563 gotoNextStateExt();
1564 }
1565 } else if (_ladderStatus == 0) {
1566 _ladderStatus = 2;
1567 _acceptInput = false;
1568 startAnimation(0x122D1505, 0, -1);
1569 SetUpdateHandler(&Klaymen::update);
1570 SetMessageHandler(&Klaymen::hmClimbLadderUpDown);
1571 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1572 } else if (_ladderStatus == 3) {
1573 _ladderStatus = 2;
1574 _acceptInput = true;
1575 startAnimationByHash(0x122D1505, 0x01084280, 0);
1576 SetUpdateHandler(&Klaymen::update);
1577 SetMessageHandler(&Klaymen::hmClimbLadderUpDown);
1578 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1579 } else if (_ladderStatus == 1) {
1580 _ladderStatus = 2;
1581 _acceptInput = true;
1582 startAnimation(0x122D1505, 29 - _currFrameIndex, -1);
1583 }
1584 }
1585 }
1586
stClimbLadderHalf()1587 void Klaymen::stClimbLadderHalf() {
1588 _busyStatus = 2;
1589 if (_ladderStatus == 1) {
1590 _ladderStatus = 0;
1591 _acceptInput = false;
1592 startAnimationByHash(0x3A292504, 0x02421405, 0);
1593 SetUpdateHandler(&Klaymen::update);
1594 SetMessageHandler(&Klaymen::hmClimbLadderHalf);
1595 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1596 } else if (_ladderStatus == 2) {
1597 _ladderStatus = 0;
1598 _acceptInput = false;
1599 startAnimationByHash(0x122D1505, 0x02421405, 0);
1600 SetUpdateHandler(&Klaymen::update);
1601 SetMessageHandler(&Klaymen::hmClimbLadderHalf);
1602 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1603 } else {
1604 gotoNextStateExt();
1605 }
1606 }
1607
hmClimbLadderHalf(int messageNum,const MessageParam & param,Entity * sender)1608 uint32 Klaymen::hmClimbLadderHalf(int messageNum, const MessageParam ¶m, Entity *sender) {
1609 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1610 switch (messageNum) {
1611 case NM_ANIMATION_START:
1612 if (param.asInteger() == 0x489B025C) {
1613 playSound(0, 0x52C4C2D7);
1614 } else if (param.asInteger() == 0x400A0E64) {
1615 playSound(0, 0x50E081D9);
1616 } else if (param.asInteger() == 0x32180101) {
1617 playSound(0, 0x405002D8);
1618 } else if (param.asInteger() == 0x0A2A9098) {
1619 playSound(0, 0x0460E2FA);
1620 }
1621 break;
1622 default:
1623 break;
1624 }
1625 return messageResult;
1626 }
1627
hmClimbLadderUpDown(int messageNum,const MessageParam & param,Entity * sender)1628 uint32 Klaymen::hmClimbLadderUpDown(int messageNum, const MessageParam ¶m, Entity *sender) {
1629 uint32 messageResult = hmLowLevel(messageNum, param, sender);
1630 switch (messageNum) {
1631 case NM_ANIMATION_START:
1632 if (param.asInteger() == 0x01084280) {
1633 _acceptInput = true;
1634 } else if (param.asInteger() == 0x489B025C) {
1635 playSound(0, 0x52C4C2D7);
1636 } else if (param.asInteger() == 0x400A0E64) {
1637 playSound(0, 0x50E081D9);
1638 } else if (param.asInteger() == 0x02421405) {
1639 if (_ladderStatus == 1) {
1640 startAnimationByHash(0x3A292504, 0x01084280, 0);
1641 if (_destY >= _y - 30)
1642 sendMessage(this, NM_SCENE_LEAVE, 0);
1643 } else {
1644 startAnimationByHash(0x122D1505, 0x01084280, 0);
1645 if (_destY <= _y)
1646 sendMessage(this, NM_SCENE_LEAVE, 0);
1647 }
1648 }
1649 break;
1650 default:
1651 break;
1652 }
1653 return messageResult;
1654 }
1655
stStartClimbLadderUp()1656 void Klaymen::stStartClimbLadderUp() {
1657 if (!stStartAction(AnimationCallback(&Klaymen::stStartClimbLadderUp))) {
1658 _busyStatus = 0;
1659 if (_destY >= _y - 30) {
1660 gotoNextStateExt();
1661 } else if (_ladderStatus == 0) {
1662 _ladderStatus = 1;
1663 _acceptInput = false;
1664 startAnimation(0x3A292504, 0, -1);
1665 SetUpdateHandler(&Klaymen::update);
1666 SetMessageHandler(&Klaymen::hmClimbLadderUpDown);
1667 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1668 } else if (_ladderStatus == 3) {
1669 _ladderStatus = 1;
1670 _acceptInput = true;
1671 startAnimationByHash(0x3A292504, 0x01084280, 0);
1672 SetUpdateHandler(&Klaymen::update);
1673 SetMessageHandler(&Klaymen::hmClimbLadderUpDown);
1674 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1675 } else if (_ladderStatus == 2) {
1676 _ladderStatus = 1;
1677 _acceptInput = true;
1678 startAnimation(0x3A292504, 29 - _currFrameIndex, -1);
1679 }
1680 }
1681 }
1682
stWalkToFrontNoStep()1683 void Klaymen::stWalkToFrontNoStep() {
1684 _busyStatus = 2;
1685 _acceptInput = false;
1686 startAnimationByHash(0xF229C003, 0x14884392, 0);
1687 SetUpdateHandler(&Klaymen::update);
1688 SetMessageHandler(&Klaymen::hmWalkToFront);
1689 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1690 }
1691
hmWalkToFront(int messageNum,const MessageParam & param,Entity * sender)1692 uint32 Klaymen::hmWalkToFront(int messageNum, const MessageParam ¶m, Entity *sender) {
1693 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1694 switch (messageNum) {
1695 case NM_ANIMATION_START:
1696 if (param.asInteger() == 0x80C110B5) {
1697 sendMessage(_parentScene, NM_MOVE_TO_BACK, 0);
1698 } else if (param.asInteger() == 0x110010D1) {
1699 sendMessage(_parentScene, NM_MOVE_TO_FRONT, 0);
1700 } else if (param.asInteger() == 0x32180101) {
1701 playSound(0, _soundFlag ? 0x48498E46 : 0x405002D8);
1702 } else if (param.asInteger() == 0x0A2A9098) {
1703 playSound(0, _soundFlag ? 0x50399F64 : 0x0460E2FA);
1704 }
1705 break;
1706 default:
1707 break;
1708 }
1709 return messageResult;
1710 }
1711
stWalkToFront()1712 void Klaymen::stWalkToFront() {
1713 if (!stStartAction(AnimationCallback(&Klaymen::stWalkToFront))) {
1714 _busyStatus = 2;
1715 _acceptInput = false;
1716 startAnimation(0xF229C003, 0, -1);
1717 SetUpdateHandler(&Klaymen::update);
1718 SetMessageHandler(&Klaymen::hmWalkToFront);
1719 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1720 }
1721 }
1722
stTurnToFront()1723 void Klaymen::stTurnToFront() {
1724 if (!stStartAction(AnimationCallback(&Klaymen::stTurnToFront))) {
1725 _busyStatus = 0;
1726 _acceptInput = false;
1727 startAnimationByHash(0xCA221107, 0, 0x8520108C);
1728 SetUpdateHandler(&Klaymen::update);
1729 SetMessageHandler(&Klaymen::hmWalkToFront);
1730 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1731 }
1732 }
1733
stTurnToBack()1734 void Klaymen::stTurnToBack() {
1735 if (!stStartAction(AnimationCallback(&Klaymen::stTurnToBack))) {
1736 _busyStatus = 2;
1737 _acceptInput = false;
1738 startAnimation(0xCA221107, 0, -1);
1739 SetUpdateHandler(&Klaymen::update);
1740 SetMessageHandler(&Klaymen::hmWalkToFront);
1741 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1742 }
1743 }
1744
stLandOnFeet()1745 void Klaymen::stLandOnFeet() {
1746 _busyStatus = 1;
1747 _acceptInput = true;
1748 startAnimation(0x18118554, 0, -1);
1749 SetUpdateHandler(&Klaymen::update);
1750 SetMessageHandler(&Klaymen::hmLandOnFeet);
1751 SetSpriteUpdate(NULL);
1752 }
1753
hmLandOnFeet(int messageNum,const MessageParam & param,Entity * sender)1754 uint32 Klaymen::hmLandOnFeet(int messageNum, const MessageParam ¶m, Entity *sender) {
1755 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1756 switch (messageNum) {
1757 case NM_ANIMATION_START:
1758 if (param.asInteger() == 0x320AC306) {
1759 playSound(0, 0x5860C640);
1760 }
1761 break;
1762 default:
1763 break;
1764 }
1765 return messageResult;
1766 }
1767
stTurnToBackToUse()1768 void Klaymen::stTurnToBackToUse() {
1769 if (!stStartAction(AnimationCallback(&Klaymen::stTurnToBackToUse))) {
1770 _busyStatus = 2;
1771 _acceptInput = false;
1772 startAnimation(0x91540140, 0, -1);
1773 SetUpdateHandler(&Klaymen::update);
1774 SetMessageHandler(&Klaymen::hmTurnToBackToUse);
1775 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1776 }
1777 }
1778
hmTurnToBackToUse(int messageNum,const MessageParam & param,Entity * sender)1779 uint32 Klaymen::hmTurnToBackToUse(int messageNum, const MessageParam ¶m, Entity *sender) {
1780 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
1781 switch (messageNum) {
1782 case NM_ANIMATION_START:
1783 if (param.asInteger() == 0xC61A0119) {
1784 playSound(0, 0x402338C2);
1785 } else if (param.asInteger() == 0x32180101) {
1786 playSound(0, 0x4924AAC4);
1787 } else if (param.asInteger() == 0x0A2A9098) {
1788 playSound(0, 0x0A2AA8E0);
1789 }
1790 break;
1791 default:
1792 break;
1793 }
1794 return messageResult;
1795 }
1796
stTurnToUse()1797 void Klaymen::stTurnToUse() {
1798 if (!stStartAction(AnimationCallback(&Klaymen::stTurnToUse))) {
1799 _busyStatus = 2;
1800 _acceptInput = false;
1801 startAnimation(0x9B250AD2, 0, -1);
1802 SetUpdateHandler(&Klaymen::update);
1803 SetMessageHandler(&Klaymen::hmTurnToUse);
1804 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1805 }
1806 }
1807
stReturnFromUse()1808 void Klaymen::stReturnFromUse() {
1809 _busyStatus = 2;
1810 _acceptInput = false;
1811 startAnimation(0x98F88391, 0, -1);
1812 SetUpdateHandler(&Klaymen::update);
1813 SetMessageHandler(&Klaymen::hmTurnToUse);
1814 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1815 }
1816
stWalkingOpenDoor()1817 void Klaymen::stWalkingOpenDoor() {
1818 _isWalkingOpenDoorNotified = false;
1819 _acceptInput = false;
1820 startAnimation(0x11A8E012, 0, -1);
1821 SetUpdateHandler(&Klaymen::update);
1822 SetMessageHandler(&Klaymen::hmStartWalking);
1823 SetSpriteUpdate(&Klaymen::suWalkingOpenDoor);
1824 }
1825
suWalkingOpenDoor()1826 void Klaymen::suWalkingOpenDoor() {
1827 if (!_isWalkingOpenDoorNotified && ABS(_destX - _x) < 80) {
1828 sendMessage(_parentScene, 0x4829, 0);
1829 _isWalkingOpenDoorNotified = true;
1830 }
1831 AnimatedSprite::updateDeltaXY();
1832 }
1833
stMoveObjectSkipTurnFaceObject()1834 void Klaymen::stMoveObjectSkipTurnFaceObject() {
1835 setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
1836 _isMoveObjectRequested = false;
1837 _acceptInput = true;
1838 startAnimationByHash(0x0C1CA072, 0x01084280, 0);
1839 SetUpdateHandler(&Klaymen::update);
1840 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1841 SetMessageHandler(&Klaymen::hmMoveObjectTurn);
1842 }
1843
evMoveObjectTurnDone()1844 void Klaymen::evMoveObjectTurnDone() {
1845 sendMessage(_attachedSprite, NM_KLAYMEN_RAISE_LEVER, 0);
1846 }
1847
hmMoveObjectTurn(int messageNum,const MessageParam & param,Entity * sender)1848 uint32 Klaymen::hmMoveObjectTurn(int messageNum, const MessageParam ¶m, Entity *sender) {
1849 switch (messageNum) {
1850 case NM_ANIMATION_START:
1851 if (param.asInteger() == 0x01084280) {
1852 sendMessage(_attachedSprite, 0x480B, _doDeltaX ? 1 : 0);
1853 } else if (param.asInteger() == 0x02421405) {
1854 if (_isMoveObjectRequested && sendMessage(_attachedSprite, 0x480C, _doDeltaX ? 1 : 0) != 0) {
1855 stMoveObjectSkipTurn();
1856 } else {
1857 FinalizeState(&Klaymen::evMoveObjectTurnDone);
1858 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
1859 }
1860 } else if (param.asInteger() == 0x32180101) {
1861 playSound(0, 0x405002D8);
1862 } else if (param.asInteger() == 0x0A2A9098) {
1863 playSound(0, 0x0460E2FA);
1864 }
1865 break;
1866 case NM_KLAYMEN_MOVE_OBJECT:
1867 _isMoveObjectRequested = true;
1868 return 0;
1869 default:
1870 break;
1871 }
1872 return hmLowLevelAnimation(messageNum, param, sender);
1873 }
1874
stMoveObjectSkipTurn()1875 void Klaymen::stMoveObjectSkipTurn() {
1876 _isMoveObjectRequested = false;
1877 _acceptInput = true;
1878 startAnimationByHash(0x0C1CA072, 0x01084280, 0);
1879 SetUpdateHandler(&Klaymen::update);
1880 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1881 SetMessageHandler(&Klaymen::hmMoveObjectTurn);
1882 }
1883
stMoveObjectFaceObject()1884 void Klaymen::stMoveObjectFaceObject() {
1885 setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
1886 if (!stStartAction(AnimationCallback(&Klaymen::stMoveObjectFaceObject))) {
1887 _busyStatus = 2;
1888 _isMoveObjectRequested = false;
1889 _acceptInput = true;
1890 startAnimation(0x0C1CA072, 0, -1);
1891 SetUpdateHandler(&Klaymen::update);
1892 SetMessageHandler(&Klaymen::hmMoveObjectTurn);
1893 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1894 }
1895 }
1896
stUseLever()1897 void Klaymen::stUseLever() {
1898 if (!stStartAction(AnimationCallback(&Klaymen::stUseLever))) {
1899 _busyStatus = 0;
1900 if (_isLeverDown) {
1901 stUseLeverRelease();
1902 } else {
1903 sendMessage(_attachedSprite, NM_MOVE_TO_FRONT, 0);
1904 startAnimation(0x0C303040, 0, -1);
1905 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1906 SetMessageHandler(&Klaymen::hmLever);
1907 SetUpdateHandler(&Klaymen::update);
1908 NextState(&Klaymen::stPullLeverDown);
1909 _acceptInput = false;
1910 }
1911 }
1912 }
1913
1914 // Exactly the same code as sub420DA0 which was removed
stPullLeverDown()1915 void Klaymen::stPullLeverDown() {
1916 startAnimation(0x0D318140, 0, -1);
1917 sendMessage(_attachedSprite, NM_KLAYMEN_LOWER_LEVER, 0);
1918 NextState(&Klaymen::stHoldLeverDown);
1919 }
1920
stHoldLeverDown()1921 void Klaymen::stHoldLeverDown() {
1922 startAnimation(0x4464A440, 0, -1);
1923 SetUpdateHandler(&Klaymen::update);
1924 SetMessageHandler(&Klaymen::hmLowLevel);
1925 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1926 _isLeverDown = true;
1927 _acceptInput = true;
1928 }
1929
stUseLeverRelease()1930 void Klaymen::stUseLeverRelease() {
1931 startAnimation(0x09018068, 0, -1);
1932 SetUpdateHandler(&Klaymen::update);
1933 SetMessageHandler(&Klaymen::hmLever);
1934 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1935 sendMessage(_attachedSprite, NM_KLAYMEN_RAISE_LEVER, 0);
1936 NextState(&Klaymen::stPullLeverDown);
1937 _acceptInput = false;
1938 }
1939
stReleaseLever()1940 void Klaymen::stReleaseLever() {
1941 if (_isLeverDown) {
1942 _busyStatus = 2;
1943 startAnimation(0x09018068, 0, -1);
1944 SetUpdateHandler(&Klaymen::update);
1945 SetMessageHandler(&Klaymen::hmLever);
1946 SetSpriteUpdate(&Klaymen::suUpdateDestX);
1947 sendMessage(_attachedSprite, NM_KLAYMEN_RAISE_LEVER, 0);
1948 NextState(&Klaymen::stLetGoOfLever);
1949 _acceptInput = false;
1950 _isLeverDown = false;
1951 } else {
1952 gotoNextStateExt();
1953 }
1954 }
1955
stLetGoOfLever()1956 void Klaymen::stLetGoOfLever() {
1957 startAnimation(0x0928C048, 0, -1);
1958 FinalizeState(&Klaymen::evLeverReleasedEvent);
1959 }
1960
evLeverReleasedEvent()1961 void Klaymen::evLeverReleasedEvent() {
1962 sendMessage(_attachedSprite, NM_MOVE_TO_BACK, 0);
1963 }
1964
stInsertDisk()1965 void Klaymen::stInsertDisk() {
1966 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stInsertDisk))) {
1967 _busyStatus = 2;
1968 _tapesToInsert = 0;
1969 for (uint32 i = 0; i < 20; i++) {
1970 if (getSubVar(VA_HAS_TAPE, i)) {
1971 setSubVar(VA_IS_TAPE_INSERTED, i, 1);
1972 setSubVar(VA_HAS_TAPE, i, 0);
1973 _tapesToInsert++;
1974 }
1975 }
1976 if (_tapesToInsert == 0) {
1977 GotoState(NULL);
1978 gotoNextStateExt();
1979 } else {
1980 startAnimation(0xD8C8D100, 0, -1);
1981 SetUpdateHandler(&Klaymen::update);
1982 SetMessageHandler(&Klaymen::hmInsertDisk);
1983 SetSpriteUpdate(&Klaymen::suAction);
1984 _acceptInput = false;
1985 _tapesToInsert--;
1986 }
1987 }
1988 }
1989
hmInsertDisk(int messageNum,const MessageParam & param,Entity * sender)1990 uint32 Klaymen::hmInsertDisk(int messageNum, const MessageParam ¶m, Entity *sender) {
1991 uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender);
1992 switch (messageNum) {
1993 case NM_ANIMATION_START:
1994 if (_tapesToInsert == 0 && param.asInteger() == 0x06040580) {
1995 nextAnimationByHash(0xD8C8D100, calcHash("GoToStartLoop/Finish"), 0);
1996 } else if (_tapesToInsert != 0 && param.asInteger() == calcHash("GoToStartLoop/Finish")) {
1997 _tapesToInsert--;
1998 startAnimationByHash(0xD8C8D100, 0x01084280, 0);
1999 } else if (param.asInteger() == 0x062A1510) {
2000 playSound(0, 0x41688704);
2001 } else if (param.asInteger() == 0x02B20220) {
2002 playSound(0, 0xC5408620);
2003 } else if (param.asInteger() == 0x0A720138) {
2004 playSound(0, 0xD4C08010);
2005 } else if (param.asInteger() == 0xB613A180) {
2006 playSound(0, 0x44051000);
2007 } else if (param.asInteger() == 0x0E040501) {
2008 playSound(1, 0xC6A129C1);
2009 }
2010 break;
2011 default:
2012 break;
2013 }
2014 return messageResult;
2015 }
2016
walkAlongPathPoints()2017 void Klaymen::walkAlongPathPoints() {
2018 if (_x <= (*_pathPoints)[0].x)
2019 _y = (*_pathPoints)[0].y;
2020 else if (_x >= (*_pathPoints)[_pathPoints->size() - 1].x)
2021 _y = (*_pathPoints)[_pathPoints->size() - 1].y;
2022 else {
2023 int16 deltaX = _x - (*_pathPoints)[0].x, deltaXIncr = 0;
2024 uint index = 0;
2025 while (deltaX > 0) {
2026 NPoint pt2 = (*_pathPoints)[index];
2027 NPoint pt1 = index + 1 >= _pathPoints->size() ? (*_pathPoints)[0] : (*_pathPoints)[index + 1];
2028 int16 xd = ABS(pt1.x - pt2.x);
2029 int16 yd = ABS(pt1.y - pt2.y);
2030 if (deltaX + deltaXIncr >= xd) {
2031 deltaX -= xd;
2032 deltaX += deltaXIncr;
2033 ++index;
2034 if (index >= _pathPoints->size())
2035 index = 0;
2036 _y = (*_pathPoints)[index].y;
2037 } else {
2038 deltaXIncr += deltaX;
2039 if (pt1.y >= pt2.y) {
2040 _y = pt2.y + (yd * deltaXIncr) / xd;
2041 } else {
2042 _y = pt2.y - (yd * deltaXIncr) / xd;
2043 }
2044 deltaX = 0;
2045 }
2046 }
2047 }
2048 }
2049
enterIdleAnimation(uint idleAnimation)2050 void Klaymen::enterIdleAnimation(uint idleAnimation) {
2051 switch (idleAnimation) {
2052 case kIdlePickEar:
2053 startIdleAnimation(0x5B20C814, AnimationCallback(&Klaymen::stIdlePickEar));
2054 break;
2055 case kIdleSpinHead:
2056 startIdleAnimation(0xD122C137, AnimationCallback(&Klaymen::stIdleSpinHead));
2057 break;
2058 case kIdleArms:
2059 startIdleAnimation(0x543CD054, AnimationCallback(&Klaymen::stIdleArms));
2060 break;
2061 case kIdleChest:
2062 startIdleAnimation(0x40A0C034, AnimationCallback(&Klaymen::stIdleChest));
2063 break;
2064 case kIdleHeadOff:
2065 startIdleAnimation(0x5120E137, AnimationCallback(&Klaymen::stIdleHeadOff));
2066 break;
2067 case kIdleTeleporterHands:
2068 startIdleAnimation(0x90EF8D38, AnimationCallback(&Klaymen::stIdleTeleporterHands));
2069 break;
2070 case kIdleTeleporterHands2:
2071 startIdleAnimation(0x900F0930, AnimationCallback(&Klaymen::stIdleTeleporterHands2));
2072 break;
2073 case kIdleWonderAbout:
2074 stIdleWonderAbout();
2075 break;
2076 default:
2077 break;
2078 }
2079 }
2080
stJumpToGrab()2081 void Klaymen::stJumpToGrab() {
2082 _busyStatus = 0;
2083 _acceptInput = false;
2084 startAnimationByHash(0x00AB8C10, 0x01084280, 0);
2085 SetUpdateHandler(&Klaymen::update);
2086 SetSpriteUpdate(&Klaymen::suJumpToGrab);
2087 SetMessageHandler(&Klaymen::hmJumpToGrab);
2088 }
2089
suJumpToGrab()2090 void Klaymen::suJumpToGrab() {
2091 updateDeltaXY();
2092 if (_y >= _destY) {
2093 _y = _destY;
2094 updateBounds();
2095 gotoNextStateExt();
2096 }
2097 }
2098
hmJumpToGrab(int messageNum,const MessageParam & param,Entity * sender)2099 uint32 Klaymen::hmJumpToGrab(int messageNum, const MessageParam ¶m, Entity *sender) {
2100 uint32 messageResult = hmLowLevel(messageNum, param, sender);
2101 switch (messageNum) {
2102 case NM_ANIMATION_START:
2103 if (param.asInteger() == 0x168050A0)
2104 sendMessage(_attachedSprite, NM_KLAYMEN_USE_OBJECT, 0);
2105 else if (param.asInteger() == 0x320AC306)
2106 startAnimationByHash(0x00AB8C10, 0x01084280, 0);
2107 else if (param.asInteger() == 0x4AB28209)
2108 sendMessage(_attachedSprite, NM_MOVE_TO_BACK, 0);
2109 else if (param.asInteger() == 0x88001184)
2110 sendMessage(_attachedSprite, NM_MOVE_TO_FRONT, 0);
2111 break;
2112 default:
2113 break;
2114 }
2115 return messageResult;
2116 }
2117
stFinishGrow()2118 void Klaymen::stFinishGrow() {
2119 _busyStatus = 2;
2120 _acceptInput = false;
2121 startAnimation(0x38445000, 0, -1);
2122 SetUpdateHandler(&Klaymen::update);
2123 SetSpriteUpdate(NULL);
2124 SetMessageHandler(&Klaymen::hmFinishGrow);
2125 }
2126
hmFinishGrow(int messageNum,const MessageParam & param,Entity * sender)2127 uint32 Klaymen::hmFinishGrow(int messageNum, const MessageParam ¶m, Entity *sender) {
2128 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
2129 switch (messageNum) {
2130 case NM_ANIMATION_START:
2131 if (param.asInteger() == 0x040C4C01)
2132 playSound(0, 0x01E11140);
2133 break;
2134 default:
2135 break;
2136 }
2137 return messageResult;
2138 }
2139
stTurnToUseExt()2140 void Klaymen::stTurnToUseExt() {
2141 if (!stStartAction(AnimationCallback(&Klaymen::stTurnToUseExt))) {
2142 _busyStatus = 2;
2143 _acceptInput = false;
2144 startAnimation(0x1B3D8216, 0, -1);
2145 SetUpdateHandler(&Klaymen::update);
2146 SetMessageHandler(&Klaymen::hmTurnToUse);
2147 SetSpriteUpdate(&Klaymen::suUpdateDestX);
2148 }
2149 }
2150
stJumpToGrabFall()2151 void Klaymen::stJumpToGrabFall() {
2152 if (!stStartAction(AnimationCallback(&Klaymen::stJumpToGrabFall))) {
2153 _busyStatus = 0;
2154 _acceptInput = false;
2155 startAnimation(0x00AB8C10, 0, -1);
2156 SetUpdateHandler(&Klaymen::update);
2157 SetMessageHandler(&Klaymen::hmJumpToGrab);
2158 SetSpriteUpdate(&Klaymen::suJumpToGrab);
2159 sendMessage(_attachedSprite, NM_MOVE_TO_FRONT, 0);
2160 }
2161 }
2162
stJumpToGrabRelease()2163 void Klaymen::stJumpToGrabRelease() {
2164 _busyStatus = 1;
2165 _acceptInput = false;
2166 startAnimationByHash(0x00AB8C10, 0x320AC306, 0);
2167 SetUpdateHandler(&Klaymen::update);
2168 SetMessageHandler(&Klaymen::hmJumpToGrabRelease);
2169 SetSpriteUpdate(NULL);
2170 NextState(&Klaymen::stReleaseRing);
2171 }
2172
hmJumpToGrabRelease(int messageNum,const MessageParam & param,Entity * sender)2173 uint32 Klaymen::hmJumpToGrabRelease(int messageNum, const MessageParam ¶m, Entity *sender) {
2174 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
2175 switch (messageNum) {
2176 case NM_ANIMATION_START:
2177 if (param.asInteger() == 0x320AC306)
2178 playSound(0, 0x5860C640);
2179 break;
2180 default:
2181 break;
2182 }
2183 return messageResult;
2184 }
2185
stIdleTeleporterHands()2186 void Klaymen::stIdleTeleporterHands() {
2187 _busyStatus = 0;
2188 _acceptInput = true;
2189 startAnimation(0x90EF8D38, 0, -1);
2190 SetUpdateHandler(&Klaymen::update);
2191 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2192 SetSpriteUpdate(NULL);
2193 NextState(&Klaymen::stSitIdleTeleporterBlinkSecond);
2194 }
2195
stIdleTeleporterHands2()2196 void Klaymen::stIdleTeleporterHands2() {
2197 _busyStatus = 0;
2198 _acceptInput = true;
2199 startAnimation(0x900F0930, 0, -1);
2200 SetUpdateHandler(&Klaymen::update);
2201 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2202 SetSpriteUpdate(NULL);
2203 NextState(&Klaymen::stSitIdleTeleporterBlinkSecond);
2204 }
2205
teleporterAppear(uint32 fileHash)2206 void Klaymen::teleporterAppear(uint32 fileHash) {
2207 _busyStatus = 0;
2208 _acceptInput = false;
2209 startAnimation(fileHash, 0, -1);
2210 SetUpdateHandler(&Klaymen::update);
2211 SetMessageHandler(&Klaymen::hmTeleporterAppearDisappear);
2212 SetSpriteUpdate(NULL);
2213 }
2214
teleporterDisappear(uint32 fileHash)2215 void Klaymen::teleporterDisappear(uint32 fileHash) {
2216 _busyStatus = 0;
2217 _acceptInput = false;
2218 startAnimation(fileHash, 0, -1);
2219 SetUpdateHandler(&Klaymen::update);
2220 SetMessageHandler(&Klaymen::hmTeleporterAppearDisappear);
2221 SetSpriteUpdate(NULL);
2222 }
2223
hmTeleporterAppearDisappear(int messageNum,const MessageParam & param,Entity * sender)2224 uint32 Klaymen::hmTeleporterAppearDisappear(int messageNum, const MessageParam ¶m, Entity *sender) {
2225 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
2226 switch (messageNum) {
2227 case NM_ANIMATION_START:
2228 if (param.asInteger() == 0x4E0A2C24) {
2229 playSound(0, 0x85B10BB8);
2230 } else if (param.asInteger() == 0x4E6A0CA0) {
2231 playSound(0, 0xC5B709B0);
2232 }
2233 break;
2234 default:
2235 break;
2236 }
2237 return messageResult;
2238 }
2239
stStandWonderAbout()2240 void Klaymen::stStandWonderAbout() {
2241 if (_x > 260)
2242 setDoDeltaX(1);
2243 _busyStatus = 0;
2244 _acceptInput = true;
2245 startAnimation(0xD820A114, 0, -1);
2246 SetUpdateHandler(&Klaymen::update);
2247 SetMessageHandler(&Klaymen::hmLowLevel);
2248 SetSpriteUpdate(NULL);
2249 _newStickFrameIndex = 10;
2250 }
2251
hmDrinkPotion(int messageNum,const MessageParam & param,Entity * sender)2252 uint32 Klaymen::hmDrinkPotion(int messageNum, const MessageParam ¶m, Entity *sender) {
2253 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
2254 switch (messageNum) {
2255 case 0x1008:
2256 if (_potionFlag1) {
2257 startAnimationByHash(0x1C388C04, 0x004A2148, 0);
2258 messageResult = 0;
2259 } else
2260 _potionFlag2 = true;
2261 break;
2262 case NM_ANIMATION_START:
2263 if (param.asInteger() == 0x0002418E)
2264 sendMessage(_parentScene, 0x2000, 0);
2265 else if (param.asInteger() == 0x924090C2) {
2266 _potionFlag1 = true;
2267 if (_potionFlag2) {
2268 startAnimationByHash(0x1C388C04, 0x004A2148, 0);
2269 messageResult = 0;
2270 }
2271 } else if (param.asInteger() == 0x004A2148)
2272 _potionFlag1 = false;
2273 else if (param.asInteger() == 0x02B20220)
2274 playSound(0, 0xC5408620);
2275 else if (param.asInteger() == 0x0A720138)
2276 playSound(0, 0xD4C08010);
2277 else if (param.asInteger() == 0x03020231)
2278 playSound(0, 0xD4C08010);
2279 else if (param.asInteger() == 0xB613A180)
2280 playSound(0, 0x44051000);
2281 else if (param.asInteger() == 0x67221A03)
2282 playSound(0, 0x44051000);
2283 else if (param.asInteger() == 0x038A010B)
2284 playSound(0, 0x00018040);
2285 else if (param.asInteger() == 0x422B0280)
2286 playSound(0, 0x166FC6E0);
2287 else if (param.asInteger() == 0x925A0C1E)
2288 playSound(0, 0x40E5884D);
2289 else if (param.asInteger() == 0x000F0082)
2290 playSound(0, 0x546CDCC1);
2291 else if (param.asInteger() == 0x00020814)
2292 playSound(0, 0x786CC6D0);
2293 else if (param.asInteger() == 0x06020500)
2294 playSound(0, 0x1069C0E1);
2295 else if (param.asInteger() == 0x02128C00)
2296 playSound(0, 0x5068C4C3);
2297 else if (param.asInteger() == 0x82022030)
2298 playSound(0, 0x5C48C0E8);
2299 break;
2300 default:
2301 break;
2302 }
2303 return messageResult;
2304 }
2305
hmGrow(int messageNum,const MessageParam & param,Entity * sender)2306 uint32 Klaymen::hmGrow(int messageNum, const MessageParam ¶m, Entity *sender) {
2307 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
2308 switch (messageNum) {
2309 case NM_ANIMATION_START:
2310 if (param.asInteger() == 0x32180101)
2311 playSound(0, 0x405002D8);
2312 else if (param.asInteger() == 0x0A2A9098)
2313 playSound(0, 0x0460E2FA);
2314 else if (param.asInteger() == 0xD00A0C0C)
2315 playSound(3);
2316 else if (param.asInteger() == 0x04121920)
2317 playSound(4);
2318 else if (param.asInteger() == 0x030B4480)
2319 playSound(5);
2320 else if (param.asInteger() == 0x422B0280)
2321 playSound(6);
2322 else if (param.asInteger() == 0x038A010B)
2323 playSound(7);
2324 else if (param.asInteger() == 0x67221A03)
2325 playSound(0, 0x44051000);
2326 else if (param.asInteger() == 0x02B20220)
2327 playSound(0, 0xC5408620);
2328 else if (param.asInteger() == 0x925A0C1E)
2329 playSound(0, 0x40E5884D);
2330 else if (param.asInteger() == 0x03020231)
2331 playSound(0, 0xD4C08010);
2332 else if (param.asInteger() == 0x08040840)
2333 setDoDeltaX(2);
2334 break;
2335 default:
2336 break;
2337 }
2338 return messageResult;
2339 }
2340
stGrow()2341 void Klaymen::stGrow() {
2342 _busyStatus = 0;
2343 _acceptInput = false;
2344 startAnimation(0x2838C010, 0, -1);
2345 SetUpdateHandler(&Klaymen::update);
2346 SetMessageHandler(&Klaymen::hmGrow);
2347 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
2348 }
2349
stDrinkPotion()2350 void Klaymen::stDrinkPotion() {
2351 _busyStatus = 1;
2352 _acceptInput = false;
2353 _potionFlag1 = false;
2354 _potionFlag2 = false;
2355 startAnimation(0x1C388C04, 0, -1);
2356 SetUpdateHandler(&Klaymen::update);
2357 SetMessageHandler(&Klaymen::hmDrinkPotion);
2358 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
2359 }
2360
hmInsertKey(int messageNum,const MessageParam & param,Entity * sender)2361 uint32 Klaymen::hmInsertKey(int messageNum, const MessageParam ¶m, Entity *sender) {
2362 uint32 messageResult = Klaymen::hmLowLevelAnimation(messageNum, param, sender);
2363 switch (messageNum) {
2364 case NM_ANIMATION_START:
2365 if (_keysToInsert == 0 && param.asInteger() == 0x06040580) {
2366 nextAnimationByHash(0xDC409440, 0x46431401, 0);
2367 } else if (_keysToInsert != 0 && param.asInteger() == 0x46431401) {
2368 _keysToInsert--;
2369 startAnimationByHash(0xDC409440, 0x01084280, 0);
2370 } else if (param.asInteger() == 0x062A1510) {
2371 playSound(0, 0x41688704);
2372 } else if (param.asInteger() == 0x02B20220) {
2373 playSound(0, 0xC5408620);
2374 } else if (param.asInteger() == 0x0A720138) {
2375 playSound(0, 0xD4C08010);
2376 } else if (param.asInteger() == 0xB613A180) {
2377 playSound(0, 0x44051000);
2378 } else if (param.asInteger() == 0x0E4C8141) {
2379 playSound(0, 0xDC4A1280);
2380 }
2381 break;
2382 default:
2383 break;
2384 }
2385 return messageResult;
2386 }
2387
stInsertKey()2388 void Klaymen::stInsertKey() {
2389 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stInsertKey))) {
2390 _busyStatus = 2;
2391 _keysToInsert = 0;
2392 for (uint32 i = 0; i < 3; i++) {
2393 if (getSubVar(VA_HAS_KEY, i)) {
2394 bool more;
2395 setSubVar(VA_IS_KEY_INSERTED, i, 1);
2396 setSubVar(VA_HAS_KEY, i, 0);
2397 do {
2398 more = false;
2399 setSubVar(VA_CURR_KEY_SLOT_NUMBERS, i, _vm->_rnd->getRandomNumber(16 - 1));
2400 for (uint j = 0; j < i && !more; j++) {
2401 if (getSubVar(VA_IS_KEY_INSERTED, j) && getSubVar(VA_CURR_KEY_SLOT_NUMBERS, j) == getSubVar(VA_CURR_KEY_SLOT_NUMBERS, i))
2402 more = true;
2403 }
2404 if (getSubVar(VA_CURR_KEY_SLOT_NUMBERS, i) == getSubVar(VA_GOOD_KEY_SLOT_NUMBERS, i))
2405 more = true;
2406 } while (more);
2407 _keysToInsert++;
2408 }
2409 }
2410 if (_keysToInsert == 0) {
2411 GotoState(NULL);
2412 gotoNextStateExt();
2413 } else {
2414 _acceptInput = false;
2415 startAnimation(0xDC409440, 0, -1);
2416 SetUpdateHandler(&Klaymen::update);
2417 SetMessageHandler(&Klaymen::hmInsertKey);
2418 SetSpriteUpdate(&Klaymen::suAction);
2419 _keysToInsert--;
2420 }
2421 }
2422 }
2423
hmPeekWallReturn(int messageNum,const MessageParam & param,Entity * sender)2424 uint32 Klaymen::hmPeekWallReturn(int messageNum, const MessageParam ¶m, Entity *sender) {
2425 uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
2426 switch (messageNum) {
2427 case NM_ANIMATION_START:
2428 if (param.asInteger() == calcHash("PopBalloon")) {
2429 sendMessage(_parentScene, 0x2000, 0);
2430 } else if (param.asInteger() == 0x02B20220) {
2431 playSound(0, 0xC5408620);
2432 } else if (param.asInteger() == 0x0A720138) {
2433 playSound(0, 0xD4C08010);
2434 } else if (param.asInteger() == 0xB613A180) {
2435 playSound(0, 0x44051000);
2436 }
2437 break;
2438 default:
2439 break;
2440 }
2441 return messageResult;
2442 }
2443
upPeekWallBlink()2444 void Klaymen::upPeekWallBlink() {
2445 Klaymen::update();
2446 _blinkCounter++;
2447 if (_blinkCounter >= _blinkCounterMax)
2448 stPeekWallBlink();
2449 }
2450
stPeekWall1()2451 void Klaymen::stPeekWall1() {
2452 _busyStatus = 0;
2453 _acceptInput = true;
2454 startAnimation(0xAC20C012, 8, 37);
2455 SetUpdateHandler(&Klaymen::update);
2456 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2457 SetSpriteUpdate(NULL);
2458 NextState(&Klaymen::stPeekWallBlink);
2459 }
2460
stPeekWall2()2461 void Klaymen::stPeekWall2() {
2462 _busyStatus = 1;
2463 _acceptInput = false;
2464 startAnimation(0xAC20C012, 43, 49);
2465 SetUpdateHandler(&Klaymen::update);
2466 SetSpriteUpdate(NULL);
2467 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2468 }
2469
stPeekWallBlink()2470 void Klaymen::stPeekWallBlink() {
2471 _blinkCounter = 0;
2472 _busyStatus = 0;
2473 _acceptInput = true;
2474 _blinkCounterMax = _vm->_rnd->getRandomNumber(64) + 24;
2475 startAnimation(0xAC20C012, 38, 42);
2476 SetUpdateHandler(&Klaymen::upPeekWallBlink);
2477 SetSpriteUpdate(NULL);
2478 SetMessageHandler(&Klaymen::hmLowLevel);
2479 _newStickFrameIndex = 42;
2480 }
2481
stPeekWallReturn()2482 void Klaymen::stPeekWallReturn() {
2483 _busyStatus = 0;
2484 _acceptInput = false;
2485 startAnimation(0x2426932E, 0, -1);
2486 SetUpdateHandler(&Klaymen::update);
2487 SetMessageHandler(&Klaymen::hmPeekWallReturn);
2488 SetSpriteUpdate(NULL);
2489 }
2490
upSpitOutFall()2491 void Klaymen::upSpitOutFall() {
2492 Klaymen::update();
2493 if (_spitOutCountdown != 0 && (--_spitOutCountdown == 0)) {
2494 _surface->setVisible(true);
2495 SetUpdateHandler(&Klaymen::update);
2496 }
2497 }
2498
hmStandIdleSpecial(int messageNum,const MessageParam & param,Entity * sender)2499 uint32 Klaymen::hmStandIdleSpecial(int messageNum, const MessageParam ¶m, Entity *sender) {
2500 switch (messageNum) {
2501 case 0x4811:
2502 playSound(0, 0x5252A0E4);
2503 setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0);
2504 if (_doDeltaX) {
2505 _x = ((Sprite*)sender)->getX() - 75;
2506 } else {
2507 _x = ((Sprite*)sender)->getX() + 75;
2508 }
2509 _y = ((Sprite*)sender)->getY() - 200;
2510 if (param.asInteger() == 0) {
2511 stSpitOutFall0();
2512 } else if (param.asInteger() == 1) {
2513 // NOTE This is never used and the code was removed
2514 // Also the animations used here in the original don't exist...
2515 } else if (param.asInteger() == 2) {
2516 stSpitOutFall2();
2517 }
2518 break;
2519 default:
2520 break;
2521 }
2522 return 0;
2523 }
2524
suFallDown()2525 void Klaymen::suFallDown() {
2526 AnimatedSprite::updateDeltaXY();
2527 HitRect *hitRect = _parentScene->findHitRectAtPos(_x, _y + 10);
2528 if (hitRect->type == 0x5001) {
2529 _y = hitRect->rect.y1;
2530 updateBounds();
2531 sendMessage(this, NM_SCENE_LEAVE, 0);
2532 }
2533 _parentScene->checkCollision(this, 0xFFFF, 0x4810, 0);
2534 }
2535
stStandIdleSpecial()2536 void Klaymen::stStandIdleSpecial() {
2537 playSound(0, 0x56548280);
2538 _busyStatus = 0;
2539 _acceptInput = false;
2540 _surface->setVisible(false);
2541 startAnimation(0x5420E254, 0, -1);
2542 SetUpdateHandler(&Klaymen::update);
2543 SetMessageHandler(&Klaymen::hmStandIdleSpecial);
2544 SetSpriteUpdate(NULL);
2545 }
2546
stSpitOutFall0()2547 void Klaymen::stSpitOutFall0() {
2548 _spitOutCountdown = 1;
2549 _busyStatus = 0;
2550 _acceptInput = false;
2551 startAnimation(0x000BAB02, 0, -1);
2552 SetUpdateHandler(&Klaymen::upSpitOutFall);
2553 SetMessageHandler(&Klaymen::hmLowLevel);
2554 SetSpriteUpdate(&Klaymen::suFallDown);
2555 NextState(&Klaymen::stFalling);
2556 sendMessage(_parentScene, 0x8000, 0);
2557 }
2558
stSpitOutFall2()2559 void Klaymen::stSpitOutFall2() {
2560 _spitOutCountdown = 1;
2561 _busyStatus = 0;
2562 _acceptInput = false;
2563 startAnimation(0x9308C132, 0, -1);
2564 SetUpdateHandler(&Klaymen::upSpitOutFall);
2565 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2566 SetSpriteUpdate(&Klaymen::suFallDown);
2567 NextState(&Klaymen::stFalling);
2568 sendMessage(_parentScene, 0x8000, 0);
2569 }
2570
stFalling()2571 void Klaymen::stFalling() {
2572 sendMessage(_parentScene, 0x1024, 1);
2573 playSound(0, 0x41648271);
2574 _busyStatus = 1;
2575 _acceptInput = false;
2576 _isWalking = false;
2577 startAnimationByHash(0x000BAB02, 0x88003000, 0);
2578 SetUpdateHandler(&Klaymen::update);
2579 SetSpriteUpdate(NULL);
2580 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2581 NextState(&Klaymen::stFallTouchdown);
2582 sendMessage(_parentScene, NM_POSITION_CHANGE, 0);
2583 _attachedSprite = NULL;
2584 sendMessage(_parentScene, 0x8001, 0);
2585 }
2586
stFallTouchdown()2587 void Klaymen::stFallTouchdown() {
2588 setDoDeltaX(2);
2589 stTryStandIdle();
2590 }
2591
suFallSkipJump()2592 void Klaymen::suFallSkipJump() {
2593 updateDeltaXY();
2594 HitRect *hitRect = _parentScene->findHitRectAtPos(_x, _y + 10);
2595 if (hitRect->type == 0x5001) {
2596 _y = hitRect->rect.y1;
2597 updateBounds();
2598 sendMessage(this, NM_SCENE_LEAVE, 0);
2599 }
2600 }
2601
stFallSkipJump()2602 void Klaymen::stFallSkipJump() {
2603 _busyStatus = 2;
2604 _acceptInput = false;
2605 startAnimationByHash(0xB93AB151, 0x40A100F8, 0);
2606 SetUpdateHandler(&Klaymen::update);
2607 SetSpriteUpdate(&Klaymen::suFallSkipJump);
2608 SetMessageHandler(&Klaymen::hmLowLevel);
2609 NextState(&Klaymen::stLandOnFeet);
2610 }
2611
upMoveObject()2612 void Klaymen::upMoveObject() {
2613 if (_x >= 380)
2614 gotoNextStateExt();
2615 Klaymen::update();
2616 }
2617
hmMoveObject(int messageNum,const MessageParam & param,Entity * sender)2618 uint32 Klaymen::hmMoveObject(int messageNum, const MessageParam ¶m, Entity *sender) {
2619 switch (messageNum) {
2620 case NM_ANIMATION_START:
2621 if (param.asInteger() == 0x01084280) {
2622 playSound(0, 0x405002D8);
2623 sendMessage(_attachedSprite, 0x480B, 0);
2624 } else if (param.asInteger() == 0x02421405) {
2625 if (_moveObjectCountdown != 0) {
2626 _moveObjectCountdown--;
2627 stContinueMoveObject();
2628 } else {
2629 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2630 }
2631 }
2632 break;
2633 default:
2634 break;
2635 }
2636 return Klaymen::hmLowLevelAnimation(messageNum, param, sender);
2637 }
2638
stMoveObject()2639 void Klaymen::stMoveObject() {
2640 if (!stStartAction(AnimationCallback(&Klaymen::stMoveObject))) {
2641 _busyStatus = 2;
2642 _acceptInput = false;
2643 _moveObjectCountdown = 8;
2644 setDoDeltaX(0);
2645 startAnimation(0x0C1CA072, 0, -1);
2646 SetUpdateHandler(&Klaymen::upMoveObject);
2647 SetMessageHandler(&Klaymen::hmMoveObject);
2648 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
2649 }
2650 }
2651
stContinueMoveObject()2652 void Klaymen::stContinueMoveObject() {
2653 _acceptInput = false;
2654 startAnimationByHash(0x0C1CA072, 0x01084280, 0);
2655 SetUpdateHandler(&Klaymen::upMoveObject);
2656 SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
2657 SetMessageHandler(&Klaymen::hmMoveObject);
2658 }
2659
suRidePlatform()2660 void Klaymen::suRidePlatform() {
2661 _x = _attachedSprite->getX() - 20;
2662 _y = _attachedSprite->getY() + 46;
2663 updateBounds();
2664 }
2665
stRidePlatform()2666 void Klaymen::stRidePlatform() {
2667 if (!stStartActionFromIdle(AnimationCallback(&Klaymen::stRidePlatform))) {
2668 _busyStatus = 1;
2669 _acceptInput = true;
2670 startAnimation(0x5420E254, 0, -1);
2671 SetUpdateHandler(&Klaymen::update);
2672 SetMessageHandler(&Klaymen::hmLowLevel);
2673 SetSpriteUpdate(&Klaymen::suRidePlatform);
2674 }
2675 }
2676
stInteractLever()2677 void Klaymen::stInteractLever() {
2678 if (!stStartAction(AnimationCallback(&Klaymen::stInteractLever))) {
2679 _busyStatus = 0;
2680 if (_isLeverDown) {
2681 stUseLeverRelease();
2682 } else {
2683 _acceptInput = false;
2684 startAnimation(0x0C303040, 0, -1);
2685 SetUpdateHandler(&Klaymen::update);
2686 SetMessageHandler(&Klaymen::hmLever);
2687 SetSpriteUpdate(&Klaymen::suUpdateDestX);
2688 NextState(&Klaymen::stPullLever);
2689 }
2690 }
2691 }
2692
stPullLever()2693 void Klaymen::stPullLever() {
2694 startAnimation(0x0D318140, 0, -1);
2695 NextState(&Klaymen::stLookLeverDown);
2696 sendMessage(_attachedSprite, NM_KLAYMEN_LOWER_LEVER, 0);
2697 }
2698
stLookLeverDown()2699 void Klaymen::stLookLeverDown() {
2700 _acceptInput = true;
2701 _isLeverDown = true;
2702 startAnimation(0x1564A2C0, 0, -1);
2703 SetUpdateHandler(&Klaymen::update);
2704 SetSpriteUpdate(&Klaymen::suUpdateDestX);
2705 NextState(&Klaymen::stWaitLeverDown);
2706 }
2707
stWaitLeverDown()2708 void Klaymen::stWaitLeverDown() {
2709 _acceptInput = true;
2710 _isLeverDown = true;
2711 startAnimation(0x4464A440, 0, -1);
2712 SetUpdateHandler(&Klaymen::update);
2713 SetMessageHandler(&Klaymen::hmLowLevel);
2714 SetSpriteUpdate(&Klaymen::suUpdateDestX);
2715 }
2716
stStartWalkingResume()2717 void Klaymen::stStartWalkingResume() {
2718 int16 frameIndex = getGlobalVar(V_KLAYMEN_FRAMEINDEX) + _walkResumeFrameIncr;
2719 if (frameIndex < 0 || frameIndex > 13)
2720 frameIndex = 0;
2721 _busyStatus = 0;
2722 _isWalking = true;
2723 _acceptInput = true;
2724 startAnimation(0x1A249001, frameIndex, -1);
2725 SetUpdateHandler(&Klaymen::update);
2726 SetMessageHandler(&Klaymen::hmWalking);
2727 SetSpriteUpdate(&Klaymen::suWalkingFirst);
2728 NextState(&Klaymen::stUpdateWalkingFirst);
2729 FinalizeState(&Klaymen::evStartWalkingDone);
2730 }
2731
upPeekInsideBlink()2732 void Klaymen::upPeekInsideBlink() {
2733 update();
2734 ++_blinkCounter;
2735 if (_blinkCounter >= _blinkCounterMax)
2736 stPeekInsideBlink();
2737 }
2738
stPeekInside()2739 void Klaymen::stPeekInside() {
2740 _busyStatus = 0;
2741 _acceptInput = true;
2742 startAnimation(0xAC20C012, 8, 37);
2743 SetUpdateHandler(&Klaymen::update);
2744 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2745 SetSpriteUpdate(NULL);
2746 NextState(&Klaymen::stPeekInsideBlink);
2747 }
2748
stPeekInsideReturn()2749 void Klaymen::stPeekInsideReturn() {
2750 _busyStatus = 1;
2751 _acceptInput = false;
2752 startAnimation(0xAC20C012, 43, 49);
2753 SetUpdateHandler(&Klaymen::update);
2754 SetMessageHandler(&Klaymen::hmLowLevelAnimation);
2755 SetSpriteUpdate(NULL);
2756 }
2757
stPeekInsideBlink()2758 void Klaymen::stPeekInsideBlink() {
2759 _busyStatus = 0;
2760 _acceptInput = true;
2761 startAnimation(0xAC20C012, 38, 42);
2762 _newStickFrameIndex = 42;
2763 SetUpdateHandler(&Klaymen::upPeekInsideBlink);
2764 SetMessageHandler(&Klaymen::hmLowLevel);
2765 SetSpriteUpdate(NULL);
2766 _blinkCounter = 0;
2767 _blinkCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
2768 }
2769
2770 } // End of namespace Neverhood
2771