1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "neverhood/modules/module2100_sprites.h"
24 
25 namespace Neverhood {
26 
AsScene2101Door(NeverhoodEngine * vm,bool isOpen)27 AsScene2101Door::AsScene2101Door(NeverhoodEngine *vm, bool isOpen)
28 	: AnimatedSprite(vm, 1100) {
29 
30 	createSurface(100, 328, 347);
31 	_x = 320;
32 	_y = 240;
33 	SetUpdateHandler(&AnimatedSprite::update);
34 	SetMessageHandler(&AsScene2101Door::handleMessage);
35 	if (isOpen) {
36 		startAnimation(0x0C202B9C, -1, -1);
37 		_newStickFrameIndex = STICK_LAST_FRAME;
38 	} else
39 		setVisible(false);
40 }
41 
handleMessage(int messageNum,const MessageParam & param,Entity * sender)42 uint32 AsScene2101Door::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
43 	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
44 	switch (messageNum) {
45 	case NM_ANIMATION_STOP:
46 		gotoNextState();
47 		break;
48 	case NM_KLAYMEN_OPEN_DOOR:
49 		stOpenDoor();
50 		break;
51 	case NM_KLAYMEN_CLOSE_DOOR:
52 		stCloseDoor();
53 		break;
54 	default:
55 		break;
56 	}
57 	return messageResult;
58 }
59 
stOpenDoor()60 void AsScene2101Door::stOpenDoor() {
61 	startAnimation(0x0C202B9C, 0, -1);
62 	_newStickFrameIndex = STICK_LAST_FRAME;
63 	setVisible(true);
64 	playSound(0, calcHash("fxDoorOpen32"));
65 }
66 
stCloseDoor()67 void AsScene2101Door::stCloseDoor() {
68 	startAnimation(0xC222A8D4, 0, -1);
69 	_newStickFrameIndex = STICK_LAST_FRAME;
70 	setVisible(true);
71 	playSound(0, calcHash("fxDoorClose32"));
72 	NextState(&AsScene2101Door::stCloseDoorDone);
73 }
74 
stCloseDoorDone()75 void AsScene2101Door::stCloseDoorDone() {
76 	stopAnimation();
77 	setVisible(false);
78 }
79 
AsScene2101HitByDoorEffect(NeverhoodEngine * vm,Sprite * klaymen)80 AsScene2101HitByDoorEffect::AsScene2101HitByDoorEffect(NeverhoodEngine *vm, Sprite *klaymen)
81 	: AnimatedSprite(vm, 1400), _klaymen(klaymen) {
82 
83 	SetUpdateHandler(&AnimatedSprite::update);
84 	SetMessageHandler(&AsScene2101HitByDoorEffect::handleMessage);
85 	createSurface(1200, 88, 165);
86 	setVisible(false);
87 }
88 
handleMessage(int messageNum,const MessageParam & param,Entity * sender)89 uint32 AsScene2101HitByDoorEffect::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
90 	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
91 	switch (messageNum) {
92 	case 0x2001:
93 		_x = _klaymen->getX();
94 		_y = _klaymen->getY() - 132;
95 		startAnimation(0x0422255A, 0, -1);
96 		setVisible(true);
97 		break;
98 	case NM_ANIMATION_STOP:
99 		stopAnimation();
100 		setVisible(false);
101 		break;
102 	default:
103 		break;
104 	}
105 	return messageResult;
106 }
107 
SsCommonFloorButton(NeverhoodEngine * vm,Scene * parentScene,uint32 fileHash1,uint32 fileHash2,int surfacePriority,uint32 soundFileHash)108 SsCommonFloorButton::SsCommonFloorButton(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash)
109 	: StaticSprite(vm, 1100), _parentScene(parentScene), _countdown(0),
110 	_fileHash1(fileHash1), _fileHash2(fileHash2), _soundFileHash(soundFileHash) {
111 
112 	SetUpdateHandler(&SsCommonFloorButton::update);
113 	SetMessageHandler(&SsCommonFloorButton::handleMessage);
114 	if (_soundFileHash == 0)
115 		_soundFileHash = 0x44141000;
116 	createSurface(1010, 61, 30);
117 	if (_fileHash1)
118 		loadSprite(_fileHash1, kSLFDefDrawOffset | kSLFDefPosition);
119 	else
120 		setVisible(false);
121 }
122 
update()123 void SsCommonFloorButton::update() {
124 	if (_countdown != 0 && (--_countdown == 0)) {
125 		sendMessage(_parentScene, NM_PRIORITY_CHANGE, 1010);
126 		if (_fileHash1)
127 			loadSprite(_fileHash1, kSLFDefDrawOffset | kSLFDefPosition);
128 		else
129 			setVisible(false);
130 	}
131 }
132 
handleMessage(int messageNum,const MessageParam & param,Entity * sender)133 uint32 SsCommonFloorButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
134 	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
135 	switch (messageNum) {
136 	case 0x480B:
137 		sendMessage(_parentScene, 0x480B, 0);
138 		setVisible(true);
139 		sendMessage(_parentScene, NM_PRIORITY_CHANGE, 990);
140 		loadSprite(_fileHash2, kSLFDefDrawOffset | kSLFDefPosition);
141 		_countdown = 16;
142 		playSound(0, _soundFileHash);
143 		break;
144 	default:
145 		break;
146 	}
147 	return messageResult;
148 }
149 
KmScene2101(NeverhoodEngine * vm,Scene * parentScene,int16 x,int16 y)150 KmScene2101::KmScene2101(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
151 	: Klaymen(vm, parentScene, x, y) {
152 
153 	// Empty
154 }
155 
xHandleMessage(int messageNum,const MessageParam & param)156 uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam &param) {
157 	uint32 messageResult = 0;
158 	switch (messageNum) {
159 	case NM_ANIMATION_UPDATE:
160 		_isSittingInTeleporter = param.asInteger() != 0;
161 		messageResult = 1;
162 		break;
163 	case 0x4001:
164 	case 0x4800:
165 		startWalkToX(param.asPoint().x, false);
166 		break;
167 	case NM_KLAYMEN_STAND_IDLE:
168 		if (_isSittingInTeleporter)
169 			GotoState(&Klaymen::stSitIdleTeleporter);
170 		else
171 			GotoState(&Klaymen::stTryStandIdle);
172 		break;
173 	case 0x4811:
174 		GotoState(&KmScene2101::stHitByDoor);
175 		break;
176 	case NM_KLAYMEN_PICKUP:
177 		if (param.asInteger() == 2)
178 			GotoState(&Klaymen::stPickUpNeedle);
179 		else if (param.asInteger() == 1)
180 			GotoState(&Klaymen::stPickUpTube);
181 		else
182 			GotoState(&Klaymen::stPickUpGeneric);
183 		break;
184 	case NM_KLAYMEN_PRESS_BUTTON:
185 		if (param.asInteger() == 1)
186 			GotoState(&Klaymen::stPressButton);
187 		else if (param.asInteger() == 2)
188 			GotoState(&Klaymen::stPressFloorButton);
189 		else
190 			GotoState(&Klaymen::stPressButtonSide);
191 		break;
192 	case 0x4817:
193 		setDoDeltaX(param.asInteger());
194 		gotoNextStateExt();
195 		break;
196 	case 0x481B:
197 		if (param.asPoint().y != 0)
198 			startWalkToXDistance(param.asPoint().y, param.asPoint().x);
199 		else
200 			startWalkToAttachedSpriteXDistance(param.asPoint().x);
201 		break;
202 	case NM_KLAYMEN_TURN_TO_USE:
203 		if (_isSittingInTeleporter)
204 			GotoState(&Klaymen::stTurnToUseInTeleporter);
205 		break;
206 	case NM_KLAYMEN_RETURN_FROM_USE:
207 		if (_isSittingInTeleporter)
208 			GotoState(&Klaymen::stReturnFromUseInTeleporter);
209 		break;
210 	case 0x4834:
211 		GotoState(&Klaymen::stStepOver);
212 		break;
213 	case 0x4835:
214 		sendMessage(_parentScene, 0x2000, 1);
215 		_isSittingInTeleporter = true;
216 		GotoState(&Klaymen::stSitInTeleporter);
217 		break;
218 	case 0x4836:
219 		sendMessage(_parentScene, 0x2000, 0);
220 		_isSittingInTeleporter = false;
221 		GotoState(&Klaymen::stGetUpFromTeleporter);
222 		break;
223 	case 0x483D:
224 		teleporterAppear(0xFF290E30);
225 		break;
226 	case 0x483E:
227 		teleporterDisappear(0x9A28CA1C);
228 		break;
229 	default:
230 		break;
231 	}
232 	return messageResult;
233 }
234 
hmHitByDoor(int messageNum,const MessageParam & param,Entity * sender)235 uint32 KmScene2101::hmHitByDoor(int messageNum, const MessageParam &param, Entity *sender) {
236 	uint32 messageResult = hmLowLevelAnimation(messageNum, param, sender);
237 	int16 speedUpFrameIndex;
238 	switch (messageNum) {
239 	case 0x1008:
240 		speedUpFrameIndex = getFrameIndex(kKlaymenSpeedUpHash);
241 		if (_currFrameIndex < speedUpFrameIndex) {
242 			startAnimation(0x35AA8059, speedUpFrameIndex, -1);
243 			_y = 438;
244 		}
245 		messageResult = 0;
246 		break;
247 	case NM_ANIMATION_START:
248 		if (param.asInteger() == 0x1A1A0785) {
249 			playSound(0, 0x40F0A342);
250 		} else if (param.asInteger() == 0x60428026) {
251 			playSound(0, 0x40608A59);
252 		}
253 		break;
254 	default:
255 		break;
256 	}
257 	return messageResult;
258 }
259 
stHitByDoor()260 void KmScene2101::stHitByDoor() {
261 	_busyStatus = 1;
262 	_acceptInput = false;
263 	startAnimation(0x35AA8059, 0, -1);
264 	SetUpdateHandler(&Klaymen::update);
265 	SetMessageHandler(&KmScene2101::hmHitByDoor);
266 	SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
267 	playSound(0, 0x402E82D4);
268 }
269 
270 } // End of namespace Neverhood
271