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 "hopkins/objects.h"
24 
25 #include "hopkins/dialogs.h"
26 #include "hopkins/files.h"
27 #include "hopkins/globals.h"
28 #include "hopkins/hopkins.h"
29 
30 #include "common/system.h"
31 #include "graphics/palette.h"
32 #include "common/file.h"
33 #include "common/rect.h"
34 #include "engines/util.h"
35 
36 namespace Hopkins {
37 
ObjectsManager(HopkinsEngine * vm)38 ObjectsManager::ObjectsManager(HopkinsEngine *vm) {
39 	_vm = vm;
40 
41 	for (int i = 0; i < 6; ++i)
42 		Common::fill((byte *)&_sprite[i], (byte *)&_sprite[i] + sizeof(SpriteItem), 0);
43 
44 	for (int i = 0; i < 36; ++i) {
45 		Common::fill((byte *)&_bob[i], (byte *)&_bob[i] + sizeof(BobItem), 0);
46 		Common::fill((byte *)&_lockedAnims[i], (byte *)&_lockedAnims[i] + sizeof(LockAnimItem), 0);
47 	}
48 
49 	for (int i = 0; i < 30; ++i) {
50 		Common::fill((byte *)&_vBob[i], (byte *)&_vBob[i] + sizeof(VBobItem), 0);
51 	}
52 
53 	for (int i = 0; i < 300; ++i)
54 		Common::fill((byte *)&_objectAuthIcons[i], (byte *)&_objectAuthIcons[i] + sizeof(ObjectAuthIcon), 0);
55 
56 	_sortedDisplayCount = 0;
57 	for (int i = 0; i < 51; ++i)
58 		Common::fill((byte *)&_sortedDisplay[i], (byte *)&_sortedDisplay[i] + sizeof(SortItem), 0);
59 
60 	for (int i = 0; i < 25; ++i)
61 		Common::fill((byte *)&_hidingItem[i], (byte *)&_hidingItem[i] + sizeof(HidingItem), 0);
62 
63 	for (int i = 0; i < 6; ++i)
64 		_hidingItemData[i] = NULL;
65 
66 	for (int i = 0; i < 6; ++i)
67 		Common::fill((byte *)&_liste[i], (byte *)&_liste[i] + sizeof(ListeItem), 0);
68 
69 	for (int i = 0; i < 35; ++i)
70 		Common::fill((byte *)&_liste2[i], (byte *)&_liste2[i] + sizeof(ListeItem), 0);
71 
72 	_helicopterFl = false;
73 	_priorityFl = false;
74 	_oldBorderPos = Common::Point(0, 0);
75 	_oldBorderSpriteIndex = 0;
76 	_borderPos = Common::Point(0, 0);
77 	_borderSpriteIndex = 0;
78 	_saveLoadX = _saveLoadY = 0;
79 	_oldCharacterPosX = _oldCharacterPosY = 0;
80 	_eraseVisibleCounter = 0;
81 	_saveLoadSprite = NULL;
82 	_saveLoadSprite2 = NULL;
83 	_spritePtr = NULL;
84 	_oldSpriteData = NULL;
85 	_saveLoadFl = false;
86 	_visibleFl = false;
87 	_zoneNum = 0;
88 	_forceZoneFl = false;
89 	_changeVerbFl = false;
90 	_verb = 0;
91 	_changeHeadFl = false;
92 	_disableFl = false;
93 	_twoCharactersFl = false;
94 	_characterPos = Common::Point(0, 0);
95 	_startSpriteIndex = 0;
96 	_jumpVerb = 0;
97 	_jumpZone = 0;
98 	_oldSpriteIndex = 0;
99 	_oldFrameIndex = 0;
100 	_oldFlipFl = false;
101 	_curObjectIndex = 0;
102 	_forestFl = false;
103 	_mapCarPosX = _mapCarPosY = 0;
104 	_forestSprite = NULL;
105 	_gestureBuf = NULL;
106 	_curGestureFile = 0;
107 	_headSprites = NULL;
108 	_homeRateCounter = 0;
109 	_lastDirection = DIR_NONE;
110 	_oldDirection = DIR_NONE;
111 	_oldDirectionSpriteIdx = 59;
112 	_objectWidth = _objectHeight = 0;
113 	_hidingActiveFl = false;
114 	_curObjectFileNum = 0;
115 	_objectDataBuf = NULL;
116 	_charactersEnabledFl = false;
117 	_refreshBobMode10Fl = false;
118 }
119 
~ObjectsManager()120 ObjectsManager::~ObjectsManager() {
121 	_vm->_globals->freeMemory(_forestSprite);
122 	_vm->_globals->freeMemory(_gestureBuf);
123 	_vm->_globals->freeMemory(_headSprites);
124 	_vm->_globals->freeMemory(_objectDataBuf);
125 	clearVBob();
126 
127 	for (int idx = 0; idx < 6; ++idx)
128 		_hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]);
129 }
130 
clearAll()131 void ObjectsManager::clearAll() {
132 	_forestFl = false;
133 	_forestSprite = _vm->_globals->freeMemory(_forestSprite);
134 	_curGestureFile = 0;
135 	_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
136 	_curObjectFileNum = 0;
137 
138 	for (int idx = 0; idx < 6; ++idx)
139 		_hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]);
140 
141 	_objectDataBuf = _vm->_globals->freeMemory(_objectDataBuf);
142 	initVBob();
143 }
144 
145 // Load Object
loadObjects()146 void ObjectsManager::loadObjects() {
147 	byte *data = _vm->_fileIO->loadFile("OBJET.DAT");
148 	byte *srcP = data;
149 
150 	for (int idx = 0; idx < 300; ++idx) {
151 		ObjectAuthIcon *objectAuthIcon = &_objectAuthIcons[idx];
152 		objectAuthIcon->_objectFileNum = *srcP++;
153 		objectAuthIcon->_idx = *srcP++;
154 		objectAuthIcon->_flag1 = *srcP++;
155 		objectAuthIcon->_flag2 = *srcP++;
156 		objectAuthIcon->_flag3 = *srcP++;
157 		objectAuthIcon->_flag4 = *srcP++;
158 		objectAuthIcon->_flag5 = *srcP++;
159 		objectAuthIcon->_flag6 = *srcP++;
160 	}
161 
162 	_vm->_globals->freeMemory(data);
163 }
164 
165 // Reset Hiding Items
resetHidingItems()166 void ObjectsManager::resetHidingItems() {
167 	for (int idx = 1; idx <= 5; ++idx) {
168 		_hidingItemData[idx] = _vm->_globals->freeMemory(_hidingItemData[idx]);
169 	}
170 
171 	for (int idx = 0; idx <= 20; ++idx) {
172 		HidingItem *hid = &_hidingItem[idx];
173 		hid->_spriteData = NULL;
174 		hid->_x = 0;
175 		hid->_y = 0;
176 		hid->_spriteIndex = 0;
177 		hid->_useCount = 0;
178 		hid->_width = 0;
179 		hid->_height = 0;
180 		hid->_resetUseCount = false;
181 		hid->_yOffset = 0;
182 	}
183 
184 	_hidingActiveFl = false;
185 }
186 
187 /**
188  * Change Object
189  */
changeObject(int objIndex)190 void ObjectsManager::changeObject(int objIndex) {
191 	_vm->_events->_objectBuf = loadObjectFromFile(objIndex, true);
192 	_curObjectIndex = objIndex;
193 }
194 
loadObjectFromFile(int objIndex,bool mode)195 byte *ObjectsManager::loadObjectFromFile(int objIndex, bool mode) {
196 	byte *dataP = NULL;
197 	int objectFileNum = _objectAuthIcons[objIndex]._objectFileNum;
198 	int idx = _objectAuthIcons[objIndex]._idx;
199 
200 	if (mode)
201 		++idx;
202 
203 	if (objectFileNum != _curObjectFileNum) {
204 		if (_objectDataBuf)
205 			removeObjectDataBuf();
206 		if (objectFileNum == 1) {
207 			_objectDataBuf = loadSprite("OBJET1.SPR");
208 		}
209 		_curObjectFileNum = objectFileNum;
210 	}
211 
212 	int width = getWidth(_objectDataBuf, idx);
213 	int height = getHeight(_objectDataBuf, idx);
214 	_objectWidth = width;
215 	_objectHeight = height;
216 
217 	if (mode) {
218 		sprite_alone(_objectDataBuf, _vm->_events->_objectBuf, idx);
219 		dataP = _vm->_events->_objectBuf;
220 	} else {
221 		dataP = _vm->_globals->allocMemory(height * width);
222 		if (dataP == NULL)
223 			error("CAPTURE_OBJET");
224 
225 		capture_mem_sprite(_objectDataBuf, dataP, idx);
226 	}
227 
228 	return dataP;
229 }
230 
231 /**
232  * Remove an Object from the inventory
233  */
removeObject(int objIndex)234 void ObjectsManager::removeObject(int objIndex) {
235 	int idx;
236 	for (idx = 1; idx <= 32; ++idx) {
237 		if (_vm->_globals->_inventory[idx] == objIndex)
238 			break;
239 	}
240 
241 	if (idx <= 32) {
242 		if (idx == 32) {
243 			_vm->_globals->_inventory[32] = 0;
244 		} else {
245 			for (int i = idx; i < 32; ++i)
246 				_vm->_globals->_inventory[i] = _vm->_globals->_inventory[i + 1];
247 		}
248 	}
249 	changeObject(14);
250 
251 }
252 
253 /**
254  * Set Offset XY
255  */
setOffsetXY(byte * data,int idx,int xp,int yp,bool isSize)256 void ObjectsManager::setOffsetXY(byte *data, int idx, int xp, int yp, bool isSize) {
257 	byte *startP = data + 3;
258 	for (int i = idx; i; --i)
259 		startP += READ_LE_UINT32(startP) + 16;
260 
261 	byte *rectP = startP + 8;
262 	if (isSize) {
263 		// Set size
264 		byte *pointP = rectP + 4;
265 		WRITE_LE_UINT16(pointP, xp);
266 		WRITE_LE_UINT16(pointP + 2, yp);
267 	} else {
268 		// Set position
269 		WRITE_LE_UINT16(rectP, xp);
270 		WRITE_LE_UINT16(rectP + 2, yp);
271 	}
272 }
273 
getOffsetX(const byte * spriteData,int spriteIndex,bool isSize)274 int ObjectsManager::getOffsetX(const byte *spriteData, int spriteIndex, bool isSize) {
275 	const byte *data = spriteData + 3;
276 	for (int i = spriteIndex; i; --i)
277 		data += READ_LE_UINT32(data) + 16;
278 
279 	int result;
280 	if (isSize)
281 		result = READ_LE_INT16(data + 12);
282 	else
283 		result = READ_LE_INT16(data + 8);
284 
285 	return result;
286 }
287 
getOffsetY(const byte * spriteData,int spriteIndex,bool isSize)288 int ObjectsManager::getOffsetY(const byte *spriteData, int spriteIndex, bool isSize) {
289 	const byte *data = spriteData + 3;
290 	for (int i = spriteIndex; i; --i)
291 		data += READ_LE_UINT32(data) + 16;
292 
293 	int result;
294 	if (isSize)
295 		result = READ_LE_INT16(data + 14);
296 	else
297 		result = READ_LE_INT16(data + 10);
298 
299 	return result;
300 }
301 
302 /**
303  * Get Width
304  */
getWidth(const byte * objectData,int idx)305 int ObjectsManager::getWidth(const byte *objectData, int idx) {
306 	const byte *rectP = objectData + 3;
307 	for (int i = idx; i; --i)
308 		rectP += READ_LE_UINT32(rectP) + 16;
309 
310 	return READ_LE_INT16(rectP + 4);
311 }
312 
313 /**
314  * Get height
315  */
getHeight(const byte * objectData,int idx)316 int ObjectsManager::getHeight(const byte *objectData, int idx) {
317 	const byte *rectP = objectData + 3;
318 	for (int i = idx; i; --i)
319 		rectP += READ_LE_UINT32(rectP) + 16;
320 
321 	return READ_LE_INT16(rectP + 6);
322 }
323 
sprite_alone(const byte * objectData,byte * sprite,int objIndex)324 void ObjectsManager::sprite_alone(const byte *objectData, byte *sprite, int objIndex) {
325 	const byte *objP = objectData + 3;
326 	for (int i = objIndex; i; --i) {
327 		objP += READ_LE_UINT32(objP) + 16;
328 	}
329 
330 	objP += 4;
331 	int result = READ_LE_INT16(objP) * READ_LE_INT16(objP + 2);
332 
333 	memcpy(sprite + 3, objP - 4, result + 16);
334 }
335 
capture_mem_sprite(const byte * objectData,byte * sprite,int objIndex)336 void ObjectsManager::capture_mem_sprite(const byte *objectData, byte *sprite, int objIndex) {
337 	const byte *objP = objectData + 3;
338 	for (int i = objIndex; i; --i) {
339 		objP += READ_LE_UINT32(objP) + 16;
340 	}
341 
342 	objP += 4;
343 	int result = READ_LE_INT16(objP) * READ_LE_INT16(objP + 2);
344 	memcpy(sprite, objP + 12, result);
345 }
346 
removeObjectDataBuf()347 void ObjectsManager::removeObjectDataBuf() {
348 	_curObjectFileNum = 0;
349 	_objectDataBuf = _vm->_globals->freeMemory(_objectDataBuf);
350 }
351 
352 /**
353  * Load Sprite from file
354  */
loadSprite(const Common::String & file)355 byte *ObjectsManager::loadSprite(const Common::String &file) {
356 	return _vm->_fileIO->loadFile(file);
357 }
358 
359 /**
360  * Add Object
361  */
addObject(int objIndex)362 void ObjectsManager::addObject(int objIndex) {
363 	int arrIndex = 0;
364 	for (;;) {
365 		++arrIndex;
366 		if ((!_vm->_globals->_inventory[arrIndex]) || (arrIndex == 32))
367 			break;
368 	}
369 
370 	_vm->_globals->_inventory[arrIndex] = objIndex;
371 }
372 
373 /**
374  * Display Sprite
375  */
displaySprite()376 void ObjectsManager::displaySprite() {
377 	int clipX;
378 	int clipY;
379 	uint16 arr[50];
380 
381 	// Handle copying any background areas that text are going to be drawn on
382 	_sortedDisplayCount = 0;
383 	for (int idx = 0; idx <= 10; ++idx) {
384 		TxtItemList *curTxtList = &_vm->_fontMan->_textList[idx];
385 		if (curTxtList->_enabledFl && _vm->_fontMan->_text[idx]._textType != 2) {
386 			clipX = curTxtList->_pos.x - 2;
387 
388 			if (clipX < _vm->_graphicsMan->_minX)
389 				clipX = _vm->_graphicsMan->_minX;
390 
391 			clipY = curTxtList->_pos.y - 2;
392 			if (clipY < _vm->_graphicsMan->_minY)
393 				clipY = _vm->_graphicsMan->_minY;
394 
395 			_vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, clipX, clipY,
396 				curTxtList->_width + 4, curTxtList->_height + 4, _vm->_graphicsMan->_frontBuffer, clipX, clipY);
397 			curTxtList->_enabledFl = false;
398 		}
399 	}
400 
401 	if (!_charactersEnabledFl) {
402 		for (int idx = 0; idx < MAX_SPRITE; ++idx) {
403 			ListeItem *curList = &_liste[idx];
404 			if (curList->_visibleFl) {
405 				clipX = curList->_posX - 2;
406 				if (clipX < _vm->_graphicsMan->_minX)
407 					clipX = _vm->_graphicsMan->_minX;
408 
409 				clipY = curList->_posY - 2;
410 				if (clipY < _vm->_graphicsMan->_minY)
411 					clipY = _vm->_graphicsMan->_minY;
412 
413 				_vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, clipX, clipY,
414 					curList->_width + 4, curList->_height + 4, _vm->_graphicsMan->_frontBuffer, clipX, clipY);
415 				curList->_visibleFl = false;
416 			}
417 		}
418 	}
419 
420 	displayBobAnim();
421 	displayVBob();
422 
423 	if (!_charactersEnabledFl) {
424 		// Handle drawing characters on the screen
425 		for (int idx = 0; idx < MAX_SPRITE; ++idx) {
426 			_liste[idx]._visibleFl = false;
427 			SpriteItem *curSpr = &_sprite[idx];
428 			if (curSpr->_animationType == 1) {
429 				computeSprite(idx);
430 				if (curSpr->_activeFl)
431 					beforeSort(SORT_SPRITE, idx, curSpr->_height + curSpr->_destY);
432 			}
433 		}
434 
435 		if (_hidingActiveFl)
436 			checkHidingItem();
437 	}
438 
439 	if (_priorityFl && _sortedDisplayCount) {
440 		for (int i = 1; i <= 48; i++)
441 			arr[i] = i;
442 
443 		bool loopCondFl;
444 		do {
445 			loopCondFl = false;
446 			for (int sortIdx = 1; sortIdx < _sortedDisplayCount; sortIdx++) {
447 				if (_sortedDisplay[arr[sortIdx]]._priority > _sortedDisplay[arr[sortIdx + 1]]._priority) {
448 					SWAP(arr[sortIdx], arr[sortIdx + 1]);
449 					loopCondFl = true;
450 				}
451 			}
452 		} while (loopCondFl);
453 
454 		for (int sortIdx = 1; sortIdx < _sortedDisplayCount + 1; sortIdx++) {
455 			int idx = arr[sortIdx];
456 			switch (_sortedDisplay[idx]._sortMode) {
457 			case SORT_BOB:
458 				setBobInfo(_sortedDisplay[idx]._index);
459 				break;
460 			case SORT_SPRITE:
461 				showSprite(_sortedDisplay[idx]._index);
462 				break;
463 			case SORT_HIDING:
464 				displayHiding(_sortedDisplay[idx]._index);
465 				break;
466 			default:
467 				break;
468 			}
469 			_sortedDisplay[idx]._sortMode = SORT_NONE;
470 		}
471 	} else {
472 		for (int idx = 1; idx < _sortedDisplayCount + 1; ++idx) {
473 			switch (_sortedDisplay[idx]._sortMode) {
474 			case SORT_BOB:
475 				setBobInfo(_sortedDisplay[idx]._index);
476 				break;
477 			case SORT_SPRITE:
478 				showSprite(_sortedDisplay[idx]._index);
479 				break;
480 			case SORT_HIDING:
481 				displayHiding(_sortedDisplay[idx]._index);
482 				break;
483 			default:
484 				break;
485 			}
486 			_sortedDisplay[idx]._sortMode = SORT_NONE;
487 		}
488 	}
489 
490 	// Reset the Sort array
491 	for (int idx = 0; idx < 50; ++idx) {
492 		SortItem *disp = &_sortedDisplay[idx];
493 		disp->_sortMode = SORT_NONE;
494 		disp->_index = 0;
495 		disp->_priority = 0;
496 	}
497 
498 	_sortedDisplayCount = 0;
499 
500 	_vm->_dialog->drawInvent(_oldBorderPos, _oldBorderSpriteIndex, _borderPos, _borderSpriteIndex);
501 
502 	if (_saveLoadFl) {
503 		int16 posX = _vm->_events->_startPos.x;
504 		_vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, _saveLoadSprite, posX + 183, 60, 274, 353);
505 		if (_saveLoadX && _saveLoadY)
506 			_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _saveLoadSprite2, _saveLoadX + posX + 300, _saveLoadY + 300, 0);
507 
508 		_vm->_graphicsMan->addDirtyRect(posX + 183, 60, posX + 457, 413);
509 	}
510 
511 	// If the Options dialog is activated, draw the elements
512 	if (_vm->_globals->_optionDialogFl) {
513 		int16 posX = _vm->_events->_startPos.x;
514 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
515 			posX + 464, 407, 0);
516 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
517 			posX + 657, 556, _vm->_globals->_menuSpeed);
518 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
519 			posX + 731, 495, _vm->_globals->_menuTextOff);
520 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
521 			posX + 731, 468, _vm->_globals->_menuVoiceOff);
522 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
523 			posX + 731, 441, _vm->_globals->_menuSoundOff);
524 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
525 			posX + 731, 414, _vm->_globals->_menuMusicOff);
526 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
527 			posX + 600, 522, _vm->_globals->_menuDisplayType);
528 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _vm->_globals->_optionDialogSpr,
529 			posX + 611, 502, _vm->_globals->_menuScrollSpeed);
530 		_vm->_graphicsMan->addDirtyRect(posX + 164, 107, posX + 498, 320);
531 	}
532 
533 	// Loop to draw any on-screen text
534 	for (int idx = 0; idx <= 10; ++idx) {
535 		TxtItem *curTxt = &_vm->_fontMan->_text[idx];
536 		if (curTxt->_textOnFl) {
537 			TxtItemList *curTxtList = &_vm->_fontMan->_textList[idx];
538 			if ((curTxt->_textType < 2) || (curTxt->_textType > 3))
539 				_vm->_fontMan->box(idx, curTxt->_messageId, curTxt->_filename, _vm->_events->_startPos.x + curTxt->_pos.x, curTxt->_pos.y);
540 			else
541 				_vm->_fontMan->box(idx, curTxt->_messageId, curTxt->_filename, curTxt->_pos.x, curTxt->_pos.y);
542 			curTxtList->_enabledFl = true;
543 
544 			if ((curTxt->_textType < 2) || (curTxt->_textType > 3))
545 				curTxtList->_pos.x = _vm->_events->_startPos.x + curTxt->_pos.x;
546 			else
547 				curTxtList->_pos.x = curTxt->_pos.x;
548 
549 			curTxtList->_pos.y = curTxt->_pos.y;
550 			curTxtList->_width = curTxt->_width;
551 			curTxtList->_height = curTxt->_height;
552 
553 			if (curTxtList->_pos.x < _vm->_graphicsMan->_minX)
554 				curTxtList->_pos.x = _vm->_graphicsMan->_minX - 1;
555 			if (curTxtList->_pos.y < _vm->_graphicsMan->_minY)
556 				curTxtList->_pos.y = _vm->_graphicsMan->_minY - 1;
557 
558 			int posX = curTxtList->_pos.x;
559 			if (curTxtList->_width + posX > _vm->_graphicsMan->_maxX)
560 				curTxtList->_width = _vm->_graphicsMan->_maxX - posX;
561 			int posY = curTxtList->_pos.y;
562 			if (curTxtList->_height + posY > _vm->_graphicsMan->_maxY)
563 				curTxtList->_height = _vm->_graphicsMan->_maxY - posY;
564 			if (curTxtList->_width <= 0 || curTxtList->_height <= 0)
565 				curTxtList->_enabledFl = false;
566 		}
567 	}
568 
569 	_vm->_dialog->inventAnim();
570 }
571 
resetBob(int idx)572 void ObjectsManager::resetBob(int idx) {
573 	BobItem &bob = _bob[idx];
574 	ListeItem &item = _liste2[idx];
575 
576 	bob._bobMode = 0;
577 	bob._spriteData = NULL;
578 	bob._xp = 0;
579 	bob._yp = 0;
580 	bob._frameIndex = 0;
581 	bob._animDataIdx = 0;
582 	bob._moveChange1 = 0;
583 	bob._moveChange2 = 0;
584 	bob._disabledAnimationFl = false;
585 	bob._animData = NULL;
586 	bob._bobMode10 = false;
587 	bob._bobModeChange = 0;
588 	bob._modeChangeCtr = 0;
589 	bob._modeChangeUnused = 0;
590 	bob._disableFl = false;
591 	bob._zoomFactor = 0;
592 	bob._flipFl = false;
593 	bob._oldX2 = 0;
594 
595 	item._visibleFl = false;
596 	item._posX = 0;
597 	item._posY = 0;
598 	item._width = 0;
599 	item._height = 0;
600 }
601 
setBobInfo(int idx)602 void ObjectsManager::setBobInfo(int idx) {
603 	BobItem *curBob = &_bob[idx];
604 
605 	if (!curBob->_activeFl)
606 		return;
607 
608 	int xp = curBob->_oldX;
609 	int yp = curBob->_oldY;
610 
611 	if (curBob->_isSpriteFl)
612 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, curBob->_spriteData,
613 			xp + 300, yp + 300, curBob->_frameIndex);
614 	else
615 		_vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer,
616 			curBob->_spriteData, xp + 300, yp + 300, curBob->_frameIndex,
617 			curBob->_zoomOutFactor, curBob->_zooInmFactor, curBob->_flipFl);
618 
619 	ListeItem *curLst = &_liste2[idx];
620 	curLst->_visibleFl = true;
621 	curLst->_posX = xp;
622 	curLst->_posY = yp;
623 
624 	curLst->_width = curBob->_oldWidth;
625 	curLst->_height = curBob->_oldHeight;
626 
627 	if (curLst->_posX < _vm->_graphicsMan->_minX) {
628 		curLst->_width -= _vm->_graphicsMan->_minX - curLst->_posX;
629 		curLst->_posX = _vm->_graphicsMan->_minX;
630 	}
631 
632 	if (curLst->_posY < _vm->_graphicsMan->_minY) {
633 		curLst->_height -= _vm->_graphicsMan->_minY - curLst->_posY;
634 		curLst->_posY = _vm->_graphicsMan->_minY;
635 	}
636 
637 	if (curLst->_width + curLst->_posX > _vm->_graphicsMan->_maxX)
638 		curLst->_width = _vm->_graphicsMan->_maxX - curLst->_posX;
639 
640 	if (curLst->_height + curLst->_posY > _vm->_graphicsMan->_maxY)
641 		curLst->_height = _vm->_graphicsMan->_maxY - curLst->_posY;
642 
643 	if (curLst->_width <= 0 || curLst->_height <= 0)
644 		curLst->_visibleFl = false;
645 
646 	if (curLst->_visibleFl)
647 		_vm->_graphicsMan->addDirtyRect(curLst->_posX, curLst->_posY, curLst->_posX + curLst->_width, curLst->_posY + curLst->_height);
648 }
649 
displayBob(int idx)650 void ObjectsManager::displayBob(int idx) {
651 	BobItem *curBob = &_bob[idx];
652 
653 	_priorityFl = true;
654 
655 	if (curBob->_bobMode)
656 		return;
657 
658 	resetBob(idx);
659 
660 	const byte *data = _vm->_animMan->_animBqe[idx]._data;
661 	int bankIdx = READ_LE_INT16(data);
662 	if (!bankIdx)
663 		return;
664 	if ((!_vm->_animMan->Bank[bankIdx]._loadedFl) || (!READ_LE_UINT16(data + 24)))
665 		return;
666 
667 
668 	int16 bobModeChange = READ_LE_INT16(data + 2);
669 	int16 modeChangeUnused = READ_LE_INT16(data + 4);
670 	// data[6] isn't used, read skipped
671 	int16 newModeChangeCtr = READ_LE_INT16(data + 8);
672 
673 	if (!bobModeChange)
674 		bobModeChange = 1;
675 	if (!newModeChangeCtr)
676 		newModeChangeCtr = -1;
677 
678 	curBob->_isSpriteFl = false;
679 
680 	if (_vm->_animMan->Bank[bankIdx]._fileHeader == 1) {
681 		curBob->_isSpriteFl = true;
682 		curBob->_zoomFactor = 0;
683 		curBob->_flipFl = false;
684 	}
685 
686 	curBob->_animData = _vm->_animMan->_animBqe[idx]._data;
687 	curBob->_bobMode = 10;
688 	curBob->_spriteData = _vm->_animMan->Bank[bankIdx]._data;
689 
690 	curBob->_bobModeChange = bobModeChange;
691 	curBob->_modeChangeCtr = newModeChangeCtr;
692 	curBob->_modeChangeUnused = modeChangeUnused;
693 }
694 
hideBob(int idx)695 void ObjectsManager::hideBob(int idx) {
696 	BobItem *curBob = &_bob[idx];
697 	if ((curBob->_bobMode == 3) || (curBob->_bobMode == 10))
698 		curBob->_bobMode++;
699 }
700 
setBobOffset(int idx,int offset)701 void ObjectsManager::setBobOffset(int idx, int offset) {
702 	_bob[idx]._oldX2 = offset;
703 }
704 
computeHideCounter(int idx)705 void ObjectsManager::computeHideCounter(int idx) {
706 	HidingItem *hid = &_hidingItem[idx];
707 	if (hid->_useCount == 0)
708 		return;
709 
710 	for (int i = 0; i <= 20; i++) {
711 		BobItem *curBob = &_bob[i];
712 		if ((curBob->_bobMode) && (!curBob->_disabledAnimationFl) && (!curBob->_disableFl) && (curBob->_frameIndex != 250)) {
713 			int oldRight = curBob->_oldX + curBob->_oldWidth;
714 			int oldBottom = curBob->_oldY + curBob->_oldHeight;
715 			int hiddenRight = hid->_x + hid->_width;
716 
717 			if ((oldBottom > hid->_y) && (oldBottom < hid->_yOffset + hid->_height + hid->_y)) {
718 				if ((oldRight >= hid->_x && oldRight <= hiddenRight)
719 				// CHECKME: The original was doing the test two times. This looks like an
720 				// original bug
721 				// || (cachedRight >= curBob->_oldWidth && curBob->_oldWidth >= hid->_x)
722 				 || (hiddenRight >= curBob->_oldWidth && curBob->_oldWidth >= hid->_x)
723 				 || (curBob->_oldWidth >= hid->_x && oldRight <= hiddenRight)
724 				 || (curBob->_oldWidth <= hid->_x && oldRight >= hiddenRight))
725 					++hid->_useCount;
726 			}
727 		}
728 	}
729 }
730 
initBobVariables(int idx)731 void ObjectsManager::initBobVariables(int idx) {
732 	BobItem *bob = &_bob[idx];
733 
734 	bob->_activeFl = false;
735 	if (bob->_isSpriteFl) {
736 		bob->_flipFl = false;
737 		bob->_zoomFactor = 0;
738 	}
739 
740 	int spriteIdx = bob->_frameIndex;
741 	if (spriteIdx == 250)
742 		return;
743 
744 	int deltaY, deltaX;
745 	if (bob->_flipFl) {
746 		deltaX = getOffsetX(bob->_spriteData, spriteIdx, true);
747 		deltaY = getOffsetY(bob->_spriteData, bob->_frameIndex, true);
748 	} else {
749 		deltaX = getOffsetX(bob->_spriteData, spriteIdx, false);
750 		deltaY = getOffsetY(bob->_spriteData, bob->_frameIndex, false);
751 	}
752 
753 	int negZoom = 0;
754 	int posZoom = 0;
755 	if (bob->_zoomFactor < 0)
756 		negZoom = CLIP(-bob->_zoomFactor, 0, 95);
757 	else
758 		posZoom = bob->_zoomFactor;
759 
760 	if (posZoom) {
761 		if (deltaX >= 0)
762 			deltaX = _vm->_graphicsMan->zoomIn(deltaX, posZoom);
763 		else
764 			deltaX = -_vm->_graphicsMan->zoomIn(-deltaX, posZoom);
765 
766 		if (deltaY >= 0)
767 			deltaY = _vm->_graphicsMan->zoomIn(deltaY, posZoom);
768 		else
769 			deltaY = -_vm->_graphicsMan->zoomIn(abs(deltaX), posZoom);
770 	}
771 
772 	if (negZoom) {
773 		if (deltaX >= 0)
774 			deltaX = _vm->_graphicsMan->zoomOut(deltaX, negZoom);
775 		else
776 			deltaX = -_vm->_graphicsMan->zoomOut(-deltaX, negZoom);
777 
778 		if (deltaY >= 0)
779 			deltaY = _vm->_graphicsMan->zoomOut(deltaY, negZoom);
780 		else
781 			deltaY = -_vm->_graphicsMan->zoomOut(abs(deltaX), negZoom);
782 	}
783 
784 	int newX = bob->_xp - deltaX;
785 	int newY = bob->_yp - deltaY;
786 	bob->_activeFl = true;
787 	bob->_oldX = newX;
788 	bob->_oldY = newY;
789 	bob->_zooInmFactor = posZoom;
790 	bob->_zoomOutFactor = negZoom;
791 
792 	ListeItem *curList = &_liste2[idx];
793 	curList->_visibleFl = true;
794 	curList->_posX = newX;
795 	curList->_posY = newY;
796 
797 	int width = getWidth(bob->_spriteData, bob->_frameIndex);
798 	int height = getHeight(bob->_spriteData, bob->_frameIndex);
799 
800 	if (posZoom) {
801 		width = _vm->_graphicsMan->zoomIn(width, posZoom);
802 		height = _vm->_graphicsMan->zoomIn(height, posZoom);
803 	} else if (negZoom) {
804 		width = _vm->_graphicsMan->zoomOut(width, negZoom);
805 		height = _vm->_graphicsMan->zoomOut(height, negZoom);
806 	}
807 
808 	curList->_width = width;
809 	curList->_height = height;
810 	bob->_oldWidth = width;
811 	bob->_oldHeight = height;
812 }
813 
checkHidingItem()814 void ObjectsManager::checkHidingItem() {
815 	for (int hidingItemIdx = 0; hidingItemIdx <= 19; hidingItemIdx++) {
816 		HidingItem *hid = &_hidingItem[hidingItemIdx];
817 		if (hid->_useCount == 0)
818 			continue;
819 
820 		int _oldUseCount = hid->_useCount;
821 		for (int spriteIdx = 0; spriteIdx <= 4; spriteIdx++) {
822 			const SpriteItem *spr = &_sprite[spriteIdx];
823 			if (spr->_animationType == 1 && spr->_spriteIndex != 250) {
824 				int right = spr->_width + spr->_destX;
825 				int bottom = spr->_height + spr->_destY;
826 				int hidingRight = hid->_width + hid->_x;
827 
828 				if (bottom > hid->_y && bottom < (hid->_yOffset + hid->_height + hid->_y)) {
829 					if ((right >= hid->_x && right <= hidingRight)
830 					// CHECKME: The original was doing the test two times. This looks like an
831 					// original bug
832 					// || (hidingRight >= spr->_destX && hid->_x <= spr->_destX)
833 					 || (hidingRight >= spr->_destX && hid->_x <= spr->_destX)
834 					 || (hid->_x <= spr->_destX && right <= hidingRight)
835 					 || (hid->_x >= spr->_destX && right >= hidingRight))
836 						++hid->_useCount;
837 				}
838 			}
839 		}
840 
841 		computeHideCounter(hidingItemIdx);
842 		if (hid->_useCount != _oldUseCount) {
843 			int priority = hid->_yOffset + hid->_height + hid->_y;
844 			if (priority > 440)
845 				priority = 500;
846 
847 			beforeSort(SORT_HIDING, hidingItemIdx, priority);
848 			hid->_useCount = 1;
849 			hid->_resetUseCount = true;
850 		} else if (hid->_resetUseCount) {
851 			hid->_resetUseCount = false;
852 			hid->_useCount = 1;
853 		}
854 
855 	}
856 }
857 
showSprite(int idx)858 void ObjectsManager::showSprite(int idx) {
859 	SpriteItem *spr = &_sprite[idx];
860 	if (!spr->_activeFl)
861 		return;
862 
863 	if (spr->_rleFl)
864 		_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, spr->_spriteData,
865 		    spr->_destX + 300, spr->_destY + 300, spr->_spriteIndex);
866 	else
867 		_vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, spr->_spriteData,
868 		    spr->_destX + 300, spr->_destY + 300,  spr->_spriteIndex, spr->_reducePct, spr->_zoomPct, spr->_flipFl);
869 
870 	ListeItem *list = &_liste[idx];
871 	list->_width = spr->_width;
872 	list->_height = spr->_height;
873 
874 	if (list->_posX < _vm->_graphicsMan->_minX) {
875 		list->_width -= _vm->_graphicsMan->_minX - list->_posX;
876 		list->_posX = _vm->_graphicsMan->_minX;
877 	}
878 
879 	if (list->_posY < _vm->_graphicsMan->_minY) {
880 		list->_height -= _vm->_graphicsMan->_minY - list->_posY;
881 		list->_posY = _vm->_graphicsMan->_minY;
882 	}
883 
884 	list->_width = MIN(list->_width, _vm->_graphicsMan->_maxX - list->_posX);
885 	list->_height = MIN(list->_height, _vm->_graphicsMan->_maxY - list->_posY);
886 
887 	if (list->_width <= 0 || list->_height <= 0)
888 		list->_visibleFl = false;
889 
890 	if (list->_visibleFl)
891 		_vm->_graphicsMan->addDirtyRect( list->_posX, list->_posY, list->_posX + list->_width, list->_posY + list->_height);
892 }
893 
displayHiding(int idx)894 void ObjectsManager::displayHiding(int idx) {
895 	HidingItem *hid = &_hidingItem[idx];
896 
897 	_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, _hidingItemData[1],
898 		hid->_x + 300, hid->_y + 300, hid->_spriteIndex);
899 	_vm->_graphicsMan->addDirtyRect(hid->_x, hid->_y, hid->_x + hid->_width, hid->_y + hid->_height);
900 }
901 
902 // Compute Sprite
computeSprite(int idx)903 void ObjectsManager::computeSprite(int idx) {
904 	SpriteItem *spr = &_sprite[idx];
905 
906 	spr->_activeFl = false;
907 	int spriteIndex = spr->_spriteIndex;
908 	if (spriteIndex == 250)
909 		return;
910 
911 	int offX;
912 	int offY;
913 	if (spr->_flipFl) {
914 		offX = getOffsetX(spr->_spriteData, spriteIndex, true);
915 		offY = getOffsetY(spr->_spriteData, spr->_spriteIndex, true);
916 	} else {
917 		offX = getOffsetX(spr->_spriteData, spriteIndex, false);
918 		offY = getOffsetY(spr->_spriteData, spr->_spriteIndex, false);
919 	}
920 
921 	int tmpX = spr->_deltaX + offX;
922 	int deltaX = tmpX;
923 	int tmpY = spr->_deltaY + offY;
924 	int deltaY = tmpY;
925 	int zoomPercent = 0;
926 	int reducePercent = 0;
927 
928 	if (spr->_zoomFactor < 0) {
929 		reducePercent = -spr->_zoomFactor;
930 		if (reducePercent > 95)
931 			reducePercent = 95;
932 	} else
933 		zoomPercent = spr->_zoomFactor;
934 
935 	if (zoomPercent) {
936 		if (tmpX >= 0)
937 			deltaX = _vm->_graphicsMan->zoomIn(tmpX, zoomPercent);
938 		else
939 			deltaX = -_vm->_graphicsMan->zoomIn(-tmpX, zoomPercent);
940 
941 		if (tmpY >= 0) {
942 			deltaY = _vm->_graphicsMan->zoomIn(tmpY, zoomPercent);
943 		} else {
944 			tmpY = abs(tmpX);
945 			deltaY = -_vm->_graphicsMan->zoomIn(tmpY, zoomPercent);
946 		}
947 	} else if (reducePercent) {
948 		if (tmpX >= 0)
949 			deltaX = _vm->_graphicsMan->zoomOut(tmpX, reducePercent);
950 		else
951 			deltaX = -_vm->_graphicsMan->zoomOut(-tmpX, reducePercent);
952 
953 		if (tmpY >= 0) {
954 			deltaY = _vm->_graphicsMan->zoomOut(tmpY, reducePercent);
955 		} else {
956 			tmpY = abs(tmpX);
957 			deltaY = -_vm->_graphicsMan->zoomOut(tmpY, reducePercent);
958 		}
959 	}
960 
961 	int newPosX = spr->_spritePos.x - deltaX;
962 	int newPosY = spr->_spritePos.y - deltaY;
963 	spr->_destX = newPosX;
964 	spr->_destY = newPosY;
965 	spr->_activeFl = true;
966 	spr->_zoomPct = zoomPercent;
967 	spr->_reducePct = reducePercent;
968 
969 	_liste[idx]._visibleFl = true;
970 	_liste[idx]._posX = newPosX;
971 	_liste[idx]._posY = newPosY;
972 
973 	int width = getWidth(spr->_spriteData, spr->_spriteIndex);
974 	int height = getHeight(spr->_spriteData, spr->_spriteIndex);
975 
976 	if (zoomPercent) {
977 		width = _vm->_graphicsMan->zoomIn(width, zoomPercent);
978 		height = _vm->_graphicsMan->zoomIn(height, zoomPercent);
979 	} else if (reducePercent) {
980 		height = _vm->_graphicsMan->zoomOut(height, reducePercent);
981 		width = _vm->_graphicsMan->zoomOut(width, reducePercent);
982 	}
983 
984 	spr->_width = width;
985 	spr->_height = height;
986 }
987 
988 // Before Sort
beforeSort(SortMode sortMode,int index,int priority)989 void ObjectsManager::beforeSort(SortMode sortMode, int index, int priority) {
990 	++_sortedDisplayCount;
991 	assert(_sortedDisplayCount <= 48);
992 
993 	_sortedDisplay[_sortedDisplayCount]._sortMode = sortMode;
994 	_sortedDisplay[_sortedDisplayCount]._index = index;
995 	_sortedDisplay[_sortedDisplayCount]._priority = priority;
996 }
997 
998 // Display BOB Anim
displayBobAnim()999 void ObjectsManager::displayBobAnim() {
1000 	for (int idx = 1; idx <= 35; idx++) {
1001 		BobItem *bob = &_bob[idx];
1002 		if (idx <= 20 && _charactersEnabledFl) {
1003 			bob->_bobMode10 = false;
1004 			continue;
1005 		}
1006 
1007 		if (bob->_bobMode != 10)
1008 			continue;
1009 
1010 		bob->_bobMode10 = false;
1011 		if (bob->_animData == NULL || bob->_disabledAnimationFl || bob->_modeChangeCtr == 0 || bob->_modeChangeCtr < -1) {
1012 			if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
1013 				bob->_bobMode10 = true;
1014 			continue;
1015 		}
1016 
1017 		if (bob->_moveChange1 == bob->_moveChange2) {
1018 			bob->_bobMode10 = true;
1019 		} else {
1020 			bob->_moveChange2++;
1021 			bob->_bobMode10 = false;
1022 		}
1023 
1024 		if (!bob->_bobMode10) {
1025 			if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
1026 				bob->_bobMode10 = true;
1027 			continue;
1028 		}
1029 
1030 		byte *dataPtr = bob->_animData + 20;
1031 		int dataIdx = bob->_animDataIdx;
1032 		bob->_xp = READ_LE_INT16(dataPtr + 2 * dataIdx);
1033 		if (_lockedAnims[idx]._enableFl)
1034 			bob->_xp = _lockedAnims[idx]._posX;
1035 		if ( _charactersEnabledFl && idx > 20)
1036 			bob->_xp += _vm->_events->_startPos.x;
1037 
1038 		bob->_yp = READ_LE_INT16(dataPtr + 2 * dataIdx + 2);
1039 		bob->_moveChange1 = READ_LE_INT16(dataPtr + 2 * dataIdx + 4);
1040 		bob->_zoomFactor = READ_LE_INT16(dataPtr + 2 * dataIdx + 6);
1041 		bob->_frameIndex = dataPtr[2 * dataIdx + 8];
1042 		bob->_flipFl = (dataPtr[2 * dataIdx + 9] != 0);
1043 		bob->_animDataIdx += 5;
1044 
1045 		if (bob->_moveChange1 > 0) {
1046 			bob->_moveChange1 /= _vm->_globals->_speed;
1047 			if (bob->_moveChange1 > 0) {
1048 				bob->_moveChange2 = 1;
1049 				if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
1050 					bob->_bobMode10 = true;
1051 				continue;
1052 			}
1053 
1054 			bob->_moveChange1 = 1;
1055 		}
1056 		if (!bob->_moveChange1) {
1057 			if (bob->_modeChangeCtr > 0)
1058 				bob->_modeChangeCtr--;
1059 			if (bob->_modeChangeCtr != -1 && bob->_modeChangeCtr <= 0) {
1060 				bob->_bobMode = 11;
1061 			} else {
1062 				bob->_animDataIdx = 0;
1063 				byte *bobData = bob->_animData + 20;
1064 				bob->_xp = READ_LE_INT16(bobData);
1065 
1066 				if (_lockedAnims[idx]._enableFl)
1067 					bob->_xp = _lockedAnims[idx]._posX;
1068 				if (_charactersEnabledFl && idx > 20)
1069 					bob->_xp += _vm->_events->_startPos.x;
1070 
1071 				bob->_yp = READ_LE_INT16(bobData + 2);
1072 				bob->_moveChange1 = READ_LE_INT16(bobData + 4);
1073 				bob->_zoomFactor = READ_LE_INT16(bobData + 6);
1074 				bob->_frameIndex = bobData[8];
1075 				bob->_flipFl = (bobData[9] != 0);
1076 				bob->_animDataIdx += 5;
1077 
1078 				if (bob->_moveChange1 > 0) {
1079 					bob->_moveChange1 /= _vm->_globals->_speed;
1080 					// Original code. It can't be negative, so the check is on == 0
1081 					if (bob->_moveChange1 <= 0)
1082 						bob->_moveChange1 = 1;
1083 				}
1084 			}
1085 		}
1086 
1087 		bob->_moveChange2 = 1;
1088 		if (bob->_bobModeChange == 1 || bob->_bobModeChange == 2)
1089 			bob->_bobMode10 = true;
1090 	}
1091 
1092 	if (!_charactersEnabledFl && _refreshBobMode10Fl) {
1093 		for (int i = 0; i < 35; i++) {
1094 			BobItem *curBob = &_bob[i];
1095 			if (curBob->_bobMode == 10 && !curBob->_disabledAnimationFl)
1096 				curBob->_bobMode10 = true;
1097 		}
1098 	}
1099 
1100 	_refreshBobMode10Fl = false;
1101 
1102 	for (int i = 1; i <= 35; i++) {
1103 		BobItem *curBob = &_bob[i];
1104 		ListeItem *curList = &_liste2[i];
1105 		if (i > 20 || !_charactersEnabledFl) {
1106 			if ((curBob->_bobMode == 10) && (curBob->_bobMode10)) {
1107 				if ((curBob->_bobModeChange != 2) && (curBob->_bobModeChange != 4)) {
1108 					if (curList->_visibleFl) {
1109 						_vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, curList->_posX, curList->_posY,
1110 							curList->_width, curList->_height, _vm->_graphicsMan->_frontBuffer, curList->_posX, curList->_posY);
1111 						curList->_visibleFl = false;
1112 					}
1113 				}
1114 			}
1115 
1116 			if (curBob->_bobMode == 11) {
1117 				if (curList->_visibleFl) {
1118 					_vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, curList->_posX, curList->_posY,
1119 						curList->_width, curList->_height, _vm->_graphicsMan->_frontBuffer, curList->_posX, curList->_posY);
1120 					curList->_visibleFl = false;
1121 				}
1122 
1123 				curBob->_bobMode = 0;
1124 			}
1125 		}
1126 	}
1127 
1128 	for (int i = 1; i <= 35; i++) {
1129 		BobItem *curBob = &_bob[i];
1130 		curBob->_oldY = 0;
1131 		if (curBob->_bobMode == 10 && !curBob->_disabledAnimationFl && curBob->_bobMode10) {
1132 			initBobVariables(i);
1133 			int priority = curBob->_oldX2 + curBob->_oldHeight + curBob->_oldY;
1134 
1135 			if (priority > 450)
1136 				priority = 600;
1137 
1138 			if (curBob->_activeFl)
1139 				beforeSort(SORT_BOB, i, priority);
1140 		}
1141 	}
1142 }
1143 
1144 // Display VBOB
displayVBob()1145 void ObjectsManager::displayVBob() {
1146 	int width, height;
1147 
1148 	for (int idx = 0; idx <= 29; idx++) {
1149 		VBobItem *vbob = &_vBob[idx];
1150 		if (vbob->_displayMode == 4) {
1151 			width = getWidth(vbob->_spriteData, vbob->_frameIndex);
1152 			height = getHeight(vbob->_spriteData, vbob->_frameIndex);
1153 
1154 			_vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_backBuffer, vbob->_surface,
1155 				vbob->_xp, vbob->_yp, width, height);
1156 
1157 			_vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, vbob->_surface,
1158 				vbob->_xp, vbob->_yp, width, height);
1159 
1160 			_vm->_graphicsMan->addDirtyRect(vbob->_xp, vbob->_yp, vbob->_xp + width, height + vbob->_yp);
1161 			vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
1162 
1163 			vbob->_displayMode = 0;
1164 			vbob->_spriteData = NULL;
1165 			vbob->_xp = 0;
1166 			vbob->_yp = 0;
1167 			vbob->_oldX = 0;
1168 			vbob->_oldY = 0;
1169 			vbob->_frameIndex = 0;
1170 			vbob->_oldFrameIndex = 0;
1171 			vbob->_oldSpriteData = NULL;
1172 		}
1173 
1174 		if (vbob->_displayMode == 3) {
1175 			width = getWidth(vbob->_oldSpriteData, vbob->_oldFrameIndex);
1176 			height = getHeight(vbob->_oldSpriteData, vbob->_oldFrameIndex);
1177 
1178 			_vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_backBuffer, vbob->_surface,
1179 				vbob->_oldX, vbob->_oldY, width, height);
1180 
1181 			_vm->_graphicsMan->restoreSurfaceRect(_vm->_graphicsMan->_frontBuffer, vbob->_surface,
1182 				vbob->_oldX, vbob->_oldY, width, height);
1183 
1184 			_vm->_graphicsMan->addDirtyRect(vbob->_oldX, vbob->_oldY, vbob->_oldX + width, vbob->_oldY + height);
1185 
1186 			vbob->_displayMode = 1;
1187 			vbob->_oldSpriteData = vbob->_spriteData;
1188 
1189 			vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
1190 
1191 			vbob->_oldX = vbob->_xp;
1192 			vbob->_oldY = vbob->_yp;
1193 			vbob->_oldFrameIndex = vbob->_frameIndex;
1194 		}
1195 
1196 		if (vbob->_displayMode == 1) {
1197 			width = getWidth(vbob->_spriteData, vbob->_frameIndex);
1198 			height = getHeight(vbob->_spriteData, vbob->_frameIndex);
1199 
1200 			vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
1201 
1202 			byte *surface = _vm->_globals->allocMemory(height * width);
1203 			vbob->_surface = surface;
1204 
1205 			_vm->_graphicsMan->copySurfaceRect(_vm->_graphicsMan->_backBuffer, surface,
1206 				vbob->_xp, vbob->_yp, width, height);
1207 
1208 			if (*vbob->_spriteData == 78) {
1209 				_vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_backBuffer, vbob->_spriteData,
1210 					vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false);
1211 
1212 				_vm->_graphicsMan->drawCompressedSprite(_vm->_graphicsMan->_frontBuffer, vbob->_spriteData,
1213 					vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex, 0, 0, false);
1214 			} else {
1215 				_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_frontBuffer, vbob->_spriteData,
1216 					vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex);
1217 
1218 				_vm->_graphicsMan->drawVesaSprite(_vm->_graphicsMan->_backBuffer, vbob->_spriteData,
1219 					vbob->_xp + 300, vbob->_yp + 300, vbob->_frameIndex);
1220 			}
1221 
1222 			_vm->_graphicsMan->addDirtyRect(vbob->_xp, vbob->_yp , vbob->_xp + width, vbob->_yp + height);
1223 			vbob->_displayMode = 2;
1224 		}
1225 	}
1226 }
1227 
1228 /**
1229  * Get Sprite X coordinate
1230  */
getSpriteX(int idx)1231 int ObjectsManager::getSpriteX(int idx) {
1232 	assert(idx  <= MAX_SPRITE);
1233 	return _sprite[idx]._spritePos.x;
1234 }
1235 
1236 /**
1237  * Get Sprite Y coordinate
1238  */
getSpriteY(int idx)1239 int ObjectsManager::getSpriteY(int idx) {
1240 	assert(idx  <= MAX_SPRITE);
1241 	return _sprite[idx]._spritePos.y;
1242 }
1243 
1244 /**
1245  * Clear sprite structure
1246  */
clearSprite()1247 void ObjectsManager::clearSprite() {
1248 	for (int idx = 0; idx < MAX_SPRITE; idx++) {
1249 		_sprite[idx]._spriteData = NULL;
1250 		_sprite[idx]._animationType = 0;
1251 	}
1252 
1253 	for (int idx = 0; idx < MAX_SPRITE; idx++) {
1254 		ListeItem *list = &_liste[idx];
1255 		list->_visibleFl = false;
1256 		list->_posX = 0;
1257 		list->_posY = 0;
1258 		list->_width = 0;
1259 		list->_height = 0;
1260 	}
1261 }
1262 
animateSprite(int idx)1263 void ObjectsManager::animateSprite(int idx) {
1264 	assert(idx  <= MAX_SPRITE);
1265 	_sprite[idx]._animationType = 1;
1266 }
1267 
addStaticSprite(const byte * spriteData,Common::Point pos,int idx,int spriteIndex,int zoomFactor,bool flipFl,int deltaX,int deltaY)1268 void ObjectsManager::addStaticSprite(const byte *spriteData, Common::Point pos, int idx, int spriteIndex, int zoomFactor, bool flipFl, int deltaX, int deltaY) {
1269 	assert(idx  <= MAX_SPRITE);
1270 
1271 	SpriteItem *spr = &_sprite[idx];
1272 	spr->_spriteData = spriteData;
1273 	spr->_spritePos = pos;
1274 	spr->_spriteIndex = spriteIndex;
1275 	spr->_zoomFactor = zoomFactor;
1276 	spr->_flipFl = flipFl;
1277 	spr->_deltaX = deltaX;
1278 	spr->_deltaY = deltaY;
1279 	spr->_animationType = 0;
1280 
1281 	if (READ_BE_UINT24(spriteData) == MKTAG24('R', 'L', 'E')) {
1282 		spr->_rleFl = true;
1283 		spr->_zoomFactor = 0;
1284 		spr->_flipFl = false;
1285 	} else
1286 		spr->_rleFl = false;
1287 
1288 }
1289 
1290 /**
1291  * Freeze sprite animation and free its memory
1292  */
removeSprite(int idx)1293 void ObjectsManager::removeSprite(int idx) {
1294 	// Type 3 was also used by freeSprite(), which has been removed as it wasn't used
1295 	_sprite[idx]._animationType = 3;
1296 }
1297 
1298 /**
1299  * Set Sprite X coordinate
1300  */
setSpriteX(int idx,int xp)1301 void ObjectsManager::setSpriteX(int idx, int xp) {
1302 	assert(idx  <= MAX_SPRITE);
1303 	_sprite[idx]._spritePos.x = xp;
1304 }
1305 
1306 /**
1307  * Set Sprite Y coordinate
1308  */
setSpriteY(int idx,int yp)1309 void ObjectsManager::setSpriteY(int idx, int yp) {
1310 	assert(idx  <= MAX_SPRITE);
1311 	_sprite[idx]._spritePos.y = yp;
1312 }
1313 
1314 /**
1315  * Set Sprite Index
1316  */
setSpriteIndex(int idx,int spriteIndex)1317 void ObjectsManager::setSpriteIndex(int idx, int spriteIndex) {
1318 	assert(idx  <= MAX_SPRITE);
1319 	_sprite[idx]._spriteIndex = spriteIndex;
1320 }
1321 
1322 // Set Sprite Size
setSpriteZoom(int idx,int zoomFactor)1323 void ObjectsManager::setSpriteZoom(int idx, int zoomFactor) {
1324 	assert(idx  <= MAX_SPRITE);
1325 	if (!_sprite[idx]._rleFl)
1326 		_sprite[idx]._zoomFactor = zoomFactor;
1327 }
1328 
setFlipSprite(int idx,bool flipFl)1329 void ObjectsManager::setFlipSprite(int idx, bool flipFl) {
1330 	assert(idx  <= MAX_SPRITE);
1331 	if (!_sprite[idx]._rleFl)
1332 		_sprite[idx]._flipFl = flipFl;
1333 }
1334 
goHome()1335 void ObjectsManager::goHome() {
1336 	if (_vm->_linesMan->_route == NULL)
1337 		return;
1338 
1339 	if (_homeRateCounter > 1) {
1340 		--_homeRateCounter;
1341 		return;
1342 	}
1343 
1344 	int newPosX;
1345 	int newPosY;
1346 	Directions newDirection;
1347 
1348 	int oldPosX = 0;
1349 	int oldPosY = 0;
1350 	int oldFrameIdx = 0;
1351 	_homeRateCounter = 0;
1352 	if (_oldDirection == DIR_NONE) {
1353 		computeAndSetSpriteSize();
1354 		newPosX = _vm->_linesMan->_route->_x;
1355 		newPosY = _vm->_linesMan->_route->_y;
1356 		newDirection = _vm->_linesMan->_route->_dir;
1357 		_vm->_linesMan->_route++;
1358 
1359 		if (newPosX != -1 || newPosY != -1) {
1360 			_oldDirection = newDirection;
1361 			_oldDirectionSpriteIdx = newDirection + 59;
1362 			_oldFrameIndex = 0;
1363 			_oldCharacterPosX = newPosX;
1364 			_oldCharacterPosY = newPosY;
1365 		} else {
1366 			setSpriteIndex(0, _oldDirection + 59);
1367 			_vm->_globals->_actionDirection = DIR_NONE;
1368 			int zoneId;
1369 			if (_vm->_globals->_actionMoveTo)
1370 				zoneId = _vm->_globals->_saveData->_data[svLastZoneNum];
1371 			else
1372 				zoneId = _zoneNum;
1373 			_vm->_linesMan->_route = NULL;
1374 			computeAndSetSpriteSize();
1375 			setFlipSprite(0, false);
1376 			_homeRateCounter = 0;
1377 			_vm->_linesMan->_route = NULL;
1378 			_oldDirection = DIR_NONE;
1379 			if (zoneId > 0) {
1380 				ZoneItem *curZone = &_vm->_linesMan->_zone[zoneId];
1381 				if (curZone->_destX && curZone->_destY && curZone->_destY != 31) {
1382 					if (curZone->_spriteIndex == -1) {
1383 						curZone->_destX = 0;
1384 						curZone->_destY = 0;
1385 						curZone->_spriteIndex = 0;
1386 					} else {
1387 						setSpriteIndex(0, curZone->_spriteIndex);
1388 						_vm->_globals->_actionDirection = curZone->_spriteIndex - 59;
1389 					}
1390 				}
1391 			}
1392 		}
1393 		_homeRateCounter = 0;
1394 		return;
1395 	}
1396 	if (_oldDirection == DIR_RIGHT) {
1397 		if (_oldFrameIndex < 24 || _oldFrameIndex > 35) {
1398 			oldPosX = _oldCharacterPosX;
1399 			oldPosY = _oldCharacterPosY;
1400 			oldFrameIdx = 24;
1401 		} else {
1402 			int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
1403 			int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
1404 
1405 			if (_sprite[0]._zoomFactor < 0) {
1406 				deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
1407 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1408 			} else if (_sprite[0]._zoomFactor > 0) {
1409 				deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
1410 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1411 			}
1412 			oldPosX = _oldCharacterPosX + deltaX;
1413 			oldPosY = _oldCharacterPosY + deltaY;
1414 			oldFrameIdx = _oldFrameIndex + 1;
1415 			if (oldFrameIdx > 35)
1416 				oldFrameIdx = 24;
1417 		}
1418 		_homeRateCounter = 5 / _vm->_globals->_speed;
1419 	}
1420 	if (_oldDirection == DIR_LEFT) {
1421 		if (_oldFrameIndex < 24 || _oldFrameIndex > 35) {
1422 			oldPosX = _oldCharacterPosX;
1423 			oldPosY = _oldCharacterPosY;
1424 			oldFrameIdx = 24;
1425 		} else {
1426 			int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
1427 			int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
1428 			if (_sprite[0]._zoomFactor < 0) {
1429 				deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
1430 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1431 			} else if (_sprite[0]._zoomFactor > 0) {
1432 				deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
1433 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1434 			}
1435 			oldPosX = _oldCharacterPosX - deltaX;
1436 			oldPosY = _oldCharacterPosY - deltaY;
1437 			oldFrameIdx = _oldFrameIndex + 1;
1438 			if (oldFrameIdx > 35)
1439 				oldFrameIdx = 24;
1440 		}
1441 		_homeRateCounter = 5 / _vm->_globals->_speed;
1442 	}
1443 	if (_oldDirection == DIR_UP) {
1444 		if (_oldFrameIndex > 11) {
1445 			oldPosX = _oldCharacterPosX;
1446 			oldPosY = _oldCharacterPosY;
1447 			oldFrameIdx = 0;
1448 		} else {
1449 			int deltaY = abs(_vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY);
1450 			if (_sprite[0]._zoomFactor < 0) {
1451 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1452 			} else if (_sprite[0]._zoomFactor > 0) {
1453 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1454 			}
1455 			oldPosX = _oldCharacterPosX;
1456 			oldPosY = _oldCharacterPosY - deltaY;
1457 			oldFrameIdx = _oldFrameIndex + 1;
1458 			if (oldFrameIdx > 11)
1459 				oldFrameIdx = 0;
1460 		}
1461 		_homeRateCounter = 4 / _vm->_globals->_speed;
1462 	}
1463 
1464 	if (_oldDirection == DIR_DOWN) {
1465 		if (_oldFrameIndex < 48 || _oldFrameIndex > 59) {
1466 			oldPosX = _oldCharacterPosX;
1467 			oldPosY = _oldCharacterPosY;
1468 			oldFrameIdx = 48;
1469 		} else {
1470 			int deltaY = abs(_vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY);
1471 			if (_sprite[0]._zoomFactor < 0) {
1472 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1473 			} else if (_sprite[0]._zoomFactor > 0) {
1474 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1475 			}
1476 			oldPosX = _oldCharacterPosX;
1477 			oldPosY = deltaY + _oldCharacterPosY;
1478 			oldFrameIdx = _oldFrameIndex + 1;
1479 			if (oldFrameIdx > 59)
1480 				oldFrameIdx = 48;
1481 		}
1482 		_homeRateCounter = 4 / _vm->_globals->_speed;
1483 	}
1484 	if (_oldDirection == DIR_UP_RIGHT) {
1485 		if (_oldFrameIndex < 12 || _oldFrameIndex > 23) {
1486 			oldPosX = _oldCharacterPosX;
1487 			oldPosY = _oldCharacterPosY;
1488 			oldFrameIdx = 12;
1489 		} else {
1490 			int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
1491 			int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
1492 			if (_sprite[0]._zoomFactor < 0) {
1493 				deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
1494 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1495 			}
1496 			if (_sprite[0]._zoomFactor > 0) {
1497 				deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
1498 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1499 			}
1500 			oldPosX = deltaX + _oldCharacterPosX;
1501 			oldPosY = _oldCharacterPosY + deltaY;
1502 			oldFrameIdx = _oldFrameIndex + 1;
1503 			if (oldFrameIdx > 23)
1504 				oldFrameIdx = 12;
1505 		}
1506 		_homeRateCounter = 5 / _vm->_globals->_speed;
1507 	}
1508 	if (_oldDirection == DIR_UP_LEFT) {
1509 		if (_oldFrameIndex < 12 || _oldFrameIndex > 23) {
1510 			oldPosX = _oldCharacterPosX;
1511 			oldPosY = _oldCharacterPosY;
1512 			oldFrameIdx = 12;
1513 		} else {
1514 			int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
1515 			int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
1516 			if (_sprite[0]._zoomFactor < 0) {
1517 				deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
1518 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1519 			} else if (_sprite[0]._zoomFactor > 0) {
1520 				deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
1521 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1522 			}
1523 			oldPosX = _oldCharacterPosX - deltaX;
1524 			oldPosY = _oldCharacterPosY + deltaY;
1525 			oldFrameIdx = _oldFrameIndex + 1;
1526 			if (oldFrameIdx > 23)
1527 				oldFrameIdx = 12;
1528 		}
1529 		_homeRateCounter = 5 / _vm->_globals->_speed;
1530 	}
1531 	if (_oldDirection == DIR_DOWN_RIGHT) {
1532 		if (_oldFrameIndex < 36 || _oldFrameIndex > 47) {
1533 			oldPosX = _oldCharacterPosX;
1534 			oldPosY = _oldCharacterPosY;
1535 			oldFrameIdx = 36;
1536 		} else {
1537 			int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
1538 			int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
1539 			if (_sprite[0]._zoomFactor < 0) {
1540 				deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
1541 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1542 			}
1543 			if (_sprite[0]._zoomFactor > 0) {
1544 				deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
1545 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1546 			}
1547 			oldPosX = deltaX + _oldCharacterPosX;
1548 			oldPosY = _oldCharacterPosY + deltaY;
1549 			oldFrameIdx = _oldFrameIndex + 1;
1550 			if (oldFrameIdx > 47)
1551 				oldFrameIdx = 36;
1552 		}
1553 		_homeRateCounter = 5 / _vm->_globals->_speed;
1554 	}
1555 	if (_oldDirection == DIR_DOWN_LEFT) {
1556 		if (_oldFrameIndex < 36 || _oldFrameIndex > 47) {
1557 			oldPosX = _oldCharacterPosX;
1558 			oldPosY = _oldCharacterPosY;
1559 			oldFrameIdx = 36;
1560 		} else {
1561 			int deltaX = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedX;
1562 			int deltaY = _vm->_globals->_hopkinsItem[_oldFrameIndex]._speedY;
1563 			if (_sprite[0]._zoomFactor < 0) {
1564 				deltaX = _vm->_graphicsMan->zoomOut(deltaX, -_sprite[0]._zoomFactor);
1565 				deltaY = _vm->_graphicsMan->zoomOut(deltaY, -_sprite[0]._zoomFactor);
1566 			}
1567 			if (_sprite[0]._zoomFactor > 0) {
1568 				deltaX = _vm->_graphicsMan->zoomIn(deltaX, _sprite[0]._zoomFactor);
1569 				deltaY = _vm->_graphicsMan->zoomIn(deltaY, _sprite[0]._zoomFactor);
1570 			}
1571 			oldPosX = _oldCharacterPosX - deltaX;
1572 			oldPosY = _oldCharacterPosY + deltaY;
1573 			oldFrameIdx = _oldFrameIndex + 1;
1574 			if (oldFrameIdx > 47)
1575 				oldFrameIdx = 36;
1576 		}
1577 		_homeRateCounter = 5 / _vm->_globals->_speed;
1578 	}
1579 	bool loopCond = false;
1580 	do {
1581 		newPosX = _vm->_linesMan->_route->_x;
1582 		newPosY = _vm->_linesMan->_route->_y;
1583 		newDirection = (Directions)_vm->_linesMan->_route->_dir;
1584 		_vm->_linesMan->_route++;
1585 
1586 		if (newPosX == -1 && newPosY == -1) {
1587 			int zoneId;
1588 			if (_vm->_globals->_actionMoveTo)
1589 				zoneId = _vm->_globals->_saveData->_data[svLastZoneNum];
1590 			else
1591 				zoneId = _zoneNum;
1592 			setSpriteIndex(0, _oldDirection + 59);
1593 			_vm->_globals->_actionDirection = DIR_NONE;
1594 			_vm->_linesMan->_route = NULL;
1595 			computeAndSetSpriteSize();
1596 			setFlipSprite(0, false);
1597 			_homeRateCounter = 0;
1598 			_oldDirection = DIR_NONE;
1599 			_oldCharacterPosX = getSpriteX(0);
1600 			_oldCharacterPosY = getSpriteY(0);
1601 
1602 			if (zoneId > 0) {
1603 				ZoneItem *curZone = &_vm->_linesMan->_zone[zoneId];
1604 				if (curZone->_destX && curZone->_destY && curZone->_destY != 31) {
1605 					if ( curZone->_spriteIndex == -1) {
1606 						curZone->_destX = 0;
1607 						curZone->_destY = 0;
1608 						curZone->_spriteIndex = 0;
1609 					} else {
1610 						setSpriteIndex(0,  curZone->_spriteIndex);
1611 						_vm->_globals->_actionDirection = curZone->_spriteIndex - 59;
1612 					}
1613 				}
1614 			}
1615 			_homeRateCounter = 0;
1616 			return;
1617 		}
1618 		if (_oldDirection != newDirection)
1619 			break;
1620 		if ((newDirection == DIR_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_LEFT && newPosX <= oldPosX) ||
1621 		    (_oldDirection == DIR_UP && newPosY <= oldPosY)   || (_oldDirection == DIR_DOWN && newPosY >= oldPosY) ||
1622 		    (_oldDirection == DIR_UP_RIGHT && newPosX >= oldPosX)   || (_oldDirection == DIR_UP_LEFT && newPosX <= oldPosX) ||
1623 		    (_oldDirection == DIR_DOWN_RIGHT && newPosX >= oldPosX) || (_oldDirection == DIR_DOWN_LEFT && newPosX <= oldPosX))
1624 			loopCond = true;
1625 	} while (!loopCond);
1626 	if (loopCond) {
1627 		computeAndSetSpriteSize();
1628 		if ((_oldDirection == DIR_DOWN_LEFT) || (_oldDirection == DIR_LEFT) || (_oldDirection == DIR_UP_LEFT))
1629 			setFlipSprite(0, true);
1630 
1631 		if ((_oldDirection == DIR_UP) || (_oldDirection == DIR_UP_RIGHT) || (_oldDirection == DIR_RIGHT) ||
1632 		    (_oldDirection == DIR_DOWN_RIGHT) || (_oldDirection == DIR_DOWN))
1633 			setFlipSprite(0, false);
1634 
1635 		setSpriteX(0, newPosX);
1636 		setSpriteY(0, newPosY);
1637 		setSpriteIndex(0, oldFrameIdx);
1638 	} else {
1639 		if ((_oldDirection == DIR_DOWN_LEFT) || (_oldDirection == DIR_LEFT) || (_oldDirection == DIR_UP_LEFT))
1640 			setFlipSprite(0, true);
1641 
1642 		if ((_oldDirection == DIR_UP) || (_oldDirection == DIR_UP_RIGHT) || (_oldDirection == DIR_RIGHT) ||
1643 		    (_oldDirection == DIR_DOWN_RIGHT) || (_oldDirection == DIR_DOWN))
1644 			setFlipSprite(0, false);
1645 		_homeRateCounter = 0;
1646 	}
1647 	_oldDirection = newDirection;
1648 	_oldDirectionSpriteIdx = newDirection + 59;
1649 	_oldFrameIndex = oldFrameIdx;
1650 	_oldCharacterPosX = newPosX;
1651 	_oldCharacterPosY = newPosY;
1652 }
1653 
goHome2()1654 void ObjectsManager::goHome2() {
1655 	if (_vm->_linesMan->_route == NULL)
1656 		return;
1657 
1658 	int realSpeed = 2;
1659 	if (_vm->_globals->_speed == 2)
1660 		realSpeed = 4;
1661 	else if (_vm->_globals->_speed == 3)
1662 		realSpeed = 6;
1663 
1664 	int countColisionPixel = 0;
1665 
1666 	for (;;) {
1667 		int nexPosX = _vm->_linesMan->_route->_x;
1668 		int newPosY = _vm->_linesMan->_route->_y;
1669 		Directions newDirection = (Directions)_vm->_linesMan->_route->_dir;
1670 		_vm->_linesMan->_route++;
1671 
1672 		if ((nexPosX == -1) && (newPosY == -1))
1673 			break;
1674 
1675 		++countColisionPixel;
1676 		if (countColisionPixel >= realSpeed) {
1677 			_lastDirection = newDirection;
1678 			setSpriteX(0, nexPosX);
1679 			setSpriteY(0, newPosY);
1680 			switch (_lastDirection) {
1681 			case DIR_UP:
1682 				setSpriteIndex(0, 4);
1683 				break;
1684 			case DIR_RIGHT:
1685 				setSpriteIndex(0, 5);
1686 				break;
1687 			case DIR_DOWN:
1688 				setSpriteIndex(0, 6);
1689 				break;
1690 			case DIR_LEFT:
1691 				setSpriteIndex(0, 7);
1692 				break;
1693 			default:
1694 				break;
1695 			}
1696 
1697 			return;
1698 		}
1699 	}
1700 
1701 	switch (_lastDirection) {
1702 	case DIR_UP:
1703 		setSpriteIndex(0, 0);
1704 		break;
1705 	case DIR_RIGHT:
1706 		setSpriteIndex(0, 1);
1707 		break;
1708 	case DIR_DOWN:
1709 		setSpriteIndex(0, 2);
1710 		break;
1711 	case DIR_LEFT:
1712 		setSpriteIndex(0, 3);
1713 		break;
1714 	default:
1715 		break;
1716 	}
1717 
1718 	_vm->_linesMan->_route = NULL;
1719 }
1720 
1721 /**
1722  * Load Zone
1723  */
loadZone(const Common::String & file)1724 void ObjectsManager::loadZone(const Common::String &file) {
1725 	for (int i = 1; i <= 100; i++) {
1726 		ZoneItem *curZone = &_vm->_linesMan->_zone[i];
1727 		curZone->_destX = 0;
1728 		curZone->_destY = 0;
1729 		curZone->_spriteIndex = 0;
1730 		curZone->_verbFl1 = 0;
1731 		curZone->_verbFl2 = 0;
1732 		curZone->_verbFl3 = 0;
1733 		curZone->_verbFl4 = 0;
1734 		curZone->_verbFl5 = 0;
1735 		curZone->_verbFl6 = 0;
1736 		curZone->_verbFl7 = 0;
1737 		curZone->_verbFl8 = 0;
1738 		curZone->_verbFl9 = 0;
1739 		curZone->_verbFl10 = 0;
1740 		curZone->_messageId = 0;
1741 		curZone->_enabledFl = false;
1742 	}
1743 
1744 	Common::File f;
1745 	if (!f.exists(file))
1746 		error("File not found : %s", file.c_str());
1747 
1748 	byte *ptr = _vm->_fileIO->loadFile(file);
1749 	int bufId = 0;
1750 	int zoneLineIdx = 0;
1751 	int bobZoneIdx;
1752 	do {
1753 		bobZoneIdx = READ_LE_INT16((uint16 *)ptr + bufId);
1754 		if (bobZoneIdx != -1) {
1755 			_vm->_linesMan->addZoneLine(
1756 			    zoneLineIdx,
1757 			    READ_LE_UINT16((uint16 *)ptr + bufId + 1),
1758 			    READ_LE_UINT16((uint16 *)ptr + bufId + 2),
1759 			    READ_LE_UINT16((uint16 *)ptr + bufId + 3),
1760 			    READ_LE_UINT16((uint16 *)ptr + bufId + 4),
1761 			    bobZoneIdx);
1762 			_vm->_linesMan->_zone[bobZoneIdx]._enabledFl = true;
1763 		}
1764 		bufId += 5;
1765 		++zoneLineIdx;
1766 	} while (bobZoneIdx != -1);
1767 
1768 	for (int i = 1; i <= 100; i++) {
1769 		ZoneItem *curZone = &_vm->_linesMan->_zone[i];
1770 		curZone->_destX = READ_LE_INT16((uint16 *)ptr + bufId);
1771 		curZone->_destY = READ_LE_INT16((uint16 *)ptr + bufId + 1);
1772 		curZone->_spriteIndex = READ_LE_INT16((uint16 *)ptr + bufId + 2);
1773 		bufId += 3;
1774 	}
1775 
1776 	byte *verbData = (ptr + 10 * zoneLineIdx + 606);
1777 	bufId = 0;
1778 	for (int i = 1; i <= 100; i++) {
1779 		ZoneItem *curZone = &_vm->_linesMan->_zone[i];
1780 		curZone->_verbFl1 = verbData[bufId];
1781 		curZone->_verbFl2 = verbData[bufId + 1];
1782 		curZone->_verbFl3 = verbData[bufId + 2];
1783 		curZone->_verbFl4 = verbData[bufId + 3];
1784 		curZone->_verbFl5 = verbData[bufId + 4];
1785 		curZone->_verbFl6 = verbData[bufId + 5];
1786 		curZone->_verbFl7 = verbData[bufId + 6];
1787 		curZone->_verbFl8 = verbData[bufId + 7];
1788 		curZone->_verbFl9 = verbData[bufId + 8];
1789 		curZone->_verbFl10 = verbData[bufId + 9];
1790 
1791 		bufId += 10;
1792 	}
1793 	verbData += 1010;
1794 	for (int i = 0; i < 100; i++)
1795 		_vm->_linesMan->_zone[i + 1]._messageId = READ_LE_UINT16(verbData + 2 * i);
1796 
1797 	_vm->_globals->freeMemory(ptr);
1798 	_vm->_linesMan->initSquareZones();
1799 }
1800 
handleCityMap()1801 void ObjectsManager::handleCityMap() {
1802 	_vm->_dialog->_inventFl = false;
1803 	_vm->_events->_gameKey = KEY_NONE;
1804 	_vm->_linesMan->setMaxLineIdx(1);
1805 	_vm->_globals->_characterMaxPosY = 440;
1806 	_vm->_globals->_cityMapEnabledFl = true;
1807 	_vm->_graphicsMan->_noFadingFl = false;
1808 	_vm->_globals->_freezeCharacterFl = false;
1809 	_spritePtr = NULL;
1810 	_vm->_globals->_exitId = 0;
1811 	_vm->_globals->_checkDistanceFl = true;
1812 	_vm->_soundMan->playSound(31);
1813 	_vm->_globals->_eventMode = EVENTMODE_IGNORE;
1814 	_vm->_graphicsMan->loadImage("PLAN");
1815 	_vm->_linesMan->loadLines("PLAN.OB2");
1816 	loadHidingItems("PLAN.CA2");
1817 	loadZone("PLAN.ZO2");
1818 	_spritePtr = _vm->_fileIO->loadFile("VOITURE.SPR");
1819 	_vm->_animMan->loadAnim("PLAN");
1820 	_vm->_graphicsMan->displayAllBob();
1821 	_vm->_graphicsMan->initScreen("PLAN", 2, false);
1822 	for (int i = 0; i <= 15; i++)
1823 		disableHidingItem(i);
1824 	disableHidingItem(19);
1825 	disableHidingItem(20);
1826 	enableHidingBehavior();
1827 
1828 	if (!_mapCarPosX && !_mapCarPosY) {
1829 		_mapCarPosX = 900;
1830 		_mapCarPosY = 319;
1831 	}
1832 	addStaticSprite(_spritePtr, Common::Point(_mapCarPosX, _mapCarPosY), 0, 1, 0, false, 5, 5);
1833 	_vm->_events->setMouseXY(_mapCarPosX, _mapCarPosY);
1834 	_vm->_events->mouseOn();
1835 	_vm->_graphicsMan->scrollScreen(getSpriteX(0) - 320);
1836 	_vm->_graphicsMan->_scrollOffset = getSpriteX(0) - 320;
1837 	animateSprite(0);
1838 	_vm->_linesMan->_route = NULL;
1839 	_vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
1840 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
1841 	_vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
1842 	_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
1843 
1844 	for (int i = 0; i <= 4; i++)
1845 		_vm->_events->refreshScreenAndEvents();
1846 
1847 	_vm->_globals->_eventMode = EVENTMODE_IGNORE;
1848 	_vm->_graphicsMan->fadeInLong();
1849 	_vm->_events->changeMouseCursor(4);
1850 	_vm->_graphicsMan->_noFadingFl = false;
1851 
1852 	bool loopCond = false;
1853 	do {
1854 		int mouseButton = _vm->_events->getMouseButton();
1855 		if (mouseButton) {
1856 			// First cop call : Go to the bank and free the hostages
1857 			if (_vm->_globals->_saveData->_data[svBankAttackAnimPlayedFl] == 1 && !_vm->_globals->_saveData->_data[svCopCall1PlayedFl]) {
1858 				_vm->_globals->_saveData->_data[svCopCall1PlayedFl] = 1;
1859 				_vm->_globals->_introSpeechOffFl = true;
1860 				_vm->_talkMan->startAnimatedCharacterDialogue("APPEL1.pe2");
1861 				_vm->_globals->_introSpeechOffFl = false;
1862 				mouseButton = 0;
1863 			}
1864 			// Second cop call: Helico has been found in the empty lot
1865 			if (_vm->_globals->_saveData->_data[svFreedHostageFl] == 1 && !_vm->_globals->_saveData->_data[svCopCall2PlayedFl]) {
1866 				_vm->_globals->_saveData->_data[svCopCall2PlayedFl] = 1;
1867 				_vm->_globals->_introSpeechOffFl = true;
1868 				_vm->_talkMan->startAnimatedCharacterDialogue("APPEL2.pe2");
1869 				_vm->_globals->_introSpeechOffFl = false;
1870 				mouseButton = 0;
1871 				_vm->_events->_curMouseButton = 0;
1872 			}
1873 			if (mouseButton == 1)
1874 				handleLeftButton();
1875 		}
1876 
1877 		_vm->_linesMan->checkZone();
1878 		goHome2();
1879 
1880 		if (_vm->_linesMan->_route == NULL && _vm->_globals->_actionMoveTo)
1881 			paradise();
1882 		_vm->_events->refreshScreenAndEvents();
1883 
1884 		if (_vm->_globals->_exitId)
1885 			loopCond = true;
1886 	} while (!_vm->shouldQuit() && !loopCond);
1887 
1888 	if (!_vm->_graphicsMan->_noFadingFl)
1889 		_vm->_graphicsMan->fadeOutLong();
1890 	_vm->_globals->_eventMode = EVENTMODE_DEFAULT;
1891 	_vm->_graphicsMan->_noFadingFl = false;
1892 	_mapCarPosX = getSpriteX(0);
1893 	_mapCarPosY = getSpriteY(0);
1894 	removeSprite(0);
1895 	_spritePtr = _vm->_globals->freeMemory(_spritePtr);
1896 	clearScreen();
1897 	_vm->_globals->_cityMapEnabledFl = false;
1898 }
1899 
1900 /**
1901  * Handle Left button
1902  */
handleLeftButton()1903 void ObjectsManager::handleLeftButton() {
1904 	_vm->_fontMan->hideText(9);
1905 	int destX = _vm->_events->getMouseX();
1906 	int destY = _vm->_events->getMouseY();
1907 
1908 	if (!_vm->_dialog->_inventFl && !_vm->_globals->_cityMapEnabledFl &&
1909 		destX > _vm->_graphicsMan->_scrollOffset - 30 && destX < _vm->_graphicsMan->_scrollOffset + 50 &&
1910 		destY > -30 && destY < 50) {
1911 		int oldMouseCursor = _vm->_events->_mouseCursorId;
1912 		_vm->_dialog->_inventFl = true;
1913 		_vm->_dialog->showInventory();
1914 		_vm->_dialog->_inventFl = false;
1915 		_vm->_events->_gameKey = KEY_NONE;
1916 		if (!_vm->_globals->_exitId) {
1917 			_vm->_dialog->_inventFl = false;
1918 			_vm->_events->_mouseCursorId = oldMouseCursor;
1919 		}
1920 		return;
1921 	}
1922 	if (_vm->_globals->_saveData->_data[svField354] == 1 && !_vm->_globals->_cityMapEnabledFl
1923 	    && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 59) {
1924 		changeCharacterHead(CHARACTER_HOPKINS_CLONE, CHARACTER_HOPKINS);
1925 		return;
1926 	}
1927 	if (_vm->_globals->_saveData->_data[svField356] == 1 && !_vm->_globals->_cityMapEnabledFl
1928 	    && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 48) {
1929 		changeCharacterHead(CHARACTER_SAMANTHA, CHARACTER_HOPKINS);
1930 		return;
1931 	}
1932 	if (_vm->_globals->_saveData->_data[svField357] == 1) {
1933 		if (_vm->_globals->_saveData->_data[svField353] == 1 && !_vm->_globals->_cityMapEnabledFl
1934 		    && destX >= 533 && destX <= 559 && destY >= 26 && destY <= 59) {
1935 			changeCharacterHead(CHARACTER_HOPKINS, CHARACTER_HOPKINS_CLONE);
1936 			return;
1937 		}
1938 		if (_vm->_globals->_saveData->_data[svField355] == 1 && !_vm->_globals->_cityMapEnabledFl
1939 		    && destX >= 567 && destX <= 593 && destY >= 26 && destY <= 59) {
1940 			changeCharacterHead(CHARACTER_HOPKINS, CHARACTER_SAMANTHA);
1941 			return;
1942 		}
1943 	}
1944 	if (_vm->_globals->_cityMapEnabledFl && _vm->_globals->_actionMoveTo) {
1945 		_vm->_linesMan->checkZone();
1946 		if (_zoneNum <= 0)
1947 			return;
1948 		int routeIdx = 0;
1949 		do {
1950 			_vm->_linesMan->_testRoute2[routeIdx] = _vm->_linesMan->_route[routeIdx];
1951 			++routeIdx;
1952 		} while (_vm->_linesMan->_route[routeIdx]._x != -1);
1953 
1954 		_vm->_linesMan->_testRoute2[routeIdx].invalidate();
1955 	}
1956 
1957 	if (_vm->_globals->_actionMoveTo) {
1958 		_vm->_linesMan->checkZone();
1959 		_vm->_globals->_actionMoveTo = false;
1960 		_vm->_globals->_saveData->_data[svLastMouseCursor] = 0;
1961 		_vm->_globals->_saveData->_data[svLastZoneNum] = 0;
1962 	}
1963 
1964 	if (_vm->_globals->_cityMapEnabledFl && (_vm->_events->_mouseCursorId != 4 || _zoneNum <= 0))
1965 		return;
1966 	if (_zoneNum != -1 && _zoneNum != 0) {
1967 		ZoneItem *curZone = &_vm->_linesMan->_zone[_zoneNum];
1968 		if (curZone->_destX && curZone->_destY && curZone->_destY != 31) {
1969 			destX = curZone->_destX;
1970 			destY = curZone->_destY;
1971 		}
1972 	}
1973 	_vm->_globals->_actionMoveTo = false;
1974 	RouteItem *oldRoute = _vm->_linesMan->_route;
1975 	_vm->_linesMan->_route = NULL;
1976 	if (_forestFl && _zoneNum >= 20 && _zoneNum <= 23) {
1977 		if (getSpriteY(0) > 374 && getSpriteY(0) <= 410) {
1978 			_vm->_linesMan->_route = NULL;
1979 			setSpriteIndex(0, _oldDirectionSpriteIdx);
1980 			_vm->_globals->_actionDirection = DIR_NONE;
1981 			_vm->_linesMan->_route = NULL;
1982 			computeAndSetSpriteSize();
1983 			setFlipSprite(0, false);
1984 			_homeRateCounter = 0;
1985 			_oldDirection = DIR_NONE;
1986 		} else {
1987 			_vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), getSpriteX(0), 390);
1988 			if (_vm->_linesMan->_route)
1989 				_vm->_linesMan->optimizeRoute(_vm->_linesMan->_route);
1990 			_oldCharacterPosX = getSpriteX(0);
1991 			_oldCharacterPosY = getSpriteY(0);
1992 			_homeRateCounter = 0;
1993 			if (_vm->_linesMan->_route || oldRoute == _vm->_linesMan->_route) {
1994 				_oldDirection = DIR_NONE;
1995 			} else {
1996 				_vm->_linesMan->_route = oldRoute;
1997 			}
1998 		}
1999 	} else {
2000 		if (!_vm->_globals->_freezeCharacterFl && !_vm->_globals->_cityMapEnabledFl) {
2001 			_vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), destX, destY);
2002 			if (_vm->_linesMan->_route)
2003 				_vm->_linesMan->optimizeRoute(_vm->_linesMan->_route);
2004 			_oldCharacterPosX = getSpriteX(0);
2005 			_oldCharacterPosY = getSpriteY(0);
2006 			_homeRateCounter = 0;
2007 			if (_vm->_linesMan->_route || oldRoute == _vm->_linesMan->_route)
2008 				_oldDirection = DIR_NONE;
2009 			else
2010 				_vm->_linesMan->_route = oldRoute;
2011 		}
2012 	}
2013 
2014 	if (!_vm->_globals->_freezeCharacterFl && _vm->_globals->_cityMapEnabledFl)
2015 		_vm->_linesMan->_route = _vm->_linesMan->cityMapCarRoute(getSpriteX(0), getSpriteY(0), destX, destY);
2016 
2017 	if (_zoneNum != -1 && _zoneNum != 0) {
2018 		if (_vm->_events->_mouseCursorId == 23)
2019 			_vm->_globals->_saveData->_data[svLastMouseCursor] = 5;
2020 		else
2021 			_vm->_globals->_saveData->_data[svLastMouseCursor] = _vm->_events->_mouseCursorId;
2022 
2023 		if (_vm->_globals->_cityMapEnabledFl)
2024 			_vm->_globals->_saveData->_data[svLastMouseCursor] = 6;
2025 		_vm->_globals->_saveData->_data[svLastZoneNum] = _zoneNum;
2026 		_vm->_globals->_saveData->_data[svLastObjectIndex] = _curObjectIndex;
2027 		_vm->_globals->_actionMoveTo = true;
2028 	}
2029 	_vm->_fontMan->hideText(5);
2030 	_vm->_graphicsMan->setColorPercentage2(251, 100, 100, 100);
2031 	if (_vm->_globals->_screenId == 20 && _vm->_globals->_saveData->_data[svField132] == 1
2032 				&& _curObjectIndex == 20 && _zoneNum == 12
2033 				&& _vm->_events->_mouseCursorId == 23) {
2034 		// Special case for throwing darts at the switch in Purgatory - the player shouldn't move
2035 		_vm->_linesMan->_route = NULL;
2036 		getSpriteX(0);
2037 		getSpriteY(0);
2038 	}
2039 }
2040 
paradise()2041 void ObjectsManager::paradise() {
2042 	char result = _vm->_globals->_saveData->_data[svLastMouseCursor];
2043 	if (result && _vm->_globals->_saveData->_data[svLastZoneNum] && result != 4 && result > 3) {
2044 		_vm->_fontMan->hideText(5);
2045 		if (!_forestFl || _zoneNum < 20 || _zoneNum > 23) {
2046 			if (_vm->_graphicsMan->_largeScreenFl) {
2047 				_vm->_graphicsMan->_scrollStatus = 2;
2048 				if (_vm->_events->_startPos.x + 320 - getSpriteX(0) > 160) {
2049 					bool loopCond = false;
2050 					do {
2051 						_vm->_graphicsMan->_scrollPosX -= _vm->_graphicsMan->_scrollSpeed;
2052 						if (_vm->_graphicsMan->_scrollPosX < 0) {
2053 							_vm->_graphicsMan->_scrollPosX = 0;
2054 							loopCond = true;
2055 						}
2056 						if (_vm->_graphicsMan->_scrollPosX > SCREEN_WIDTH) {
2057 							_vm->_graphicsMan->_scrollPosX = SCREEN_WIDTH;
2058 							loopCond = true;
2059 						}
2060 						if (_vm->_events->getMouseX() > _vm->_graphicsMan->_scrollPosX + 620)
2061 							_vm->_events->setMouseXY(_vm->_events->_mousePos.x - 4, _vm->_events->getMouseY());
2062 
2063 						_vm->_events->refreshScreenAndEvents();
2064 					} while (!loopCond && _vm->_events->_startPos.x > getSpriteX(0) - 320);
2065 				} else if (_vm->_events->_startPos.x + 320 - getSpriteX(0) < -160) {
2066 					bool loopCond = false;
2067 					do {
2068 						_vm->_graphicsMan->_scrollPosX += _vm->_graphicsMan->_scrollSpeed;
2069 						if (_vm->_graphicsMan->_scrollPosX < 0) {
2070 							_vm->_graphicsMan->_scrollPosX = 0;
2071 							loopCond = true;
2072 						}
2073 						if (_vm->_graphicsMan->_scrollPosX > SCREEN_WIDTH) {
2074 							_vm->_graphicsMan->_scrollPosX = SCREEN_WIDTH;
2075 							loopCond = true;
2076 						}
2077 						if (_vm->_events->getMouseX() < _vm->_graphicsMan->_scrollPosX + 10)
2078 							_vm->_events->setMouseXY(_vm->_events->_mousePos.x + 4, _vm->_events->getMouseY());
2079 
2080 						_vm->_events->refreshScreenAndEvents();
2081 					} while (!loopCond && _vm->_events->_startPos.x < getSpriteX(0) - 320);
2082 				}
2083 				if (_vm->_events->getMouseX() > _vm->_graphicsMan->_scrollPosX + 620)
2084 					_vm->_events->setMouseXY(_vm->_graphicsMan->_scrollPosX + 610, 0);
2085 				if (_vm->_events->getMouseX() < _vm->_graphicsMan->_scrollPosX + 10)
2086 					_vm->_events->setMouseXY(_vm->_graphicsMan->_scrollPosX + 10, 0);
2087 				_vm->_events->refreshScreenAndEvents();
2088 				_vm->_graphicsMan->_scrollStatus = 0;
2089 			}
2090 			_vm->_talkMan->handleAnswer(_vm->_globals->_saveData->_data[svLastZoneNum], _vm->_globals->_saveData->_data[svLastMouseCursor]);
2091 		} else {
2092 			_vm->_talkMan->handleForestAnswser(_vm->_globals->_saveData->_data[svLastZoneNum], _vm->_globals->_saveData->_data[svLastMouseCursor]);
2093 		}
2094 		_vm->_events->changeMouseCursor(4);
2095 		if (_zoneNum != -1 && _zoneNum != 0 && !_vm->_linesMan->_zone[_zoneNum]._enabledFl) {
2096 			_zoneNum = -1;
2097 			_forceZoneFl = true;
2098 		}
2099 		if (_zoneNum != _vm->_globals->_saveData->_data[svLastZoneNum] || _zoneNum == -1 || _zoneNum == 0) {
2100 			_vm->_events->_mouseCursorId = 4;
2101 			_changeVerbFl = false;
2102 		} else {
2103 			_vm->_events->_mouseCursorId = _vm->_globals->_saveData->_data[svLastMouseCursor];
2104 			if (_changeVerbFl) {
2105 				nextVerbIcon();
2106 				_changeVerbFl = false;
2107 			}
2108 			if (_vm->_events->_mouseCursorId == 5)
2109 				_vm->_events->_mouseCursorId = 4;
2110 		}
2111 		if (_vm->_events->_mouseCursorId != 23)
2112 			_vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId);
2113 		_zoneNum = 0;
2114 		_vm->_globals->_saveData->_data[svLastMouseCursor] = 0;
2115 		_vm->_globals->_saveData->_data[svLastZoneNum] = 0;
2116 	}
2117 	if (_vm->_globals->_cityMapEnabledFl) {
2118 		_vm->_events->_mouseCursorId = 0;
2119 		_vm->_events->changeMouseCursor(0);
2120 	}
2121 	if (_vm->_globals->_freezeCharacterFl && _vm->_events->_mouseCursorId == 4) {
2122 		if (_zoneNum != -1 && _zoneNum != 0)
2123 			handleRightButton();
2124 	}
2125 	_vm->_globals->_actionMoveTo = false;
2126 }
2127 
2128 /**
2129  * Clear Screen
2130  */
clearScreen()2131 void ObjectsManager::clearScreen() {
2132 	clearSprite();
2133 	_vm->_graphicsMan->endDisplayBob();
2134 	_vm->_fontMan->hideText(5);
2135 	_vm->_fontMan->hideText(9);
2136 	clearVBob();
2137 	_vm->_animMan->clearAnim();
2138 	_vm->_linesMan->clearAllZones();
2139 	_vm->_linesMan->resetLines();
2140 	resetHidingItems();
2141 
2142 	for (int i = 0; i <= 48; i++) {
2143 		_vm->_linesMan->_bobZone[i] = 0;
2144 		_vm->_linesMan->_bobZoneFl[i] = false;
2145 	}
2146 	_vm->_events->_mouseCursorId = 4;
2147 	_verb = 4;
2148 	_zoneNum = 0;
2149 	_forceZoneFl = true;
2150 	_vm->_linesMan->resetLinesNumb();
2151 	_vm->_linesMan->resetLastLine();
2152 	_vm->_linesMan->_route = NULL;
2153 	_vm->_globals->_answerBuffer = _vm->_globals->freeMemory(_vm->_globals->_answerBuffer);
2154 	_vm->_globals->_levelSpriteBuf = _vm->_globals->freeMemory(_vm->_globals->_levelSpriteBuf);
2155 	_vm->_events->_startPos.x = 0;
2156 	_vm->_events->_mouseSpriteId = 0;
2157 	_vm->_globals->_saveData->_data[svLastMouseCursor] = 0;
2158 	_vm->_globals->_saveData->_data[svLastZoneNum] = 0;
2159 	_vm->_globals->_actionMoveTo = false;
2160 	_forceZoneFl = true;
2161 	_changeVerbFl = false;
2162 	_vm->_linesMan->_route = NULL;
2163 	_oldDirection = DIR_NONE;
2164 	_vm->_graphicsMan->resetDirtyRects();
2165 }
2166 
2167 /**
2168  * Change the currently active player face / Head
2169  * @param oldCharacter		Previously played character
2170  * @param newCharacter		New character to play
2171  */
changeCharacterHead(PlayerCharacter oldCharacter,PlayerCharacter newCharacter)2172 void ObjectsManager::changeCharacterHead(PlayerCharacter oldCharacter, PlayerCharacter newCharacter) {
2173 	CharacterLocation *loc;
2174 
2175 	_changeHeadFl = true;
2176 	_vm->_graphicsMan->copySurface(_vm->_graphicsMan->_backBuffer, 532, 25, 65, 40, _vm->_graphicsMan->_frontBuffer, 532, 25);
2177 	_vm->_graphicsMan->addDirtyRect(532, 25, 597, 65);
2178 	_vm->_globals->_checkDistanceFl = true;
2179 	_vm->_linesMan->_route = NULL;
2180 
2181 	if (oldCharacter == CHARACTER_SAMANTHA && newCharacter == CHARACTER_HOPKINS
2182 		&& _vm->_globals->_saveData->_realHopkins._location == _vm->_globals->_screenId) {
2183 		_changeHeadFl = false;
2184 		loc = &_vm->_globals->_saveData->_samantha;
2185 		loc->_pos.x = getSpriteX(0);
2186 		loc->_pos.y = getSpriteY(0);
2187 		loc->_startSpriteIndex = 64;
2188 		loc->_location = _vm->_globals->_screenId;
2189 		loc->_zoomFactor = _sprite[0]._zoomFactor;
2190 
2191 		removeSprite(1);
2192 		addStaticSprite(_headSprites, loc->_pos, 1, 3, loc->_zoomFactor, false, 20, 127);
2193 		animateSprite(1);
2194 		removeSprite(0);
2195 
2196 		_vm->_globals->_saveData->_data[svField354] = 0;
2197 		_vm->_globals->_saveData->_data[svField356] = 0;
2198 		_vm->_globals->_saveData->_data[svField357] = 1;
2199 
2200 		loc = &_vm->_globals->_saveData->_realHopkins;
2201 		_vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR");
2202 		_vm->_globals->_characterType = CHARACTER_HOPKINS;
2203 		addStaticSprite(_vm->_globals->_characterSpriteBuf, loc->_pos, 0, 64, loc->_zoomFactor, false, 34, 190);
2204 		animateSprite(0);
2205 		_vm->_globals->loadCharacterData();
2206 	} else if (oldCharacter == CHARACTER_HOPKINS && newCharacter == CHARACTER_SAMANTHA
2207 			&& _vm->_globals->_saveData->_samantha._location == _vm->_globals->_screenId) {
2208 		_changeHeadFl = false;
2209 		loc = &_vm->_globals->_saveData->_realHopkins;
2210 		loc->_pos.x = getSpriteX(0);
2211 		loc->_pos.y = getSpriteY(0);
2212 		loc->_startSpriteIndex = 64;
2213 		loc->_location = _vm->_globals->_screenId;
2214 		loc->_zoomFactor = _sprite[0]._zoomFactor;
2215 
2216 		removeSprite(1);
2217 		addStaticSprite(_headSprites, loc->_pos, 1, 2, loc->_zoomFactor, false, 34, 190);
2218 		animateSprite(1);
2219 		removeSprite(0);
2220 
2221 		_vm->_globals->_saveData->_data[svField354] = 0;
2222 		_vm->_globals->_saveData->_data[svField356] = 1;
2223 		_vm->_globals->_saveData->_data[svField357] = 0;
2224 
2225 		loc = &_vm->_globals->_saveData->_samantha;
2226 		_vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PSAMAN.SPR");
2227 		_vm->_globals->_characterType = CHARACTER_SAMANTHA;
2228 		addStaticSprite(_vm->_globals->_characterSpriteBuf, loc->_pos, 0, 64, loc->_zoomFactor, false, 20, 127);
2229 		animateSprite(0);
2230 		_vm->_globals->loadCharacterData();
2231 	} else {
2232 		switch (oldCharacter) {
2233 		case CHARACTER_HOPKINS:
2234 			loc = &_vm->_globals->_saveData->_realHopkins;
2235 			loc->_pos.x = getSpriteX(0);
2236 			loc->_pos.y = getSpriteY(0);
2237 			loc->_startSpriteIndex = 64;
2238 			loc->_location = _vm->_globals->_screenId;
2239 			loc->_zoomFactor = _sprite[0]._zoomFactor;
2240 			break;
2241 		case CHARACTER_HOPKINS_CLONE:
2242 			loc = &_vm->_globals->_saveData->_cloneHopkins;
2243 			loc->_pos.x = getSpriteX(0);
2244 			loc->_pos.y = getSpriteY(0);
2245 			loc->_startSpriteIndex = 64;
2246 			loc->_location = _vm->_globals->_screenId;
2247 			loc->_zoomFactor = _sprite[0]._zoomFactor;
2248 			break;
2249 		case CHARACTER_SAMANTHA:
2250 			loc = &_vm->_globals->_saveData->_samantha;
2251 			loc->_pos.x = getSpriteX(0);
2252 			loc->_pos.y = getSpriteY(0);
2253 			loc->_startSpriteIndex = 64;
2254 			loc->_location = _vm->_globals->_screenId;
2255 			loc->_zoomFactor = _sprite[0]._zoomFactor;
2256 			break;
2257 		default:
2258 			break;
2259 		}
2260 
2261 		switch (newCharacter) {
2262 		case CHARACTER_HOPKINS:
2263 			_vm->_globals->_saveData->_data[svHopkinsCloneFl] = 0;
2264 			_vm->_globals->_saveData->_data[svField354] = 0;
2265 			_vm->_globals->_saveData->_data[svField356] = 0;
2266 			_vm->_globals->_saveData->_data[svField357] = 1;
2267 			_vm->_globals->_exitId = _vm->_globals->_saveData->_realHopkins._location;
2268 			break;
2269 		case CHARACTER_HOPKINS_CLONE:
2270 			_vm->_globals->_saveData->_data[svHopkinsCloneFl] = 1;
2271 			_vm->_globals->_saveData->_data[svField354] = 1;
2272 			_vm->_globals->_saveData->_data[svField356] = 0;
2273 			_vm->_globals->_saveData->_data[svField357] = 0;
2274 			_vm->_globals->_exitId = _vm->_globals->_saveData->_cloneHopkins._location;
2275 			break;
2276 		case CHARACTER_SAMANTHA:
2277 			_vm->_globals->_saveData->_data[svHopkinsCloneFl] = 0;
2278 			_vm->_globals->_saveData->_data[svField354] = 0;
2279 			_vm->_globals->_saveData->_data[svField356] = 1;
2280 			_vm->_globals->_saveData->_data[svField357] = 0;
2281 			_vm->_globals->_exitId = _vm->_globals->_saveData->_samantha._location;
2282 			break;
2283 		default:
2284 			break;
2285 		}
2286 	}
2287 }
2288 
2289 // Check Size
computeAndSetSpriteSize()2290 void ObjectsManager::computeAndSetSpriteSize() {
2291 	int size = _vm->_globals->_spriteSize[getSpriteY(0)];
2292 	if (_vm->_globals->_characterType == CHARACTER_HOPKINS_CLONE) {
2293 		size = 20 * (5 * abs(size) - 100) / -80;
2294 	} else if (_vm->_globals->_characterType == CHARACTER_SAMANTHA) {
2295 		size = 20 * (5 * abs(size) - 165) / -67;
2296 	}
2297 	setSpriteZoom(0, size);
2298 }
2299 
2300 /**
2301  * Get next verb icon (or text)
2302  */
nextVerbIcon()2303 void ObjectsManager::nextVerbIcon() {
2304 	_vm->_events->_mouseCursorId++;
2305 
2306 	for(;;) {
2307 		if (_vm->_events->_mouseCursorId == 4) {
2308 			if (!_vm->_globals->_freezeCharacterFl || _zoneNum == -1 || _zoneNum == 0)
2309 				return;
2310 
2311 			++_vm->_events->_mouseCursorId;
2312 		}
2313 
2314 		if (_vm->_events->_mouseCursorId == 5 || _vm->_events->_mouseCursorId == 6) {
2315 			_vm->_events->_mouseCursorId = 6;
2316 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl1 == 1)
2317 				return;
2318 
2319 			++_vm->_events->_mouseCursorId;
2320 		}
2321 
2322 		if (_vm->_events->_mouseCursorId == 7) {
2323 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl2 == 1)
2324 				return;
2325 
2326 			++_vm->_events->_mouseCursorId;
2327 		}
2328 
2329 		if (_vm->_events->_mouseCursorId == 8) {
2330 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl3 == 1)
2331 				return;
2332 
2333 			++_vm->_events->_mouseCursorId;
2334 		}
2335 
2336 		if (_vm->_events->_mouseCursorId == 9) {
2337 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 1)
2338 				return;
2339 
2340 			++_vm->_events->_mouseCursorId;
2341 		}
2342 
2343 		if (_vm->_events->_mouseCursorId == 10) {
2344 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl5 == 1)
2345 				return;
2346 			++_vm->_events->_mouseCursorId;
2347 		}
2348 
2349 		if (_vm->_events->_mouseCursorId == 11) {
2350 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl6 == 1)
2351 				return;
2352 
2353 			++_vm->_events->_mouseCursorId;
2354 		}
2355 
2356 		if (_vm->_events->_mouseCursorId == 12) {
2357 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl7 == 1)
2358 				return;
2359 
2360 			++_vm->_events->_mouseCursorId;
2361 		}
2362 
2363 		if (_vm->_events->_mouseCursorId == 13) {
2364 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl8 == 1)
2365 				return;
2366 
2367 			++_vm->_events->_mouseCursorId;
2368 		}
2369 
2370 		if (_vm->_events->_mouseCursorId == 14) {
2371 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl9 == 1)
2372 				return;
2373 
2374 			++_vm->_events->_mouseCursorId;
2375 		}
2376 
2377 		if (_vm->_events->_mouseCursorId == 15) {
2378 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl10 == 1)
2379 				return;
2380 
2381 			++_vm->_events->_mouseCursorId;
2382 		}
2383 
2384 		if (_vm->_events->_mouseCursorId == 16) {
2385 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl1 == 2)
2386 				return;
2387 
2388 			++_vm->_events->_mouseCursorId;
2389 		}
2390 
2391 		if (_vm->_events->_mouseCursorId == 17) {
2392 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 2)
2393 				return;
2394 
2395 			++_vm->_events->_mouseCursorId;
2396 		}
2397 
2398 		if (_vm->_events->_mouseCursorId == 18) {
2399 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl5 == 2)
2400 				return;
2401 
2402 			++_vm->_events->_mouseCursorId;
2403 		}
2404 
2405 		if (_vm->_events->_mouseCursorId == 19) {
2406 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl6 == 2)
2407 				return;
2408 
2409 			++_vm->_events->_mouseCursorId;
2410 		}
2411 
2412 		if (_vm->_events->_mouseCursorId == 20) {
2413 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl7 == 2)
2414 				return;
2415 
2416 			++_vm->_events->_mouseCursorId;
2417 		}
2418 
2419 		if (_vm->_events->_mouseCursorId == 21) {
2420 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl10 == 2)
2421 				return;
2422 
2423 			++_vm->_events->_mouseCursorId;
2424 		}
2425 
2426 		if (_vm->_events->_mouseCursorId == 22) {
2427 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl8 == 2)
2428 				return;
2429 
2430 			++_vm->_events->_mouseCursorId;
2431 		}
2432 
2433 		if (_vm->_events->_mouseCursorId == 23) {
2434 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl3 == 2)
2435 				return;
2436 
2437 			++_vm->_events->_mouseCursorId;
2438 		}
2439 
2440 		if (_vm->_events->_mouseCursorId == 24) {
2441 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl4 == 3)
2442 				return;
2443 
2444 			++_vm->_events->_mouseCursorId;
2445 		}
2446 
2447 		if (_vm->_events->_mouseCursorId == 25) {
2448 			if (_vm->_linesMan->_zone[_zoneNum]._verbFl9 == 2)
2449 				return;
2450 		}
2451 		_vm->_events->_mouseCursorId = 4;
2452 	}
2453 }
2454 
2455 /**
2456  * Handle Right button
2457  */
handleRightButton()2458 void ObjectsManager::handleRightButton() {
2459 	if (_zoneNum != -1 && _zoneNum != 0) {
2460 		nextVerbIcon();
2461 		if (_vm->_events->_mouseCursorId != 23)
2462 			_vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId);
2463 		_verb = _vm->_events->_mouseCursorId;
2464 	}
2465 }
2466 
2467 /**
2468  * Prepare border used to highlight the place below mouse cursor, in the inventory.
2469  * Also set the mouse cursor
2470  */
initBorder(int zoneIdx)2471 void ObjectsManager::initBorder(int zoneIdx) {
2472 	_oldBorderPos = _borderPos;
2473 	_oldBorderSpriteIndex = _borderSpriteIndex;
2474 	if (zoneIdx >= 1 && zoneIdx <= 6)
2475 		_borderPos.y = 120;
2476 	else if (zoneIdx >= 7 && zoneIdx <= 12)
2477 		_borderPos.y = 158;
2478 	else if (zoneIdx >= 13 && zoneIdx <= 18)
2479 		_borderPos.y = 196;
2480 	else if (zoneIdx >= 19 && zoneIdx <= 24)
2481 		_borderPos.y = 234;
2482 	else if (zoneIdx >= 25 && zoneIdx <= 29)
2483 		_borderPos.y = 272;
2484 	else if (zoneIdx == 30)
2485 		_borderPos.y = 272;
2486 	else if (zoneIdx == 31)
2487 		_borderPos.y = 290;
2488 
2489 	if (zoneIdx == 1 || zoneIdx == 7 || zoneIdx == 13 || zoneIdx == 19 || zoneIdx == 25)
2490 		_borderPos.x = _vm->_graphicsMan->_scrollOffset + 158;
2491 	else if (zoneIdx == 2 || zoneIdx == 8 || zoneIdx == 14 || zoneIdx == 20 || zoneIdx == 26)
2492 		_borderPos.x = _vm->_graphicsMan->_scrollOffset + 212;
2493 	else if (zoneIdx == 3 || zoneIdx == 9 || zoneIdx == 15 || zoneIdx == 21 || zoneIdx == 27)
2494 		_borderPos.x = _vm->_graphicsMan->_scrollOffset + 266;
2495 	else if (zoneIdx == 4 || zoneIdx == 10 || zoneIdx == 16 || zoneIdx == 22 || zoneIdx == 28)
2496 		_borderPos.x = _vm->_graphicsMan->_scrollOffset + 320;
2497 	else if (zoneIdx == 5 || zoneIdx == 11 || zoneIdx == 17 || zoneIdx == 23 || zoneIdx == 29)
2498 		_borderPos.x = _vm->_graphicsMan->_scrollOffset + 374;
2499 	else if (zoneIdx == 6 || zoneIdx == 12 || zoneIdx == 18 || zoneIdx == 24 || zoneIdx == 30 || zoneIdx == 31)
2500 		_borderPos.x = _vm->_graphicsMan->_scrollOffset + 428;
2501 
2502 	if (zoneIdx >= 1 && zoneIdx <= 29)
2503 		_borderSpriteIndex = 0;
2504 	else if (zoneIdx == 30 || zoneIdx == 31)
2505 		_borderSpriteIndex = 2;
2506 	else if (!zoneIdx || zoneIdx == 32) {
2507 		_borderPos = Common::Point(0, 0);
2508 		_borderSpriteIndex = 0;
2509 	}
2510 
2511 	if (!zoneIdx)
2512 		_vm->_events->_mouseCursorId = 0;
2513 	else if (zoneIdx >= 1 && zoneIdx <= 28)
2514 		_vm->_events->_mouseCursorId = 8;
2515 	else if (zoneIdx == 29)
2516 		_vm->_events->_mouseCursorId = 1;
2517 	else if (zoneIdx == 30)
2518 		_vm->_events->_mouseCursorId = 2;
2519 	else if (zoneIdx == 31)
2520 		_vm->_events->_mouseCursorId = 3;
2521 	else if (zoneIdx == 32)
2522 		_vm->_events->_mouseCursorId = 16;
2523 
2524 	if (zoneIdx >= 1 && zoneIdx <= 28 && !_vm->_globals->_inventory[zoneIdx]) {
2525 		_vm->_events->_mouseCursorId = 0;
2526 		_borderPos = Common::Point(0, 0);
2527 		_borderSpriteIndex = 0;
2528 	}
2529 
2530 	if (_vm->_events->_mouseCursorId != 23)
2531 		_vm->_events->changeMouseCursor(_vm->_events->_mouseCursorId);
2532 	_vm->_events->getMouseX();
2533 	_vm->_events->getMouseY();
2534 }
2535 
2536 /**
2537  * Get next icon for an object in the inventory
2538  */
nextObjectIcon(int idx)2539 void ObjectsManager::nextObjectIcon(int idx) {
2540 	int cursorId = _vm->_events->_mouseCursorId;
2541 	ObjectAuthIcon *curAuthIco = &_objectAuthIcons[_vm->_globals->_inventory[idx]];
2542 
2543 	if (cursorId == 0 || cursorId == 2 || cursorId == 3 || cursorId == 16)
2544 		return;
2545 
2546 	int nextCursorId = cursorId + 1;
2547 	if (nextCursorId > 25)
2548 		nextCursorId = 6;
2549 
2550 	do {
2551 		if (nextCursorId == 2 || nextCursorId == 5 || nextCursorId == 6) {
2552 			_vm->_events->_mouseCursorId = 6;
2553 			if (curAuthIco->_flag1 == 1)
2554 				return;
2555 			nextCursorId++;
2556 		}
2557 		if (nextCursorId == 7) {
2558 			_vm->_events->_mouseCursorId = 7;
2559 			if (curAuthIco->_flag2 == 1)
2560 				return;
2561 			nextCursorId++;
2562 		}
2563 		if (nextCursorId == 8) {
2564 			_vm->_events->_mouseCursorId = 8;
2565 			return;
2566 		}
2567 		if (nextCursorId == 9 || nextCursorId == 10) {
2568 			_vm->_events->_mouseCursorId = 10;
2569 			if (curAuthIco->_flag6 == 1)
2570 				return;
2571 			nextCursorId = 11;
2572 		}
2573 
2574 		if (nextCursorId == 11) {
2575 			_vm->_events->_mouseCursorId = 11;
2576 			if (curAuthIco->_flag3 == 1)
2577 				return;
2578 			nextCursorId++;
2579 		}
2580 
2581 		if (nextCursorId == 12 || nextCursorId == 13) {
2582 			_vm->_events->_mouseCursorId = 13;
2583 			if (curAuthIco->_flag4 == 1)
2584 				return;
2585 			nextCursorId = 14;
2586 		}
2587 
2588 		if (nextCursorId == 14 || nextCursorId == 15) {
2589 			_vm->_events->_mouseCursorId = 15;
2590 			if (curAuthIco->_flag5 == 1)
2591 				return;
2592 			nextCursorId = 23;
2593 		}
2594 
2595 		if (nextCursorId >= 16 && nextCursorId <= 23) {
2596 			_vm->_events->_mouseCursorId = 23;
2597 			if (curAuthIco->_flag5 == 2)
2598 				return;
2599 			nextCursorId = 24;
2600 		}
2601 
2602 		if (nextCursorId == 24 || nextCursorId == 25) {
2603 			_vm->_events->_mouseCursorId = 25;
2604 		}
2605 
2606 		nextCursorId = 6;
2607 	} while (curAuthIco->_flag6 != 2);
2608 }
2609 
takeInventoryObject(int idx)2610 void ObjectsManager::takeInventoryObject(int idx) {
2611 	if (_vm->_events->_mouseCursorId == 8)
2612 		changeObject(idx);
2613 }
2614 
loadObjectIniFile()2615 void ObjectsManager::loadObjectIniFile() {
2616 	byte *data;
2617 	Common::String file;
2618 	int lastOpcodeResult = 1;
2619 
2620 	file = "OBJET1.ini";
2621 	bool fileFoundFl = false;
2622 	data = _vm->_fileIO->searchCat(file, RES_INI, fileFoundFl);
2623 	if (!fileFoundFl) {
2624 		data = _vm->_fileIO->loadFile(file);
2625 		if (data == NULL)
2626 			error("INI file %s not found", file.c_str());
2627 	}
2628 
2629 	if (READ_BE_UINT24(data) != MKTAG24('I', 'N', 'I'))
2630 		error("File %s is not an INI file", file.c_str());
2631 
2632 	for (;;) {
2633 		int opcodeType = _vm->_script->handleOpcode(data + 20 * lastOpcodeResult);
2634 		if (opcodeType == -1 || _vm->shouldQuit())
2635 			return;
2636 
2637 		if (opcodeType == 2)
2638 			lastOpcodeResult = _vm->_script->handleGoto(data + 20 * lastOpcodeResult);
2639 		else if (opcodeType == 3)
2640 			lastOpcodeResult = _vm->_script->handleIf(data, lastOpcodeResult);
2641 
2642 		if (lastOpcodeResult == -1)
2643 			error("defective IFF function");
2644 
2645 		if (opcodeType == 1 || opcodeType == 4)
2646 			++lastOpcodeResult;
2647 		else if (!opcodeType || opcodeType == 5)
2648 			break;
2649 	}
2650 
2651 	_vm->_globals->freeMemory(data);
2652 }
2653 
handleSpecialGames()2654 void ObjectsManager::handleSpecialGames() {
2655 	byte *oldPalette;
2656 
2657 	switch (_vm->_globals->_screenId) {
2658 	case 5:
2659 		if ((getSpriteY(0) > 399) || _vm->_globals->_saveData->_data[svField173])
2660 			break;
2661 
2662 		_vm->_globals->_saveData->_data[svField173] = 1;
2663 		_vm->_globals->_introSpeechOffFl = true;
2664 		_vm->_talkMan->startAnimatedCharacterDialogue("flicspe1.pe2");
2665 		_vm->_globals->_introSpeechOffFl = false;
2666 
2667 		if (_vm->_globals->_censorshipFl)
2668 			break;
2669 
2670 		oldPalette = _vm->_globals->allocMemory(1000);
2671 		memcpy(oldPalette, _vm->_graphicsMan->_palette, 769);
2672 
2673 		_vm->_graphicsMan->backupScreen();
2674 
2675 		if (!_vm->_graphicsMan->_lineNbr)
2676 			_vm->_graphicsMan->_scrollOffset = 0;
2677 		_vm->_graphicsMan->displayScreen(true);
2678 		_vm->_soundMan->_specialSoundNum = 198;
2679 		_charactersEnabledFl = true;
2680 		_vm->_animMan->unsetClearAnimFlag();
2681 		_vm->_animMan->playAnim("OTAGE.ANM", "OTAGE.ANM", 1, 24, 500, true);
2682 		_vm->_soundMan->_specialSoundNum = 0;
2683 		_vm->_graphicsMan->displayScreen(false);
2684 
2685 		_vm->_graphicsMan->restoreScreen();
2686 
2687 		_charactersEnabledFl = false;
2688 		memcpy(_vm->_graphicsMan->_palette, oldPalette, 769);
2689 		_vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
2690 		_vm->_globals->freeMemory(oldPalette);
2691 		_vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
2692 		memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399);
2693 
2694 		_vm->_graphicsMan->_scrollStatus = 0;
2695 		_vm->_graphicsMan->updateScreen();
2696 		break;
2697 	case 20:
2698 		_vm->_globals->_saveData->_data[svField132] = (getSpriteX(0) > 65 && getSpriteX(0) <= 124 && getSpriteY(0) > 372 && getSpriteY(0) <= 398) ? 1 : 0;
2699 		break;
2700 	case 35:
2701 		if (_vm->_globals->_prevScreenId == 16)
2702 			handleForest(35, 500, 555, 100, 440, 1);
2703 		else if (_vm->_globals->_prevScreenId == 36)
2704 			handleForest(35, 6, 84, 100, 440, 4);
2705 		break;
2706 	case 36:
2707 		if (_vm->_globals->_prevScreenId == 35)
2708 			handleForest(36, 551, 633, 100, 440, 2);
2709 		else if (_vm->_globals->_prevScreenId == 37)
2710 			handleForest(36, 6, 84, 100, 440, 4);
2711 		break;
2712 	case 37:
2713 		if (_vm->_globals->_prevScreenId == 36)
2714 			handleForest(37, 551, 633, 100, 440, 1);
2715 		else if (_vm->_globals->_prevScreenId == 38)
2716 			handleForest(37, 392, 529, 100, 440, 2);
2717 		break;
2718 	case 38:
2719 		if (_vm->_globals->_prevScreenId == 37)
2720 			handleForest(38, 133, 252, 100, 440, 4);
2721 		else if (_vm->_globals->_prevScreenId == 39)
2722 			handleForest(38, 6, 84, 100, 440, 3);
2723 		break;
2724 	case 39:
2725 		if (_vm->_globals->_prevScreenId == 38)
2726 			handleForest(39, 551, 633, 100, 440, 2);
2727 		else if (_vm->_globals->_prevScreenId == 40)
2728 			handleForest(39, 6, 84, 100, 440, 3);
2729 		break;
2730 	case 40:
2731 		if (_vm->_globals->_prevScreenId == 39)
2732 			handleForest(40, 133, 252, 100, 440, 4);
2733 		else if (_vm->_globals->_prevScreenId == 41)
2734 			handleForest(40, 392, 529, 100, 440, 2);
2735 		break;
2736 	case 41:
2737 		if (_vm->_globals->_prevScreenId == 40)
2738 			handleForest(41, 551, 633, 100, 440, 1);
2739 		else if (_vm->_globals->_prevScreenId == 17)
2740 			handleForest(41, 6, 84, 100, 440, 3);
2741 		break;
2742 	case 57:
2743 		_vm->_globals->_disableInventFl = true;
2744 		if (_vm->_globals->_saveData->_data[svField261] == 1 && getBobAnimDataIdx(5) == 37) {
2745 			stopBobAnimation(5);
2746 			setBobAnimDataIdx(5, 0);
2747 			setBobAnimation(6);
2748 			_vm->_globals->_saveData->_data[svField261] = 2;
2749 			_vm->_linesMan->disableZone(15);
2750 			_vm->_soundMan->playSoundFile("SOUND75.WAV");
2751 		}
2752 		if (_vm->_globals->_saveData->_data[svField261] == 2 && getBobAnimDataIdx(6) == 6) {
2753 			stopBobAnimation(6);
2754 			setBobAnimDataIdx(6, 0);
2755 			setBobAnimation(7);
2756 			_vm->_linesMan->enableZone(14);
2757 			_vm->_globals->_saveData->_data[svField261] = 3;
2758 		}
2759 		_vm->_globals->_disableInventFl = false;
2760 		break;
2761 	case 93:
2762 		if (_vm->_globals->_saveData->_data[svField333])
2763 			break;
2764 
2765 		_vm->_globals->_disableInventFl = true;
2766 		do {
2767 			_vm->_events->refreshScreenAndEvents();
2768 		} while (getBobAnimDataIdx(8) != 3);
2769 		_vm->_globals->_introSpeechOffFl = true;
2770 		_vm->_talkMan->startAnimatedCharacterDialogue("GM3.PE2");
2771 		stopBobAnimation(8);
2772 		_vm->_globals->_saveData->_data[svField333] = 1;
2773 		_vm->_globals->_disableInventFl = false;
2774 		break;
2775 	default:
2776 		break;
2777 	}
2778 }
2779 
quickDisplayBobSprite(int idx)2780 void ObjectsManager::quickDisplayBobSprite(int idx) {
2781 	int startPos = 10 * idx;
2782 	if (!READ_LE_UINT16(_vm->_talkMan->_characterAnim + startPos + 4))
2783 		return;
2784 
2785 	int xp = READ_LE_INT16(_vm->_talkMan->_characterAnim + startPos);
2786 	int yp = READ_LE_INT16(_vm->_talkMan->_characterAnim + startPos + 2);
2787 	int spriteIndex = _vm->_talkMan->_characterAnim[startPos + 8];
2788 
2789 	_vm->_graphicsMan->fastDisplay(_vm->_talkMan->_characterSprite, xp, yp, spriteIndex);
2790 }
2791 
initVbob(const byte * src,int idx,int xp,int yp,int frameIndex)2792 void ObjectsManager::initVbob(const byte *src, int idx, int xp, int yp, int frameIndex) {
2793 	if (idx > 29)
2794 		error("MAX_VBOB exceeded");
2795 
2796 	VBobItem *vbob = &_vBob[idx];
2797 	if (vbob->_displayMode <= 1) {
2798 		vbob->_displayMode = 1;
2799 		vbob->_xp = xp;
2800 		vbob->_yp = yp;
2801 		vbob->_frameIndex = frameIndex;
2802 		vbob->_oldX = xp;
2803 		vbob->_oldY = yp;
2804 		vbob->_oldFrameIndex = frameIndex;
2805 		vbob->_spriteData = src;
2806 		vbob->_oldSpriteData = src;
2807 		vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
2808 	} else if (vbob->_displayMode == 2 || vbob->_displayMode == 4) {
2809 		vbob->_displayMode = 3;
2810 		vbob->_oldX = vbob->_xp;
2811 		vbob->_oldY = vbob->_yp;
2812 		vbob->_oldSpriteData = vbob->_spriteData;
2813 		vbob->_oldFrameIndex = vbob->_frameIndex;
2814 		vbob->_xp = xp;
2815 		vbob->_yp = yp;
2816 		vbob->_frameIndex = frameIndex;
2817 		vbob->_spriteData = src;
2818 	}
2819 }
2820 
disableVbob(int idx)2821 void ObjectsManager::disableVbob(int idx) {
2822 	if (idx > 29)
2823 		error("MAX_VBOB exceeded");
2824 
2825 	VBobItem *vbob = &_vBob[idx];
2826 	if (vbob->_displayMode <= 1)
2827 		vbob->_displayMode = 0;
2828 	else
2829 		vbob->_displayMode = 4;
2830 }
2831 
doActionBack(int idx)2832 void ObjectsManager::doActionBack(int idx) {
2833 	if (_curGestureFile != 1) {
2834 		_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
2835 		_curGestureFile = 1;
2836 		_gestureBuf = _vm->_fileIO->loadFile("DOS.SPR");
2837 	}
2838 
2839 	switch (idx) {
2840 	case 1:
2841 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, false);
2842 		break;
2843 	case 2:
2844 		showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,13,-1,", 8, false);
2845 		break;
2846 	case 3:
2847 		showSpecialActionAnimation(_gestureBuf, "12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8);
2848 		break;
2849 	case 4:
2850 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,8,9,10,11,12,13,12,11,12,13,12,11,12,13,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, false);
2851 		break;
2852 	case 5:
2853 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, false);
2854 		break;
2855 	case 6:
2856 		showSpecialActionAnimation(_gestureBuf, "20,19,18,17,16,15,-1,", 8);
2857 		break;
2858 	case 7:
2859 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 8, false);
2860 		break;
2861 	case 8:
2862 		showSpecialActionAnimation(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 8);
2863 		break;
2864 	case 9:
2865 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,22,23,24,-1,", 8, false);
2866 		break;
2867 	case 10:
2868 		showSpecialActionAnimation(_gestureBuf, "23,22,21,20,19,18,17,16,15,-1,", 8);
2869 		break;
2870 	default:
2871 		break;
2872 	}
2873 }
2874 
doActionRight(int idx)2875 void ObjectsManager::doActionRight(int idx) {
2876 	if (_curGestureFile != 3) {
2877 		_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
2878 		_curGestureFile = 3;
2879 		_gestureBuf = _vm->_fileIO->loadFile("PROFIL.SPR");
2880 	}
2881 
2882 	switch (idx) {
2883 	case 1:
2884 		showActionAnimation(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 8, false);
2885 		break;
2886 	case 2:
2887 		showSpecialActionAnimationWithFlip(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 8, false);
2888 		break;
2889 	case 3:
2890 		showSpecialActionAnimation(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 8);
2891 		break;
2892 	case 4:
2893 		showActionAnimation(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 8, false);
2894 		break;
2895 	case 5:
2896 		showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,-1,", 8, false);
2897 		break;
2898 	case 6:
2899 		showSpecialActionAnimation(_gestureBuf, "24,23,-1,", 8);
2900 		break;
2901 	case 7:
2902 		showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,-1,", 8, false);
2903 		break;
2904 	case 8:
2905 		showSpecialActionAnimation(_gestureBuf, "26,25,24,23,-1,", 8);
2906 		break;
2907 	case 9:
2908 		showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,28,29,-1,", 8, false);
2909 		break;
2910 	case 10:
2911 		showSpecialActionAnimation(_gestureBuf, "28,27,26,25,24,23,-1,", 8);
2912 		break;
2913 	default:
2914 		break;
2915 	}
2916 }
2917 
doActionDiagRight(int idx)2918 void ObjectsManager::doActionDiagRight(int idx) {
2919 	if (_curGestureFile != 4) {
2920 		_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
2921 		_curGestureFile = 4;
2922 		_gestureBuf = _vm->_fileIO->loadFile("3Q.SPR");
2923 	}
2924 
2925 	switch (idx) {
2926 	case 1:
2927 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, false);
2928 		break;
2929 	case 2:
2930 		showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 8, false);
2931 		break;
2932 	case 3:
2933 		showSpecialActionAnimation(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8);
2934 		break;
2935 	case 4:
2936 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,11,12,11,12,11,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, false);
2937 		break;
2938 	case 5:
2939 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,-1,", 8, false);
2940 		break;
2941 	case 6:
2942 		showSpecialActionAnimation(_gestureBuf, "17,16,15,-1,", 8);
2943 		break;
2944 	case 7:
2945 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,-1,", 8, false);
2946 		break;
2947 	case 8:
2948 		showSpecialActionAnimation(_gestureBuf, "19,18,17,16,15,-1,", 8);
2949 		break;
2950 	case 9:
2951 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, false);
2952 		break;
2953 	case 10:
2954 		showSpecialActionAnimation(_gestureBuf, "20,19,18,17,15,-1,", 8);
2955 		break;
2956 	default:
2957 		break;
2958 	}
2959 }
2960 
doActionFront(int idx)2961 void ObjectsManager::doActionFront(int idx) {
2962 	if (_curGestureFile != 2) {
2963 		_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
2964 		_curGestureFile = 2;
2965 		_gestureBuf = _vm->_fileIO->loadFile("FACE.SPR");
2966 	}
2967 
2968 	switch (idx) {
2969 	case 1:
2970 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,9,9,9,9,9,9,7,6,5,4,3,2,1,0,-1,", 8, false);
2971 		break;
2972 	case 2:
2973 		showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,15,-1,", 8, false);
2974 		break;
2975 	case 3:
2976 		showSpecialActionAnimation(_gestureBuf, "14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 8);
2977 		break;
2978 	case 4:
2979 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,9,10,11,12,13,14,13,12,11,10,9,7,6,5,4,3,2,1,0,-1,", 8, false);
2980 		break;
2981 	default:
2982 		break;
2983 	}
2984 }
2985 
doActionDiagLeft(int idx)2986 void ObjectsManager::doActionDiagLeft(int idx) {
2987 	if (_curGestureFile != 4) {
2988 		_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
2989 		_curGestureFile = 4;
2990 		_gestureBuf = _vm->_fileIO->loadFile("3Q.SPR");
2991 	}
2992 
2993 	switch (idx) {
2994 	case 1:
2995 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,8,8,8,8,7,6,5,4,3,2,1,0,-1,", 8, true);
2996 		break;
2997 	case 2:
2998 		showSpecialActionAnimationWithFlip(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,-1,", 8, true);
2999 		break;
3000 	case 3:
3001 		showSpecialActionAnimation(_gestureBuf, "11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8);
3002 		break;
3003 	case 4:
3004 		showActionAnimation(_gestureBuf, "0,1,2,3,4,5,6,7,8,9,10,11,12,11,12,11,12,11,12,11,10,9,8,7,6,5,4,3,2,1,0,-1,", 8, true);
3005 		break;
3006 	case 5:
3007 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,-1,", 8, true);
3008 		break;
3009 	case 6:
3010 		showSpecialActionAnimation(_gestureBuf, "17,16,15,-1,", 8);
3011 		break;
3012 	case 7:
3013 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,-1,", 8, true);
3014 		break;
3015 	case 8:
3016 		showSpecialActionAnimation(_gestureBuf, "19,18,17,16,15,-1,", 8);
3017 		break;
3018 	case 9:
3019 		showSpecialActionAnimationWithFlip(_gestureBuf, "15,16,17,18,19,20,21,-1,", 8, true);
3020 		break;
3021 	case 10:
3022 		showSpecialActionAnimation(_gestureBuf, "20,19,18,17,15,-1,", 8);
3023 		break;
3024 	default:
3025 		break;
3026 	}
3027 }
3028 
doActionLeft(int idx)3029 void ObjectsManager::doActionLeft(int idx) {
3030 	if (_curGestureFile != 3) {
3031 		_gestureBuf = _vm->_globals->freeMemory(_gestureBuf);
3032 		_curGestureFile = 3;
3033 		_gestureBuf = _vm->_fileIO->loadFile("PROFIL.SPR");
3034 	}
3035 
3036 	switch (idx) {
3037 	case 1:
3038 		showActionAnimation(_gestureBuf, "20,19,18,17,16,15,14,13,13,13,13,13,14,15,16,17,18,19,20,-1,", 8, true);
3039 		break;
3040 	case 2:
3041 		showSpecialActionAnimationWithFlip(_gestureBuf, "1,2,3,4,5,6,7,8,-1,", 8, true);
3042 		break;
3043 	case 3:
3044 		showSpecialActionAnimation(_gestureBuf, "9,10,11,12,13,14,15,16,17,18,19,20,-1,", 8);
3045 		break;
3046 	case 4:
3047 		showActionAnimation(_gestureBuf, "1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1,-1,", 8, true);
3048 		break;
3049 	case 5:
3050 		showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,-1,", 8, true);
3051 		break;
3052 	case 6:
3053 		showSpecialActionAnimation(_gestureBuf, "24,23,-1,", 8);
3054 		break;
3055 	case 7:
3056 		showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,-1,", 8, true);
3057 		break;
3058 	case 8:
3059 		showSpecialActionAnimation(_gestureBuf, "26,25,24,23,-1,", 8);
3060 		break;
3061 	case 9:
3062 		showSpecialActionAnimationWithFlip(_gestureBuf, "23,24,25,26,27,28,29,-1,", 8, true);
3063 		break;
3064 	case 10:
3065 		showSpecialActionAnimation(_gestureBuf, "28,27,26,25,24,23,-1,", 8);
3066 		break;
3067 	default:
3068 		break;
3069 	}
3070 }
3071 
setAndPlayAnim(int idx,int animIdx,int destPosi,bool animAction)3072 void ObjectsManager::setAndPlayAnim(int idx, int animIdx, int destPosi, bool animAction) {
3073 	// Set Hopkins animation and position
3074 	setBobAnimation(idx);
3075 	setBobAnimDataIdx(idx, animIdx);
3076 
3077 	// Make Hopkins walk to the expected place
3078 	do {
3079 		_vm->_events->refreshScreenAndEvents();
3080 	} while (destPosi != getBobAnimDataIdx(idx));
3081 
3082 	if (!animAction)
3083 		stopBobAnimation(idx);
3084 	else {
3085 		BobItem *bob = &_bob[idx];
3086 		_vm->_graphicsMan->fastDisplay(bob->_spriteData, bob->_oldX, bob->_oldY, bob->_frameIndex);
3087 		stopBobAnimation(idx);
3088 		_vm->_events->refreshScreenAndEvents();
3089 	}
3090 }
3091 
getBobAnimDataIdx(int idx)3092 int ObjectsManager::getBobAnimDataIdx(int idx) {
3093 	return _bob[idx]._animDataIdx / 5;
3094 }
3095 
setBobAnimDataIdx(int idx,int animIdx)3096 void ObjectsManager::setBobAnimDataIdx(int idx, int animIdx) {
3097 	BobItem *bob = &_bob[idx];
3098 	bob->_animDataIdx = 5 * animIdx;
3099 	bob->_moveChange1 = 0;
3100 	bob->_moveChange2 = 0;
3101 }
3102 
3103 /**
3104  * Set Hopkins animation
3105  */
setBobAnimation(int idx)3106 void ObjectsManager::setBobAnimation(int idx) {
3107 	assert(idx < 36);
3108 	BobItem *bob = &_bob[idx];
3109 	if (!bob->_disabledAnimationFl)
3110 		return;
3111 
3112 	bob->_disabledAnimationFl = false;
3113 	bob->_animDataIdx = 5;
3114 	bob->_frameIndex = 250;
3115 	bob->_moveChange1 = 0;
3116 	bob->_moveChange2 = 0;
3117 }
3118 
3119 /**
3120  * Stop Hopkins animation
3121  */
stopBobAnimation(int idx)3122 void ObjectsManager::stopBobAnimation(int idx) {
3123 	assert(idx < 36);
3124 	_bob[idx]._disabledAnimationFl = true;
3125 }
3126 
3127 /**
3128  * Get X position
3129  */
getBobPosX(int idx)3130 int ObjectsManager::getBobPosX(int idx) {
3131 	return _bob[idx]._xp;
3132 }
3133 
loadLinkFile(const Common::String & file,bool skipDetails)3134 void ObjectsManager::loadLinkFile(const Common::String &file, bool skipDetails) {
3135 	Common::File f;
3136 	Common::String filename = file + ".LNK";
3137 	bool fileFoundFl = false;
3138 	byte *ptr = _vm->_fileIO->searchCat(filename, RES_LIN, fileFoundFl);
3139 	size_t nbytes = _vm->_fileIO->_catalogSize;
3140 	if (!fileFoundFl) {
3141 		if (!f.open(filename))
3142 			error("Error opening file - %s", filename.c_str());
3143 
3144 		nbytes = f.size();
3145 		ptr = _vm->_globals->allocMemory(nbytes);
3146 		if (ptr == NULL)
3147 			error("INILINK");
3148 		_vm->_fileIO->readStream(f, ptr, nbytes);
3149 		f.close();
3150 	}
3151 	if (!skipDetails) {
3152 		for (int idx = 0; idx < 500; ++idx)
3153 			_vm->_globals->_spriteSize[idx] = READ_LE_INT16((uint16 *)ptr + idx);
3154 
3155 		resetHidingItems();
3156 
3157 		Common::String filename2 = Common::String((const char *)ptr + 1000);
3158 		if (!filename2.empty()) {
3159 			fileFoundFl = false;
3160 			_hidingItemData[1] = _vm->_fileIO->searchCat(filename2, RES_SLI, fileFoundFl);
3161 
3162 			if (!fileFoundFl) {
3163 				_hidingItemData[1] = _vm->_fileIO->loadFile(filename2);
3164 			} else {
3165 				_hidingItemData[1] = _vm->_fileIO->loadFile("RES_SLI.RES");
3166 			}
3167 
3168 			int curDataCacheId = 60;
3169 			byte *curDataPtr = ptr + 1000;
3170 			for (int hidingIdx = 0; hidingIdx <= 21; hidingIdx++) {
3171 				HidingItem *hid = &_hidingItem[hidingIdx];
3172 				int curSpriteId = READ_LE_INT16(curDataPtr + 2 * curDataCacheId);
3173 				hid->_spriteIndex = curSpriteId;
3174 				hid->_x = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 2);
3175 				hid->_y = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 4);
3176 				hid->_yOffset = READ_LE_INT16(curDataPtr + 2 * curDataCacheId + 8);
3177 
3178 				if (!_hidingItemData[1]) {
3179 					hid->_useCount = 0;
3180 				} else {
3181 					hid->_spriteData = _hidingItemData[1];
3182 					hid->_width = getWidth(_hidingItemData[1], curSpriteId);
3183 					hid->_height = getHeight(_hidingItemData[1], curSpriteId);
3184 					hid->_useCount = 1;
3185 				}
3186 				if (!hid->_x && !hid->_y && !hid->_spriteIndex)
3187 					hid->_useCount = 0;
3188 
3189 				curDataCacheId += 5;
3190 			}
3191 			enableHidingBehavior();
3192 		}
3193 	}
3194 
3195 	_vm->_linesMan->resetLines();
3196 	for (size_t idx = 0; idx < nbytes - 3; idx++) {
3197 		if (READ_BE_UINT24(&ptr[idx]) == MKTAG24('O', 'B', '2')) {
3198 			byte *curDataPtr = &ptr[idx + 4];
3199 			int lineDataIdx = 0;
3200 			int curLineIdx = 0;
3201 			_vm->_linesMan->resetLinesNumb();
3202 			Directions curDirection;
3203 			do {
3204 				curDirection = (Directions)READ_LE_INT16(curDataPtr + 2 * lineDataIdx);
3205 				if (curDirection != DIR_NONE) {
3206 					_vm->_linesMan->addLine(
3207 					    curLineIdx,
3208 					    curDirection,
3209 					    READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 2),
3210 					    READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 4),
3211 					    READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 6),
3212 					    READ_LE_INT16(curDataPtr + 2 * lineDataIdx + 8));
3213 				}
3214 				lineDataIdx += 5;
3215 				++curLineIdx;
3216 			} while (curDirection != DIR_NONE);
3217 			_vm->_linesMan->initRoute();
3218 		}
3219 	}
3220 
3221 	if (!skipDetails) {
3222 		for (size_t idx = 0; idx < nbytes - 3; idx++) {
3223 			if (READ_BE_UINT24(&ptr[idx]) == MKTAG24('Z', 'O', '2')) {
3224 				byte *curDataPtr = &ptr[idx + 4];
3225 				int curDataIdx = 0;
3226 				for (int i = 1; i <= 100; i++) {
3227 					ZoneItem *curZone = &_vm->_linesMan->_zone[i];
3228 					curZone->_destX = 0;
3229 					curZone->_destY = 0;
3230 					curZone->_spriteIndex = 0;
3231 					curZone->_verbFl1 = 0;
3232 					curZone->_verbFl2 = 0;
3233 					curZone->_verbFl3 = 0;
3234 					curZone->_verbFl4 = 0;
3235 					curZone->_verbFl5 = 0;
3236 					curZone->_verbFl6 = 0;
3237 					curZone->_verbFl7 = 0;
3238 					curZone->_verbFl8 = 0;
3239 					curZone->_verbFl9 = 0;
3240 					curZone->_verbFl10 = 0;
3241 					curZone->_messageId = 0;
3242 				}
3243 
3244 				int curLineIdx = 0;
3245 				for (;;) {
3246 					int bobZoneId = READ_LE_INT16(curDataPtr + 2 * curDataIdx);
3247 					if (bobZoneId != -1) {
3248 						_vm->_linesMan->addZoneLine(
3249 						    curLineIdx,
3250 						    READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2),
3251 						    READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4),
3252 						    READ_LE_INT16(curDataPtr + 2 * curDataIdx + 6),
3253 						    READ_LE_INT16(curDataPtr + 2 * curDataIdx + 8),
3254 						    bobZoneId);
3255 						_vm->_linesMan->_zone[bobZoneId]._enabledFl = true;
3256 					}
3257 					curDataIdx += 5;
3258 					++curLineIdx;
3259 					if (bobZoneId == -1)
3260 						break;
3261 				}
3262 				for (int i = 1; i <= 100; i++) {
3263 					ZoneItem *curZone = &_vm->_linesMan->_zone[i];
3264 					curZone->_destX = READ_LE_INT16(curDataPtr + 2 * curDataIdx);
3265 					curZone->_destY = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 2);
3266 					curZone->_spriteIndex = READ_LE_INT16(curDataPtr + 2 * curDataIdx + 4);
3267 					curDataIdx += 3;
3268 				}
3269 
3270 				byte *verbData = ptr + idx + (10 * curLineIdx + 606) + 4;
3271 				for (int i = 1; i <= 100; i++) {
3272 					int j = (i - 1) * 10;
3273 					ZoneItem *curZone = &_vm->_linesMan->_zone[i];
3274 					curZone->_verbFl1 = verbData[j];
3275 					curZone->_verbFl2 = verbData[j + 1];
3276 					curZone->_verbFl3 = verbData[j + 2];
3277 					curZone->_verbFl4 = verbData[j + 3];
3278 					curZone->_verbFl5 = verbData[j + 4];
3279 					curZone->_verbFl6 = verbData[j + 5];
3280 					curZone->_verbFl7 = verbData[j + 6];
3281 					curZone->_verbFl8 = verbData[j + 7];
3282 					curZone->_verbFl9 = verbData[j + 8];
3283 					curZone->_verbFl10 = verbData[j + 9];
3284 				}
3285 				int dep = 1010;
3286 				for (int i = 1; i <= 100; i++) {
3287 					_vm->_linesMan->_zone[i]._messageId = READ_LE_INT16(verbData + dep);
3288 					dep += 2;
3289 				}
3290 				_vm->_linesMan->initSquareZones();
3291 			}
3292 		}
3293 	}
3294 	_vm->_globals->freeMemory(ptr);
3295 }
3296 
sceneSpecialIni()3297 void ObjectsManager::sceneSpecialIni() {
3298 	switch (_vm->_globals->_screenId) {
3299 	case 17:
3300 		if (_vm->_globals->_prevScreenId == 20) {
3301 			_vm->_globals->_disableInventFl = true;
3302 			_vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
3303 			_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
3304 			_vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
3305 			_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
3306 			for (int i = 0; i <= 4; i++)
3307 				_vm->_events->refreshScreenAndEvents();
3308 			_vm->_graphicsMan->fadeInLong();
3309 			animateSprite(0);
3310 			for (int i = 0; i <= 4; i++)
3311 				_vm->_events->refreshScreenAndEvents();
3312 			initVbob(_vm->_globals->_levelSpriteBuf, 5, 15, 28, 1);
3313 			_vm->_fontMan->hideText(9);
3314 			bool displayedTxtFl = false;
3315 			if (!_vm->_soundMan->_textOffFl) {
3316 				_vm->_fontMan->initTextBuffers(9, 383, _vm->_globals->_textFilename, 220, 72, 6, 36, 253);
3317 				_vm->_fontMan->showText(9);
3318 				displayedTxtFl = true;
3319 			}
3320 			if (!_vm->_soundMan->_voiceOffFl)
3321 				_vm->_soundMan->mixVoice(383, 4, displayedTxtFl);
3322 			_vm->_globals->_saveData->_data[svField270] = 1;
3323 			_vm->_globals->_saveData->_data[svField300] = 1;
3324 			_vm->_globals->_saveData->_data[svField320] = 1;
3325 			if (_vm->_soundMan->_voiceOffFl) {
3326 				for (int i = 0; i <= 199; i++)
3327 					_vm->_events->refreshScreenAndEvents();
3328 			}
3329 			_vm->_fontMan->hideText(9);
3330 			disableVbob(5);
3331 			for (int i = 0; i <= 3; i++)
3332 				_vm->_events->refreshScreenAndEvents();
3333 			_vm->_graphicsMan->_noFadingFl = true;
3334 			_vm->_globals->_disableInventFl = false;
3335 		}
3336 		break;
3337 
3338 	case 18:
3339 		if (_vm->_globals->_prevScreenId == 17) {
3340 			_vm->_events->_mouseSpriteId = 4;
3341 			for (int i = 0; i <= 4; i++)
3342 				_vm->_events->refreshScreenAndEvents();
3343 			_vm->_graphicsMan->fadeInLong();
3344 			_vm->_globals->_eventMode = EVENTMODE_IGNORE;
3345 			_vm->_globals->_disableInventFl = false;
3346 			_vm->_graphicsMan->_noFadingFl = true;
3347 			_vm->_globals->_introSpeechOffFl = true;
3348 			_vm->_talkMan->startAnimatedCharacterDialogue("MAGE1.pe2");
3349 			_vm->_graphicsMan->_noFadingFl = true;
3350 			_vm->_globals->_disableInventFl = false;
3351 		}
3352 		break;
3353 
3354 	case 35:
3355 	case 36:
3356 	case 37:
3357 	case 38:
3358 	case 39:
3359 	case 40:
3360 	case 41:
3361 		_vm->_linesMan->_bobZone[20] = 1;
3362 		_vm->_linesMan->_bobZone[21] = 2;
3363 		_vm->_linesMan->_bobZone[22] = 3;
3364 		_vm->_linesMan->_bobZone[23] = 4;
3365 		_vm->_linesMan->_bobZoneFl[20] = true;
3366 		_vm->_linesMan->_bobZoneFl[21] = true;
3367 		_vm->_linesMan->_bobZoneFl[22] = true;
3368 		_vm->_linesMan->_bobZoneFl[23] = true;
3369 		enableVerb(20, 5);
3370 		enableVerb(21, 5);
3371 		enableVerb(22, 5);
3372 		enableVerb(23, 5);
3373 		_vm->_linesMan->_zone[20]._messageId = 30;
3374 		_vm->_linesMan->_zone[21]._messageId = 30;
3375 		_vm->_linesMan->_zone[22]._messageId = 30;
3376 		_vm->_linesMan->_zone[23]._messageId = 30;
3377 		for (int i = svField200; i <= svField214; i++) {
3378 			if (_vm->_globals->_saveData->_data[i] != 2)
3379 				_vm->_globals->_saveData->_data[i] = 0;
3380 		}
3381 		break;
3382 
3383 	case 73:
3384 		if (!_vm->_globals->_saveData->_data[svSecondElevatorAvailableFl]) {
3385 			resetHidingUseCount(0);
3386 			resetHidingUseCount(1);
3387 		}
3388 		break;
3389 
3390 	case 93:
3391 		if (!_vm->_globals->_saveData->_data[svField333])
3392 			setBobAnimation(8);
3393 		break;
3394 
3395 	default:
3396 		break;
3397 	}
3398 }
3399 
setMultiBobAnim(int idx1,int idx2,int anim1Idx,int anim2Idx)3400 void ObjectsManager::setMultiBobAnim(int idx1, int idx2, int anim1Idx, int anim2Idx) {
3401 	if (idx1 != -1)
3402 		setBobAnimation(idx1);
3403 	if (idx2 != -1)
3404 		setBobAnimation(idx2);
3405 	if (idx1 != -1)
3406 		setBobAnimDataIdx(idx1, anim1Idx);
3407 	if (idx2 != -1)
3408 		setBobAnimDataIdx(idx2, anim2Idx);
3409 }
3410 
checkEventBobAnim(int idx,int animIdx,int animDataIdx,int a4)3411 void ObjectsManager::checkEventBobAnim(int idx, int animIdx, int animDataIdx, int a4) {
3412 	_vm->_events->_curMouseButton = 0;
3413 	_vm->_events->_mouseButton = 0;
3414 
3415 	if (a4 != 3) {
3416 		setBobAnimation(idx);
3417 		setBobAnimDataIdx(idx, animIdx);
3418 	}
3419 
3420 	do {
3421 		_vm->_events->refreshScreenAndEvents();
3422 		if (_vm->_events->_curMouseButton)
3423 			break;
3424 	} while (animDataIdx != getBobAnimDataIdx(idx));
3425 	if (!a4)
3426 		stopBobAnimation(idx);
3427 }
3428 
disableVerb(int idx,int a2)3429 void ObjectsManager::disableVerb(int idx, int a2) {
3430 	ZoneItem *curZone = &_vm->_linesMan->_zone[idx];
3431 	switch (a2) {
3432 	case 6:
3433 	case 16:
3434 		curZone->_verbFl1 = 0;
3435 		break;
3436 	case 7:
3437 		curZone->_verbFl2 = 0;
3438 		break;
3439 	case 5:
3440 	case 8:
3441 		curZone->_verbFl3 = 0;
3442 		break;
3443 	case 9:
3444 	case 17:
3445 	case 24:
3446 		curZone->_verbFl4 = 0;
3447 		break;
3448 	case 10:
3449 	case 18:
3450 		curZone->_verbFl5 = 0;
3451 		break;
3452 	case 11:
3453 	case 19:
3454 		curZone->_verbFl6 = 0;
3455 		break;
3456 	case 12:
3457 	case 20:
3458 		curZone->_verbFl7 = 0;
3459 		break;
3460 	case 13:
3461 	case 22:
3462 		curZone->_verbFl8 = 0;
3463 		break;
3464 	case 14:
3465 	case 21:
3466 	case 25:
3467 		curZone->_verbFl9 = 0;
3468 		break;
3469 	case 15:
3470 		curZone->_verbFl10 = 0;
3471 		break;
3472 	default:
3473 		break;
3474 	}
3475 	_changeVerbFl = true;
3476 }
3477 
enableVerb(int idx,int a2)3478 void ObjectsManager::enableVerb(int idx, int a2) {
3479 	ZoneItem *curZone = &_vm->_linesMan->_zone[idx];
3480 
3481 	switch (a2) {
3482 	case 5:
3483 		curZone->_verbFl3 = 2;
3484 		break;
3485 	case 6:
3486 		curZone->_verbFl1 = 1;
3487 		break;
3488 	case 7:
3489 		curZone->_verbFl2 = 1;
3490 		break;
3491 	case 8:
3492 		curZone->_verbFl3 = 1;
3493 		break;
3494 	case 9:
3495 		curZone->_verbFl4 = 1;
3496 		break;
3497 	case 10:
3498 		curZone->_verbFl5 = 1;
3499 		break;
3500 	case 11:
3501 		curZone->_verbFl6 = 1;
3502 		break;
3503 	case 12:
3504 		curZone->_verbFl7 = 1;
3505 		break;
3506 	case 13:
3507 		curZone->_verbFl8 = 1;
3508 		break;
3509 	case 14:
3510 		curZone->_verbFl8 = 1;
3511 		break;
3512 	case 15:
3513 		curZone->_verbFl9 = 1;
3514 		break;
3515 	case 16:
3516 		curZone->_verbFl1 = 2;
3517 		break;
3518 	case 17:
3519 		curZone->_verbFl4 = 2;
3520 		break;
3521 	case 18:
3522 		curZone->_verbFl5 = 2;
3523 		break;
3524 	case 19:
3525 		curZone->_verbFl6 = 2;
3526 		break;
3527 	case 20:
3528 		curZone->_verbFl7 = 2;
3529 		break;
3530 	case 21:
3531 		curZone->_verbFl9 = 2;
3532 		break;
3533 	case 22:
3534 		curZone->_verbFl8 = 2;
3535 		break;
3536 	case 24:
3537 		curZone->_verbFl4 = 3;
3538 		break;
3539 	case 25:
3540 		curZone->_verbFl9 = 2;
3541 		break;
3542 	default:
3543 		break;
3544 	}
3545 }
3546 
showActionAnimation(const byte * spriteData,const Common::String & actionStr,int speed,bool flipFl)3547 void ObjectsManager::showActionAnimation(const byte *spriteData, const Common::String &actionStr, int speed, bool flipFl) {
3548 	Common::String tmpStr = "";
3549 	int realSpeed = speed;
3550 	if (_vm->_globals->_speed == 2)
3551 		realSpeed = speed / 2;
3552 	else if (_vm->_globals->_speed == 3)
3553 		realSpeed = speed / 3;
3554 	const byte *oldSpriteData = _sprite[0]._spriteData;
3555 	int spriteIndex = _sprite[0]._spriteIndex;
3556 	bool oldFlipFl = _sprite[0]._flipFl;
3557 	_sprite[0]._flipFl = flipFl;
3558 
3559 	int idx = 0;
3560 	for (int strPos = 0; ; strPos++) {
3561 		bool tokenCompleteFl = false;
3562 		char curChar = actionStr[strPos];
3563 		if (curChar == ',') {
3564 			idx = atoi(tmpStr.c_str());
3565 			tmpStr = "";
3566 			tokenCompleteFl = true;
3567 		} else {
3568 			tmpStr += curChar;
3569 		}
3570 
3571 		if (tokenCompleteFl) {
3572 			if (idx == -1) {
3573 				_sprite[0]._spriteData = oldSpriteData;
3574 				_sprite[0]._spriteIndex = spriteIndex;
3575 				_sprite[0]._flipFl = oldFlipFl;
3576 			} else {
3577 				_sprite[0]._spriteData = spriteData;
3578 				_sprite[0]._spriteIndex = idx;
3579 			}
3580 			for (int i = 0; i < realSpeed; i++)
3581 				_vm->_events->refreshScreenAndEvents();
3582 			if (idx == -1)
3583 				break;
3584 		}
3585 	}
3586 }
3587 
showSpecialActionAnimationWithFlip(const byte * spriteData,const Common::String & animationSeq,int speed,bool flipFl)3588 void ObjectsManager::showSpecialActionAnimationWithFlip(const byte *spriteData, const Common::String &animationSeq, int speed, bool flipFl) {
3589 	Common::String tmpStr = "";
3590 
3591 	int realSpeed = speed;
3592 	if (_vm->_globals->_speed == 2)
3593 		realSpeed = speed / 2;
3594 	else if (_vm->_globals->_speed == 3)
3595 		realSpeed = speed / 3;
3596 
3597 	_oldSpriteData = _sprite[0]._spriteData;
3598 	_oldSpriteIndex = _sprite[0]._spriteIndex;
3599 	_oldFlipFl = _sprite[0]._flipFl;
3600 	_sprite[0]._flipFl = flipFl;
3601 
3602 	uint strPos = 0;
3603 	int spriteIndex = 0;
3604 	do {
3605 		bool completeTokenFl = false;
3606 		do {
3607 			char nextChar = animationSeq[strPos];
3608 			if ((animationSeq[strPos] == ',') || (strPos == animationSeq.size() - 1)) {
3609 				// Safeguard: if the sequence doesn't end with a coma, simulate it's present.
3610 				if (animationSeq[strPos] != ',')
3611 					tmpStr += nextChar;
3612 				spriteIndex = atoi(tmpStr.c_str());
3613 				tmpStr = "";
3614 				completeTokenFl = true;
3615 			} else {
3616 				tmpStr += nextChar;
3617 			}
3618 			++strPos;
3619 		} while (!completeTokenFl);
3620 
3621 		if (spriteIndex != -1) {
3622 			_sprite[0]._spriteData = spriteData;
3623 			_sprite[0]._spriteIndex = spriteIndex;
3624 		}
3625 		for (int i = 0; i < realSpeed; i++)
3626 			_vm->_events->refreshScreenAndEvents();
3627 	} while (spriteIndex != -1);
3628 }
3629 
showSpecialActionAnimation(const byte * spriteData,const Common::String & animString,int speed)3630 void ObjectsManager::showSpecialActionAnimation(const byte *spriteData, const Common::String &animString, int speed) {
3631 	Common::String tmpStr = "";
3632 	int realSpeed = speed;
3633 	if (_vm->_globals->_speed == 2)
3634 		realSpeed = speed / 2;
3635 	else if (_vm->_globals->_speed == 3)
3636 		realSpeed = speed / 3;
3637 
3638 	int spriteIndex = 0;
3639 
3640 	for (int idx = 0; ; idx++) {
3641 		bool completeTokenFl = false;
3642 		char nextChar = animString[idx];
3643 		if (nextChar == ',') {
3644 			spriteIndex = atoi(tmpStr.c_str());
3645 			tmpStr = "";
3646 			completeTokenFl = true;
3647 		} else {
3648 			tmpStr += nextChar;
3649 		}
3650 
3651 		if (completeTokenFl) {
3652 			if (spriteIndex == -1) {
3653 				_sprite[0]._spriteData = _oldSpriteData;
3654 				_sprite[0]._spriteIndex = _oldSpriteIndex;
3655 				_sprite[0]._flipFl = _oldFlipFl;
3656 			} else {
3657 				_sprite[0]._spriteData = spriteData;
3658 				_sprite[0]._spriteIndex = spriteIndex;
3659 			}
3660 
3661 			for (int i = 0; i < realSpeed; i++)
3662 				_vm->_events->refreshScreenAndEvents();
3663 
3664 			if (spriteIndex == -1)
3665 				break;
3666 		}
3667 	}
3668 }
3669 
handleForest(int screenId,int minX,int maxX,int minY,int maxY,int idx)3670 void ObjectsManager::handleForest(int screenId, int minX, int maxX, int minY, int maxY, int idx) {
3671 	int savegameIdx = screenId;
3672 	if (_vm->_globals->_screenId != screenId)
3673 		return;
3674 
3675 	switch (_vm->_globals->_screenId) {
3676 	case 35:
3677 		if (idx > 2)
3678 			savegameIdx = 201;
3679 		else
3680 			savegameIdx = 200;
3681 		break;
3682 	case 36:
3683 		if (idx > 2)
3684 			savegameIdx = 203;
3685 		else
3686 			savegameIdx = 202;
3687 		break;
3688 	case 37:
3689 		if (idx > 2)
3690 			savegameIdx = 205;
3691 		else
3692 			savegameIdx = 204;
3693 		break;
3694 	case 38:
3695 		if (idx > 2)
3696 			savegameIdx = 207;
3697 		else
3698 			savegameIdx = 206;
3699 		break;
3700 	case 39:
3701 		if (idx > 2)
3702 			savegameIdx = 209;
3703 		else
3704 			savegameIdx = 208;
3705 		break;
3706 	case 40:
3707 		if (idx > 2)
3708 			savegameIdx = 211;
3709 		else
3710 			savegameIdx = 210;
3711 		break;
3712 	case 41:
3713 		if (idx > 2)
3714 			savegameIdx = 213;
3715 		else
3716 			savegameIdx = 212;
3717 		break;
3718 	default:
3719 		break;
3720 	}
3721 
3722 	if (_vm->_globals->_saveData->_data[savegameIdx] == 2)
3723 		return;
3724 
3725 	if (_vm->_globals->_saveData->_data[savegameIdx]) {
3726 		if (_vm->_globals->_saveData->_data[savegameIdx] == 1) {
3727 			if (((idx == 1 || idx == 2) && getBobAnimDataIdx(idx) == 26) || ((idx == 3 || idx == 4) && getBobAnimDataIdx(idx) == 27)) {
3728 				_vm->_dialog->disableInvent();
3729 				_vm->_soundMan->playSample(1);
3730 				_vm->_globals->_saveData->_data[savegameIdx] = 4;
3731 			}
3732 		}
3733 		if (_vm->_globals->_saveData->_data[savegameIdx] == 4) {
3734 			if (idx >= 1 && idx <= 4 && getBobAnimDataIdx(idx) > 30)
3735 				_vm->_globals->_saveData->_data[savegameIdx] = 3;
3736 		}
3737 		if (_vm->_globals->_saveData->_data[savegameIdx] == 3) {
3738 			_vm->_graphicsMan->_fadingFl = true;
3739 			_vm->_animMan->playAnim("CREVE2.ANM", "CREVE2.ANM", 100, 24, 500);
3740 			_vm->_globals->_exitId = 150;
3741 			_vm->_graphicsMan->_noFadingFl = true;
3742 			hideBob(1);
3743 			hideBob(2);
3744 			hideBob(3);
3745 			hideBob(4);
3746 		}
3747 	} else if (minX < getSpriteX(0)
3748 	           && maxX > getSpriteX(0)
3749 	           && minY < getSpriteY(0)
3750 	           && maxY > getSpriteY(0)) {
3751 		if (idx >= 1 && idx <= 4)
3752 			setBobAnimation(idx);
3753 		_vm->_globals->_saveData->_data[savegameIdx] = 1;
3754 	}
3755 }
3756 
lockAnimX(int idx,int x)3757 void ObjectsManager::lockAnimX(int idx, int x) {
3758 	_lockedAnims[idx]._enableFl = true;
3759 	_lockedAnims[idx]._posX = x;
3760 }
3761 
3762 /**
3763  * Game scene control method
3764  */
sceneControl(const Common::String & backgroundFile,const Common::String & linkFile,const Common::String & animFile,const Common::String & s4,int soundNum,bool initializeScreen)3765 void ObjectsManager::sceneControl(const Common::String &backgroundFile, const Common::String &linkFile,
3766 							   const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) {
3767 	_vm->_dialog->_inventFl = false;
3768 	_vm->_events->_gameKey = KEY_NONE;
3769 	_vm->_dialog->enableInvent();
3770 	_vm->_graphicsMan->_scrollOffset = 0;
3771 	_vm->_globals->_cityMapEnabledFl = false;
3772 	_vm->_globals->_eventMode = EVENTMODE_IGNORE;
3773 	_vm->_soundMan->playSound(soundNum);
3774 	_vm->_linesMan->_route = NULL;
3775 	_vm->_globals->_freezeCharacterFl = true;
3776 	_vm->_globals->_exitId = 0;
3777 	if (!backgroundFile.empty())
3778 		_vm->_graphicsMan->loadImage(backgroundFile);
3779 	if (!linkFile.empty())
3780 		loadLinkFile(linkFile);
3781 	if (!animFile.empty())
3782 		_vm->_animMan->loadAnim(animFile);
3783 	_vm->_graphicsMan->displayAllBob();
3784 	if (!s4.empty()) {
3785 		if (initializeScreen)
3786 			_vm->_graphicsMan->initScreen(s4, 0, initializeScreen);
3787 		else
3788 			_vm->_graphicsMan->initScreen(s4, 2, initializeScreen);
3789 	}
3790 	_vm->_events->mouseOn();
3791 	if (_vm->_globals->_screenId == 61) {
3792 		addStaticSprite(_vm->_globals->_characterSpriteBuf, Common::Point(330, 418), 0, 60, 0, false, 34, 190);
3793 		animateSprite(0);
3794 		_vm->_linesMan->_route = NULL;
3795 		computeAndSetSpriteSize();
3796 	}
3797 	_vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
3798 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
3799 	_vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
3800 	_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
3801 	_vm->_events->changeMouseCursor(4);
3802 	for (int i = 0; i <= 4; i++)
3803 		_vm->_events->refreshScreenAndEvents();
3804 	_vm->_graphicsMan->fadeInLong();
3805 	if (_vm->_globals->_screenId == 61) {
3806 		_vm->_animMan->playSequence("OUVRE.SEQ", 10, 4, 10, false, false);
3807 		stopBobAnimation(3);
3808 		_vm->_globals->_checkDistanceFl = true;
3809 		_oldCharacterPosX = getSpriteX(0);
3810 		_oldDirection = DIR_NONE;
3811 		_homeRateCounter = 0;
3812 		_vm->_linesMan->_route = NULL;
3813 		_vm->_linesMan->_route = _vm->_linesMan->findRoute(getSpriteX(0), getSpriteY(0), 330, 345);
3814 		_vm->_globals->_checkDistanceFl = true;
3815 		do {
3816 			goHome();
3817 			_vm->_events->refreshScreenAndEvents();
3818 		} while (_vm->_linesMan->_route);
3819 		setSpriteIndex(0, 64);
3820 	}
3821 	do {
3822 		int mouseButton = _vm->_events->getMouseButton();
3823 		if (mouseButton == 1) {
3824 			handleLeftButton();
3825 			mouseButton = 1;
3826 		} else if (mouseButton == 2)
3827 			handleRightButton();
3828 		_vm->_dialog->testDialogOpening();
3829 		_vm->_linesMan->checkZone();
3830 		if (_vm->_globals->_actionMoveTo)
3831 			paradise();
3832 		if (!_vm->_globals->_exitId)
3833 			_vm->_events->refreshScreenAndEvents();
3834 
3835 		if (_vm->_globals->_exitId)
3836 			break;
3837 	} while (!_vm->shouldQuit());
3838 	if (_vm->shouldQuit())
3839 		return;
3840 
3841 	_vm->_graphicsMan->fadeOutLong();
3842 	if (!animFile.empty())
3843 		_vm->_graphicsMan->endDisplayBob();
3844 	if (_vm->_globals->_screenId == 61)
3845 		removeSprite(0);
3846 	clearScreen();
3847 	_vm->_globals->_eventMode = EVENTMODE_DEFAULT;
3848 }
3849 
3850 /**
3851  * Game scene control method
3852  */
sceneControl2(const Common::String & backgroundFile,const Common::String & linkFile,const Common::String & animFile,const Common::String & s4,int soundNum,bool initializeScreen)3853 void ObjectsManager::sceneControl2(const Common::String &backgroundFile, const Common::String &linkFile,
3854 								const Common::String &animFile, const Common::String &s4, int soundNum, bool initializeScreen) {
3855 	_vm->_dialog->_inventFl = false;
3856 	_vm->_events->_gameKey = KEY_NONE;
3857 	_verb = 4;
3858 	_vm->_graphicsMan->_scrollOffset = 0;
3859 	_vm->_dialog->enableInvent();
3860 	_vm->_globals->_cityMapEnabledFl = false;
3861 	_vm->_graphicsMan->_noFadingFl = false;
3862 	_vm->_globals->_freezeCharacterFl = false;
3863 	_vm->_globals->_exitId = 0;
3864 	_vm->_globals->_checkDistanceFl = true;
3865 	_vm->_soundMan->playSound(soundNum);
3866 	_vm->_globals->_eventMode = EVENTMODE_IGNORE;
3867 	if (!backgroundFile.empty())
3868 		_vm->_graphicsMan->loadImage(backgroundFile);
3869 	if (!linkFile.empty())
3870 		loadLinkFile(linkFile);
3871 	if (!animFile.empty()) {
3872 		_vm->_animMan->loadAnim(animFile);
3873 		_vm->_graphicsMan->displayAllBob();
3874 	}
3875 	if (!s4.empty()) {
3876 		if (initializeScreen)
3877 			_vm->_graphicsMan->initScreen(s4, 0, initializeScreen);
3878 		else
3879 			_vm->_graphicsMan->initScreen(s4, 2, initializeScreen);
3880 	}
3881 	_vm->_events->mouseOn();
3882 	_vm->_events->_mouseCursorId = 4;
3883 	_vm->_graphicsMan->setColorPercentage(252, 100, 100, 100);
3884 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
3885 	_vm->_graphicsMan->setColorPercentage(251, 100, 100, 100);
3886 	_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
3887 	if (_vm->_globals->_characterType != CHARACTER_HOPKINS && !_vm->_globals->_saveData->_data[svAlternateSpriteFl] && !_vm->_globals->_saveData->_data[svField356]) {
3888 		_vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PERSO.SPR");
3889 		_vm->_globals->_characterType = CHARACTER_HOPKINS;
3890 	}
3891 
3892 	if (_vm->_globals->_characterType == CHARACTER_HOPKINS && _vm->_globals->_saveData->_data[svAlternateSpriteFl] == 1) {
3893 		_vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("HOPFEM.SPR");
3894 		_vm->_globals->_characterType = CHARACTER_HOPKINS_CLONE;
3895 	}
3896 
3897 	if (_vm->_globals->_characterType != CHARACTER_SAMANTHA && _vm->_globals->_saveData->_data[svField356] == 1) {
3898 		_vm->_globals->_characterSpriteBuf = _vm->_fileIO->loadFile("PSAMAN.SPR");
3899 		_vm->_globals->_characterType = CHARACTER_SAMANTHA;
3900 	}
3901 	_vm->_globals->loadCharacterData();
3902 	switch (_vm->_globals->_characterType) {
3903 	case CHARACTER_HOPKINS:
3904 		addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 34, 190);
3905 		break;
3906 	case CHARACTER_HOPKINS_CLONE:
3907 		addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 28, 155);
3908 		break;
3909 	case CHARACTER_SAMANTHA:
3910 		addStaticSprite(_vm->_globals->_characterSpriteBuf, _characterPos, 0, _startSpriteIndex, 0, false, 20, 127);
3911 		break;
3912 	default:
3913 		break;
3914 	}
3915 	_vm->_events->setMouseXY(_characterPos);
3916 	if (_vm->_graphicsMan->_largeScreenFl)
3917 		_vm->_graphicsMan->_scrollPosX = (int16)getSpriteX(0) - 320;
3918 	computeAndSetSpriteSize();
3919 	animateSprite(0);
3920 	enableHidingBehavior();
3921 	_vm->_linesMan->_route = NULL;
3922 	computeAndSetSpriteSize();
3923 	sceneSpecialIni();
3924 	_vm->_events->_mouseSpriteId = 4;
3925 	_oldCharacterPosX = _characterPos.x;
3926 	_oldCharacterPosY = _characterPos.y;
3927 	_oldDirection = DIR_NONE;
3928 	_homeRateCounter = 0;
3929 
3930 	for (int idx = 0; idx < 5; ++idx)
3931 		_vm->_events->refreshScreenAndEvents();
3932 
3933 	_vm->_globals->_eventMode = EVENTMODE_IGNORE;
3934 	if (!_vm->_graphicsMan->_noFadingFl)
3935 		_vm->_graphicsMan->fadeInLong();
3936 	_vm->_graphicsMan->_noFadingFl = false;
3937 	_vm->_events->changeMouseCursor(4);
3938 
3939 	int xCheck = 0;
3940 	int yCheck = 0;
3941 
3942 	bool breakFlag = false;
3943 	while (!_vm->shouldQuit() && !breakFlag) {
3944 		int mouseButtons = _vm->_events->getMouseButton();
3945 		if (mouseButtons) {
3946 			if (mouseButtons == 1) {
3947 				if (_verb == 16 && _vm->_events->_mouseCursorId == 16) {
3948 					int xp = _vm->_events->getMouseX();
3949 					int yp = _vm->_events->getMouseY();
3950 
3951 					if ((xCheck == xp) && (yCheck == yp)) {
3952 						_vm->_linesMan->_route = NULL;
3953 						paradise();
3954 						if (_vm->_globals->_exitId)
3955 							breakFlag = true;
3956 					}
3957 					xCheck = xp;
3958 					yCheck = yp;
3959 				}
3960 				handleLeftButton();
3961 			} else if (mouseButtons == 2) {
3962 				handleRightButton();
3963 			}
3964 		}
3965 		if (!_vm->_globals->_exitId) {
3966 			_vm->_dialog->testDialogOpening();
3967 			_vm->_linesMan->checkZone();
3968 			if (_vm->_linesMan->_route == NULL
3969 					|| (goHome(), _vm->_linesMan->_route == NULL)) {
3970 				if (_vm->_globals->_actionMoveTo)
3971 					paradise();
3972 			}
3973 			handleSpecialGames();
3974 			_vm->_events->refreshScreenAndEvents();
3975 			if (!_vm->_globals->_exitId)
3976 				continue;
3977 		}
3978 		breakFlag = true;
3979 	}
3980 
3981 	if (_vm->_globals->_exitId != 8 || _vm->_globals->_screenId != 5 || !_helicopterFl) {
3982 		if (!_vm->_graphicsMan->_noFadingFl)
3983 			_vm->_graphicsMan->fadeOutLong();
3984 		_vm->_graphicsMan->_noFadingFl = false;
3985 		removeSprite(0);
3986 		if (_twoCharactersFl) {
3987 			removeSprite(1);
3988 			_twoCharactersFl = false;
3989 		}
3990 		if (!animFile.empty())
3991 			_vm->_graphicsMan->endDisplayBob();
3992 		clearScreen();
3993 	} else {
3994 		_helicopterFl = false;
3995 	}
3996 	_vm->_globals->_eventMode = EVENTMODE_DEFAULT;
3997 }
3998 
setVerb(int id)3999 void ObjectsManager::setVerb(int id) {
4000 	_verb = id;
4001 }
4002 
resetHidingUseCount(int idx)4003 void ObjectsManager::resetHidingUseCount(int idx) {
4004 	_hidingItem[idx]._useCount = 0;
4005 }
4006 
setHidingUseCount(int idx)4007 void ObjectsManager::setHidingUseCount(int idx) {
4008 	_hidingItem[idx]._useCount = 1;
4009 }
4010 
4011 // Load Hiding Items
loadHidingItems(const Common::String & file)4012 void ObjectsManager::loadHidingItems(const Common::String &file) {
4013 	resetHidingItems();
4014 	byte *ptr = _vm->_fileIO->loadFile(file);
4015 	Common::String filename = Common::String((const char *)ptr);
4016 
4017 	Common::File f;
4018 	if (!f.exists(filename))
4019 		return;
4020 
4021 	byte *spriteData = _vm->_fileIO->loadFile(filename);
4022 	_hidingItemData[1] = spriteData;
4023 	int curBufIdx = 60;
4024 	for (int i = 0; i <= 21; i++) {
4025 		HidingItem *hid = &_hidingItem[i];
4026 		hid->_spriteIndex = READ_LE_INT16((uint16 *)ptr + curBufIdx);
4027 		hid->_x = READ_LE_INT16((uint16 *)ptr + curBufIdx + 1);
4028 		hid->_y = READ_LE_INT16((uint16 *)ptr + curBufIdx + 2);
4029 		hid->_yOffset = READ_LE_INT16((uint16 *)ptr + curBufIdx + 4);
4030 		if (spriteData == NULL) {
4031 			hid->_useCount = 0;
4032 		} else {
4033 			hid->_spriteData = spriteData;
4034 			hid->_width = getWidth(spriteData, hid->_spriteIndex);
4035 			hid->_height = getHeight(spriteData, hid->_spriteIndex);
4036 			hid->_useCount = 1;
4037 		}
4038 
4039 		if ( !hid->_x && !hid->_y && !hid->_spriteIndex)
4040 			hid->_useCount = 0;
4041 		curBufIdx += 5;
4042 	}
4043 	enableHidingBehavior();
4044 	_vm->_globals->freeMemory(ptr);
4045 }
4046 
initVBob()4047 void ObjectsManager::initVBob() {
4048 	for (int idx = 0; idx < 30; ++idx) {
4049 		VBobItem *vbob = &_vBob[idx];
4050 		vbob->_displayMode = 0;
4051 		vbob->_xp = 0;
4052 		vbob->_yp = 0;
4053 		vbob->_frameIndex = 0;
4054 		vbob->_surface = NULL;
4055 		vbob->_spriteData = NULL;
4056 		vbob->_oldSpriteData = NULL;
4057 	}
4058 }
4059 
clearVBob()4060 void ObjectsManager::clearVBob() {
4061 	for (int idx = 0; idx < 30; ++idx) {
4062 		VBobItem *vbob = &_vBob[idx];
4063 		vbob->_displayMode = 0;
4064 		vbob->_xp = 0;
4065 		vbob->_yp = 0;
4066 		vbob->_frameIndex = 0;
4067 		vbob->_surface = _vm->_globals->freeMemory(vbob->_surface);
4068 		vbob->_spriteData = NULL;
4069 		vbob->_oldSpriteData = NULL;
4070 	}
4071 }
4072 
disableHidingItem(int idx)4073 void ObjectsManager::disableHidingItem(int idx) {
4074 	assert(idx < 36);
4075 	_bob[idx]._disableFl = true;
4076 }
4077 
enableHidingBehavior()4078 void ObjectsManager::enableHidingBehavior() {
4079 	_hidingActiveFl = true;
4080 }
4081 
disableHidingBehavior()4082 void ObjectsManager::disableHidingBehavior() {
4083 	_hidingActiveFl = false;
4084 }
4085 
4086 } // End of namespace Hopkins
4087