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 &param) {
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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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 &param, 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