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 "trecision/anim.h"
24 #include "trecision/dialog.h"
25 #include "trecision/logic.h"
26 #include "trecision/pathfinding3d.h"
27 #include "trecision/scheduler.h"
28 #include "trecision/text.h"
29 #include "trecision/trecision.h"
30 #include "trecision/video.h"
31 
32 namespace Trecision {
33 
34 #define ATF_WAITTEXT 1
35 
AnimTypeManager(TrecisionEngine * vm)36 AnimTypeManager::AnimTypeManager(TrecisionEngine *vm) : _vm(vm) {
37 	for (int i = 0; i < 3; ++i) {
38 		_animType[i]._curFrame = 1;
39 		_animType[i]._lastFrame = 0;
40 		_animType[i]._object = 0;
41 		_animType[i]._status = 0;
42 		_animType[i]._curAnim = nullptr;
43 	}
44 
45 	_oneSpeakDialogCount = 0;
46 }
47 
~AnimTypeManager()48 AnimTypeManager::~AnimTypeManager() {
49 
50 }
51 
executeAtFrameDoit(ATFHandle * h,int doit,uint16 objectId)52 void AnimTypeManager::executeAtFrameDoit(ATFHandle *h, int doit, uint16 objectId) {
53 	SAnim *anim = &_vm->_animMgr->_animTab[_vm->_room[_vm->_curRoom]._bkgAnim];
54 
55 	switch (doit) {
56 	case fCLROBJSTATUS:
57 		_vm->setObjectVisible(objectId, false);
58 		break;
59 	case fSETOBJSTATUS:
60 		_vm->setObjectVisible(objectId, true);
61 		break;
62 	case fONETIME:
63 		_vm->setObjectAnim(objectId, 0);
64 		break;
65 	case fCREPACCIO:
66 		if (_vm->_room[kRoom2E].hasExtra())
67 			_vm->_obj[oCRACK2E]._position = 7;
68 		else
69 			_vm->_obj[oCRACK2E]._position = 6;
70 		break;
71 	case fSERPVIA:
72 		_vm->_scheduler->doEvent(_vm->_snake52._class, _vm->_snake52._event, _vm->_snake52._priority, _vm->_snake52._u16Param1, _vm->_snake52._u16Param2, _vm->_snake52._u8Param, _vm->_snake52._u32Param);
73 		break;
74 	case fPIRANHA:
75 		_vm->setObjectAnim(oLUCCHETTO53, 0);
76 		_vm->setObjectAnim(oGRATAC53, 0);
77 		_vm->setObjectAnim(oGRATAA53, 0);
78 		_vm->_obj[oLUCCHETTO53]._action = 1240;
79 		_vm->_obj[oGRATAC53]._action = 1243;
80 		_vm->_obj[oGRATAA53]._action = 1246;
81 		_vm->_obj[oLAGO53]._examine = 1237;
82 		break;
83 	case fMOREAU:
84 		_vm->setObjectAnim(oWINDOWB58, 0);
85 		_vm->_obj[oWINDOWB58]._action = 1358;
86 		break;
87 	case fDOOR58:
88 		_vm->_scheduler->leftClick(468, 180 + TOP);
89 		break;
90 	case fHELLEN:
91 		_vm->_scheduler->leftClick(336, 263 + TOP);
92 		break;
93 	case fVALVEON34:
94 		if (!(_vm->_dialogMgr->isDialogFinished(616)) && // if the fmv is not done
95 			(_vm->isObjectVisible(oTUBOA34)) &&                      // if there's a cut pipe
96 			!(_vm->isObjectVisible(oTUBOFT34)))                      // if there's not tube outside
97 			_vm->_animMgr->smkToggleTrackAudio(0, 2, true);
98 		break;
99 	case fVALVEOFF34:
100 		_vm->_animMgr->smkToggleTrackAudio(0, 2, false);
101 		break;
102 
103 	case fCHARACTEROFF:
104 		_vm->_flagShowCharacter = false;
105 		break;
106 	case fCHARACTERON:
107 		_vm->_flagShowCharacter = true;
108 		break;
109 	case fCHARACTERFOREGROUND:
110 		_vm->_pathFind->setForcedActorPos(BOX_FOREGROUND);
111 		break;
112 	case fCHARACTERBACKGROUND:
113 		_vm->_pathFind->setForcedActorPos(BOX_BACKGROUND);
114 		break;
115 	case fCHARACTERNORM:
116 		_vm->_pathFind->setForcedActorPos(BOX_NORMAL);
117 		break;
118 	case fSETEXTRA:
119 		_vm->_obj[objectId].setFlagExtra(true);
120 		break;
121 	case fCLREXTRA:
122 		_vm->_obj[objectId].setFlagExtra(false);
123 		break;
124 
125 	case fANIMOFF1:
126 		anim->toggleAnimArea(1, false);
127 		if (_vm->_curRoom == kRoom11 ||
128 			_vm->_curRoom == kRoom1D ||
129 			_vm->_curRoom == kRoom14 ||
130 			_vm->_curRoom == kRoom22 ||
131 			_vm->_curRoom == kRoom48 ||
132 			_vm->_curRoom == kRoom4P)
133 			_vm->_animMgr->smkToggleTrackAudio(0, 1, false);
134 		break;
135 	case fANIMOFF2:
136 		anim->toggleAnimArea(2, false);
137 		if (_vm->_curRoom == kRoom2E)
138 			_vm->_animMgr->smkToggleTrackAudio(0, 2, false);
139 		break;
140 	case fANIMOFF3:
141 		anim->toggleAnimArea(3, false);
142 		break;
143 	case fANIMOFF4:
144 		anim->toggleAnimArea(4, false);
145 		if (_vm->_curRoom == kRoom28)
146 			_vm->_animMgr->smkToggleTrackAudio(0, 1, false);
147 		break;
148 
149 	case fANIMON1:
150 		anim->toggleAnimArea(1, true);
151 		if (_vm->_curRoom == kRoom14 || _vm->_curRoom == kRoom1D || _vm->_curRoom == kRoom22 || _vm->_curRoom == kRoom48 || _vm->_curRoom == kRoom4P) {
152 			_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
153 		}
154 		break;
155 	case fANIMON2:
156 		anim->toggleAnimArea(2, true);
157 		if (_vm->_curRoom == kRoom2E)
158 			_vm->_animMgr->smkToggleTrackAudio(0, 2, true);
159 		break;
160 	case fANIMON3:
161 		anim->toggleAnimArea(3, true);
162 		break;
163 	case fANIMON4:
164 		anim->toggleAnimArea(4, true);
165 		break;
166 	case fENDDEMO:
167 		_vm->demoOver();
168 		_vm->quitGame();
169 		break;
170 	case fSTOP2TXT:
171 		h->_status |= ATF_WAITTEXT;
172 		// Sets a flag that is always cleared when you finish speaking
173 		// if the flag is cleared the anim no longer plays
174 		// (to be done in the smacker player)
175 		// also the counters in next() stops
176 		break;
177 	default:
178 		break;
179 	}
180 }
181 
processAtFrame(ATFHandle * h,int type,int atf)182 void AnimTypeManager::processAtFrame(ATFHandle *h, int type, int atf) {
183 	const uint16 index = h->_curAnim->_atFrame[atf]._index;
184 
185 	switch (type) {
186 	case ATFTEXT:
187 		_vm->_textMgr->characterSayInAction(index);
188 		break;
189 	case ATFTEXTACT:
190 		_vm->_textMgr->characterSayInAction(_vm->_obj[h->_object]._action);
191 		break;
192 	case ATFTEXTEX:
193 		_vm->_textMgr->characterSayInAction(_vm->_obj[h->_object]._examine);
194 		break;
195 	case ATFCLR:
196 		_vm->setObjectVisible(index, false);
197 		break;
198 	case ATFCLRI:
199 		_vm->removeIcon(index);
200 		break;
201 	case ATFCEX:
202 		_vm->_obj[h->_object]._examine = index;
203 		break;
204 	case ATFCACT:
205 		_vm->_obj[h->_object]._action = index;
206 		break;
207 	case ATFSET:
208 		_vm->setObjectVisible(index, true);
209 		break;
210 	case ATFSETI:
211 		_vm->addIcon(index);
212 		break;
213 	case ATFDO:
214 		executeAtFrameDoit(h, index, h->_object);
215 		break;
216 	case ATFROOM:
217 		_vm->changeRoom(index);
218 		break;
219 	case ATFSETPOS:
220 		_vm->_pathFind->setPosition(index);
221 		break;
222 	case ATFDIALOG:
223 		_vm->_dialogMgr->playDialog(index);
224 		break;
225 	case ATFCOBJANIM:
226 		_vm->_obj[h->_object]._anim = index;
227 		break;
228 	case ATFCOBJBOX:
229 		_vm->_obj[h->_object]._nbox = index;
230 		break;
231 	case ATFCOBJPOS:
232 		_vm->_obj[h->_object]._position = index;
233 		break;
234 	case ATFSETFORE:
235 		_vm->_obj[index]._nbox = BOX_FOREGROUND;
236 		break;
237 	case ATFSETBACK:
238 		_vm->_obj[index]._nbox = BOX_BACKGROUND;
239 		break;
240 	case ATFSWITCH:
241 		_vm->setObjectVisible(index, !_vm->isObjectVisible(index));
242 		break;
243 	case ATFSETROOMT:
244 		_vm->_logicMgr->setupAltRoom(index, true);
245 		break;
246 	case ATFSETROOMF:
247 		_vm->_logicMgr->setupAltRoom(index, false);
248 		break;
249 	case ATFREADBOX:
250 		switch (index) {
251 		case 1: {
252 			const Common::String filename = Common::String::format("%s.3d", _vm->_room[_vm->_curRoom]._baseName);
253 			_vm->read3D(filename);
254 			_vm->_room[_vm->_curRoom].setExtra(false);
255 			}
256 			break;
257 		case 2: {
258 			const Common::String filename = Common::String::format("%s2.3d", _vm->_room[_vm->_curRoom]._baseName);
259 			_vm->read3D(filename);
260 			_vm->_room[_vm->_curRoom].setExtra(true);
261 			if (_vm->_curRoom == kRoom37)
262 				_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
263 			} break;
264 		default:
265 			break;
266 		}
267 		break;
268 	case ATFONESPEAK:
269 		switch (index) {
270 		case 1:	// Storekeeper's wife
271 			if (_vm->_room[kRoom1D].hasExtra())
272 				break;
273 
274 			// Quotes spoken by the storekeeper's wife while she is in the cellar
275 			_vm->_textMgr->someoneSay(307 + _oneSpeakDialogCount, oDONNA1D);
276 			if (_oneSpeakDialogCount < 6)
277 				++_oneSpeakDialogCount;
278 			break;
279 
280 		case 2:	// Storekeeper
281 			// Quote when you enter the liquor store: "Ah, it's you again... look round
282 			// if you want, but don't disturb me, I've got a lot to do"
283 			_vm->_textMgr->someoneSay(1788, ocNEGOZIANTE1A);
284 			break;
285 		default:
286 			break;
287 		}
288 		break;
289 	case ATFEND:
290 		_vm->demoOver();
291 		_vm->quitGame();
292 		break;
293 	default:
294 		break;
295 	}
296 }
297 
init(uint16 an,uint16 obj)298 void AnimTypeManager::init(uint16 an, uint16 obj) {
299 	SAnim *anim = &_vm->_animMgr->_animTab[an];
300 	ATFHandle *handle = &_animType[kAnimTypeCharacter];
301 
302 	if (anim->_flag & SMKANIM_BKG)
303 		handle = &_animType[kAnimTypeBackground];
304 	if (anim->_flag & SMKANIM_ICON)
305 		handle = &_animType[kAnimTypeIcon];
306 
307 	handle->_curAnim = anim;
308 	handle->_object = obj ? obj : _vm->_curObj;
309 	handle->_curFrame = 0;
310 	handle->_lastFrame = -1;
311 	handle->_status = 0;
312 }
313 
next()314 void AnimTypeManager::next() {
315 	for (int i = 0; i < 3; ++i) {
316 		if (!(_animType[i]._status & ATF_WAITTEXT) || !_vm->_flagCharacterSpeak)
317 			++_animType[i]._curFrame;
318 	}
319 }
320 
end(int type)321 void AnimTypeManager::end(int type) {
322 	ATFHandle *h = &_animType[type];
323 	SAnim *anim = h->_curAnim;
324 	h->_curFrame = 0;
325 
326 	// if this ATFrame has already been handled
327 	if (h->_curFrame == h->_lastFrame)
328 		return;
329 
330 	h->_lastFrame = h->_curFrame;
331 
332 	for (int32 i = 0; i < MAXATFRAME; ++i) {
333 		// if it's time to run this AtFrame
334 		if (anim->_atFrame[i]._numFrame == 0 && anim->_atFrame[i]._type) {
335 			const uint8 area = anim->_atFrame[i]._area;
336 			if ( area == 0 ||
337 				(area == 1 && anim->isAnimAreaShown(1)) ||
338 				(area == 2 && anim->isAnimAreaShown(2)) ||
339 				(area == 3 && anim->isAnimAreaShown(3)) ||
340 				(area == 4 && anim->isAnimAreaShown(4)))
341 				processAtFrame(h, anim->_atFrame[i]._type, i);
342 		}
343 	}
344 
345 	h->_curAnim = nullptr;
346 }
347 
handler(int type)348 void AnimTypeManager::handler(int type) {
349 	ATFHandle *h = &_animType[type];
350 	SAnim *anim = h->_curAnim;
351 	if (anim == nullptr)
352 		return;
353 
354 	if (h->_curFrame == 0)
355 		++h->_curFrame;
356 	// if this ATFrame has already been applied
357 	if (h->_curFrame <= h->_lastFrame)
358 		return;
359 
360 	for (int32 i = 0; i < MAXATFRAME; ++i) {
361 		// if it's time to run this AtFrame
362 		if (anim->_atFrame[i]._numFrame > h->_lastFrame &&
363 			anim->_atFrame[i]._numFrame <= h->_curFrame &&
364 			anim->_atFrame[i]._numFrame != 0) {
365 			const uint8 child = anim->_atFrame[i]._area;
366 			if ( child == 0 ||
367 				(child == 1 && anim->isAnimAreaShown(1)) ||
368 				(child == 2 && anim->isAnimAreaShown(2)) ||
369 				(child == 3 && anim->isAnimAreaShown(3)) ||
370 				(child == 4 && anim->isAnimAreaShown(4)))
371 				processAtFrame(h, anim->_atFrame[i]._type, i);
372 		}
373 	}
374 
375 	// set _lastFrame
376 	h->_lastFrame = h->_curFrame;
377 }
378 
379 } // End of namespace Trecision
380