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 "lastexpress/game/entities.h"
24 
25 // Data
26 #include "lastexpress/data/scene.h"
27 #include "lastexpress/data/sequence.h"
28 
29 // Entities
30 #include "lastexpress/entities/abbot.h"
31 #include "lastexpress/entities/alexei.h"
32 #include "lastexpress/entities/alouan.h"
33 #include "lastexpress/entities/anna.h"
34 #include "lastexpress/entities/august.h"
35 #include "lastexpress/entities/boutarel.h"
36 #include "lastexpress/entities/chapters.h"
37 #include "lastexpress/entities/cooks.h"
38 #include "lastexpress/entities/coudert.h"
39 #include "lastexpress/entities/entity39.h"
40 #include "lastexpress/entities/francois.h"
41 #include "lastexpress/entities/gendarmes.h"
42 #include "lastexpress/entities/hadija.h"
43 #include "lastexpress/entities/ivo.h"
44 #include "lastexpress/entities/kahina.h"
45 #include "lastexpress/entities/kronos.h"
46 #include "lastexpress/entities/mahmud.h"
47 #include "lastexpress/entities/max.h"
48 #include "lastexpress/entities/mertens.h"
49 #include "lastexpress/entities/milos.h"
50 #include "lastexpress/entities/mmeboutarel.h"
51 #include "lastexpress/entities/pascale.h"
52 #include "lastexpress/entities/rebecca.h"
53 #include "lastexpress/entities/salko.h"
54 #include "lastexpress/entities/sophie.h"
55 #include "lastexpress/entities/tables.h"
56 #include "lastexpress/entities/tatiana.h"
57 #include "lastexpress/entities/train.h"
58 #include "lastexpress/entities/vassili.h"
59 #include "lastexpress/entities/verges.h"
60 #include "lastexpress/entities/vesna.h"
61 #include "lastexpress/entities/waiter1.h"
62 #include "lastexpress/entities/waiter2.h"
63 #include "lastexpress/entities/yasmin.h"
64 
65 // Game
66 #include "lastexpress/game/logic.h"
67 #include "lastexpress/game/savepoint.h"
68 #include "lastexpress/game/scenes.h"
69 #include "lastexpress/game/state.h"
70 
71 #include "lastexpress/sound/queue.h"
72 
73 #include "lastexpress/graphics.h"
74 #include "lastexpress/lastexpress.h"
75 #include "lastexpress/resource.h"
76 
77 namespace LastExpress {
78 
79 #define STORE_VALUE(data) ((uint)1 << (uint)data)
80 
81 static const EntityPosition objectsPosition[8] = {kPosition_8200, kPosition_7500,
82 	                                              kPosition_6470, kPosition_5790,
83 	                                              kPosition_4840, kPosition_4070,
84 	                                              kPosition_3050, kPosition_2740};
85 
86 static const EntityPosition entityPositions[41] = {kPositionNone,  kPosition_851,  kPosition_1430, kPosition_2110, kPositionNone,
87 	                                               kPosition_2410, kPosition_2980, kPosition_3450, kPosition_3760, kPosition_4100,
88 	                                               kPosition_4680, kPosition_5140, kPosition_5440, kPosition_5810, kPosition_6410,
89 	                                               kPosition_6850, kPosition_7160, kPosition_7510, kPosition_8514, kPositionNone,
90 	                                               kPositionNone,  kPositionNone,  kPosition_2086, kPosition_2690, kPositionNone,
91 	                                               kPosition_3110, kPosition_3390, kPosition_3890, kPosition_4460, kPosition_4770,
92 	                                               kPosition_5090, kPosition_5610, kPosition_6160, kPosition_6460, kPosition_6800,
93 	                                               kPosition_7320, kPosition_7870, kPosition_8160, kPosition_8500, kPosition_9020,
94 	                                               kPosition_9269};
95 
96 #define ADD_ENTITY(class) \
97 	_entities.push_back(new class(engine));
98 
99 #define COMPUTE_SEQUENCE_NAME(sequenceTo, sequenceFrom) { \
100 	sequenceTo = sequenceFrom; \
101 	for (int seqIdx = 0; seqIdx < 7; seqIdx++) \
102 		sequenceTo.deleteLastChar(); \
103 	if (isInsideTrainCar(entityIndex, kCarGreenSleeping) || isInsideTrainCar(entityIndex, kCarRedSleeping)) { \
104 		if (data->car < getData(kEntityPlayer)->car || (data->car == getData(kEntityPlayer)->car && data->entityPosition < getData(kEntityPlayer)->entityPosition)) \
105 			sequenceTo += "R.SEQ"; \
106 		else \
107 			sequenceTo += "F.SEQ"; \
108 	} else { \
109 		sequenceTo += ".SEQ"; \
110 	} \
111 }
112 
113 #define TRY_LOAD_SEQUENCE(sequence, name, name1, name2) { \
114 	if (data->car == getData(kEntityPlayer)->car) \
115 		sequence = loadSequence1(name1, field30); \
116 	if (sequence) { \
117 		name = name1; \
118 	} else { \
119 		if (name2 != "") \
120 			sequence = loadSequence1(name2, field30); \
121 		name = (sequence ? name2 : ""); \
122 	} \
123 }
124 
125 //////////////////////////////////////////////////////////////////////////
126 // Entities
127 //////////////////////////////////////////////////////////////////////////
Entities(LastExpressEngine * engine)128 Entities::Entities(LastExpressEngine *engine) : _engine(engine) {
129 	_header = new EntityData();
130 
131 	_entities.push_back(NULL);      // Header
132 	ADD_ENTITY(Anna);
133 	ADD_ENTITY(August);
134 	ADD_ENTITY(Mertens);
135 	ADD_ENTITY(Coudert);
136 	ADD_ENTITY(Pascale);
137 	ADD_ENTITY(Waiter1);
138 	ADD_ENTITY(Waiter2);
139 	ADD_ENTITY(Cooks);
140 	ADD_ENTITY(Verges);
141 	ADD_ENTITY(Tatiana);
142 	ADD_ENTITY(Vassili);
143 	ADD_ENTITY(Alexei);
144 	ADD_ENTITY(Abbot);
145 	ADD_ENTITY(Milos);
146 	ADD_ENTITY(Vesna);
147 	ADD_ENTITY(Ivo);
148 	ADD_ENTITY(Salko);
149 	ADD_ENTITY(Kronos);
150 	ADD_ENTITY(Kahina);
151 	ADD_ENTITY(Francois);
152 	ADD_ENTITY(MmeBoutarel);
153 	ADD_ENTITY(Boutarel);
154 	ADD_ENTITY(Rebecca);
155 	ADD_ENTITY(Sophie);
156 	ADD_ENTITY(Mahmud);
157 	ADD_ENTITY(Yasmin);
158 	ADD_ENTITY(Hadija);
159 	ADD_ENTITY(Alouan);
160 	ADD_ENTITY(Gendarmes);
161 	ADD_ENTITY(Max);
162 	ADD_ENTITY(Chapters);
163 	ADD_ENTITY(Train);
164 
165 	// Special case for tables
166 	_entities.push_back(new Tables(engine, kEntityTables0));
167 	_entities.push_back(new Tables(engine, kEntityTables1));
168 	_entities.push_back(new Tables(engine, kEntityTables2));
169 	_entities.push_back(new Tables(engine, kEntityTables3));
170 	_entities.push_back(new Tables(engine, kEntityTables4));
171 	_entities.push_back(new Tables(engine, kEntityTables5));
172 
173 	ADD_ENTITY(Entity39);
174 
175 	// Init compartments & positions
176 	memset(&_compartments, 0, sizeof(_compartments));
177 	memset(&_compartments1, 0, sizeof(_compartments1));
178 	memset(&_positions, 0, sizeof(_positions));
179 }
180 
~Entities()181 Entities::~Entities() {
182 	SAFE_DELETE(_header);
183 
184 	for (uint i = 0; i < _entities.size(); i++)
185 		SAFE_DELETE(_entities[i]);
186 
187 	_entities.clear();
188 
189 	// Zero passed pointers
190 	_engine = NULL;
191 }
192 
193 //////////////////////////////////////////////////////////////////////////
194 // Accessors
195 //////////////////////////////////////////////////////////////////////////
get(EntityIndex entity)196 Entity *Entities::get(EntityIndex entity) {
197 	assert((uint)entity < _entities.size());
198 
199 	if (entity == kEntityPlayer)
200 		error("[Entities::get] Cannot get entity for kEntityPlayer");
201 
202 	return _entities[entity];
203 }
204 
getData(EntityIndex entity) const205 EntityData::EntityCallData *Entities::getData(EntityIndex entity) const {
206 	assert((uint)entity < _entities.size());
207 
208 	if (entity == kEntityPlayer)
209 		return _header->getCallData();
210 
211 	return _entities[entity]->getData();
212 }
213 
getPosition(CarIndex car,Position position) const214 int Entities::getPosition(CarIndex car, Position position) const {
215 	int index = 100 * car + position;
216 
217 	if (car > 10)
218 		error("[Entities::getPosition] Trying to access an invalid car (was: %d, valid:0-9)", car);
219 
220 	if (position > 100)
221 		error("[Entities::getPosition] Trying to access an invalid position (was: %d, valid:0-100)", position);
222 
223 	return _positions[index];
224 }
225 
getCompartments(int index) const226 int Entities::getCompartments(int index) const {
227 	if (index >= _compartmentsCount)
228 		error("[Entities::getCompartments] Trying to access an invalid compartment (was: %d, valid:0-15)", index);
229 
230 	return _compartments[index];
231 }
232 
getCompartments1(int index) const233 int Entities::getCompartments1(int index) const {
234 	if (index >= _compartmentsCount)
235 		error("[Entities::getCompartments] Trying to access an invalid compartment (was: %d, valid:0-15)", index);
236 
237 	return _compartments1[index];
238 }
239 
240 //////////////////////////////////////////////////////////////////////////
241 // Savegame
242 //////////////////////////////////////////////////////////////////////////
saveLoadWithSerializer(Common::Serializer & s)243 void Entities::saveLoadWithSerializer(Common::Serializer &s) {
244 	_header->saveLoadWithSerializer(s, NULL);
245 	for (uint i = 1; i < _entities.size(); i++)
246 		_entities[i]->saveLoadWithSerializer(s);
247 }
248 
savePositions(Common::Serializer & s)249 void Entities::savePositions(Common::Serializer &s) {
250 	for (uint i = 0; i < (uint)_positionsCount; i++)
251 		s.syncAsUint32LE(_positions[i]);
252 }
253 
saveCompartments(Common::Serializer & s)254 void Entities::saveCompartments(Common::Serializer &s) {
255 	for (uint i = 0; i < (uint)_compartmentsCount; i++)
256 		s.syncAsUint32LE(_compartments[i]);
257 
258 	for (uint i = 0; i < (uint)_compartmentsCount; i++)
259 		s.syncAsUint32LE(_compartments1[i]);
260 }
261 
262 //////////////////////////////////////////////////////////////////////////
263 // Setup
264 //////////////////////////////////////////////////////////////////////////
setup(bool isFirstChapter,EntityIndex entityIndex)265 void Entities::setup(bool isFirstChapter, EntityIndex entityIndex) {
266 	setupChapter(isFirstChapter ? kChapter1 : kChapterAll);
267 
268 	bool flag_4 = false;
269 
270 	if (!isFirstChapter) {
271 		getFlags()->flag_4 = false;
272 
273 		if (entityIndex) {
274 			getSavePoints()->call(kEntityPlayer, entityIndex, kActionNone);
275 			flag_4 = getFlags()->flag_4;
276 		}
277 	}
278 
279 	getFlags()->flag_4 = flag_4;
280 	if (!getFlags()->flag_4)
281 		getScenes()->loadScene(getState()->scene);
282 }
283 
setupChapter(ChapterIndex chapter)284 void Entities::setupChapter(ChapterIndex chapter) {
285 	if (chapter) {
286 		// Reset current call, inventory item & draw sequences
287 		for (uint i = 1; i < _entities.size(); i++) {
288 			getData((EntityIndex)i)->currentCall = 0;
289 			getData((EntityIndex)i)->inventoryItem = kItemNone;
290 
291 			clearSequences((EntityIndex)i);
292 		}
293 
294 		// Init compartments & positions
295 		memset(&_compartments, 0, sizeof(_compartments));
296 		memset(&_compartments1, 0, sizeof(_compartments1));
297 		memset(&_positions, 0, sizeof(_positions));
298 
299 		getSoundQueue()->stopAllExcept(kSoundTagMenu);
300 	}
301 
302 	// we skip the header when doing entity setup
303 	for (uint i = 1; i < _entities.size(); i++) {
304 		// Special case of chapters (prevents infinite loop as we will be called from Chapters functions when changing chapters)
305 		if (i == kEntityChapters && chapter >= 2)
306 			continue;
307 
308 		_entities[i]->setup(chapter);
309 	}
310 }
311 
reset()312 void Entities::reset() {
313 	// Reset header
314 	delete _header;
315 	_header = new EntityData();
316 
317 	for (uint i = 1; i < _entities.size(); i++)
318 		resetSequences((EntityIndex)i);
319 
320 	getScenes()->resetDoorsAndClock();
321 }
322 
323 //////////////////////////////////////////////////////////////////////////
324 // State & Sequences
325 //////////////////////////////////////////////////////////////////////////
326 
canInteractWith(const Common::Point & point) const327 EntityIndex Entities::canInteractWith(const Common::Point &point) const {
328 	if (!getFlags()->isGameRunning)
329 		return kEntityPlayer;
330 
331 	EntityIndex index = kEntityPlayer;
332 	int location = 10000;
333 
334 	// Check if there is an entity we can interact with
335 	for (uint i = 0; i < _entities.size(); i++) {
336 
337 		// Skip entities with no current frame
338 		if (!getData((EntityIndex)i)->frame)
339 			continue;
340 
341 		FrameInfo *info =  getData((EntityIndex)i)->frame->getInfo();
342 
343 		// Check the hotspot
344 		if (info->hotspot.contains(point)) {
345 
346 			// If closer to us, update with its values
347 			if (location > info->location) {
348 				location = info->location;
349 				index = (EntityIndex)i;
350 			}
351 		}
352 	}
353 
354 	// Check if we found an entity
355 	if (!index)
356 		return kEntityPlayer;
357 
358 	// Check that there is an item to interact with
359 	if (!getData(index)->inventoryItem)
360 		return kEntityPlayer;
361 
362 	return index;
363 }
364 
resetState(EntityIndex entityIndex)365 void Entities::resetState(EntityIndex entityIndex) {
366 	getData(entityIndex)->currentCall = 0;
367 	getData(entityIndex)->inventoryItem = kItemNone;
368 
369 	if (getSoundQueue()->isBuffered(entityIndex))
370 		getSoundQueue()->stop(entityIndex);
371 
372 	clearSequences(entityIndex);
373 
374 	if (entityIndex == kEntity39)
375 		entityIndex = kEntityPlayer;
376 
377 	if (entityIndex > kEntityChapters)
378 		return;
379 
380 	// reset compartments and positions for this entity
381 	for (int i = 0; i < _positionsCount; i++)
382 		_positions[i] &= ~STORE_VALUE(entityIndex);
383 
384 	for (int i = 0; i < _compartmentsCount; i++) {
385 		_compartments[i] &= ~STORE_VALUE(entityIndex);
386 		_compartments1[i] &= ~STORE_VALUE(entityIndex);
387 	}
388 
389 	getLogic()->updateCursor();
390 }
391 
updateFields() const392 void Entities::updateFields() const {
393 	if (!getFlags()->isGameRunning)
394 		return;
395 
396 	for (int i = 0; i < (int)_entities.size(); i++) {
397 
398 		if (!getSavePoints()->getCallback((EntityIndex)i))
399 			continue;
400 
401 		EntityData::EntityCallData *data = getData((EntityIndex)i);
402 		int positionDelta = data->field_4A3 * 10;
403 		switch (data->direction) {
404 		default:
405 			break;
406 
407 		case kDirectionUp:
408 			if (data->entityPosition >= 10000 - positionDelta)
409 				data->entityPosition = (EntityPosition)(data->entityPosition + positionDelta);
410 			break;
411 
412 		case kDirectionDown:
413 			if (data->entityPosition > positionDelta)
414 				data->entityPosition = (EntityPosition)(data->entityPosition - positionDelta);
415 			break;
416 
417 		case kDirectionLeft:
418 			data->currentFrame++;
419 			break;
420 
421 		case kDirectionRight:
422 			data->field_4A1 += 9;
423 			break;
424 
425 		case kDirectionSwitch:
426 			if (data->directionSwitch == kDirectionRight)
427 				data->field_4A1 += 9;
428 			break;
429 
430 		}
431 	}
432 }
433 
updateFrame(EntityIndex entityIndex) const434 void Entities::updateFrame(EntityIndex entityIndex) const {
435 	Sequence *sequence = NULL;
436 	int16 *currentFrame = NULL;
437 	bool found = false;
438 
439 	if (getData(entityIndex)->direction == kDirectionSwitch) {
440 		sequence = getData(entityIndex)->sequence2;
441 		currentFrame = &getData(entityIndex)->currentFrame2;
442 	} else {
443 		sequence = getData(entityIndex)->sequence;
444 		currentFrame = &getData(entityIndex)->currentFrame;
445 	}
446 
447 	if (!sequence)
448 		return;
449 
450 	// Save current values
451 	int16 oldFrame = *currentFrame;
452 	int16 field_4A1 = getData(entityIndex)->field_4A1;
453 
454 	do {
455 		// Check we do not get past the end
456 		if (*currentFrame >= (int)sequence->count() - 1)
457 			break;
458 
459 		// Get the proper frame
460 		FrameInfo *info = sequence->getFrameInfo((uint16)*currentFrame);
461 
462 		if (info->field_33 & 8) {
463 			found = true;
464 		} else {
465 			if (info->soundAction == 35)
466 				found = true;
467 
468 			getData(entityIndex)->field_4A1 += info->field_30;
469 
470 			// Progress to the next frame
471 			++*currentFrame;
472 		}
473 	} while (!found);
474 
475 	// Restore old values
476 	if (!found) {
477 		*currentFrame = oldFrame;
478 		getData(entityIndex)->field_4A1 = field_4A1;
479 	}
480 }
481 
updateSequences() const482 void Entities::updateSequences() const {
483 	if (!getFlags()->isGameRunning)
484 		return;
485 
486 	// Update the train clock & doors
487 	getScenes()->updateDoorsAndClock();
488 
489 	//////////////////////////////////////////////////////////////////////////
490 	// First pass: Drawing
491 	//////////////////////////////////////////////////////////////////////////
492 	for (uint i = 1; i < _entities.size(); i++) {
493 		EntityIndex entityIndex = (EntityIndex)i;
494 
495 		if (!getSavePoints()->getCallback(entityIndex))
496 			continue;
497 
498 		EntityData::EntityCallData *data = getData(entityIndex);
499 
500 		if (data->frame) {
501 			getScenes()->removeFromQueue(data->frame);
502 			SAFE_DELETE(data->frame);
503 		}
504 
505 		if (data->frame1) {
506 			getScenes()->removeFromQueue(data->frame1);
507 			SAFE_DELETE(data->frame1);
508 		}
509 
510 		if (data->direction == kDirectionSwitch) {
511 
512 			// Clear sequence 2
513 			if (data->sequence)
514 				SAFE_DELETE(data->sequence);
515 
516 			// Replace by sequence 3 if available
517 			if (data->sequence2) {
518 				data->sequence = data->sequence2;
519 				data->sequenceName = data->sequenceName2;
520 
521 				data->sequence2 = NULL;
522 				data->sequenceName2 = "";
523 			}
524 
525 			data->direction = data->directionSwitch;
526 			data->currentFrame = -1;
527 			data->field_49B = 0;
528 		}
529 
530 		// Draw sequences
531 		drawSequences(entityIndex, data->direction, false);
532 	}
533 
534 	//////////////////////////////////////////////////////////////////////////
535 	// Second pass: Load sequences for next pass
536 	//////////////////////////////////////////////////////////////////////////
537 	for (uint i = 1; i < _entities.size(); i++) {
538 		EntityIndex entityIndex = (EntityIndex)i;
539 
540 		if (!getSavePoints()->getCallback(entityIndex))
541 			continue;
542 
543 		EntityData::EntityCallData *data = getData(entityIndex);
544 		byte field30 = (data->direction == kDirectionLeft ? entityIndex + 35 : 15);
545 
546 		if (data->sequenceName != "" && !data->sequence) {
547 			data->sequence = loadSequence1(data->sequenceName, field30);
548 
549 			// If sequence 2 was loaded correctly, remove the copied name
550 			// otherwise, compute new name
551 			if (data->sequence) {
552 				data->sequenceNameCopy = "";
553 			} else {
554 				Common::String sequenceName;
555 
556 				// Left and down directions
557 				if (data->direction == kDirectionLeft || data->direction == kDirectionRight) {
558 					COMPUTE_SEQUENCE_NAME(sequenceName, data->sequenceName);
559 
560 					// Try loading the sequence
561 					data->sequence = loadSequence1(sequenceName, field30);
562 				}
563 
564 				// Update sequence names
565 				data->sequenceNameCopy = (data->sequence ? "" : data->sequenceName);
566 				data->sequenceName = (data->sequence ? sequenceName : "");
567 			}
568 		}
569 
570 		// Update sequence 3
571 		if (data->sequenceName2 != "" && !data->sequence2) {
572 
573 			if (data->car == getData(kEntityPlayer)->car)
574 				data->sequence2 = loadSequence1(data->sequenceName2, field30);
575 
576 			if (!data->sequence2) {
577 				Common::String sequenceName;
578 
579 				// Left and down directions
580 				if (data->directionSwitch == kDirectionLeft || data->directionSwitch == kDirectionRight) {
581 					COMPUTE_SEQUENCE_NAME(sequenceName, data->sequenceName2);
582 
583 					// Try loading the sequence
584 					data->sequence2 = loadSequence1(sequenceName, field30);
585 				}
586 
587 				// Update sequence names
588 				data->sequenceName2 = (data->sequence2 ? sequenceName : "");
589 			}
590 		}
591 	}
592 }
593 
resetSequences(EntityIndex entityIndex) const594 void Entities::resetSequences(EntityIndex entityIndex) const {
595 
596 	// Reset direction
597 	if (getData(entityIndex)->direction == kDirectionSwitch) {
598 		getData(entityIndex)->direction = getData(entityIndex)->directionSwitch;
599 		getData(entityIndex)->field_49B = 0;
600 		getData(entityIndex)->currentFrame = -1;
601 	}
602 
603 	SAFE_DELETE(getData(entityIndex)->frame);
604 	SAFE_DELETE(getData(entityIndex)->frame1);
605 
606 	SAFE_DELETE(getData(entityIndex)->sequence);
607 	SAFE_DELETE(getData(entityIndex)->sequence2);
608 	SAFE_DELETE(getData(entityIndex)->sequence3);
609 
610 	getData(entityIndex)->field_4A9 = false;
611 	getData(entityIndex)->field_4AA = false;
612 
613 	strcpy((char *)&getData(entityIndex)->sequenceNameCopy, "");
614 	strcpy((char *)&getData(entityIndex)->sequenceName, "");
615 	strcpy((char *)&getData(entityIndex)->sequenceName2, "");
616 
617 	getScenes()->resetQueue();
618 }
619 
620 //////////////////////////////////////////////////////////////////////////
621 // Callbacks
622 //////////////////////////////////////////////////////////////////////////
updateCallbacks()623 void Entities::updateCallbacks() {
624 	if (!getFlags()->isGameRunning)
625 		return;
626 
627 	getFlags()->flag_entities_0 = false;
628 
629 	if (getFlags()->flag_entities_1) {
630 		executeCallbacks();
631 		getFlags()->flag_entities_0 = true;
632 	} else {
633 		getFlags()->flag_entities_1 = true;
634 		executeCallbacks();
635 		getFlags()->flag_entities_1 = false;
636 	}
637 }
638 
executeCallbacks()639 void Entities::executeCallbacks() {
640 	for (uint i = 1; i < _entities.size(); i++) {
641 		if (getFlags()->flag_entities_0)
642 			break;
643 
644 		if (getSavePoints()->getCallback((EntityIndex)i))
645 			processEntity((EntityIndex)i);
646 	}
647 
648 	if (getFlags()->flag_entities_0)
649 		return;
650 
651 	bool processed = true;
652 	do {
653 		processed = true;
654 		for (int i = 1; i < (int)_entities.size(); i++) {
655 			if (getFlags()->flag_entities_0)
656 				break;
657 
658 			if (getSavePoints()->getCallback((EntityIndex)i)) {
659 				if (getData((EntityIndex)i)->doProcessEntity) {
660 					processed = false;
661 					processEntity((EntityIndex)i);
662 				}
663 			}
664 		}
665 	} while (!processed);
666 }
667 
668 //////////////////////////////////////////////////////////////////////////
669 // Processing
670 //////////////////////////////////////////////////////////////////////////
incrementDirectionCounter(EntityData::EntityCallData * data) const671 void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) const {
672 	data->doProcessEntity = false;
673 
674 	if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight))
675 		++data->field_4A1;
676 }
677 
processEntity(EntityIndex entityIndex)678 void Entities::processEntity(EntityIndex entityIndex) {
679 	EntityData::EntityCallData *data = getData(entityIndex);
680 	bool keepPreviousFrame = false;
681 
682 	data->doProcessEntity = false;
683 
684 	if (getData(kEntityPlayer)->car != data->car && data->direction != kDirectionRight && data->direction != kDirectionSwitch) {
685 
686 		if (data->position) {
687 			updatePositionExit(entityIndex, data->car2, data->position);
688 			data->car2 = kCarNone;
689 			data->position = 0;
690 		}
691 
692 		getScenes()->removeAndRedraw(&data->frame, false);
693 		getScenes()->removeAndRedraw(&data->frame1, false);
694 
695 		incrementDirectionCounter(data);
696 		return;
697 	}
698 
699 	if (data->frame1) {
700 		getScenes()->removeAndRedraw(&data->frame1, false);
701 
702 		if (data->frame && data->frame->getInfo()->subType != kFrameType3) {
703 			data->frame->getInfo()->subType = kFrameTypeNone;
704 			getScenes()->setFlagDrawSequences();
705 		}
706 	}
707 
708 	SAFE_DELETE(data->sequence3);
709 
710 	if (!data->frame || !data->direction) {
711 		if (!data->sequence)
712 label_nosequence:
713 			drawSequences(entityIndex, data->direction, true);
714 
715 		data->doProcessEntity = false;
716 		computeCurrentFrame(entityIndex);
717 
718 		if (getFlags()->flag_entities_0 || data->doProcessEntity)
719 			return;
720 
721 		if (data->sequence && data->currentFrame != -1 && data->currentFrame <= (int16)(data->sequence->count() - 1)) {
722 			processFrame(entityIndex, false, true);
723 
724 			if (!getFlags()->flag_entities_0 && !data->doProcessEntity) {
725 				incrementDirectionCounter(data);
726 				return;
727 			}
728 		} else {
729 			if (data->direction == kDirectionRight && data->field_4A1 > 100) {
730 				getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
731 				getSavePoints()->process();
732 
733 				if (getFlags()->flag_entities_0 || data->doProcessEntity)
734 					return;
735 			}
736 
737 			if (data->position) {
738 				updatePositionExit(entityIndex, data->car2, data->position);
739 				data->car2 = kCarNone;
740 				data->position = 0;
741 			}
742 
743 			incrementDirectionCounter(data);
744 		}
745 		return;
746 	}
747 
748 	if (!data->sequence)
749 		goto label_nosequence;
750 
751 	if (data->frame->getInfo()->field_30 > (data->field_49B + 1) || (data->direction == kDirectionLeft && data->sequence->count() == 1)) {
752 		++data->field_49B;
753 	} else if (data->frame->getInfo()->field_30 <= data->field_49B || data->frame->getInfo()->keepPreviousFrame) {
754 		if (data->frame->getInfo()->keepPreviousFrame == 1)
755 			keepPreviousFrame = true;
756 
757 		// Increment current frame
758 		++data->currentFrame;
759 
760 		if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) {
761 
762 			if (data->direction == kDirectionLeft) {
763 				data->currentFrame = 0;
764 			} else {
765 				keepPreviousFrame = true;
766 				drawNextSequence(entityIndex);
767 
768 				if (getFlags()->flag_entities_0 || data->doProcessEntity)
769 					return;
770 
771 				if (!data->sequence2) {
772 					updateEntityPosition(entityIndex);
773 					data->doProcessEntity = false;
774 					return;
775 				}
776 
777 				copySequenceData(entityIndex);
778 			}
779 
780 		}
781 
782 		processFrame(entityIndex, keepPreviousFrame, false);
783 
784 		if (getFlags()->flag_entities_0 || data->doProcessEntity)
785 			return;
786 	} else {
787 		++data->field_49B;
788 	}
789 
790 	incrementDirectionCounter(data);
791 }
792 
computeCurrentFrame(EntityIndex entityIndex) const793 void Entities::computeCurrentFrame(EntityIndex entityIndex) const {
794 	EntityData::EntityCallData *data = getData(entityIndex);
795 	int16 originalCurrentFrame = data->currentFrame;
796 
797 	if (!data->sequence) {
798 		data->currentFrame = -1;
799 		return;
800 	}
801 
802 	switch (data->direction) {
803 	default:
804 		break;
805 
806 	case kDirectionNone:
807 	case kDirectionSwitch:
808 		data->currentFrame = -1;
809 		break;
810 
811 	case kDirectionUp:
812 	case kDirectionDown: {
813 		Scene *scene = getScenes()->get(getState()->scene);
814 
815 		if (scene->position > 40)
816 			break;
817 
818 		switch (scene->position) {
819 		default:
820 		case 4:
821 		case 19:
822 		case 20:
823 		case 21:
824 		case 24:
825 			break;
826 
827 		case 1:
828 		case 18:
829 		case 22:
830 		case 40:
831 			data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
832 			break;
833 
834 		case 2:
835 		case 3:
836 		case 5:
837 		case 6:
838 		case 7:
839 		case 8:
840 		case 9:
841 		case 10:
842 		case 11:
843 		case 12:
844 		case 13:
845 		case 14:
846 		case 15:
847 		case 16:
848 		case 17:
849 			if (data->field_4A9) {
850 				if (getData(kEntityPlayer)->entityPosition >= data->entityPosition) {
851 					data->currentFrame = -1;
852 				} else {
853 					data->currentFrame = getCurrentFrame(entityIndex, data->sequence, getEntityPositionFromCurrentPosition(), true);
854 
855 					if (data->currentFrame != -1 && originalCurrentFrame == data->currentFrame)
856 						if (data->currentFrame < (int)(data->sequence->count() - 2))
857 							data->currentFrame += 2;
858 				}
859 			} else {
860 				data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
861 			}
862 			break;
863 
864 		case 23:
865 		case 25:
866 		case 26:
867 		case 27:
868 		case 28:
869 		case 29:
870 		case 30:
871 		case 31:
872 		case 32:
873 		case 33:
874 		case 34:
875 		case 35:
876 		case 36:
877 		case 37:
878 		case 38:
879 		case 39:
880 			if (data->field_4A9) {
881 				if (getData(kEntityPlayer)->entityPosition <= data->entityPosition) {
882 					data->currentFrame = -1;
883 				} else {
884 					data->currentFrame = getCurrentFrame(entityIndex, data->sequence, getEntityPositionFromCurrentPosition(), true);
885 
886 					if (data->currentFrame != -1 && originalCurrentFrame == data->currentFrame)
887 						if (data->currentFrame < (int)(data->sequence->count() - 2))
888 							data->currentFrame += 2;
889 				}
890 			} else {
891 				data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
892 			}
893 			break;
894 		}
895 
896 		}
897 		break;
898 
899 	case kDirectionLeft:
900 		if (data->currentFrame == -1 || data->currentFrame >= (int32)data->sequence->count()) {
901 			data->currentFrame = 0;
902 			data->field_49B = 0;
903 		}
904 		break;
905 
906 	case kDirectionRight:
907 		bool found = false;
908 		bool flag = false;
909 		uint16 frameIndex = 0;
910 		byte field30 = 0;
911 
912 		int16 currentFrameCopy = (!data->currentFrame && !data->field_4A1) ? -1 : data->currentFrame;
913 
914 		// Process frames
915 		do {
916 			if (frameIndex >= data->sequence->count())
917 				break;
918 
919 			FrameInfo *info = data->sequence->getFrameInfo(frameIndex);
920 
921 			if (field30 + info->field_30 >= data->field_4A1) {
922 				found = true;
923 				break;
924 			}
925 
926 			if (field30 > data->field_4A1 - 10) {
927 				if (info->soundAction)
928 					getSound()->playSoundEvent(entityIndex, info->soundAction, (field30 <= data->field_4A1 - info->field_31) ? 0 : (byte)(field30 + info->field_31 - data->field_4A1));
929 			}
930 
931 			field30 += info->field_30;
932 
933 			if (info->field_33 & 4)
934 				flag = true;
935 
936 			if (info->field_33 & 2) {
937 				flag = false;
938 
939 				getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
940 				getSavePoints()->process();
941 
942 				if (getFlags()->flag_entities_0 || data->doProcessEntity)
943 					return;
944 			}
945 
946 			if (info->field_33 & 16) {
947 				getSavePoints()->push(kEntityPlayer, entityIndex, kAction4);
948 				getSavePoints()->process();
949 
950 				if (getFlags()->flag_entities_0 || data->doProcessEntity)
951 					return;
952 			}
953 
954 			frameIndex++;
955 
956 		} while (!found);
957 
958 		if (found) {
959 
960 			if (flag) {
961 				bool found2 = false;
962 
963 				do {
964 					if (frameIndex >= data->sequence->count())
965 						break;
966 
967 					FrameInfo *info = data->sequence->getFrameInfo(frameIndex);
968 					if (info->field_33 & 2) {
969 						found2 = true;
970 
971 						getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
972 						getSavePoints()->process();
973 
974 						if (getFlags()->flag_entities_0 || data->doProcessEntity)
975 							return;
976 
977 					} else {
978 						data->field_4A1 += info->field_30;
979 
980 						byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
981 						if (soundAction)
982 							getSound()->playSoundEvent(entityIndex, soundAction);
983 
984 						++frameIndex;
985 					}
986 
987 				} while (!found2);
988 
989 				if (found2) {
990 					data->currentFrame = frameIndex;
991 					data->field_49B = 0;
992 
993 					byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
994 					byte field31 = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_31;
995 					if (soundAction && data->currentFrame != currentFrameCopy)
996 						getSound()->playSoundEvent(entityIndex, soundAction, field31);
997 
998 				} else {
999 					data->currentFrame = (int16)(data->sequence->count() - 1);
1000 					data->field_49B = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_30;
1001 				}
1002 
1003 			} else {
1004 
1005 				data->currentFrame = frameIndex;
1006 				data->field_49B = data->field_4A1 - field30;
1007 
1008 				byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
1009 				byte field31 = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_31;
1010 				if (soundAction && data->currentFrame != currentFrameCopy)
1011 					getSound()->playSoundEvent(entityIndex, soundAction, field31 <= data->field_49B ? 0 : (byte)(field31 - data->field_49B));
1012 			}
1013 		} else {
1014 			data->currentFrame = (int16)(data->sequence->count() - 1);
1015 			data->field_49B = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_30;
1016 
1017 			getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
1018 			getSavePoints()->process();
1019 		}
1020 		break;
1021 	}
1022 }
1023 
getCurrentFrame(EntityIndex entity,Sequence * sequence,EntityPosition position,bool doProcessing) const1024 int16 Entities::getCurrentFrame(EntityIndex entity, Sequence *sequence, EntityPosition position, bool doProcessing) const {
1025 	EntityData::EntityCallData *data = getData(entity);
1026 
1027 	EntityPosition firstFramePosition = sequence->getFrameInfo(0)->entityPosition;
1028 	EntityPosition lastFramePosition = sequence->getFrameInfo(sequence->count() - 1)->entityPosition;
1029 
1030 	bool isGoingForward = (firstFramePosition < lastFramePosition);
1031 
1032 	if (!doProcessing) {
1033 		if (!isGoingForward) {
1034 			if (data->field_4A3 + firstFramePosition < data->entityPosition || lastFramePosition - data->field_4A3 > data->entityPosition)
1035 				return -1;
1036 		} else {
1037 			if (firstFramePosition - data->field_4A3 > data->entityPosition || lastFramePosition + data->field_4A3 < data->entityPosition)
1038 				return -1;
1039 		}
1040 	}
1041 
1042 	if (sequence->count() == 0)
1043 		return 0;
1044 
1045 	// Search for the correct frame
1046 	// TODO: looks slightly like some sort of binary search
1047 	uint16 frame = 0;
1048 	uint16 numFrames = sequence->count() - 1;
1049 
1050 	for (;;) {
1051 		uint16 currentFrame = (frame + numFrames) / 2;
1052 
1053 		if (position + sequence->getFrameInfo(currentFrame)->entityPosition <= data->entityPosition) {
1054 			if (!isGoingForward)
1055 				numFrames = (frame + numFrames) / 2;
1056 			else
1057 				frame = (frame + numFrames) / 2;
1058 		} else {
1059 			if (isGoingForward)
1060 				numFrames = (frame + numFrames) / 2;
1061 			else
1062 				frame = (frame + numFrames) / 2;
1063 		}
1064 
1065 		if (numFrames - frame == 1) {
1066 			uint16 lastFramePos = ABS(position - (sequence->getFrameInfo(numFrames)->entityPosition + data->entityPosition));
1067 			uint16 framePosition = ABS(position - (sequence->getFrameInfo(frame)->entityPosition + data->entityPosition));
1068 
1069 			return (framePosition > lastFramePos) ? numFrames : frame;
1070 		}
1071 
1072 		if (numFrames <= frame)
1073 			return currentFrame;
1074 	}
1075 }
1076 
processFrame(EntityIndex entityIndex,bool keepPreviousFrame,bool dontPlaySound)1077 void Entities::processFrame(EntityIndex entityIndex, bool keepPreviousFrame, bool dontPlaySound) {
1078 	EntityData::EntityCallData *data = getData(entityIndex);
1079 
1080 	// Set frame to be drawn again
1081 	if (data->frame && keepPreviousFrame) {
1082 		if (data->frame->getInfo()->subType != kFrameType3)
1083 			data->frame->getInfo()->subType = kFrameType2;
1084 
1085 		getScenes()->setFlagDrawSequences();
1086 	}
1087 
1088 	// Remove old frame from queue
1089 	if (data->frame && !keepPreviousFrame)
1090 		getScenes()->removeFromQueue(data->frame);
1091 
1092 	// Stop if nothing else to draw
1093 	if (data->currentFrame < 0)
1094 		return;
1095 
1096 	if (data->currentFrame > (int)data->sequence->count())
1097 		return;
1098 
1099 	// Get new frame info
1100 	FrameInfo *info = data->sequence->getFrameInfo((uint16)data->currentFrame);
1101 
1102 	if (data->frame && data->frame->getInfo()->subType != kFrameType3 && (!info->field_2E || keepPreviousFrame))
1103 		getScenes()->setCoordinates(data->frame);
1104 
1105 	// Update position
1106 	if (info->entityPosition) {
1107 		data->entityPosition = info->entityPosition;
1108 		if (data->field_4A9)
1109 			data->entityPosition = (EntityPosition)(data->entityPosition + getEntityPositionFromCurrentPosition());
1110 	}
1111 
1112 	info->location = entityIndex + ABS(getData(entityIndex)->entityPosition - getData(kEntityPlayer)->entityPosition);
1113 
1114 	if (info->subType != kFrameType3) {
1115 		info->subType = kFrameType1;
1116 
1117 		if (!keepPreviousFrame)
1118 			info->subType = kFrameTypeNone;
1119 	}
1120 
1121 	if (info->field_33 & 1)
1122 		getSavePoints()->push(kEntityPlayer, entityIndex, kActionExcuseMeCath);
1123 
1124 	if (info->field_33 & 2) {
1125 		getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
1126 		getSavePoints()->process();
1127 
1128 		if (getFlags()->flag_entities_0 || data->doProcessEntity)
1129 			return;
1130 	}
1131 
1132 	if (info->field_33 & 16) {
1133 		getSavePoints()->push(kEntityPlayer, entityIndex, kAction4);
1134 		getSavePoints()->process();
1135 
1136 		if (getFlags()->flag_entities_0 || data->doProcessEntity)
1137 			return;
1138 	}
1139 
1140 	if (data->position) {
1141 		updatePositionExit(entityIndex, data->car2, data->position);
1142 		data->car2 = kCarNone;
1143 		data->position = 0;
1144 	}
1145 
1146 	if (info->position) {
1147 		data->car2 = data->car;
1148 		data->position = info->position;
1149 		updatePositionEnter(entityIndex, data->car2, data->position);
1150 
1151 		if (getFlags()->flag_entities_0 || data->doProcessEntity)
1152 			return;
1153 	}
1154 
1155 	if (info->soundAction && !dontPlaySound)
1156 		getSound()->playSoundEvent(entityIndex, info->soundAction, info->field_31);
1157 
1158 	// Add the new frame to the queue
1159 	SequenceFrame *frame = new SequenceFrame(data->sequence, (uint16)data->currentFrame);
1160 	getScenes()->addToQueue(frame);
1161 
1162 	// Keep previous frame if needed and store the new frame
1163 	if (keepPreviousFrame) {
1164 		SAFE_DELETE(data->frame1);
1165 		data->frame1 = data->frame;
1166 	} else {
1167 		SAFE_DELETE(data->frame);
1168 	}
1169 
1170 	data->frame = frame;
1171 
1172 	if (!dontPlaySound)
1173 		data->field_49B = keepPreviousFrame ? 0 : 1;
1174 }
1175 
drawNextSequence(EntityIndex entityIndex) const1176 void Entities::drawNextSequence(EntityIndex entityIndex) const {
1177 	EntityData::EntityCallData *data = getData(entityIndex);
1178 
1179 	if (data->direction == kDirectionRight) {
1180 		getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
1181 		getSavePoints()->process();
1182 
1183 		if (getFlags()->flag_entities_0 || data->doProcessEntity)
1184 			return;
1185 	}
1186 
1187 	if (!isDirectionUpOrDown(entityIndex))
1188 		return;
1189 
1190 	if (data->sequence2)
1191 		return;
1192 
1193 	if (!getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingAtDoors))
1194 		return;
1195 
1196 	if (getData(kEntityPlayer)->car != data->car)
1197 		return;
1198 
1199 	if (!data->field_4A9 || isWalkingOppositeToPlayer(entityIndex)) {
1200 		if (!data->field_4A9 && isWalkingOppositeToPlayer(entityIndex)) {
1201 			data->entityPosition = kPosition_2088;
1202 
1203 			if (data->direction != kDirectionUp)
1204 				data->entityPosition = kPosition_8512;
1205 
1206 			drawSequences(entityIndex, data->direction, true);
1207 		}
1208 	} else {
1209 		data->entityPosition = kPosition_8514;
1210 
1211 		if (data->direction != kDirectionUp)
1212 			data->entityPosition = kPosition_2086;
1213 
1214 		drawSequences(entityIndex, data->direction, true);
1215 	}
1216 }
1217 
updateEntityPosition(EntityIndex entityIndex) const1218 void Entities::updateEntityPosition(EntityIndex entityIndex) const {
1219 	EntityData::EntityCallData *data = getData(entityIndex);
1220 
1221 	getScenes()->removeAndRedraw(&data->frame, false);
1222 
1223 	SAFE_DELETE(data->frame1);
1224 	data->field_49B = 0;
1225 
1226 	if (isDirectionUpOrDown(entityIndex)
1227 	 && (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) || getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
1228 	 && data->car == getData(kEntityPlayer)->car) {
1229 
1230 		if (isWalkingOppositeToPlayer(entityIndex)) {
1231 			data->entityPosition = getData(kEntityPlayer)->entityPosition;
1232 		} else if (data->field_4A9) {
1233 			data->entityPosition = (data->direction == kDirectionUp) ? kPosition_8514 : kPosition_2086;
1234 		} else {
1235 			if (isPlayerPosition(kCarGreenSleeping, 1) || isPlayerPosition(kCarGreenSleeping, 40)
1236 			 || isPlayerPosition(kCarRedSleeping, 1) || isPlayerPosition(kCarRedSleeping, 40)) {
1237 				 data->entityPosition = (data->direction == kDirectionUp) ? kPosition_2588 : kPosition_8012;
1238 			} else {
1239 				data->entityPosition = (data->direction == kDirectionUp) ? kPosition_9271 : kPosition_849;
1240 			}
1241 		}
1242 	}
1243 
1244 	SAFE_DELETE(data->sequence);
1245 	data->sequenceName = "";
1246 	data->field_4A9 = false;
1247 
1248 	if (data->directionSwitch)
1249 		data->direction = data->directionSwitch;
1250 }
1251 
copySequenceData(EntityIndex entityIndex) const1252 void Entities::copySequenceData(EntityIndex entityIndex) const {
1253 	EntityData::EntityCallData *data = getData(entityIndex);
1254 
1255 	if (data->sequence)
1256 		data->sequence3 = data->sequence;
1257 
1258 	data->sequence = data->sequence2;
1259 	data->sequenceName = data->sequenceName2;
1260 	data->field_4A9 = data->field_4AA;
1261 
1262 	if (data->directionSwitch)
1263 		data->direction = data->directionSwitch;
1264 
1265 	// Clear sequence 3
1266 	data->sequence2 = NULL;
1267 	data->sequenceName2 = "";
1268 	data->field_4AA = false;
1269 	data->directionSwitch = kDirectionNone;
1270 
1271 	if (data->field_4A9) {
1272 		computeCurrentFrame(entityIndex);
1273 
1274 		if (data->currentFrame == -1)
1275 			data->currentFrame = 0;
1276 	} else {
1277 		data->currentFrame = data->currentFrame2;
1278 		data->currentFrame2 = 0;
1279 
1280 		if (data->currentFrame == -1)
1281 			data->currentFrame = 0;
1282 	}
1283 }
1284 
1285 //////////////////////////////////////////////////////////////////////////
1286 // Drawing
1287 //////////////////////////////////////////////////////////////////////////
drawSequenceLeft(EntityIndex index,const char * sequence) const1288 void Entities::drawSequenceLeft(EntityIndex index, const char *sequence) const {
1289 	drawSequence(index, sequence, kDirectionLeft);
1290 }
1291 
drawSequenceRight(EntityIndex index,const char * sequence) const1292 void Entities::drawSequenceRight(EntityIndex index, const char *sequence) const {
1293 	drawSequence(index, sequence, kDirectionRight);
1294 }
1295 
clearSequences(EntityIndex entityIndex) const1296 void Entities::clearSequences(EntityIndex entityIndex) const {
1297 	debugC(8, kLastExpressDebugLogic, "Clear sequences for entity %s", ENTITY_NAME(entityIndex));
1298 
1299 	EntityData::EntityCallData *data = getData(entityIndex);
1300 
1301 	getScenes()->removeAndRedraw(&data->frame, false);
1302 	getScenes()->removeAndRedraw(&data->frame1, false);
1303 
1304 	if (data->sequence2) {
1305 		SAFE_DELETE(data->sequence2);
1306 		data->sequenceName2 = "";
1307 		data->field_4AA = false;
1308 		data->directionSwitch = kDirectionNone;
1309 	}
1310 
1311 	if (data->sequence) {
1312 		SAFE_DELETE(data->sequence);
1313 		data->sequenceName = "";
1314 		data->field_4A9 = false;
1315 		data->currentFrame = -1;
1316 	}
1317 
1318 	data->sequenceNamePrefix = "";
1319 	data->direction = kDirectionNone;
1320 	data->doProcessEntity = true;
1321 }
1322 
drawSequence(EntityIndex index,const char * sequence,EntityDirection direction) const1323 void Entities::drawSequence(EntityIndex index, const char *sequence, EntityDirection direction) const {
1324 	debugC(8, kLastExpressDebugLogic, "Drawing sequence %s for entity %s with direction %s", sequence, ENTITY_NAME(index), DIRECTION_NAME(direction));
1325 
1326 	// Copy sequence name
1327 	getData(index)->sequenceNamePrefix = sequence;
1328 	getData(index)->sequenceNamePrefix.toUppercase();
1329 	getData(index)->sequenceNamePrefix += "-";
1330 
1331 	// Reset fields
1332 	getData(index)->field_49B = 0;
1333 	getData(index)->currentFrame = 0;
1334 	getData(index)->field_4A1 = 0;
1335 
1336 	drawSequences(index, direction, true);
1337 }
1338 
drawSequences(EntityIndex entityIndex,EntityDirection direction,bool loadSequence) const1339 void Entities::drawSequences(EntityIndex entityIndex, EntityDirection direction, bool loadSequence) const {
1340 	EntityData::EntityCallData *data = getData(entityIndex);
1341 
1342 	// Compute value for loading sequence depending on direction
1343 	byte field30 = (direction == kDirectionLeft ? entityIndex + 35 : 15);
1344 
1345 	data->doProcessEntity = true;
1346 	bool field4A9 = data->field_4A9;
1347 
1348 	// First case: different car and not going right: cleanup and return
1349 	if (data->car != getData(kEntityPlayer)->car && direction != kDirectionRight) {
1350 		clearEntitySequenceData(data, direction);
1351 		return;
1352 	}
1353 
1354 	data->directionSwitch = kDirectionNone;
1355 
1356 	// Process sequence names
1357 	Common::String sequenceName;
1358 	Common::String sequenceName1;
1359 	Common::String sequenceName2;
1360 	Common::String sequenceName3;
1361 
1362 	getSequenceName(entityIndex, direction, sequenceName1, sequenceName2);
1363 
1364 	// No sequence 1: cleanup and return
1365 	if (sequenceName1 == "") {
1366 		clearEntitySequenceData(data, direction);
1367 		return;
1368 	}
1369 
1370 	if (sequenceName1 == data->sequenceNameCopy) {
1371 		data->direction = direction;
1372 		return;
1373 	}
1374 
1375 	if (direction == kDirectionLeft || direction == kDirectionRight) {
1376 		COMPUTE_SEQUENCE_NAME(sequenceName, sequenceName1);
1377 
1378 		if (sequenceName3 != "")
1379 			COMPUTE_SEQUENCE_NAME(sequenceName3, sequenceName2);
1380 	}
1381 
1382 	if (!data->frame) {
1383 		data->direction = direction;
1384 
1385 		if (sequenceName1 == data->sequenceName) {
1386 			if (sequenceName2 == "")
1387 				return;
1388 
1389 			loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1390 			return;
1391 		}
1392 
1393 		SAFE_DELETE(data->sequence);
1394 
1395 		if (sequenceName1 != data->sequenceName2) {
1396 
1397 			if (loadSequence) {
1398 
1399 				if (data->car == getData(kEntityPlayer)->car)
1400 					data->sequence = loadSequence1(sequenceName1, field30);
1401 
1402 				if (data->sequence) {
1403 					data->sequenceName = sequenceName1;
1404 					data->sequenceNameCopy = "";
1405 				} else {
1406 					if (sequenceName != "")
1407 						data->sequence = loadSequence1(sequenceName, field30);
1408 
1409 					data->sequenceName = (data->sequence ? sequenceName : "");
1410 					data->sequenceNameCopy = (data->sequence ? "" : sequenceName1);
1411 				}
1412 			} else {
1413 				data->sequenceName = sequenceName1;
1414 			}
1415 
1416 			if (sequenceName2 != "") {
1417 				loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1418 				return;
1419 			}
1420 
1421 			if (!data->sequence2) {
1422 				if (sequenceName2 == "")
1423 					return;
1424 
1425 				loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1426 				return;
1427 			}
1428 
1429 			SAFE_DELETE(data->sequence2);
1430 		} else {
1431 			data->sequence = data->sequence2;
1432 			data->sequenceName = data->sequenceName2;
1433 			data->sequence2 = NULL;
1434 		}
1435 
1436 		data->sequenceName2 = "";
1437 
1438 		if (sequenceName2 == "")
1439 			return;
1440 
1441 		loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1442 		return;
1443 	}
1444 
1445 	if (data->sequenceName != sequenceName1) {
1446 
1447 		if (data->sequenceName2 != sequenceName1) {
1448 			SAFE_DELETE(data->sequence2);
1449 			TRY_LOAD_SEQUENCE(data->sequence2, data->sequenceName2, sequenceName1, sequenceName);
1450 		}
1451 
1452 		data->field_4AA = data->field_4A9;
1453 		if ((direction != kDirectionUp && direction != kDirectionDown) || data->field_4AA || !data->sequence2) {
1454 			data->currentFrame2 = 0;
1455 		} else {
1456 			data->currentFrame2 = getCurrentFrame(entityIndex, data->sequence2, kPositionNone, false);
1457 
1458 			if (data->currentFrame2 == -1) {
1459 				clearSequences(entityIndex);
1460 				return;
1461 			}
1462 		}
1463 
1464 		data->field_4A9 = field4A9;
1465 		data->field_49B = data->frame->getInfo()->field_30;
1466 		data->currentFrame = (int16)(data->sequence->count() - 1);
1467 		data->direction = kDirectionSwitch;
1468 		data->directionSwitch = direction;
1469 	} else {
1470 		SAFE_DELETE(data->sequence2);
1471 
1472 		data->sequence2 = loadSequence1(data->sequence->getName(), data->sequence->getField30());
1473 
1474 		data->sequenceName2 = data->sequenceName;
1475 		data->field_4AA = data->field_4A9;
1476 		data->field_49B = data->frame->getInfo()->field_30;
1477 		data->currentFrame = (int16)(data->sequence->count() - 1);
1478 		data->direction = kDirectionSwitch;
1479 		data->directionSwitch = direction;
1480 
1481 		if ((direction != kDirectionUp && direction != kDirectionDown) || data->field_4AA || !data->sequence2) {
1482 			data->currentFrame2 = 0;
1483 		} else {
1484 			data->currentFrame2 = getCurrentFrame(entityIndex, data->sequence2, kPositionNone, false);
1485 
1486 			if (data->currentFrame2 == -1)
1487 				clearSequences(entityIndex);
1488 		}
1489 	}
1490 }
1491 
loadSequence2(EntityIndex entityIndex,Common::String sequenceName,Common::String sequenceName2,byte field30,bool reloadSequence) const1492 void Entities::loadSequence2(EntityIndex entityIndex, Common::String sequenceName, Common::String sequenceName2, byte field30, bool reloadSequence) const {
1493 	EntityData::EntityCallData *data = getData(entityIndex);
1494 
1495 	if (data->sequenceName2 == sequenceName)
1496 		return;
1497 
1498 	if (data->sequence2)
1499 		SAFE_DELETE(data->sequence2);
1500 
1501 	if (reloadSequence) {
1502 		TRY_LOAD_SEQUENCE(data->sequence2, data->sequenceName2, sequenceName, sequenceName2);
1503 	} else {
1504 		data->sequenceName2 = sequenceName;
1505 	}
1506 }
1507 
getSequenceName(EntityIndex index,EntityDirection direction,Common::String & sequence1,Common::String & sequence2) const1508 void Entities::getSequenceName(EntityIndex index, EntityDirection direction, Common::String &sequence1, Common::String &sequence2) const {
1509 	EntityData::EntityCallData *data = getData(index);
1510 	Position position = getScenes()->get(getState()->scene)->position;
1511 
1512 	// reset fields
1513 	data->field_4A9 = false;
1514 	data->field_4AA = false;
1515 
1516 	switch (direction) {
1517 	default:
1518 		break;
1519 
1520 	case kDirectionUp:
1521 		switch (position) {
1522 		default:
1523 			break;
1524 
1525 		case 1:
1526 			if (data->entityPosition < kPosition_2587)
1527 				sequence1 = Common::String::format("%02d%01d-01u.seq", index, data->clothes);
1528 			break;
1529 
1530 		case 2:
1531 		case 3:
1532 		case 5:
1533 		case 6:
1534 		case 7:
1535 		case 8:
1536 		case 9:
1537 		case 10:
1538 		case 11:
1539 		case 12:
1540 		case 13:
1541 		case 14:
1542 		case 15:
1543 		case 16:
1544 		case 17:
1545 			if (data->entityPosition >= kPosition_9270)
1546 				break;
1547 
1548 			if (data->entityPosition >= kPosition_8513) {
1549 				sequence1 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
1550 			} else {
1551 				sequence1 = Common::String::format("%02d%01d-03u.seq", index, data->clothes);
1552 				sequence2 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
1553 				data->field_4A9 = true;
1554 			}
1555 			break;
1556 
1557 		case 18:
1558 			if (data->entityPosition < kPosition_9270)
1559 				sequence1 = Common::String::format("%02d%01d-18u.seq", index, data->clothes);
1560 			break;
1561 
1562 		case 22:
1563 			if (getData(kEntityPlayer)->entityPosition > data->entityPosition)
1564 				sequence1 = Common::String::format("%02d%01d-22u.seq", index, data->clothes);
1565 			break;
1566 
1567 		case 23:
1568 		case 25:
1569 		case 26:
1570 		case 27:
1571 		case 28:
1572 		case 29:
1573 		case 30:
1574 		case 31:
1575 		case 32:
1576 		case 33:
1577 		case 34:
1578 		case 35:
1579 		case 36:
1580 		case 37:
1581 		case 38:
1582 		case 39:
1583 			if (getData(kEntityPlayer)->entityPosition <= data->entityPosition)
1584 				break;
1585 
1586 			if (data->entityPosition >= kPosition_2087) {
1587 				sequence1 = Common::String::format("%02d%01d-38u.seq", index, data->clothes);
1588 				data->field_4A9 = true;
1589 			} else {
1590 				sequence1 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
1591 				sequence2 = Common::String::format("%02d%01d-38u.seq", index, data->clothes);
1592 				data->field_4AA = true;
1593 			}
1594 			break;
1595 
1596 		case 40:
1597 			if (getData(kEntityPlayer)->entityPosition > data->entityPosition)
1598 				sequence1 = Common::String::format("%02d%01d-40u.seq", index, data->clothes);
1599 			break;
1600 		}
1601 		break;
1602 
1603 	case kDirectionDown:
1604 		switch (position) {
1605 		default:
1606 			break;
1607 
1608 		case 1:
1609 			if (getData(kEntityPlayer)->entityPosition < data->entityPosition)
1610 				sequence1 = Common::String::format("%02d%01d-01d.seq", index, data->clothes);
1611 			break;
1612 
1613 		case 2:
1614 		case 3:
1615 		case 5:
1616 		case 6:
1617 		case 7:
1618 		case 8:
1619 		case 9:
1620 		case 10:
1621 		case 11:
1622 		case 12:
1623 		case 13:
1624 		case 14:
1625 		case 15:
1626 		case 16:
1627 		case 17:
1628 			if (getData(kEntityPlayer)->entityPosition >= data->entityPosition)
1629 				break;
1630 
1631 			if (data->entityPosition <= kPosition_8513) {
1632 				sequence1 = Common::String::format("%02d%01d-03d.seq", index, data->clothes);
1633 				data->field_4A9 = true;
1634 			} else {
1635 				sequence1 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
1636 				sequence2 = Common::String::format("%02d%01d-03d.seq", index, data->clothes);
1637 				data->field_4AA = true;
1638 			}
1639 			break;
1640 
1641 		case 18:
1642 			if (getData(kEntityPlayer)->entityPosition < data->entityPosition)
1643 				sequence1 = Common::String::format("%02d%01d-18d.seq", index, data->clothes);
1644 			break;
1645 
1646 		case 22:
1647 			if (data->entityPosition > kPosition_850)
1648 				sequence1 = Common::String::format("%02d%01d-22d.seq", index, data->clothes);
1649 			break;
1650 
1651 		case 23:
1652 		case 25:
1653 		case 26:
1654 		case 27:
1655 		case 28:
1656 		case 29:
1657 		case 30:
1658 		case 31:
1659 		case 32:
1660 		case 33:
1661 		case 34:
1662 		case 35:
1663 		case 36:
1664 		case 37:
1665 		case 38:
1666 		case 39:
1667 			if (data->entityPosition <= kPosition_850)
1668 				break;
1669 
1670 			if (data->entityPosition <= kPosition_2087) {
1671 				sequence1 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
1672 			} else {
1673 				sequence1 = Common::String::format("%02d%01d-38d.seq", index, data->clothes);
1674 				sequence2 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
1675 				data->field_4A9 = true;
1676 			}
1677 			break;
1678 
1679 		case 40:
1680 			if (getData(kEntityPlayer)->entityPosition > kPosition_8013)
1681 				sequence1 = Common::String::format("%02d%01d-40d.seq", index, data->clothes);
1682 			break;
1683 		}
1684 		break;
1685 
1686 	// First part of sequence is already set
1687 	case kDirectionLeft:
1688 	case kDirectionRight:
1689 		sequence1 = Common::String::format("%s%02d.seq", data->sequenceNamePrefix.c_str(), position);
1690 		break;
1691 	}
1692 }
1693 
1694 //////////////////////////////////////////////////////////////////////////
1695 /// Compartments
1696 //////////////////////////////////////////////////////////////////////////
enterCompartment(EntityIndex entity,ObjectIndex compartment,bool useCompartment1)1697 void Entities::enterCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1) {
1698 	if (entity > kEntityChapters)
1699 		return;
1700 
1701 	switch (compartment) {
1702 	default:
1703 		// Return here so we do not update the compartments
1704 		return;
1705 
1706 	case kObjectCompartment1:
1707 		updatePositionsEnter(entity, kCarGreenSleeping, 41, 51, 17, 38);
1708 		break;
1709 
1710 	case kObjectCompartment2:
1711 		updatePositionsEnter(entity, kCarGreenSleeping, 42, 52, 15, 36);
1712 		break;
1713 
1714 	case kObjectCompartment3:
1715 		updatePositionsEnter(entity, kCarGreenSleeping, 43, 53, 13, 34);
1716 		break;
1717 
1718 	case kObjectCompartment4:
1719 		updatePositionsEnter(entity, kCarGreenSleeping, 44, 54, 11, 32);
1720 		break;
1721 
1722 	case kObjectCompartment5:
1723 		updatePositionsEnter(entity, kCarGreenSleeping, 45, 55, 9, 30);
1724 		break;
1725 
1726 	case kObjectCompartment6:
1727 		updatePositionsEnter(entity, kCarGreenSleeping, 46, 56, 7, 28);
1728 		break;
1729 
1730 	case kObjectCompartment7:
1731 		updatePositionsEnter(entity, kCarGreenSleeping, 47, 57, 5, 26);
1732 		break;
1733 
1734 	case kObjectCompartment8:
1735 		updatePositionsEnter(entity, kCarGreenSleeping, 48, 58, 3, 25);
1736 		break;
1737 
1738 	case kObjectCompartmentA:
1739 		updatePositionsEnter(entity, kCarRedSleeping, 41, 51, 17, 38);
1740 		break;
1741 
1742 	case kObjectCompartmentB:
1743 		updatePositionsEnter(entity, kCarRedSleeping, 42, 52, 15, 36);
1744 		break;
1745 
1746 	case kObjectCompartmentC:
1747 		updatePositionsEnter(entity, kCarRedSleeping, 43, 53, 13, 34);
1748 		break;
1749 
1750 	case kObjectCompartmentD:
1751 		updatePositionsEnter(entity, kCarRedSleeping, 44, 54, 11, 32);
1752 		break;
1753 
1754 	case kObjectCompartmentE:
1755 		updatePositionsEnter(entity, kCarRedSleeping, 45, 55, 9, 30);
1756 		break;
1757 
1758 	case kObjectCompartmentF:
1759 		updatePositionsEnter(entity, kCarRedSleeping, 46, 56, 7, 28);
1760 		break;
1761 
1762 	case kObjectCompartmentG:
1763 		updatePositionsEnter(entity, kCarRedSleeping, 47, 57, 5, 26);
1764 		break;
1765 
1766 	case kObjectCompartmentH:
1767 		updatePositionsEnter(entity, kCarRedSleeping, 48, 58, 3, 25);
1768 		break;
1769 	}
1770 
1771 	// Update compartments
1772 	int index = (compartment < 32 ? compartment - 1 : compartment - 24);
1773 	assert(index < 16);
1774 
1775 	if (useCompartment1)
1776 		_compartments1[index] |= STORE_VALUE(entity);
1777 	else
1778 		_compartments[index] |= STORE_VALUE(entity);
1779 }
1780 
exitCompartment(EntityIndex entity,ObjectIndex compartment,bool useCompartment1)1781 void Entities::exitCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1) {
1782 	if (entity > kEntityChapters)
1783 		return;
1784 
1785 	// TODO factorize in one line
1786 	switch (compartment) {
1787 	default:
1788 		// Return here so we do not update the compartments
1789 		return;
1790 
1791 	case kObjectCompartment1:
1792 		updatePositionsExit(entity, kCarGreenSleeping, 41, 51);
1793 		break;
1794 
1795 	case kObjectCompartment2:
1796 		updatePositionsExit(entity, kCarGreenSleeping, 42, 52);
1797 		break;
1798 
1799 	case kObjectCompartment3:
1800 		updatePositionsExit(entity, kCarGreenSleeping, 43, 53);
1801 		break;
1802 
1803 	case kObjectCompartment4:
1804 		updatePositionsExit(entity, kCarGreenSleeping, 44, 54);
1805 		break;
1806 
1807 	case kObjectCompartment5:
1808 		updatePositionsExit(entity, kCarGreenSleeping, 45, 55);
1809 		break;
1810 
1811 	case kObjectCompartment6:
1812 		updatePositionsExit(entity, kCarGreenSleeping, 46, 56);
1813 		break;
1814 
1815 	case kObjectCompartment7:
1816 		updatePositionsExit(entity, kCarGreenSleeping, 47, 57);
1817 		break;
1818 
1819 	case kObjectCompartment8:
1820 		updatePositionsExit(entity, kCarGreenSleeping, 48, 58);
1821 		break;
1822 
1823 	case kObjectCompartmentA:
1824 		updatePositionsExit(entity, kCarRedSleeping, 41, 51);
1825 		break;
1826 
1827 	case kObjectCompartmentB:
1828 		updatePositionsExit(entity, kCarRedSleeping, 42, 52);
1829 		break;
1830 
1831 	case kObjectCompartmentC:
1832 		updatePositionsExit(entity, kCarRedSleeping, 43, 53);
1833 		break;
1834 
1835 	case kObjectCompartmentD:
1836 		updatePositionsExit(entity, kCarRedSleeping, 44, 54);
1837 		break;
1838 
1839 	case kObjectCompartmentE:
1840 		updatePositionsExit(entity, kCarRedSleeping, 45, 55);
1841 		break;
1842 
1843 	case kObjectCompartmentF:
1844 		updatePositionsExit(entity, kCarRedSleeping, 46, 56);
1845 		break;
1846 
1847 	case kObjectCompartmentG:
1848 		updatePositionsExit(entity, kCarRedSleeping, 47, 57);
1849 		break;
1850 
1851 	case kObjectCompartmentH:
1852 		updatePositionsExit(entity, kCarRedSleeping, 48, 58);
1853 		break;
1854 	}
1855 
1856 	// Update compartments
1857 	int index = (compartment < 32 ? compartment - 1 : compartment - 24);
1858 	assert(index < 16);
1859 
1860 	if (useCompartment1)
1861 		_compartments1[index] &= ~STORE_VALUE(entity);
1862 	else
1863 		_compartments[index] &= ~STORE_VALUE(entity);
1864 }
1865 
updatePositionEnter(EntityIndex entity,CarIndex car,Position position)1866 void Entities::updatePositionEnter(EntityIndex entity, CarIndex car, Position position) {
1867 	if (entity == kEntity39)
1868 		entity = kEntityPlayer;
1869 
1870 	if (entity > kEntityChapters)
1871 		return;
1872 
1873 	_positions[100 * car + position] |= STORE_VALUE(entity);
1874 
1875 	if (isPlayerPosition(car, position) || (car == kCarRestaurant && position == 57 && isPlayerPosition(kCarRestaurant, 50))) {
1876 		getSound()->excuseMe(entity);
1877 		getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
1878 		getSound()->playSound(kEntityPlayer, "CAT1127A");
1879 	} else {
1880 		getLogic()->updateCursor();
1881 	}
1882 }
1883 
updatePositionExit(EntityIndex entity,CarIndex car,Position position)1884 void Entities::updatePositionExit(EntityIndex entity, CarIndex car, Position position) {
1885 	if (entity == kEntity39)
1886 		entity = kEntityPlayer;
1887 
1888 	if (entity > kEntityChapters)
1889 		return;
1890 
1891 	_positions[100 * car + position] &= ~STORE_VALUE(entity);
1892 
1893 	getLogic()->updateCursor();
1894 }
1895 
updatePositionsEnter(EntityIndex entity,CarIndex car,Position position1,Position position2,Position position3,Position position4)1896 void Entities::updatePositionsEnter(EntityIndex entity, CarIndex car, Position position1, Position position2, Position position3, Position position4) {
1897 	if (entity == kEntity39)
1898 		entity = kEntityPlayer;
1899 
1900 	if (entity > kEntityChapters)
1901 		return;
1902 
1903 	_positions[100 * car + position1] |= STORE_VALUE(entity);
1904 	_positions[100 * car + position2] |= STORE_VALUE(entity);
1905 
1906 	// FIXME: also checking two DWORD values that do not seem to updated anywhere...
1907 	if (isPlayerPosition(car, position1) || isPlayerPosition(car, position2) || isPlayerPosition(car, position3) || isPlayerPosition(car, position4)) {
1908 		getSound()->excuseMe(entity);
1909 		getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
1910 		getSound()->playSound(kEntityPlayer, "CAT1127A");
1911 	} else {
1912 		getLogic()->updateCursor();
1913 	}
1914 }
1915 
updatePositionsExit(EntityIndex entity,CarIndex car,Position position1,Position position2)1916 void Entities::updatePositionsExit(EntityIndex entity, CarIndex car, Position position1, Position position2) {
1917 	if (entity == kEntity39)
1918 		entity = kEntityPlayer;
1919 
1920 	if (entity > kEntityChapters)
1921 		return;
1922 
1923 	_positions[100 * car + position1] &= ~STORE_VALUE(entity);
1924 	_positions[100 * car + position2] &= ~STORE_VALUE(entity);
1925 
1926 	getLogic()->updateCursor();
1927 }
1928 
loadSceneFromEntityPosition(CarIndex car,EntityPosition entityPosition,bool alternate) const1929 void Entities::loadSceneFromEntityPosition(CarIndex car, EntityPosition entityPosition, bool alternate) const {
1930 
1931 	// Determine position
1932 	Position position = (alternate ? 1 : 40);
1933 	do {
1934 		if (alternate ? entityPosition < entityPositions[position] : entityPosition > entityPositions[position]) {
1935 			if (alternate)
1936 				break;
1937 
1938 			// For default value, we ignore position 24
1939 			if (position != 24)
1940 				break;
1941 		}
1942 
1943 		alternate ? ++position : --position;
1944 
1945 	} while (alternate ? position <= 18 : position >= 22);
1946 
1947 	// For position outside bounds, use minimal value
1948 	if ((alternate && position > 18) || (!alternate && position < 22)) {
1949 		getScenes()->loadSceneFromPosition(car, alternate ? 18 : 22);
1950 		return;
1951 	}
1952 
1953 	// Load scene from position
1954 	switch (position) {
1955 	default:
1956 		getScenes()->loadSceneFromPosition(car, (Position)(position + (alternate ? - 1 : 1)));
1957 		break;
1958 
1959 	// Alternate
1960 	case 1:
1961 		if (alternate) getScenes()->loadSceneFromPosition(car, 1);
1962 		break;
1963 
1964 	case 5:
1965 		if (alternate) getScenes()->loadSceneFromPosition(car, 3);
1966 		break;
1967 
1968 	// Default
1969 	case 23:
1970 		if (!alternate) getScenes()->loadSceneFromPosition(car, 25);
1971 		break;
1972 
1973 	case 40:
1974 		if (!alternate) getScenes()->loadSceneFromPosition(car, 40);
1975 		break;
1976 	}
1977 }
1978 
1979 //////////////////////////////////////////////////////////////////////////
1980 //	Checks
1981 //////////////////////////////////////////////////////////////////////////
hasValidFrame(EntityIndex entity) const1982 bool Entities::hasValidFrame(EntityIndex entity) const {
1983 	return (getData(entity)->frame && (getData(entity)->frame->getInfo()->subType != kFrameType3));
1984 }
1985 
compare(EntityIndex entity1,EntityIndex entity2) const1986 bool Entities::compare(EntityIndex entity1, EntityIndex entity2) const {
1987 	EntityData::EntityCallData *data1 = getData(entity1);
1988 	EntityData::EntityCallData *data2 = getData(entity2);
1989 
1990 	if (data2->car != data1->car
1991 	 || data1->car < kCarGreenSleeping
1992 	 || data1->car > kCarRedSleeping)
1993 		return false;
1994 
1995 	EntityPosition position1 = (data1->entityPosition >= data2->entityPosition) ? data1->entityPosition : data2->entityPosition;
1996 	EntityPosition position2 = (data1->entityPosition >= data2->entityPosition) ? data2->entityPosition : data1->entityPosition;
1997 
1998 	// Compute position
1999 	int index1 = 7;
2000 	do {
2001 		if (objectsPosition[index1] >= position2)
2002 			break;
2003 
2004 		--index1;
2005 	} while (index1 > -1);
2006 
2007 	int index2 = 0;
2008 	do {
2009 		if (objectsPosition[index2] <= position2)
2010 			break;
2011 
2012 		++index2;
2013 	} while (index2 < 8);
2014 
2015 	if (index1 > -1 && index2 < 8 && index2 <= index1) {
2016 		while (index2 <= index1) {
2017 			if (getCompartments(index2 + (data1->car == kCarGreenSleeping ? 0 : 8)))
2018 				return true;
2019 
2020 			if (getCompartments1(index2 + (data1->car == kCarGreenSleeping ? 0 : 8)))
2021 				return true;
2022 
2023 			++index2;
2024 		}
2025 	}
2026 
2027 	for (EntityIndex entity = kEntityAnna; entity <= kEntity39; entity = (EntityIndex)(entity + 1)) {
2028 
2029 		if (entity1 == entity || entity2 == entity)
2030 			continue;
2031 
2032 		if (!isDirectionUpOrDown(entity))
2033 			continue;
2034 
2035 		if (data1->car == getEntityData(entity)->car
2036 		 && getEntityData(entity)->entityPosition > position2
2037 		 && getEntityData(entity)->entityPosition < position1)
2038 			return true;
2039 	}
2040 
2041 	return false;
2042 }
2043 
updateEntity(EntityIndex entity,CarIndex car,EntityPosition position) const2044 bool Entities::updateEntity(EntityIndex entity, CarIndex car, EntityPosition position) const {
2045 	EntityData::EntityCallData *data = getData(entity);
2046 	EntityDirection direction = kDirectionNone;
2047 	int delta = 0;
2048 	bool flag1 = false;
2049 	bool flag2 = false;
2050 	bool flag3 = false;
2051 
2052 	if (position == kPosition_2000
2053 	 && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)
2054 	 && !isPlayerPosition(kCarGreenSleeping, 1)
2055 	 && !isPlayerPosition(kCarRedSleeping, 2))
2056 		 position = kPosition_1500;
2057 
2058 	if (data->direction != kDirectionUp && data->direction != kDirectionDown)
2059 		data->field_497 = 0;
2060 
2061 	if (data->field_497) {
2062 		data->field_497--;
2063 
2064 		if (data->field_497 == 128)
2065 			data->field_497 = 0;
2066 
2067 		if ((data->field_497 & 127) != 8) {
2068 			data->field_49B = 0;
2069 			return false;
2070 		}
2071 
2072 		flag1 = true;
2073 
2074 		if (data->field_497 & 128)
2075 			flag2 = true;
2076 	}
2077 
2078 	if (data->car != car)
2079 		goto label_process_entity;
2080 
2081 	// Calculate delta
2082 	delta = ABS(data->entityPosition - position);
2083 	if (delta < 100 || (position > kPosition_850 && position < kPosition_9270 && delta < 300))
2084 		flag3 = true;
2085 
2086 	if (!flag3) {
2087 		if ((getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) && data->direction == kDirectionUp)
2088 		 || (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) && data->direction == kDirectionDown)) {
2089 			 if (!checkPosition(position) && isDistanceBetweenEntities(entity, kEntityPlayer, 250))
2090 				 flag3 = true;
2091 		}
2092 
2093 		if (!flag3)
2094 			goto label_process_entity;
2095 	}
2096 
2097 	if (getEntities()->hasValidFrame(entity)
2098 	 && getEntities()->isWalkingOppositeToPlayer(entity)
2099 	 && !getEntities()->checkPosition(position)) {
2100 		flag3 = false;
2101 		position = (EntityPosition)(getData(kEntityPlayer)->entityPosition + 250 * (data->direction == kDirectionUp ? 1 : -1));
2102 	}
2103 
2104 	if (!flag3) {
2105 label_process_entity:
2106 
2107 		// Calculate direction
2108 		if (data->car < car)
2109 			direction = kDirectionUp;
2110 		else if (data->car > car)
2111 			direction = kDirectionDown;
2112 		else // same car
2113 			direction = (data->entityPosition < position) ? kDirectionUp : kDirectionDown;
2114 
2115 		if (data->direction == direction) {
2116 			if (!flag1) {
2117 
2118 				if (checkDistanceFromPosition(entity, kPosition_1500, 750) && entity != kEntityFrancois) {
2119 
2120 					if (data->entity == kEntityPlayer) {
2121 						if (data->direction != kDirectionUp || (position <= kPosition_2000 && data->car == car)) {
2122 							if (data->direction == kDirectionDown && (position < kPosition_1500 || data->car != car)) {
2123 								if (data->entityPosition > kPosition_1500 && (data->car == kCarGreenSleeping || data->car == kCarRedSleeping)) {
2124 									data->entity = (data->car == kCarGreenSleeping) ? kEntityMertens : kEntityCoudert;
2125 									getSavePoints()->push(entity, data->entity, kAction11);
2126 								}
2127 							}
2128 						} else {
2129 							if (data->entityPosition < kPosition_1500 && (data->car == kCarGreenSleeping || data->car == kCarRedSleeping)) {
2130 								data->entity = (data->car == kCarGreenSleeping) ? kEntityMertens : kEntityCoudert;
2131 								getSavePoints()->push(entity, data->entity, kAction11, 1);
2132 							}
2133 						}
2134 					}
2135 
2136 				} else if (data->entity) {
2137 					getSavePoints()->push(entity, data->entity, kAction16);
2138 					data->entity = kEntityPlayer;
2139 				}
2140 
2141 				if (hasValidFrame(entity)) {
2142 
2143 					if (!data->field_4A9)
2144 						return false;
2145 
2146 					int compartmentIndex = 0;
2147 					if (data->car == kCarGreenSleeping)
2148 						compartmentIndex = 0;
2149 					else if (data->car == kCarRedSleeping)
2150 						compartmentIndex = 8;
2151 
2152 					for (int i = 0; i < 8; i++) {
2153 						if (getCompartments(compartmentIndex) || getCompartments1(compartmentIndex)) {
2154 							if (checkDistanceFromPosition(entity, objectsPosition[i], 750)) {
2155 								if (checkPosition(objectsPosition[i])) {
2156 
2157 									if ((data->direction == kDirectionUp   && data->entityPosition < objectsPosition[i] && (data->car != car || position > objectsPosition[i]))
2158 									 || (data->direction == kDirectionDown && data->entityPosition > objectsPosition[i] && (data->car != car || position < objectsPosition[i]))) {
2159 
2160 										 getSound()->excuseMe(entity, (EntityIndex)(State::getPowerOfTwo((uint32)(getCompartments(compartmentIndex) ? getCompartments(compartmentIndex) : getCompartments1(compartmentIndex)))));
2161 
2162 										 data->field_497 = 144;
2163 
2164 										 break;
2165 									}
2166 								}
2167 							}
2168 						}
2169 
2170 						compartmentIndex++;
2171 					}
2172 
2173 					for (EntityIndex entityIndex = kEntityAnna; entityIndex <= kEntity39; entityIndex = (EntityIndex)(entityIndex + 1)) {
2174 						if (getSavePoints()->getCallback(entityIndex)
2175 						 && hasValidFrame(entityIndex)
2176 						 && entityIndex != entity
2177 						 && isDistanceBetweenEntities(entity, entityIndex, 750)
2178 						 && isDirectionUpOrDown(entityIndex)
2179 						 && (entity != kEntityRebecca || entityIndex != kEntitySophie)
2180 						 && (entity != kEntitySophie || entityIndex != kEntityRebecca)
2181 						 && (entity != kEntityIvo || entityIndex != kEntitySalko)
2182 						 && (entity != kEntitySalko || entityIndex != kEntityIvo)
2183 						 && (entity != kEntityMilos || entityIndex != kEntityVesna)
2184 						 && (entity != kEntityVesna || entityIndex != kEntityMilos)) {
2185 
2186 							 EntityData::EntityCallData *data2 = getData(entityIndex);
2187 
2188 							 if (data->direction != data2->direction) {
2189 
2190 								 if ((data->direction != kDirectionUp || data2->entityPosition <= data->entityPosition)
2191 								  && (data->direction != kDirectionDown || data2->entityPosition >= data->entityPosition))
2192 									continue;
2193 
2194 								 data->field_49B = 0;
2195 								 data2->field_49B = 0;
2196 
2197 								 data->field_497 = 16;
2198 								 data2->field_497 = 16;
2199 
2200 								 getSound()->excuseMe(entity, entityIndex);
2201 								 getSound()->excuseMe(entityIndex, entity);
2202 
2203 								 if (entityIndex > entity)
2204 									 ++data2->field_497;
2205 
2206 								 break;
2207 							 }
2208 
2209 							 if (ABS(data2->entityPosition - getData(kEntityPlayer)->entityPosition) < ABS(data->entityPosition - getData(kEntityPlayer)->entityPosition)) {
2210 
2211 								 if (!isWalkingOppositeToPlayer(entity)) {
2212 
2213 									 if (direction == kDirectionUp) {
2214 										 if (data->entityPosition < kPosition_9500)
2215 											 data->entityPosition = (EntityPosition)(data->entityPosition + 500);
2216 									 } else {
2217 										 if (data->entityPosition > kPosition_500)
2218 											 data->entityPosition = (EntityPosition)(data->entityPosition - 500);
2219 									 }
2220 
2221 									 drawSequences(entity, direction, true);
2222 
2223 									 return false;
2224 								 }
2225 								 data->field_49B = 0;
2226 
2227 								 break;
2228 							 }
2229 						}
2230 					}
2231 
2232 					return false;
2233 				}
2234 
2235 				if (data->direction == kDirectionUp) {
2236 					if (data->entityPosition + data->field_4A3 < 10000)
2237 						data->entityPosition = (EntityPosition)(data->entityPosition + data->field_4A3);
2238 				} else {
2239 					if (data->entityPosition > data->field_4A3)
2240 						data->entityPosition = (EntityPosition)(data->entityPosition - data->field_4A3);
2241 				}
2242 
2243 				if (data->entityPosition <= kPosition_9270 || data->direction != kDirectionUp) {
2244 					if (data->entityPosition < kPosition_850 && data->direction == kDirectionDown) {
2245 						if (changeCar(data, entity, car, position, false, kPosition_9269, kCarKronos))
2246 							return true;
2247 					}
2248 				} else {
2249 					if (changeCar(data, entity, car, position, true, kPosition_851, kCarGreenSleeping))
2250 						return true;
2251 				}
2252 
2253 				if (getData(kEntityPlayer)->car == data->car && data->location == kLocationOutsideCompartment) {
2254 					if (data->direction == kDirectionUp) {
2255 
2256 						if (getData(kEntityPlayer)->entityPosition > data->entityPosition
2257 						 && getData(kEntityPlayer)->entityPosition - data->entityPosition >= 500
2258 						 && data->field_4A3 + 500 > getData(kEntityPlayer)->entityPosition - data->entityPosition) {
2259 
2260 							 if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) || getScenes()->checkCurrentPosition(false)) {
2261 								 getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
2262 
2263 								 if (getScenes()->checkCurrentPosition(false))
2264 									 getScenes()->loadSceneFromObject((ObjectIndex)getScenes()->get(getState()->scene)->param1, true);
2265 
2266 							 } else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown)) {
2267 								 getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
2268 							 }
2269 						}
2270 					} else {
2271 						if (getData(kEntityPlayer)->entityPosition < data->entityPosition
2272 						 && data->entityPosition - getData(kEntityPlayer)->entityPosition >= 500
2273 						 && data->field_4A3 + 500 > data->entityPosition - getData(kEntityPlayer)->entityPosition) {
2274 
2275 							if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)) {
2276 								 getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
2277 							} else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)) {
2278 								 getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
2279 
2280 								 if (getScenes()->checkCurrentPosition(false))
2281 									 getScenes()->loadSceneFromObject((ObjectIndex)getScenes()->get(getState()->scene)->param1);
2282 							}
2283 						}
2284 					}
2285 				}
2286 				return false;
2287 			}
2288 		} else if (!flag1) {
2289 			drawSequences(entity, direction, true);
2290 			return false;
2291 		}
2292 
2293 		//////////////////////////////////////////////////////////////////////////
2294 		// Adjust positions
2295 
2296 		// Direction Up
2297 		if (direction == kDirectionUp) {
2298 			if (data->entityPosition < (flag2 ? kPosition_8800 : kPosition_9250))
2299 				data->entityPosition = (EntityPosition)(data->entityPosition + (flag2 ? kPosition_1200 : kPosition_750));
2300 
2301 			if (data->car == car && data->entityPosition >= position) {
2302 				data->entityPosition = position;
2303 				data->direction = kDirectionNone;
2304 				data->entity = kEntityPlayer;
2305 				return true;
2306 			}
2307 
2308 			drawSequences(entity, direction, true);
2309 			return false;
2310 		}
2311 
2312 		// Direction Down
2313 		if (data->entityPosition > (flag2 ? kPosition_1200 : kPosition_750))
2314 			data->entityPosition = (EntityPosition)(data->entityPosition - (flag2 ? kPosition_1200 : kPosition_750));
2315 
2316 		if (data->car == car && data->entityPosition <= position) {
2317 			data->entityPosition = position;
2318 			data->direction = kDirectionNone;
2319 			data->entity = kEntityPlayer;
2320 			return true;
2321 		}
2322 
2323 		drawSequences(entity, direction, true);
2324 		return false;
2325 	}
2326 
2327 	data->entityPosition = position;
2328 	if (data->direction == kDirectionUp || data->direction == kDirectionDown)
2329 		data->direction = kDirectionNone;
2330 	data->entity = kEntityPlayer;
2331 
2332 	return true;
2333 }
2334 
changeCar(EntityData::EntityCallData * data,EntityIndex entity,CarIndex car,EntityPosition position,bool increment,EntityPosition newPosition,CarIndex newCar) const2335 bool Entities::changeCar(EntityData::EntityCallData *data, EntityIndex entity, CarIndex car, EntityPosition position, bool increment, EntityPosition newPosition, CarIndex newCar) const {
2336 	if (getData(kEntityPlayer)->car == data->car) {
2337 		getSound()->playSoundEvent(entity, 36);
2338 		getSound()->playSoundEvent(entity, 37, 30);
2339 	}
2340 
2341 	data->car = (CarIndex)(increment ? data->car + 1 : data->car - 1);
2342 	data->entityPosition = newPosition;
2343 
2344 	if (data->car == newCar) {
2345 		if (isInGreenCarEntrance(kEntityPlayer)) {
2346 			getSound()->playSoundEvent(kEntityPlayer, 14);
2347 			getSound()->excuseMe(entity, kEntityPlayer, kVolumeFull);
2348 			getScenes()->loadSceneFromPosition(kCarGreenSleeping, 1);
2349 			getSound()->playSound(kEntityPlayer, "CAT1127A");
2350 			getSound()->playSoundEvent(kEntityPlayer, 15);
2351 		}
2352 	}
2353 
2354 	if ((increment ? data->car > car : data->car < car) || (data->car == car && (increment ? data->entityPosition >= position : data->entityPosition <= position))) {
2355 		data->car = car;
2356 		data->entityPosition = position;
2357 		data->direction = kDirectionNone;
2358 		data->entity = kEntityPlayer;
2359 
2360 		return true;
2361 	}
2362 
2363 	if (data->car == newCar) {
2364 		if (isInKronosCarEntrance(kEntityPlayer)) {
2365 			getSound()->playSoundEvent(kEntityPlayer, 14);
2366 			getSound()->excuseMe(entity, kEntityPlayer, kVolumeFull);
2367 			getScenes()->loadSceneFromPosition(kCarGreenSleeping, 62);
2368 			getSound()->playSound(kEntityPlayer, "CAT1127A");
2369 			getSound()->playSoundEvent(kEntityPlayer, 15);
2370 		}
2371 	}
2372 
2373 	if (data->car == getData(kEntityPlayer)->car) {
2374 		getSound()->playSoundEvent(entity, 36);
2375 		getSound()->playSoundEvent(entity, 37, 30);
2376 	}
2377 
2378 	return false;
2379 }
2380 
2381 //////////////////////////////////////////////////////////////////////////
2382 // CHECKS
2383 //////////////////////////////////////////////////////////////////////////
isInsideCompartment(EntityIndex entity,CarIndex car,EntityPosition position) const2384 bool Entities::isInsideCompartment(EntityIndex entity, CarIndex car, EntityPosition position) const {
2385 	return (getData(entity)->entityPosition == position
2386 		 && getData(entity)->location == kLocationInsideCompartment
2387 		 && getData(entity)->car == car);
2388 }
2389 
checkFields2(ObjectIndex object) const2390 bool Entities::checkFields2(ObjectIndex object) const {
2391 
2392 	EntityPosition position = kPositionNone;
2393 	CarIndex car = kCarNone;
2394 
2395 	switch (object) {
2396 	default:
2397 		return false;
2398 
2399 	case kObjectCompartment1:
2400 	case kObjectCompartment2:
2401 	case kObjectCompartment3:
2402 	case kObjectCompartment4:
2403 	case kObjectCompartment5:
2404 	case kObjectCompartment6:
2405 	case kObjectCompartment7:
2406 	case kObjectCompartment8:
2407 		position = objectsPosition[object - 1];
2408 		car = kCarGreenSleeping;
2409 		if (isInsideCompartment(kEntityPlayer, car, position))
2410 			return false;
2411 		break;
2412 
2413 	case kObjectHandleBathroom:
2414 	case kObjectHandleInsideBathroom:
2415 	case kObjectKitchen:
2416 	case kObject20:
2417 	case kObject21:
2418 	case kObject22:
2419 		position = objectsPosition[object-17];
2420 		car = kCarGreenSleeping;
2421 		break;
2422 
2423 	case kObjectCompartmentA:
2424 	case kObjectCompartmentB:
2425 	case kObjectCompartmentC:
2426 	case kObjectCompartmentD:
2427 	case kObjectCompartmentE:
2428 	case kObjectCompartmentF:
2429 	case kObjectCompartmentG:
2430 	case kObjectCompartmentH:
2431 		position = objectsPosition[object-32];
2432 		car = kCarRedSleeping;
2433 		if (isInsideCompartment(kEntityPlayer, car, position))
2434 			return false;
2435 		break;
2436 
2437 	case kObject48:
2438 	case kObject49:
2439 	case kObject50:
2440 	case kObject51:
2441 	case kObject52:
2442 	case kObject53:
2443 		position = objectsPosition[object-48];
2444 		car = kCarRedSleeping;
2445 		break;
2446 
2447 	}
2448 
2449 	uint index = 1;
2450 	while (!isInsideCompartment((EntityIndex)index, car, position) || index == kEntityVassili) {
2451 		index++;
2452 		if (index >= 40)
2453 			return false;
2454 	}
2455 
2456 	return true;
2457 }
2458 
isInsideCompartments(EntityIndex entity) const2459 bool Entities::isInsideCompartments(EntityIndex entity) const {
2460 	return (getData(entity)->car == kCarGreenSleeping
2461 		 || getData(entity)->car == kCarRedSleeping)
2462 		 && getData(entity)->location == kLocationInsideCompartment;
2463 }
2464 
isPlayerPosition(CarIndex car,Position position) const2465 bool Entities::isPlayerPosition(CarIndex car, Position position) const {
2466 	return getData(kEntityPlayer)->car == car && getScenes()->get(getState()->scene)->position == position;
2467 }
2468 
isInsideTrainCar(EntityIndex entity,CarIndex car) const2469 bool Entities::isInsideTrainCar(EntityIndex entity, CarIndex car) const {
2470 	return getData(entity)->car == car && getData(entity)->location <= kLocationInsideCompartment;
2471 }
2472 
isInGreenCarEntrance(EntityIndex entity) const2473 bool Entities::isInGreenCarEntrance(EntityIndex entity) const {
2474 	return isInsideTrainCar(entity, kCarGreenSleeping) && getData(entity)->entityPosition < kPosition_850;
2475 }
2476 
isPlayerInCar(CarIndex car) const2477 bool Entities::isPlayerInCar(CarIndex car) const {
2478 	return isInsideTrainCar(kEntityPlayer, car) && getData(kEntityPlayer)->location && !isInGreenCarEntrance(kEntityPlayer);
2479 }
2480 
isDirectionUpOrDown(EntityIndex entity) const2481 bool Entities::isDirectionUpOrDown(EntityIndex entity) const {
2482 	return getData(entity)->direction == kDirectionUp || getData(entity)->direction == kDirectionDown;
2483 }
2484 
isDistanceBetweenEntities(EntityIndex entity1,EntityIndex entity2,uint distance) const2485 bool Entities::isDistanceBetweenEntities(EntityIndex entity1, EntityIndex entity2, uint distance) const {
2486 	return getData(entity1)->car == getData(entity2)->car
2487 	    && (uint)ABS(getData(entity1)->entityPosition - getData(entity2)->entityPosition) <= distance
2488 		&& (getData(entity1)->location != kLocationOutsideTrain || getData(entity2)->location != kLocationOutsideTrain);
2489 }
2490 
checkFields10(EntityIndex entity) const2491 bool Entities::checkFields10(EntityIndex entity) const {
2492 	return getData(entity)->location <= kLocationOutsideTrain;
2493 }
2494 
isSomebodyInsideRestaurantOrSalon() const2495 bool Entities::isSomebodyInsideRestaurantOrSalon() const {
2496 	for (uint i = 1; i < _entities.size(); i++) {
2497 		EntityIndex index = (EntityIndex)i;
2498 
2499 		if (getData(index)->location == kLocationOutsideCompartment && (isInSalon(index) || isInRestaurant(index)))
2500 			return false;
2501 	}
2502 
2503 	return true;
2504 }
2505 
isInSalon(EntityIndex entity) const2506 bool Entities::isInSalon(EntityIndex entity) const {
2507 	return isInsideTrainCar(entity, kCarRestaurant)
2508 		&& getData(entity)->entityPosition >= kPosition_1540
2509 		&& getData(entity)->entityPosition <= kPosition_3650;
2510 }
2511 
isInRestaurant(EntityIndex entity) const2512 bool Entities::isInRestaurant(EntityIndex entity) const {
2513 	return isInsideTrainCar(entity, kCarRestaurant)
2514 		&& getData(entity)->entityPosition >= kPosition_3650
2515 		&& getData(entity)->entityPosition <= kPosition_5800;
2516 }
2517 
isInKronosSalon(EntityIndex entity) const2518 bool Entities::isInKronosSalon(EntityIndex entity) const {
2519 	return isInsideTrainCar(entity, kCarKronos)
2520 		&& getData(entity)->entityPosition >= kPosition_5500
2521 		&& getData(entity)->entityPosition <= kPosition_7500;
2522 }
2523 
isOutsideAlexeiWindow() const2524 bool Entities::isOutsideAlexeiWindow() const {
2525 	return (getData(kEntityPlayer)->entityPosition == kPosition_7500 || getData(kEntityPlayer)->entityPosition == kPosition_8200)
2526 		 && getData(kEntityPlayer)->location == kLocationOutsideTrain
2527 		 && getData(kEntityPlayer)->car == kCarGreenSleeping;
2528 }
2529 
isOutsideAnnaWindow() const2530 bool Entities::isOutsideAnnaWindow() const {
2531 	return (getData(kEntityPlayer)->entityPosition == kPosition_4070 || getData(kEntityPlayer)->entityPosition == kPosition_4840)
2532 		 && getData(kEntityPlayer)->location == kLocationOutsideTrain
2533 		 && getData(kEntityPlayer)->car == kCarRedSleeping;
2534 }
2535 
isInKitchen(EntityIndex entity) const2536 bool Entities::isInKitchen(EntityIndex entity) const {
2537 	return isInsideTrainCar(entity, kCarRestaurant) && getData(entity)->entityPosition > kPosition_5800;
2538 }
2539 
isNobodyInCompartment(CarIndex car,EntityPosition position) const2540 bool Entities::isNobodyInCompartment(CarIndex car, EntityPosition position) const {
2541 	for (uint i = 1; i < _entities.size(); i++) {
2542 		if (isInsideCompartment((EntityIndex)i, car, position))
2543 			return false;
2544 	}
2545 	return true;
2546 }
2547 
checkFields19(EntityIndex entity,CarIndex car,EntityPosition position) const2548 bool Entities::checkFields19(EntityIndex entity, CarIndex car, EntityPosition position) const {
2549 
2550 	if (getData(entity)->car != car ||  getData(entity)->location != kLocationInsideCompartment)
2551 		return false;
2552 
2553 	EntityPosition entityPosition = getData(entity)->entityPosition;
2554 
2555 	// Test values
2556 	if (position == kPosition_4455) {
2557 		if (entityPosition == kPosition_4070 || entityPosition == kPosition_4455 || entityPosition == kPosition_4840)
2558 			return true;
2559 
2560 		return false;
2561 	}
2562 
2563 	if (position == kPosition_6130) {
2564 		if (entityPosition == kPosition_5790 || entityPosition == kPosition_6130 || entityPosition == kPosition_6470)
2565 			return true;
2566 
2567 		return false;
2568 	}
2569 
2570 	if (position != kPosition_7850
2571 	 || (entityPosition != kPosition_7500 && entityPosition != kPosition_7850 && entityPosition != kPosition_8200))
2572 		return false;
2573 
2574 	return true;
2575 }
2576 
isInBaggageCarEntrance(EntityIndex entity) const2577 bool Entities::isInBaggageCarEntrance(EntityIndex entity) const {
2578 	return isInsideTrainCar(entity, kCarBaggage)
2579 		&& getData(entity)->entityPosition >= kPosition_4500
2580 		&& getData(entity)->entityPosition <= kPosition_5500;
2581 }
2582 
isInBaggageCar(EntityIndex entity) const2583 bool Entities::isInBaggageCar(EntityIndex entity) const {
2584 	return isInsideTrainCar(entity, kCarBaggage) && getData(entity)->entityPosition < kPosition_4500;
2585 }
2586 
isInKronosSanctum(EntityIndex entity) const2587 bool Entities::isInKronosSanctum(EntityIndex entity) const {
2588 	return isInsideTrainCar(entity, kCarKronos)
2589 		&& getData(entity)->entityPosition >= kPosition_3500
2590 		&& getData(entity)->entityPosition <= kPosition_5500;
2591 }
2592 
isInKronosCarEntrance(EntityIndex entity) const2593 bool Entities::isInKronosCarEntrance(EntityIndex entity) const {
2594 	return isInsideTrainCar(entity, kCarKronos) && getData(entity)->entityPosition > kPosition_7900;
2595 }
2596 
checkDistanceFromPosition(EntityIndex entity,EntityPosition position,int distance) const2597 bool Entities::checkDistanceFromPosition(EntityIndex entity, EntityPosition position, int distance) const {
2598 	return distance >= ABS(getData(entity)->entityPosition - position);
2599 }
2600 
isWalkingOppositeToPlayer(EntityIndex entity) const2601 bool Entities::isWalkingOppositeToPlayer(EntityIndex entity) const {
2602 	if (getData(entity)->direction == kDirectionUp && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
2603 		return true;
2604 
2605 	return (getData(entity)->direction == kDirectionDown && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp));
2606 }
2607 
isFemale(EntityIndex entity)2608 bool Entities::isFemale(EntityIndex entity) {
2609 	return (entity == kEntityAnna
2610 		 || entity == kEntityTatiana
2611 		 || entity == kEntityVesna
2612 		 || entity == kEntityKahina
2613 		 || entity == kEntityMmeBoutarel
2614 		 || entity == kEntityRebecca
2615 		 || entity == kEntitySophie
2616 		 || entity == kEntityYasmin
2617 		 || entity == kEntityHadija
2618 		 || entity == kEntityAlouan);
2619 }
2620 
isMarried(EntityIndex entity)2621 bool Entities::isMarried(EntityIndex entity) {
2622 	return (entity != kEntityTatiana
2623 		 && entity != kEntityRebecca
2624 		 && entity != kEntitySophie);
2625 }
2626 
checkPosition(EntityPosition position) const2627 bool Entities::checkPosition(EntityPosition position) const {
2628 	Position position1 = 0;
2629 	Position position2 = 0;
2630 
2631 	switch (position) {
2632 	default:
2633 		return true;
2634 
2635 	case kPosition_1500:
2636 		position1 = 1;
2637 		position2 = 23;
2638 		break;
2639 
2640 	case kPosition_2740:
2641 		position1 = 3;
2642 		position2 = 25;
2643 		break;
2644 
2645 	case kPosition_3050:
2646 		position1 = 5;
2647 		position2 = 26;
2648 		break;
2649 
2650 	case kPosition_4070:
2651 		position1 = 7;
2652 		position2 = 28;
2653 		break;
2654 
2655 	case kPosition_4840:
2656 		position1 = 9;
2657 		position2 = 30;
2658 		break;
2659 
2660 	case kPosition_5790:
2661 		position1 = 11;
2662 		position2 = 32;
2663 		break;
2664 
2665 	case kPosition_6470:
2666 		position1 = 13;
2667 		position2 = 34;
2668 		break;
2669 
2670 	case kPosition_7500:
2671 		position1 = 15;
2672 		position2 = 36;
2673 		break;
2674 
2675 	case kPosition_8200:
2676 		position1 = 17;
2677 		position2 = 38;
2678 		break;
2679 	}
2680 
2681 	if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) && entityPositions[position1] >= getEntityData(kEntityPlayer)->entityPosition)
2682 		return true;
2683 	else
2684 		return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) && entityPositions[position2] <= getEntityData(kEntityPlayer)->entityPosition);
2685 }
2686 
checkSequenceFromPosition(EntityIndex entity) const2687 bool Entities::checkSequenceFromPosition(EntityIndex entity) const {
2688 	FrameInfo *info = getEntityData(entity)->sequence->getFrameInfo((uint16)getEntityData(entity)->currentFrame);
2689 
2690 	if (getEntityData(entity)->direction == kDirectionUp)
2691 		return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)
2692 			 && info->entityPosition + getEntityPositionFromCurrentPosition() > kPosition_8513);
2693 
2694 	if (getEntityData(entity)->direction == kDirectionDown)
2695 		return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown)
2696 			 && info->entityPosition + getEntityPositionFromCurrentPosition() < kPosition_2087);
2697 
2698 	return false;
2699 }
2700 
getEntityPositionFromCurrentPosition() const2701 EntityPosition Entities::getEntityPositionFromCurrentPosition() const {
2702 	// Get the scene position first
2703 	Position position = getScenes()->get(getState()->scene)->position;
2704 
2705 	if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp))
2706 		return (EntityPosition)(entityPositions[position] - kPosition_1430);
2707 
2708 	if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
2709 		return (EntityPosition)(entityPositions[position] - kPosition_9020);
2710 
2711 	return kPositionNone;
2712 }
2713 
clearEntitySequenceData(EntityData::EntityCallData * data,EntityDirection direction) const2714 void Entities::clearEntitySequenceData(EntityData::EntityCallData *data, EntityDirection direction) const {
2715 	getScenes()->removeAndRedraw(&data->frame, false);
2716 	getScenes()->removeAndRedraw(&data->frame1, false);
2717 
2718 	SAFE_DELETE(data->sequence);
2719 	SAFE_DELETE(data->sequence2);
2720 
2721 	data->sequenceName = "";
2722 	data->sequenceName2 = "";
2723 
2724 	data->field_4A9 = false;
2725 	data->field_4AA = false;
2726 	data->directionSwitch = kDirectionNone;
2727 
2728 	data->currentFrame = -1;
2729 	data->currentFrame2 = 0;
2730 
2731 	data->direction = direction;
2732 }
2733 
2734 } // End of namespace LastExpress
2735