1
/* ScummVM - Graphic Adventure Engine
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.
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.
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.
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.
26
#include "lastexpress/game/entities.h"
29
#include "lastexpress/data/scene.h"
30
#include "lastexpress/data/sequence.h"
33
#include "lastexpress/entities/entity.h"
35
#include "lastexpress/entities/abbot.h"
36
#include "lastexpress/entities/alexei.h"
37
#include "lastexpress/entities/alouan.h"
38
#include "lastexpress/entities/anna.h"
39
#include "lastexpress/entities/august.h"
40
#include "lastexpress/entities/boutarel.h"
41
#include "lastexpress/entities/chapters.h"
42
#include "lastexpress/entities/cooks.h"
43
#include "lastexpress/entities/coudert.h"
44
#include "lastexpress/entities/entity39.h"
45
#include "lastexpress/entities/francois.h"
46
#include "lastexpress/entities/gendarmes.h"
47
#include "lastexpress/entities/hadija.h"
48
#include "lastexpress/entities/ivo.h"
49
#include "lastexpress/entities/kahina.h"
50
#include "lastexpress/entities/kronos.h"
51
#include "lastexpress/entities/mahmud.h"
52
#include "lastexpress/entities/max.h"
53
#include "lastexpress/entities/mertens.h"
54
#include "lastexpress/entities/milos.h"
55
#include "lastexpress/entities/mmeboutarel.h"
56
#include "lastexpress/entities/pascale.h"
57
#include "lastexpress/entities/rebecca.h"
58
#include "lastexpress/entities/salko.h"
59
#include "lastexpress/entities/servers0.h"
60
#include "lastexpress/entities/servers1.h"
61
#include "lastexpress/entities/sophie.h"
62
#include "lastexpress/entities/tables.h"
63
#include "lastexpress/entities/tatiana.h"
64
#include "lastexpress/entities/train.h"
65
#include "lastexpress/entities/vassili.h"
66
#include "lastexpress/entities/verges.h"
67
#include "lastexpress/entities/vesna.h"
68
#include "lastexpress/entities/yasmin.h"
71
#include "lastexpress/game/logic.h"
72
#include "lastexpress/game/savepoint.h"
73
#include "lastexpress/game/scenes.h"
74
#include "lastexpress/game/sound.h"
75
#include "lastexpress/game/state.h"
77
#include "lastexpress/graphics.h"
78
#include "lastexpress/helpers.h"
79
#include "lastexpress/lastexpress.h"
80
#include "lastexpress/resource.h"
82
namespace LastExpress {
84
#define STORE_VALUE(data) ((uint)1 << (uint)data)
86
static const EntityPosition objectsPosition[8] = {kPosition_8200, kPosition_7500,
87
kPosition_6470, kPosition_5790,
88
kPosition_4840, kPosition_4070,
89
kPosition_3050, kPosition_2740};
91
static const EntityPosition entityPositions[41] = {
92
kPositionNone, kPosition_851, kPosition_1430, kPosition_2110, kPositionNone,
93
kPosition_2410, kPosition_2980, kPosition_3450, kPosition_3760, kPosition_4100,
94
kPosition_4680, kPosition_5140, kPosition_5440, kPosition_5810, kPosition_6410,
95
kPosition_6850, kPosition_7160, kPosition_7510, kPosition_8514, kPositionNone,
96
kPositionNone, kPositionNone, kPosition_2086, kPosition_2690, kPositionNone,
97
kPosition_3110, kPosition_3390, kPosition_3890, kPosition_4460, kPosition_4770,
98
kPosition_5090, kPosition_5610, kPosition_6160, kPosition_6460, kPosition_6800,
99
kPosition_7320, kPosition_7870, kPosition_8160, kPosition_8500, kPosition_9020,
102
#define ADD_ENTITY(class) \
103
_entities.push_back(new class(engine));
105
#define COMPUTE_SEQUENCE_NAME(sequenceTo, sequenceFrom) { \
106
sequenceTo = sequenceFrom; \
107
for (int seqIdx = 0; seqIdx < 7; seqIdx++) \
108
sequenceTo.deleteLastChar(); \
109
if (isInsideTrainCar(entityIndex, kCarGreenSleeping) || isInsideTrainCar(entityIndex, kCarGreenSleeping)) { \
110
if (data->car < getData(kEntityPlayer)->car || (data->car == getData(kEntityPlayer)->car && data->entityPosition < getData(kEntityPlayer)->entityPosition)) \
111
sequenceTo += "R.SEQ"; \
113
sequenceTo += "F.SEQ"; \
115
sequenceTo += ".SEQ"; \
119
#define TRY_LOAD_SEQUENCE(sequence, name, name1, name2) { \
120
if (data->car == getData(kEntityPlayer)->car) \
121
sequence = loadSequence1(name1, field30); \
126
sequence = loadSequence1(name2, field30); \
127
name = (sequence ? name2 : ""); \
131
//////////////////////////////////////////////////////////////////////////
133
//////////////////////////////////////////////////////////////////////////
134
Entities::Entities(LastExpressEngine *engine) : _engine(engine) {
135
_header = new EntityData();
137
_entities.push_back(NULL); // Header
143
ADD_ENTITY(Servers0);
144
ADD_ENTITY(Servers1);
157
ADD_ENTITY(Francois);
158
ADD_ENTITY(MmeBoutarel);
159
ADD_ENTITY(Boutarel);
166
ADD_ENTITY(Gendarmes);
168
ADD_ENTITY(Chapters);
171
// Special case for tables
172
_entities.push_back(new Tables(engine, kEntityTables0));
173
_entities.push_back(new Tables(engine, kEntityTables1));
174
_entities.push_back(new Tables(engine, kEntityTables2));
175
_entities.push_back(new Tables(engine, kEntityTables3));
176
_entities.push_back(new Tables(engine, kEntityTables4));
177
_entities.push_back(new Tables(engine, kEntityTables5));
179
ADD_ENTITY(Entity39);
181
// Init compartments & positions
182
memset(&_compartments, 0, sizeof(_compartments));
183
memset(&_compartments1, 0, sizeof(_compartments1));
184
memset(&_positions, 0, sizeof(_positions));
187
Entities::~Entities() {
188
SAFE_DELETE(_header);
190
for (int i = 0; i < (int)_entities.size(); i++)
191
SAFE_DELETE(_entities[i]);
195
// Zero passed pointers
199
//////////////////////////////////////////////////////////////////////////
201
//////////////////////////////////////////////////////////////////////////
202
Entity *Entities::get(EntityIndex entity) {
203
assert((uint)entity < _entities.size());
205
if (entity == kEntityPlayer)
206
error("Cannot get entity for index == 0!");
208
return _entities[entity];
211
EntityData::EntityCallData *Entities::getData(EntityIndex entity) const {
212
assert((uint)entity < _entities.size());
214
if (entity == kEntityPlayer)
215
return _header->getCallData();
217
return _entities[entity]->getData();
220
int Entities::getPosition(CarIndex car, Position position) const {
221
int index = 100 * car + position;
224
error("Entities::getPosition: trying to access an invalid car (was: %d, valid:0-9)", car);
227
error("Entities::getPosition: trying to access an invalid position (was: %d, valid:0-100)", position);
229
return _positions[index];
232
int Entities::getCompartments(int index) const {
233
if (index >= _compartmentsCount)
234
error("Entities::getCompartments: trying to access an invalid compartment (was: %d, valid:0-15)", index);
236
return _compartments[index];
239
int Entities::getCompartments1(int index) const {
240
if (index >= _compartmentsCount)
241
error("Entities::getCompartments: trying to access an invalid compartment (was: %d, valid:0-15)", index);
243
return _compartments1[index];
246
//////////////////////////////////////////////////////////////////////////
248
//////////////////////////////////////////////////////////////////////////
249
void Entities::saveLoadWithSerializer(Common::Serializer &s) {
250
_header->saveLoadWithSerializer(s);
251
for (uint i = 1; i < _entities.size(); i++)
252
_entities[i]->saveLoadWithSerializer(s);
255
void Entities::savePositions(Common::Serializer &s) {
256
for (uint i = 0; i < (uint)_positionsCount; i++)
257
s.syncAsUint32LE(_positions[i]);
260
void Entities::saveCompartments(Common::Serializer &s) {
261
for (uint i = 0; i < (uint)_compartmentsCount; i++)
262
s.syncAsUint32LE(_compartments[i]);
264
for (uint i = 0; i < (uint)_compartmentsCount; i++)
265
s.syncAsUint32LE(_compartments1[i]);
268
//////////////////////////////////////////////////////////////////////////
270
//////////////////////////////////////////////////////////////////////////
271
void Entities::setup(bool isFirstChapter, EntityIndex entityIndex) {
272
setupChapter(isFirstChapter ? kChapter1 : kChapterAll);
276
if (!isFirstChapter) {
277
getFlags()->flag_4 = false;
280
getSavePoints()->call(kEntityPlayer, entityIndex, kActionNone);
281
flag_4 = getFlags()->flag_4;
285
getFlags()->flag_4 = flag_4;
286
if (!getFlags()->flag_4)
287
getScenes()->loadScene(getState()->scene);
290
void Entities::setupChapter(ChapterIndex chapter) {
292
// Reset current call, inventory item & draw sequences
293
for (uint i = 1; i < _entities.size(); i++) {
294
getData((EntityIndex)i)->currentCall = 0;
295
getData((EntityIndex)i)->inventoryItem = kItemNone;
297
clearSequences((EntityIndex)i);
300
// Init compartments & positions
301
memset(&_compartments, 0, sizeof(_compartments));
302
memset(&_compartments1, 0, sizeof(_compartments1));
303
memset(&_positions, 0, sizeof(_positions));
305
getSound()->resetQueue(SoundManager::kSoundType13);
308
// we skip the header when doing entity setup
309
for (uint i = 1; i < _entities.size(); i++) {
310
// Special case of chapters (prevents infinite loop as we will be called from Chapters functions when changing chapters)
311
if (i == kEntityChapters && chapter >= 2)
314
_entities[i]->setup(chapter);
318
void Entities::reset() {
321
_header = new EntityData();
323
for (uint i = 1; i < _entities.size(); i++)
324
resetSequences((EntityIndex)i);
326
getScenes()->resetDoorsAndClock();
329
//////////////////////////////////////////////////////////////////////////
331
//////////////////////////////////////////////////////////////////////////
333
EntityIndex Entities::canInteractWith(const Common::Point &point) const {
334
if (!getFlags()->isGameRunning)
335
return kEntityPlayer;
337
EntityIndex index = kEntityPlayer;
338
int location = 10000;
340
// Check if there is an entity we can interact with
341
for (uint i = 0; i < _entities.size(); i++) {
343
// Skip entities with no current frame
344
if (!getData((EntityIndex)i)->frame)
347
FrameInfo *info = getData((EntityIndex)i)->frame->getInfo();
350
if (info->hotspot.contains(point)) {
352
// If closer to us, update with its values
353
if (location > info->location) {
354
location = info->location;
355
index = (EntityIndex)i;
360
// Check if we found an entity
362
return kEntityPlayer;
364
// Check that there is an item to interact with
365
if (!getData(index)->inventoryItem)
366
return kEntityPlayer;
371
void Entities::resetState(EntityIndex entityIndex) {
372
getData(entityIndex)->currentCall = 0;
373
getData(entityIndex)->inventoryItem = kItemNone;
375
if (getSound()->isBuffered(entityIndex))
376
getSound()->removeFromQueue(entityIndex);
378
clearSequences(entityIndex);
380
if (entityIndex == kEntity39)
381
entityIndex = kEntityPlayer;
383
if (entityIndex > kEntityChapters)
386
// reset compartments and positions for this entity
387
for (int i = 0; i < _positionsCount; i++)
388
_positions[i] &= ~STORE_VALUE(entityIndex);
390
for (int i = 0; i < _compartmentsCount; i++) {
391
_compartments[i] &= ~STORE_VALUE(entityIndex);
392
_compartments1[i] &= ~STORE_VALUE(entityIndex);
395
getLogic()->updateCursor();
399
void Entities::updateFields() const {
400
if (!getFlags()->isGameRunning)
403
for (int i = 0; i < (int)_entities.size(); i++) {
405
if (!getSavePoints()->getCallback((EntityIndex)i))
408
EntityData::EntityCallData *data = getData((EntityIndex)i);
409
int positionDelta = data->field_4A3 * 10;
410
switch (data->direction) {
415
if (data->entityPosition >= 10000 - positionDelta)
416
data->entityPosition = (EntityPosition)(data->entityPosition + positionDelta);
420
if (data->entityPosition > positionDelta)
421
data->entityPosition = (EntityPosition)(data->entityPosition - positionDelta);
425
data->currentFrame++;
428
case kDirectionRight:
429
data->field_4A1 += 9;
432
case kDirectionSwitch:
433
if (data->directionSwitch == kDirectionRight)
434
data->field_4A1 += 9;
441
void Entities::updateFrame(EntityIndex entityIndex) const {
442
Sequence *sequence = NULL;
443
int16 *currentFrame = NULL;
446
if (getData(entityIndex)->direction == kDirectionSwitch) {
447
sequence = getData(entityIndex)->sequence2;
448
currentFrame = &getData(entityIndex)->currentFrame2;
450
sequence = getData(entityIndex)->sequence;
451
currentFrame = &getData(entityIndex)->currentFrame;
457
// Save current values
458
int16 oldFrame = *currentFrame;
459
int16 field_4A1 = getData(entityIndex)->field_4A1;
462
// Check we do not get past the end
463
if (*currentFrame >= (int)sequence->count() - 1)
466
// Get the proper frame
467
FrameInfo *info = sequence->getFrameInfo((uint16)*currentFrame);
469
if (info->field_33 & 8) {
472
if (info->soundAction == 35)
475
getData(entityIndex)->field_4A1 += info->field_30;
477
// Progress to the next frame
482
// Restore old values
484
*currentFrame = oldFrame;
485
getData(entityIndex)->field_4A1 = field_4A1;
489
void Entities::updateSequences() const {
490
if (!getFlags()->isGameRunning)
493
// Update the train clock & doors
494
getScenes()->updateDoorsAndClock();
496
//////////////////////////////////////////////////////////////////////////
497
// First pass: Drawing
498
//////////////////////////////////////////////////////////////////////////
499
for (uint i = 1; i < _entities.size(); i++) {
500
EntityIndex entityIndex = (EntityIndex)i;
502
if (!getSavePoints()->getCallback(entityIndex))
505
EntityData::EntityCallData *data = getData(entityIndex);
508
getScenes()->removeFromQueue(data->frame);
509
SAFE_DELETE(data->frame);
513
getScenes()->removeFromQueue(data->frame1);
514
SAFE_DELETE(data->frame1);
517
if (data->direction == kDirectionSwitch) {
521
SAFE_DELETE(data->sequence);
523
// Replace by sequence 3 if available
524
if (data->sequence2) {
525
data->sequence = data->sequence2;
526
data->sequenceName = data->sequenceName2;
528
data->sequence2 = NULL;
529
data->sequenceName2 = "";
532
data->direction = data->directionSwitch;
533
data->currentFrame = -1;
538
drawSequences(entityIndex, data->direction, false);
541
//////////////////////////////////////////////////////////////////////////
542
// Second pass: Load sequences for next pass
543
//////////////////////////////////////////////////////////////////////////
544
for (uint i = 1; i < _entities.size(); i++) {
545
EntityIndex entityIndex = (EntityIndex)i;
547
if (!getSavePoints()->getCallback(entityIndex))
550
EntityData::EntityCallData *data = getData(entityIndex);
551
byte field30 = (data->direction == kDirectionLeft ? entityIndex + 35 : 15);
553
if (data->sequenceName != "" && !data->sequence) {
554
data->sequence = loadSequence1(data->sequenceName, field30);
556
// If sequence 2 was loaded correctly, remove the copied name
557
// otherwise, compute new name
558
if (data->sequence) {
559
data->sequenceNameCopy = "";
561
Common::String sequenceName;
563
// Left and down directions
564
if (data->direction == kDirectionLeft || data->direction == kDirectionRight) {
565
COMPUTE_SEQUENCE_NAME(sequenceName, data->sequenceName);
567
// Try loading the sequence
568
data->sequence = loadSequence1(sequenceName, field30);
571
// Update sequence names
572
data->sequenceNameCopy = (data->sequence ? "" : data->sequenceName);
573
data->sequenceName = (data->sequence ? sequenceName : "");
578
if (data->sequenceName2 != "" && !data->sequence2) {
580
if (data->car == getData(kEntityPlayer)->car)
581
data->sequence2 = loadSequence1(data->sequenceName2, field30);
583
if (!data->sequence2) {
584
Common::String sequenceName;
586
// Left and down directions
587
if (data->directionSwitch == kDirectionLeft || data->directionSwitch == kDirectionRight) {
588
COMPUTE_SEQUENCE_NAME(sequenceName, data->sequenceName2);
590
// Try loading the sequence
591
data->sequence2 = loadSequence1(sequenceName, field30);
594
// Update sequence names
595
data->sequenceName2 = (data->sequence2 ? sequenceName : "");
601
void Entities::resetSequences(EntityIndex entityIndex) const {
604
if (getData(entityIndex)->direction == kDirectionSwitch) {
605
getData(entityIndex)->direction = getData(entityIndex)->directionSwitch;
606
getData(entityIndex)->field_49B = 0;
607
getData(entityIndex)->currentFrame = -1;
610
SAFE_DELETE(getData(entityIndex)->frame);
611
SAFE_DELETE(getData(entityIndex)->frame1);
613
SAFE_DELETE(getData(entityIndex)->sequence);
614
SAFE_DELETE(getData(entityIndex)->sequence2);
615
SAFE_DELETE(getData(entityIndex)->sequence3);
617
getData(entityIndex)->field_4A9 = false;
618
getData(entityIndex)->field_4AA = false;
620
strcpy((char*)&getData(entityIndex)->sequenceNameCopy, "");
621
strcpy((char*)&getData(entityIndex)->sequenceName, "");
622
strcpy((char*)&getData(entityIndex)->sequenceName2, "");
624
getScenes()->resetQueue();
627
//////////////////////////////////////////////////////////////////////////
629
//////////////////////////////////////////////////////////////////////////
630
void Entities::updateCallbacks() {
631
if (!getFlags()->isGameRunning)
634
getFlags()->flag_entities_0 = false;
636
if (getFlags()->flag_entities_1) {
638
getFlags()->flag_entities_0 = true;
640
getFlags()->flag_entities_1 = true;
642
getFlags()->flag_entities_1 = false;
646
void Entities::executeCallbacks() {
647
for (uint i = 1; i < _entities.size(); i++) {
648
if (getFlags()->flag_entities_0)
651
if (getSavePoints()->getCallback((EntityIndex)i))
652
processEntity((EntityIndex)i);
655
if (getFlags()->flag_entities_0)
658
bool processed = true;
661
for (int i = 1; i < (int)_entities.size(); i++) {
662
if (getFlags()->flag_entities_0)
665
if (getSavePoints()->getCallback((EntityIndex)i)) {
666
if (getData((EntityIndex)i)->doProcessEntity) {
668
processEntity((EntityIndex)i);
672
} while (!processed);
675
//////////////////////////////////////////////////////////////////////////
677
//////////////////////////////////////////////////////////////////////////
678
#define INCREMENT_DIRECTION_COUNTER() { \
679
data->doProcessEntity = false; \
680
if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) \
684
void Entities::processEntity(EntityIndex entityIndex) {
685
EntityData::EntityCallData *data = getData(entityIndex);
686
bool keepPreviousFrame = false;
688
data->doProcessEntity = false;
690
if (getData(kEntityPlayer)->car != data->car && data->direction != kDirectionRight && data->direction != kDirectionSwitch) {
692
if (data->position) {
693
updatePositionExit(entityIndex, data->car2, data->position);
694
data->car2 = kCarNone;
698
getScenes()->removeAndRedraw(&data->frame, false);
699
getScenes()->removeAndRedraw(&data->frame1, false);
701
INCREMENT_DIRECTION_COUNTER();
706
getScenes()->removeAndRedraw(&data->frame1, false);
708
if (data->frame && data->frame->getInfo()->subType != kFrameType3) {
709
data->frame->getInfo()->subType = kFrameTypeNone;
710
getScenes()->setFlagDrawSequences();
714
SAFE_DELETE(data->sequence3);
716
if (!data->frame || !data->direction) {
719
drawSequences(entityIndex, data->direction, true);
721
data->doProcessEntity = false;
722
computeCurrentFrame(entityIndex);
724
if (getFlags()->flag_entities_0 || data->doProcessEntity)
727
if (data->sequence && data->currentFrame != -1 && data->currentFrame <= (int16)(data->sequence->count() - 1)) {
728
processFrame(entityIndex, false, true);
730
if (!getFlags()->flag_entities_0 && !data->doProcessEntity) {
731
INCREMENT_DIRECTION_COUNTER();
735
if (data->direction == kDirectionRight && data->field_4A1 > 100) {
736
getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
737
getSavePoints()->process();
739
if (getFlags()->flag_entities_0 || data->doProcessEntity)
743
if (data->position) {
744
updatePositionExit(entityIndex, data->car2, data->position);
745
data->car2 = kCarNone;
749
INCREMENT_DIRECTION_COUNTER();
755
goto label_nosequence;
757
if (data->frame->getInfo()->field_30 > data->field_49B + 1 || (data->direction == kDirectionLeft && data->sequence->count() == 1)) {
759
INCREMENT_DIRECTION_COUNTER();
763
if (data->frame->getInfo()->field_30 > data->field_49B && !data->frame->getInfo()->keepPreviousFrame) {
765
INCREMENT_DIRECTION_COUNTER();
769
if (data->frame->getInfo()->keepPreviousFrame == 1)
770
keepPreviousFrame = true;
772
// Increment current frame
773
++data->currentFrame;
775
if (data->currentFrame > (int16)(data->sequence->count() - 1) || (data->field_4A9 && checkSequenceFromPosition(entityIndex))) {
777
if (data->direction == kDirectionLeft) {
778
data->currentFrame = 0;
780
keepPreviousFrame = true;
781
drawNextSequence(entityIndex);
783
if (getFlags()->flag_entities_0 || data->doProcessEntity)
786
if (!data->sequence2) {
787
updateEntityPosition(entityIndex);
788
data->doProcessEntity = false;
792
copySequenceData(entityIndex);
797
processFrame(entityIndex, keepPreviousFrame, false);
799
if (!getFlags()->flag_entities_0 && !data->doProcessEntity)
800
INCREMENT_DIRECTION_COUNTER();
803
void Entities::computeCurrentFrame(EntityIndex entityIndex) const {
804
EntityData::EntityCallData *data = getData(entityIndex);
805
int16 originalCurrentFrame = data->currentFrame;
807
if (!data->sequence) {
808
data->currentFrame = -1;
812
switch (data->direction) {
817
case kDirectionSwitch:
818
data->currentFrame = -1;
822
case kDirectionDown: {
823
Scene *scene = getScenes()->get(getState()->scene);
825
if (scene->position > 40)
828
switch (scene->position) {
841
data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
859
if (data->field_4A9) {
860
if (getData(kEntityPlayer)->entityPosition >= data->entityPosition) {
861
data->currentFrame = -1;
863
data->currentFrame = getCurrentFrame(entityIndex, data->sequence, getEntityPositionFromCurrentPosition(), true);
865
if (data->currentFrame != -1 && originalCurrentFrame == data->currentFrame)
866
if (data->currentFrame < (int)(data->sequence->count() - 2))
867
data->currentFrame += 2;
870
data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
890
if (data->field_4A9) {
891
if (getData(kEntityPlayer)->entityPosition <= data->entityPosition) {
892
data->currentFrame = -1;
894
data->currentFrame = getCurrentFrame(entityIndex, data->sequence, getEntityPositionFromCurrentPosition(), true);
896
if (data->currentFrame != -1 && originalCurrentFrame == data->currentFrame)
897
if (data->currentFrame < (int)(data->sequence->count() - 2))
898
data->currentFrame += 2;
901
data->currentFrame = getCurrentFrame(entityIndex, data->sequence, kPositionNone, false);
911
if (data->currentFrame == -1 || data->currentFrame >= (int32)data->sequence->count()) {
912
data->currentFrame = 0;
917
case kDirectionRight:
920
uint16 frameIndex = 0;
923
int16 currentFrameCopy = (!data->currentFrame && !data->field_4A1) ? -1 : data->currentFrame;
927
if (frameIndex >= data->sequence->count())
930
FrameInfo *info = data->sequence->getFrameInfo(frameIndex);
932
if (field30 + info->field_30 >= data->field_4A1) {
937
if (field30 > data->field_4A1 - 10) {
938
if (info->soundAction)
939
getSound()->playSoundEvent(entityIndex, info->soundAction, (field30 <= data->field_4A1 - info->field_31) ? 0 : (byte)(field30 + info->field_31 - data->field_4A1));
942
field30 += info->field_30;
944
if (info->field_33 & 4)
947
if (info->field_33 & 2) {
950
getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
951
getSavePoints()->process();
953
if (getFlags()->flag_entities_0 || data->doProcessEntity)
957
if (info->field_33 & 16) {
958
getSavePoints()->push(kEntityPlayer, entityIndex, kAction4);
959
getSavePoints()->process();
961
if (getFlags()->flag_entities_0 || data->doProcessEntity)
975
if (frameIndex >= data->sequence->count())
978
FrameInfo *info = data->sequence->getFrameInfo(frameIndex);
979
if (info->field_33 & 2) {
982
getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
983
getSavePoints()->process();
985
if (getFlags()->flag_entities_0 || data->doProcessEntity)
989
data->field_4A1 += info->field_30;
991
byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
993
getSound()->playSoundEvent(entityIndex, soundAction);
1001
data->currentFrame = frameIndex;
1002
data->field_49B = 0;
1004
byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
1005
byte field31 = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_31;
1006
if (soundAction && data->currentFrame != currentFrameCopy)
1007
getSound()->playSoundEvent(entityIndex, soundAction, field31);
1010
data->currentFrame = (int16)(data->sequence->count() - 1);
1011
data->field_49B = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_30;
1016
data->currentFrame = frameIndex;
1017
data->field_49B = data->field_4A1 - field30;
1019
byte soundAction = data->sequence->getFrameInfo((uint16)data->currentFrame)->soundAction;
1020
byte field31 = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_31;
1021
if (soundAction && data->currentFrame != currentFrameCopy)
1022
getSound()->playSoundEvent(entityIndex, soundAction, field31 <= data->field_49B ? 0 : (byte)(field31 - data->field_49B));
1025
data->currentFrame = (int16)(data->sequence->count() - 1);
1026
data->field_49B = data->sequence->getFrameInfo((uint16)data->currentFrame)->field_30;
1028
getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
1029
getSavePoints()->process();
1035
int16 Entities::getCurrentFrame(EntityIndex entity, Sequence *sequence, EntityPosition position, bool doProcessing) const {
1036
EntityData::EntityCallData *data = getData(entity);
1038
EntityPosition firstFramePosition = sequence->getFrameInfo(0)->entityPosition;
1039
EntityPosition lastFramePosition = sequence->getFrameInfo(sequence->count() - 1)->entityPosition;
1041
bool isGoingForward = (firstFramePosition < lastFramePosition);
1043
if (!doProcessing) {
1044
if (!isGoingForward) {
1045
if (data->field_4A3 + firstFramePosition < data->entityPosition || lastFramePosition - data->field_4A3 > data->entityPosition)
1048
if (firstFramePosition - data->field_4A3 > data->entityPosition || lastFramePosition + data->field_4A3 < data->entityPosition)
1053
if (sequence->count() == 0)
1056
// Search for the correct frame
1057
// TODO: looks slightly like some sort of binary search
1059
uint16 numFrames = sequence->count() - 1;
1062
uint16 currentFrame = (frame + numFrames) / 2;
1064
if (position + sequence->getFrameInfo(currentFrame)->entityPosition <= data->entityPosition) {
1065
if (!isGoingForward)
1066
numFrames = (frame + numFrames) / 2;
1068
frame = (frame + numFrames) / 2;
1071
numFrames = (frame + numFrames) / 2;
1073
frame = (frame + numFrames) / 2;
1076
if (numFrames - frame == 1) {
1077
uint16 lastFramePos = ABS(position - (sequence->getFrameInfo(numFrames)->entityPosition + data->entityPosition));
1078
uint16 framePosition = ABS(position - (sequence->getFrameInfo(frame)->entityPosition + data->entityPosition));
1080
return (framePosition > lastFramePos) ? numFrames : frame;
1083
if (numFrames <= frame)
1084
return currentFrame;
1088
void Entities::processFrame(EntityIndex entityIndex, bool keepPreviousFrame, bool dontPlaySound) {
1089
EntityData::EntityCallData *data = getData(entityIndex);
1091
// Set frame to be drawn again
1092
if (data->frame && keepPreviousFrame) {
1093
if (data->frame->getInfo()->subType != kFrameType3)
1094
data->frame->getInfo()->subType = kFrameType2;
1096
getScenes()->setFlagDrawSequences();
1099
// Remove old frame from queue
1100
if (data->frame && !keepPreviousFrame)
1101
getScenes()->removeFromQueue(data->frame);
1103
// Stop if nothing else to draw
1104
if (data->currentFrame < 0)
1107
if (data->currentFrame > (int)data->sequence->count())
1110
// Get new frame info
1111
FrameInfo *info = data->sequence->getFrameInfo((uint16)data->currentFrame);
1113
if (data->frame && data->frame->getInfo()->subType != kFrameType3)
1114
if (!info->field_2E || keepPreviousFrame)
1115
getScenes()->setCoordinates(data->frame);
1118
if (info->entityPosition) {
1119
data->entityPosition = info->entityPosition;
1120
if (data->field_4A9)
1121
data->entityPosition = (EntityPosition)(data->entityPosition + getEntityPositionFromCurrentPosition());
1124
info->location = entityIndex + ABS(getData(entityIndex)->entityPosition - getData(kEntityPlayer)->entityPosition);
1126
if (info->subType != kFrameType3) {
1127
info->subType = kFrameType1;
1129
if (!keepPreviousFrame)
1130
info->subType = kFrameTypeNone;
1133
if (info->field_33 & 1)
1134
getSavePoints()->push(kEntityPlayer, entityIndex, kActionExcuseMeCath);
1136
if (info->field_33 & 2) {
1137
getSavePoints()->push(kEntityPlayer, entityIndex, kAction10);
1138
getSavePoints()->process();
1140
if (getFlags()->flag_entities_0 || data->doProcessEntity)
1144
if (info->field_33 & 16) {
1145
getSavePoints()->push(kEntityPlayer, entityIndex, kAction4);
1146
getSavePoints()->process();
1148
if (getFlags()->flag_entities_0 || data->doProcessEntity)
1152
if (data->position) {
1153
updatePositionExit(entityIndex, data->car2, data->position);
1154
data->car2 = kCarNone;
1158
if (info->position) {
1159
data->car2 = data->car;
1160
data->position = info->position;
1161
updatePositionEnter(entityIndex, data->car2, data->position);
1163
if (getFlags()->flag_entities_0 || data->doProcessEntity)
1167
if (info->soundAction && !dontPlaySound)
1168
getSound()->playSoundEvent(entityIndex, info->soundAction, info->field_31);
1170
// Add the new frame to the queue
1171
SequenceFrame *frame = new SequenceFrame(data->sequence, (uint16)data->currentFrame);
1172
getScenes()->addToQueue(frame);
1174
// Keep previous frame if needed and store the new frame
1175
if (keepPreviousFrame) {
1176
SAFE_DELETE(data->frame1);
1177
data->frame1 = data->frame;
1179
SAFE_DELETE(data->frame);
1182
data->frame = frame;
1185
data->field_49B = keepPreviousFrame ? 0 : 1;
1188
void Entities::drawNextSequence(EntityIndex entityIndex) const {
1189
EntityData::EntityCallData *data = getData(entityIndex);
1191
if (data->direction == kDirectionRight) {
1192
getSavePoints()->push(kEntityPlayer, entityIndex, kActionExitCompartment);
1193
getSavePoints()->process();
1195
if (getFlags()->flag_entities_0 || data->doProcessEntity)
1199
if (!isDirectionUpOrDown(entityIndex))
1202
if (data->sequence2)
1205
if (!getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingAtDoors))
1208
if (getData(kEntityPlayer)->car != data->car)
1211
if (!data->field_4A9 || isWalkingOppositeToPlayer(entityIndex)) {
1212
if (!data->field_4A9 && isWalkingOppositeToPlayer(entityIndex)) {
1213
data->entityPosition = kPosition_2088;
1215
if (data->direction != kDirectionUp)
1216
data->entityPosition = kPosition_8512;
1218
drawSequences(entityIndex, data->direction, true);
1221
data->entityPosition = kPosition_8514;
1223
if (data->direction != kDirectionUp)
1224
data->entityPosition = kPosition_2086;
1226
drawSequences(entityIndex, data->direction, true);
1230
void Entities::updateEntityPosition(EntityIndex entityIndex) const {
1231
EntityData::EntityCallData *data = getData(entityIndex);
1233
getScenes()->removeAndRedraw(&data->frame, false);
1235
SAFE_DELETE(data->frame1);
1236
data->field_49B = 0;
1238
if (isDirectionUpOrDown(entityIndex)
1239
&& (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) || getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
1240
&& data->car == getData(kEntityPlayer)->car) {
1242
if (isWalkingOppositeToPlayer(entityIndex)) {
1243
data->entityPosition = getData(kEntityPlayer)->entityPosition;
1244
} else if (data->field_4A9) {
1245
data->entityPosition = (data->direction == kDirectionUp) ? kPosition_8514 : kPosition_2086;
1247
if (isPlayerPosition(kCarGreenSleeping, 1) || isPlayerPosition(kCarGreenSleeping, 40)
1248
|| isPlayerPosition(kCarRedSleeping, 1) || isPlayerPosition(kCarRedSleeping, 40)) {
1249
data->entityPosition = (data->direction == kDirectionUp) ? kPosition_2588 : kPosition_8012;
1251
data->entityPosition = (data->direction == kDirectionUp) ? kPosition_9271 : kPosition_849;
1256
SAFE_DELETE(data->sequence);
1257
data->sequenceName = "";
1258
data->field_4A9 = false;
1260
if (data->directionSwitch)
1261
data->direction = data->directionSwitch;
1264
void Entities::copySequenceData(EntityIndex entityIndex) const {
1265
EntityData::EntityCallData *data = getData(entityIndex);
1268
data->sequence3 = data->sequence;
1270
data->sequence = data->sequence2;
1271
data->sequenceName = data->sequenceName2;
1272
data->field_4A9 = data->field_4AA;
1274
if (data->directionSwitch)
1275
data->direction = data->directionSwitch;
1278
data->sequence2 = NULL;
1279
data->sequenceName2 = "";
1280
data->field_4AA = false;
1281
data->directionSwitch = kDirectionNone;
1283
if (data->field_4A9) {
1284
computeCurrentFrame(entityIndex);
1286
if (data->currentFrame == -1)
1287
data->currentFrame = 0;
1289
data->currentFrame = data->currentFrame2;
1290
data->currentFrame2 = 0;
1292
if (data->currentFrame == -1)
1293
data->currentFrame = 0;
1297
//////////////////////////////////////////////////////////////////////////
1299
//////////////////////////////////////////////////////////////////////////
1300
void Entities::drawSequenceLeft(EntityIndex index, const char *sequence) const {
1301
drawSequence(index, sequence, kDirectionLeft);
1304
void Entities::drawSequenceRight(EntityIndex index, const char *sequence) const {
1305
drawSequence(index, sequence, kDirectionRight);
1308
void Entities::clearSequences(EntityIndex entityIndex) const {
1309
debugC(8, kLastExpressDebugLogic, "Clear sequences for entity %s", ENTITY_NAME(entityIndex));
1311
EntityData::EntityCallData *data = getData(entityIndex);
1313
getScenes()->removeAndRedraw(&data->frame, false);
1314
getScenes()->removeAndRedraw(&data->frame1, false);
1316
if (data->sequence2) {
1317
SAFE_DELETE(data->sequence2);
1318
data->sequenceName2 = "";
1319
data->field_4AA = false;
1320
data->directionSwitch = kDirectionNone;
1323
if (data->sequence) {
1324
SAFE_DELETE(data->sequence);
1325
data->sequenceName = "";
1326
data->field_4A9 = false;
1327
data->currentFrame = -1;
1330
data->sequenceNamePrefix = "";
1331
data->direction = kDirectionNone;
1332
data->doProcessEntity = true;
1335
void Entities::drawSequence(EntityIndex index, const char *sequence, EntityDirection direction) const {
1336
debugC(8, kLastExpressDebugLogic, "Drawing sequence %s for entity %s with direction %s", sequence, ENTITY_NAME(index), DIRECTION_NAME(direction));
1338
// Copy sequence name
1339
getData(index)->sequenceNamePrefix = sequence;
1340
getData(index)->sequenceNamePrefix.toUppercase();
1341
getData(index)->sequenceNamePrefix += "-";
1344
getData(index)->field_49B = 0;
1345
getData(index)->currentFrame = 0;
1346
getData(index)->field_4A1 = 0;
1348
drawSequences(index, direction, true);
1351
void Entities::drawSequences(EntityIndex entityIndex, EntityDirection direction, bool loadSequence) const {
1352
EntityData::EntityCallData *data = getData(entityIndex);
1354
// Compute value for loading sequence depending on direction
1355
byte field30 = (direction == kDirectionLeft ? entityIndex + 35 : 15);
1357
data->doProcessEntity = true;
1358
bool field4A9 = data->field_4A9;
1360
// First case: different car and not going right: cleanup and return
1361
if (data->car != getData(kEntityPlayer)->car && direction != kDirectionRight) {
1362
clearEntitySequenceData(data, direction);
1366
data->directionSwitch = kDirectionNone;
1368
// Process sequence names
1369
Common::String sequenceName;
1370
Common::String sequenceName1;
1371
Common::String sequenceName2;
1372
Common::String sequenceName3;
1374
getSequenceName(entityIndex, direction, sequenceName1, sequenceName2);
1376
// No sequence 1: cleanup and return
1377
if (sequenceName1 == "") {
1378
clearEntitySequenceData(data, direction);
1382
if (sequenceName1 == data->sequenceNameCopy) {
1383
data->direction = direction;
1387
if (direction == kDirectionLeft || direction == kDirectionRight) {
1388
COMPUTE_SEQUENCE_NAME(sequenceName, sequenceName1);
1390
if (sequenceName3 != "")
1391
COMPUTE_SEQUENCE_NAME(sequenceName3, sequenceName2);
1395
data->direction = direction;
1397
if (sequenceName1 == data->sequenceName) {
1398
if (sequenceName2 == "")
1401
loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1405
SAFE_DELETE(data->sequence);
1407
if (sequenceName1 != data->sequenceName2) {
1411
if (data->car == getData(kEntityPlayer)->car)
1412
data->sequence = loadSequence1(sequenceName1, field30);
1414
if (data->sequence) {
1415
data->sequenceName = sequenceName1;
1416
data->sequenceNameCopy = "";
1418
if (sequenceName != "")
1419
data->sequence = loadSequence1(sequenceName, field30);
1421
data->sequenceName = (data->sequence ? sequenceName : "");
1422
data->sequenceNameCopy = (data->sequence ? "" : sequenceName1);
1425
data->sequenceName = sequenceName1;
1428
if (sequenceName2 != "") {
1429
loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1433
if (!data->sequence2) {
1434
if (sequenceName2 == "")
1437
loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1441
SAFE_DELETE(data->sequence2);
1443
data->sequence = data->sequence2;
1444
data->sequenceName = data->sequenceName2;
1445
data->sequence2 = NULL;
1448
data->sequenceName2 = "";
1450
if (sequenceName2 == "")
1453
loadSequence2(entityIndex, sequenceName2, sequenceName3, field30, loadSequence);
1457
if (data->sequenceName != sequenceName1) {
1459
if (data->sequenceName2 != sequenceName1) {
1460
SAFE_DELETE(data->sequence2);
1461
TRY_LOAD_SEQUENCE(data->sequence2, data->sequenceName2, sequenceName1, sequenceName);
1464
data->field_4AA = data->field_4A9;
1465
if ((direction != kDirectionUp && direction != kDirectionDown) || data->field_4AA || !data->sequence2) {
1466
data->currentFrame2 = 0;
1468
data->currentFrame2 = getCurrentFrame(entityIndex, data->sequence2, kPositionNone, false);
1470
if (data->currentFrame2 == -1) {
1471
clearSequences(entityIndex);
1476
data->field_4A9 = field4A9;
1477
data->field_49B = data->frame->getInfo()->field_30;
1478
data->currentFrame = (int16)(data->sequence->count() - 1);
1479
data->direction = kDirectionSwitch;
1480
data->directionSwitch = direction;
1482
SAFE_DELETE(data->sequence2);
1484
data->sequence2 = loadSequence1(data->sequence->getName(), data->sequence->getField30());
1486
data->sequenceName2 = data->sequenceName;
1487
data->field_4AA = data->field_4A9;
1488
data->field_49B = data->frame->getInfo()->field_30;
1489
data->currentFrame = (int16)(data->sequence->count() - 1);
1490
data->direction = kDirectionSwitch;
1491
data->directionSwitch = direction;
1493
if ((direction != kDirectionUp && direction != kDirectionDown) || data->field_4AA || !data->sequence2) {
1494
data->currentFrame2 = 0;
1496
data->currentFrame2 = getCurrentFrame(entityIndex, data->sequence2, kPositionNone, false);
1498
if (data->currentFrame2 == -1)
1499
clearSequences(entityIndex);
1504
void Entities::loadSequence2(EntityIndex entityIndex, Common::String sequenceName, Common::String sequenceName2, byte field30, bool reloadSequence) const {
1505
EntityData::EntityCallData *data = getData(entityIndex);
1507
if (data->sequenceName2 == sequenceName)
1510
if (data->sequence2)
1511
SAFE_DELETE(data->sequence2);
1513
if (reloadSequence) {
1514
TRY_LOAD_SEQUENCE(data->sequence2, data->sequenceName2, sequenceName, sequenceName2);
1516
data->sequenceName2 = sequenceName;
1520
void Entities::getSequenceName(EntityIndex index, EntityDirection direction, Common::String &sequence1, Common::String &sequence2) const {
1521
EntityData::EntityCallData *data = getData(index);
1522
Position position = getScenes()->get(getState()->scene)->position;
1525
data->field_4A9 = false;
1526
data->field_4AA = false;
1528
switch (direction) {
1538
if (data->entityPosition < kPosition_2587)
1539
sequence1 = Common::String::format("%02d%01d-01u.seq", index, data->clothes);
1557
if (data->entityPosition >= kPosition_9270)
1560
if (data->entityPosition >= kPosition_8513) {
1561
sequence1 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
1563
sequence1 = Common::String::format("%02d%01d-03u.seq", index, data->clothes);
1564
sequence2 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
1565
data->field_4A9 = true;
1570
if (data->entityPosition < kPosition_9270)
1571
sequence1 = Common::String::format("%02d%01d-18u.seq", index, data->clothes);
1575
if (getData(kEntityPlayer)->entityPosition > data->entityPosition)
1576
sequence1 = Common::String::format("%02d%01d-22u.seq", index, data->clothes);
1595
if (getData(kEntityPlayer)->entityPosition <= data->entityPosition)
1598
if (data->entityPosition >= kPosition_2087) {
1599
sequence1 = Common::String::format("%02d%01d-38u.seq", index, data->clothes);
1600
data->field_4A9 = true;
1602
sequence1 = Common::String::format("%02d%01d-%02deu.seq", index, data->clothes, position);
1603
sequence2 = Common::String::format("%02d%01d-38u.seq", index, data->clothes);
1604
data->field_4AA = true;
1609
if (getData(kEntityPlayer)->entityPosition > data->entityPosition)
1610
sequence1 = Common::String::format("%02d%01d-40u.seq", index, data->clothes);
1615
case kDirectionDown:
1621
if (getData(kEntityPlayer)->entityPosition < data->entityPosition)
1622
sequence1 = Common::String::format("%02d%01d-01d.seq", index, data->clothes);
1640
if (getData(kEntityPlayer)->entityPosition >= data->entityPosition)
1643
if (data->entityPosition <= kPosition_8513) {
1644
sequence1 = Common::String::format("%02d%01d-03d.seq", index, data->clothes);
1645
data->field_4A9 = true;
1647
sequence1 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
1648
sequence2 = Common::String::format("%02d%01d-03d.seq", index, data->clothes);
1649
data->field_4AA = true;
1654
if (getData(kEntityPlayer)->entityPosition < data->entityPosition)
1655
sequence1 = Common::String::format("%02d%01d-18d.seq", index, data->clothes);
1659
if (data->entityPosition > kPosition_850)
1660
sequence1 = Common::String::format("%02d%01d-22d.seq", index, data->clothes);
1679
if (data->entityPosition <= kPosition_850)
1682
if (data->entityPosition <= kPosition_2087) {
1683
sequence1 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
1685
sequence1 = Common::String::format("%02d%01d-38d.seq", index, data->clothes);
1686
sequence2 = Common::String::format("%02d%01d-%02ded.seq", index, data->clothes, position);
1687
data->field_4A9 = true;
1692
if (getData(kEntityPlayer)->entityPosition > kPosition_8013)
1693
sequence1 = Common::String::format("%02d%01d-40d.seq", index, data->clothes);
1698
// First part of sequence is already set
1699
case kDirectionLeft:
1700
case kDirectionRight:
1701
sequence1 = Common::String::format("%s%02d.seq", data->sequenceNamePrefix.c_str(), position);
1706
//////////////////////////////////////////////////////////////////////////
1708
//////////////////////////////////////////////////////////////////////////
1709
void Entities::enterCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1) {
1710
if (entity > kEntityChapters)
1713
switch (compartment) {
1715
// Return here so we do not update the compartments
1718
case kObjectCompartment1:
1719
updatePositionsEnter(entity, kCarGreenSleeping, 41, 51, 17, 38);
1722
case kObjectCompartment2:
1723
updatePositionsEnter(entity, kCarGreenSleeping, 42, 52, 15, 36);
1726
case kObjectCompartment3:
1727
updatePositionsEnter(entity, kCarGreenSleeping, 43, 53, 13, 34);
1730
case kObjectCompartment4:
1731
updatePositionsEnter(entity, kCarGreenSleeping, 44, 54, 11, 32);
1734
case kObjectCompartment5:
1735
updatePositionsEnter(entity, kCarGreenSleeping, 45, 55, 9, 30);
1738
case kObjectCompartment6:
1739
updatePositionsEnter(entity, kCarGreenSleeping, 46, 56, 7, 28);
1742
case kObjectCompartment7:
1743
updatePositionsEnter(entity, kCarGreenSleeping, 47, 57, 5, 26);
1746
case kObjectCompartment8:
1747
updatePositionsEnter(entity, kCarGreenSleeping, 48, 58, 3, 25);
1750
case kObjectCompartmentA:
1751
updatePositionsEnter(entity, kCarRedSleeping, 41, 51, 17, 38);
1754
case kObjectCompartmentB:
1755
updatePositionsEnter(entity, kCarRedSleeping, 42, 52, 15, 36);
1758
case kObjectCompartmentC:
1759
updatePositionsEnter(entity, kCarRedSleeping, 43, 53, 13, 34);
1762
case kObjectCompartmentD:
1763
updatePositionsEnter(entity, kCarRedSleeping, 44, 54, 11, 32);
1766
case kObjectCompartmentE:
1767
updatePositionsEnter(entity, kCarRedSleeping, 45, 55, 9, 30);
1770
case kObjectCompartmentF:
1771
updatePositionsEnter(entity, kCarRedSleeping, 46, 56, 7, 28);
1774
case kObjectCompartmentG:
1775
updatePositionsEnter(entity, kCarRedSleeping, 47, 57, 5, 26);
1778
case kObjectCompartmentH:
1779
updatePositionsEnter(entity, kCarRedSleeping, 48, 58, 3, 25);
1783
// Update compartments
1784
int index = (compartment < 32 ? compartment - 1 : compartment - 24);
1786
error("Entities::exitCompartment: invalid compartment index!");
1788
if (useCompartment1)
1789
_compartments1[index] |= STORE_VALUE(entity);
1791
_compartments[index] |= STORE_VALUE(entity);
1794
void Entities::exitCompartment(EntityIndex entity, ObjectIndex compartment, bool useCompartment1) {
1795
if (entity > kEntityChapters)
1798
// TODO factorize in one line
1799
switch (compartment) {
1801
// Return here so we do not update the compartments
1804
case kObjectCompartment1:
1805
updatePositionsExit(entity, kCarGreenSleeping, 41, 51);
1808
case kObjectCompartment2:
1809
updatePositionsExit(entity, kCarGreenSleeping, 42, 52);
1812
case kObjectCompartment3:
1813
updatePositionsExit(entity, kCarGreenSleeping, 43, 53);
1816
case kObjectCompartment4:
1817
updatePositionsExit(entity, kCarGreenSleeping, 44, 54);
1820
case kObjectCompartment5:
1821
updatePositionsExit(entity, kCarGreenSleeping, 45, 55);
1824
case kObjectCompartment6:
1825
updatePositionsExit(entity, kCarGreenSleeping, 46, 56);
1828
case kObjectCompartment7:
1829
updatePositionsExit(entity, kCarGreenSleeping, 47, 57);
1832
case kObjectCompartment8:
1833
updatePositionsExit(entity, kCarGreenSleeping, 48, 58);
1836
case kObjectCompartmentA:
1837
updatePositionsExit(entity, kCarRedSleeping, 41, 51);
1840
case kObjectCompartmentB:
1841
updatePositionsExit(entity, kCarRedSleeping, 42, 52);
1844
case kObjectCompartmentC:
1845
updatePositionsExit(entity, kCarRedSleeping, 43, 53);
1848
case kObjectCompartmentD:
1849
updatePositionsExit(entity, kCarRedSleeping, 44, 54);
1852
case kObjectCompartmentE:
1853
updatePositionsExit(entity, kCarRedSleeping, 45, 55);
1856
case kObjectCompartmentF:
1857
updatePositionsExit(entity, kCarRedSleeping, 46, 56);
1860
case kObjectCompartmentG:
1861
updatePositionsExit(entity, kCarRedSleeping, 47, 57);
1864
case kObjectCompartmentH:
1865
updatePositionsExit(entity, kCarRedSleeping, 48, 58);
1869
// Update compartments
1870
int index = (compartment < 32 ? compartment - 1 : compartment - 24);
1872
error("Entities::exitCompartment: invalid compartment index!");
1874
if (useCompartment1)
1875
_compartments1[index] &= ~STORE_VALUE(entity);
1877
_compartments[index] &= ~STORE_VALUE(entity);
1880
void Entities::updatePositionEnter(EntityIndex entity, CarIndex car, Position position) {
1881
if (entity == kEntity39)
1882
entity = kEntityPlayer;
1884
if (entity > kEntityChapters)
1887
_positions[100 * car + position] |= STORE_VALUE(entity);
1889
if (isPlayerPosition(car, position) || (car == kCarRestaurant && position == 57 && isPlayerPosition(kCarRestaurant, 50))) {
1890
getSound()->excuseMe(entity);
1891
getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
1892
getSound()->playSound(kEntityPlayer, "CAT1127A");
1894
getLogic()->updateCursor();
1898
void Entities::updatePositionExit(EntityIndex entity, CarIndex car, Position position) {
1899
if (entity == kEntity39)
1900
entity = kEntityPlayer;
1902
if (entity > kEntityChapters)
1905
_positions[100 * car + position] &= ~STORE_VALUE(entity);
1907
getLogic()->updateCursor();
1910
void Entities::updatePositionsEnter(EntityIndex entity, CarIndex car, Position position1, Position position2, Position position3, Position position4) {
1911
if (entity == kEntity39)
1912
entity = kEntityPlayer;
1914
if (entity > kEntityChapters)
1917
_positions[100 * car + position1] |= STORE_VALUE(entity);
1918
_positions[100 * car + position2] |= STORE_VALUE(entity);
1920
// FIXME: also checking two DWORD values that do not seem to updated anywhere...
1921
if (isPlayerPosition(car, position1) || isPlayerPosition(car, position2) || isPlayerPosition(car, position3) || isPlayerPosition(car, position4)) {
1922
getSound()->excuseMe(entity);
1923
getScenes()->loadScene(getScenes()->processIndex(getState()->scene));
1924
getSound()->playSound(kEntityPlayer, "CAT1127A");
1926
getLogic()->updateCursor();
1930
void Entities::updatePositionsExit(EntityIndex entity, CarIndex car, Position position1, Position position2) {
1931
if (entity == kEntity39)
1932
entity = kEntityPlayer;
1934
if (entity > kEntityChapters)
1937
_positions[100 * car + position1] &= ~STORE_VALUE(entity);
1938
_positions[100 * car + position2] &= ~STORE_VALUE(entity);
1940
getLogic()->updateCursor();
1943
void Entities::loadSceneFromEntityPosition(CarIndex car, EntityPosition entityPosition, bool alternate) const {
1945
// Determine position
1946
Position position = (alternate ? 1 : 40);
1948
if (entityPosition > entityPositions[position]) {
1952
// For default value, we ignore position 24
1957
alternate ? ++position : --position;
1959
} while (alternate ? position <= 18 : position >= 22);
1961
// For position outside bounds, use minimal value
1962
if ((alternate && position > 18) || (alternate && position < 22)) {
1963
getScenes()->loadSceneFromPosition(car, alternate ? 18 : 22);
1967
// Load scene from position
1970
getScenes()->loadSceneFromPosition(car, (Position)(position + (alternate ? - 1 : 1)));
1975
if (alternate) getScenes()->loadSceneFromPosition(car, 1);
1979
if (alternate) getScenes()->loadSceneFromPosition(car, 3);
1984
if (!alternate) getScenes()->loadSceneFromPosition(car, 25);
1988
if (!alternate) getScenes()->loadSceneFromPosition(car, 40);
1993
//////////////////////////////////////////////////////////////////////////
1995
//////////////////////////////////////////////////////////////////////////
1996
bool Entities::hasValidFrame(EntityIndex entity) const {
1997
return (getData(entity)->frame && (getData(entity)->frame->getInfo()->subType != kFrameType3));
2000
bool Entities::compare(EntityIndex entity1, EntityIndex entity2) const {
2001
EntityData::EntityCallData *data1 = getData(entity1);
2002
EntityData::EntityCallData *data2 = getData(entity2);
2004
if (data2->car != data1->car
2005
|| data1->car < kCarGreenSleeping
2006
|| data1->car > kCarRedSleeping)
2009
EntityPosition position1 = (data1->entityPosition >= data2->entityPosition) ? data1->entityPosition : data2->entityPosition;
2010
EntityPosition position2 = (data1->entityPosition >= data2->entityPosition) ? data2->entityPosition : data1->entityPosition;
2015
if (objectsPosition[index1] >= position2)
2019
} while (index1 > -1);
2023
if (objectsPosition[index2] <= position2)
2027
} while (index2 < 8);
2029
if (index1 > -1 && index2 < 8 && index2 <= index1) {
2030
while (index2 <= index1) {
2031
if (getCompartments(index2 + (data1->car == kCarGreenSleeping ? 0 : 8)))
2034
if (getCompartments1(index2 + (data1->car == kCarGreenSleeping ? 0 : 8)))
2041
for (EntityIndex entity = kEntityAnna; entity <= kEntity39; entity = (EntityIndex)(entity + 1)) {
2043
if (entity1 == entity || entity2 == entity)
2046
if (!isDirectionUpOrDown(entity))
2049
if (data1->car == getEntityData(entity)->car
2050
&& getEntityData(entity)->entityPosition > position2
2051
&& getEntityData(entity)->entityPosition < position1)
2058
bool Entities::updateEntity(EntityIndex entity, CarIndex car, EntityPosition position) const {
2059
EntityData::EntityCallData *data = getData(entity);
2060
EntityDirection direction = kDirectionNone;
2066
if (position == kPosition_2000
2067
&& getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)
2068
&& !isPlayerPosition(kCarGreenSleeping, 1)
2069
&& !isPlayerPosition(kCarRedSleeping, 2))
2070
position = kPosition_1500;
2072
if (data->direction != kDirectionUp && data->direction != kDirectionDown)
2073
data->field_497 = 0;
2075
if (data->field_497) {
2078
if (data->field_497 == 128)
2079
data->field_497 = 0;
2081
if ((data->field_497 & 127) != 8) {
2082
data->field_49B = 0;
2088
if (data->field_497 & 128)
2092
if (data->car != car)
2093
goto label_process_entity;
2096
delta = ABS(data->entityPosition - position);
2097
if (delta < 100 || (position > kPosition_850 && position < kPosition_9270 && delta < 300))
2101
if ((getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) && data->direction == kDirectionUp)
2102
|| (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) && data->direction == kDirectionDown)) {
2103
if (!checkPosition(position) && isDistanceBetweenEntities(entity, kEntityPlayer, 250))
2108
goto label_process_entity;
2111
if (getEntities()->hasValidFrame(entity)
2112
&& getEntities()->isWalkingOppositeToPlayer(entity)
2113
&& !getEntities()->checkPosition(position)) {
2115
position = (EntityPosition)(getData(kEntityPlayer)->entityPosition + 250 * (data->direction == kDirectionUp ? 1 : -1));
2119
label_process_entity:
2121
// Calculate direction
2122
if (data->car < car)
2123
direction = kDirectionUp;
2124
else if (data->car > car)
2125
direction = kDirectionDown;
2127
direction = (data->entityPosition < position) ? kDirectionUp : kDirectionDown;
2129
if (data->direction == direction) {
2132
if (checkDistanceFromPosition(entity, kPosition_1500, 750) && entity != kEntityFrancois) {
2134
if (data->entity != kEntityPlayer) {
2135
if (data->direction != kDirectionUp || (position <= kPosition_2000 && data->car == car)) {
2136
if (data->direction == kDirectionDown && (position < kPosition_1500 || data->car != car)) {
2137
if (data->entityPosition > kPosition_1500 && (data->car == kCarGreenSleeping || data->car == kCarRedSleeping)) {
2138
data->entity = (data->car == kCarGreenSleeping) ? kEntityMertens : kEntityCoudert;
2139
getSavePoints()->push(entity, data->entity, kAction11);
2143
if (data->entityPosition < kPosition_1500 && (data->car == kCarGreenSleeping || data->car == kCarRedSleeping)) {
2144
data->entity = (data->car == kCarGreenSleeping) ? kEntityMertens : kEntityCoudert;
2145
getSavePoints()->push(entity, data->entity, kAction11, 1);
2150
} else if (data->entity) {
2151
getSavePoints()->push(entity, data->entity, kAction16);
2152
data->entity = kEntityPlayer;
2155
if (hasValidFrame(entity)) {
2157
if (!data->field_4A9)
2160
int compartmentIndex = 0;
2161
if (data->car == kCarGreenSleeping)
2162
compartmentIndex = 0;
2163
else if (data->car == kCarRedSleeping)
2164
compartmentIndex = 8;
2166
for (int i = 0; i < 8; i++) {
2167
if (getCompartments(compartmentIndex) || getCompartments1(compartmentIndex)) {
2168
if (checkDistanceFromPosition(entity, objectsPosition[i], 750)) {
2169
if (checkPosition(objectsPosition[i])) {
2171
if ((data->direction == kDirectionUp && data->entityPosition < objectsPosition[i] && (data->car != car || position > objectsPosition[i]))
2172
|| (data->direction == kDirectionDown && data->entityPosition > objectsPosition[i] && (data->car != car || position < objectsPosition[i]))) {
2174
getSound()->excuseMe(entity, (EntityIndex)(State::getPowerOfTwo((uint32)(getCompartments(compartmentIndex) ? getCompartments(compartmentIndex) : getCompartments1(compartmentIndex)))));
2176
data->field_497 = 144;
2187
for (EntityIndex entityIndex = kEntityAnna; entityIndex <= kEntity39; entityIndex = (EntityIndex)(entityIndex + 1)) {
2188
if (getSavePoints()->getCallback(entityIndex)
2189
&& hasValidFrame(entityIndex)
2190
&& entityIndex != entity
2191
&& isDistanceBetweenEntities(entity, entityIndex, 750)
2192
&& isDirectionUpOrDown(entityIndex)
2193
&& (entity != kEntityRebecca || entityIndex != kEntitySophie)
2194
&& (entity != kEntitySophie || entityIndex != kEntityRebecca)
2195
&& (entity != kEntityIvo || entityIndex != kEntitySalko)
2196
&& (entity != kEntitySalko || entityIndex != kEntityIvo)
2197
&& (entity != kEntityMilos || entityIndex != kEntityVesna)
2198
&& (entity != kEntityVesna || entityIndex != kEntityMilos)) {
2200
EntityData::EntityCallData *data2 = getData(entityIndex);
2202
if (data->direction != data2->direction) {
2204
if ((data->direction != kDirectionUp || data2->entityPosition <= data->entityPosition)
2205
&& (data->direction != kDirectionDown || data2->entityPosition >= data->entityPosition))
2208
data->field_49B = 0;
2209
data2->field_49B = 0;
2211
data->field_497 = 16;
2212
data2->field_497 = 16;
2214
getSound()->excuseMe(entity, entityIndex);
2215
getSound()->excuseMe(entityIndex, entity);
2217
if (entityIndex > entity)
2223
if (ABS(data2->entityPosition - getData(kEntityPlayer)->entityPosition) < ABS(data->entityPosition - getData(kEntityPlayer)->entityPosition)) {
2225
if (!isWalkingOppositeToPlayer(entity)) {
2227
if (direction == kDirectionUp) {
2228
if (data->entityPosition < kPosition_9500)
2229
data->entityPosition = (EntityPosition)(data->entityPosition + 500);
2231
if (data->entityPosition > kPosition_500)
2232
data->entityPosition = (EntityPosition)(data->entityPosition - 500);
2235
drawSequences(entity, direction, true);
2239
data->field_49B = 0;
2249
if (data->direction == kDirectionUp) {
2250
if (data->entityPosition + data->field_4A3 < 10000)
2251
data->entityPosition = (EntityPosition)(data->entityPosition + data->field_4A3);
2253
if (data->entityPosition > data->field_4A3)
2254
data->entityPosition = (EntityPosition)(data->entityPosition - data->field_4A3);
2257
if (data->entityPosition <= kPosition_9270 || data->direction != kDirectionUp) {
2258
if (data->entityPosition < kPosition_850 && data->direction == kDirectionDown) {
2259
if (changeCar(data, entity, car, position, false, kPosition_9269, kCarKronos))
2263
if (changeCar(data, entity, car, position, true, kPosition_851, kCarGreenSleeping))
2267
if (getData(kEntityPlayer)->car == data->car && data->location == kLocationOutsideCompartment) {
2268
if (data->direction == kDirectionUp) {
2270
if (getData(kEntityPlayer)->entityPosition > data->entityPosition
2271
&& getData(kEntityPlayer)->entityPosition - data->entityPosition >= 500
2272
&& data->field_4A3 + 500 > getData(kEntityPlayer)->entityPosition - data->entityPosition) {
2274
if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) || getScenes()->checkCurrentPosition(false)) {
2275
getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
2277
if (getScenes()->checkCurrentPosition(false))
2278
getScenes()->loadSceneFromObject((ObjectIndex)getScenes()->get(getState()->scene)->param1, true);
2280
} else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown)) {
2281
getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
2285
if (getData(kEntityPlayer)->entityPosition < data->entityPosition
2286
&& data->entityPosition - getData(kEntityPlayer)->entityPosition >= 500
2287
&& data->field_4A3 + 500 > data->entityPosition - getData(kEntityPlayer)->entityPosition) {
2289
if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)) {
2290
getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMeCath);
2291
} else if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) || getScenes()->checkCurrentPosition(false)){
2292
getSavePoints()->push(kEntityPlayer, entity, kActionExcuseMe);
2294
if (getScenes()->checkCurrentPosition(false))
2295
getScenes()->loadSceneFromObject((ObjectIndex)getScenes()->get(getState()->scene)->param1);
2302
} else if (!flag1) {
2303
drawSequences(entity, direction, true);
2307
//////////////////////////////////////////////////////////////////////////
2311
if (direction == kDirectionUp) {
2312
if (data->entityPosition < (flag2 ? kPosition_8800 : kPosition_9250))
2313
data->entityPosition = (EntityPosition)(data->entityPosition + (flag2 ? kPosition_1200 : kPosition_750));
2315
if (data->car == car && data->entityPosition >= position) {
2316
data->entityPosition = position;
2317
data->direction = kDirectionNone;
2318
data->entity = kEntityPlayer;
2322
drawSequences(entity, direction, true);
2327
if (data->entityPosition > (flag2 ? kPosition_1200 : kPosition_750))
2328
data->entityPosition = (EntityPosition)(data->entityPosition - (flag2 ? kPosition_1200 : kPosition_750));
2330
if (data->car == car && data->entityPosition <= position) {
2331
data->entityPosition = position;
2332
data->direction = kDirectionNone;
2333
data->entity = kEntityPlayer;
2337
drawSequences(entity, direction, true);
2341
data->entityPosition = position;
2342
if (data->direction == kDirectionUp || data->direction == kDirectionDown)
2343
data->direction = kDirectionNone;
2344
data->entity = kEntityPlayer;
2349
bool Entities::changeCar(EntityData::EntityCallData *data, EntityIndex entity, CarIndex car, EntityPosition position, bool increment, EntityPosition newPosition, CarIndex newCar) const {
2350
if (getData(kEntityPlayer)->car == data->car) {
2351
getSound()->playSoundEvent(entity, 36);
2352
getSound()->playSoundEvent(entity, 37, 30);
2355
data->car = (CarIndex)(increment ? data->car + 1 : data->car - 1);
2356
data->entityPosition = newPosition;
2358
if (data->car == newCar) {
2359
if (isInGreenCarEntrance(kEntityPlayer)) {
2360
getSound()->playSoundEvent(kEntityPlayer, 14);
2361
getSound()->excuseMe(entity, kEntityPlayer, SoundManager::kFlagDefault);
2362
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 1);
2363
getSound()->playSound(kEntityPlayer, "CAT1127A");
2364
getSound()->playSoundEvent(kEntityPlayer, 15);
2368
if ((increment ? data->car > car : data->car < car) || (data->car == car && (increment ? data->entityPosition >= position : data->entityPosition <= position))) {
2370
data->entityPosition = position;
2371
data->direction = kDirectionNone;
2372
data->entity = kEntityPlayer;
2377
if (data->car == newCar) {
2378
if (isInKronosCarEntrance(kEntityPlayer)) {
2379
getSound()->playSoundEvent(kEntityPlayer, 14);
2380
getSound()->excuseMe(entity, kEntityPlayer, SoundManager::kFlagDefault);
2381
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 62);
2382
getSound()->playSound(kEntityPlayer, "CAT1127A");
2383
getSound()->playSoundEvent(kEntityPlayer, 15);
2387
if (data->car == getData(kEntityPlayer)->car) {
2388
getSound()->playSoundEvent(entity, 36);
2389
getSound()->playSoundEvent(entity, 37, 30);
2395
//////////////////////////////////////////////////////////////////////////
2397
//////////////////////////////////////////////////////////////////////////
2398
bool Entities::isInsideCompartment(EntityIndex entity, CarIndex car, EntityPosition position) const {
2399
return (getData(entity)->entityPosition == position
2400
&& getData(entity)->location == kLocationInsideCompartment
2401
&& getData(entity)->car == car);
2404
bool Entities::checkFields2(ObjectIndex object) const {
2406
EntityPosition position = kPositionNone;
2407
CarIndex car = kCarNone;
2413
case kObjectCompartment1:
2414
case kObjectCompartment2:
2415
case kObjectCompartment3:
2416
case kObjectCompartment4:
2417
case kObjectCompartment5:
2418
case kObjectCompartment6:
2419
case kObjectCompartment7:
2420
case kObjectCompartment8:
2421
position = objectsPosition[object - 1];
2422
car = kCarGreenSleeping;
2423
if (isInsideCompartment(kEntityPlayer, car, position))
2427
case kObjectHandleBathroom:
2428
case kObjectHandleInsideBathroom:
2429
case kObjectKitchen:
2433
position = objectsPosition[object-17];
2434
car = kCarGreenSleeping;
2437
case kObjectCompartmentA:
2438
case kObjectCompartmentB:
2439
case kObjectCompartmentC:
2440
case kObjectCompartmentD:
2441
case kObjectCompartmentE:
2442
case kObjectCompartmentF:
2443
case kObjectCompartmentG:
2444
case kObjectCompartmentH:
2445
position = objectsPosition[object-32];
2446
car = kCarRedSleeping;
2447
if (isInsideCompartment(kEntityPlayer, car, position))
2457
position = objectsPosition[object-48];
2458
car = kCarRedSleeping;
2464
while (!isInsideCompartment((EntityIndex)index, car, position) || index == kEntityVassili) {
2473
bool Entities::isInsideCompartments(EntityIndex entity) const {
2474
return (getData(entity)->car == kCarGreenSleeping
2475
|| getData(entity)->car == kCarRedSleeping)
2476
&& getData(entity)->location == kLocationInsideCompartment;
2479
bool Entities::isPlayerPosition(CarIndex car, Position position) const {
2480
return getData(kEntityPlayer)->car == car && getScenes()->get(getState()->scene)->position == position;
2483
bool Entities::isInsideTrainCar(EntityIndex entity, CarIndex car) const {
2484
return getData(entity)->car == car && getData(entity)->location <= kLocationInsideCompartment;
2487
bool Entities::isInGreenCarEntrance(EntityIndex entity) const {
2488
return isInsideTrainCar(entity, kCarGreenSleeping) && getData(entity)->entityPosition < kPosition_850;
2491
bool Entities::isPlayerInCar(CarIndex car) const {
2492
return isInsideTrainCar(kEntityPlayer, car) && getData(kEntityPlayer)->location && !isInGreenCarEntrance(kEntityPlayer);
2495
bool Entities::isDirectionUpOrDown(EntityIndex entity) const {
2496
return getData(entity)->direction == kDirectionUp || getData(entity)->direction == kDirectionDown;
2499
bool Entities::isDistanceBetweenEntities(EntityIndex entity1, EntityIndex entity2, uint distance) const {
2500
return getData(entity1)->car == getData(entity2)->car
2501
&& (uint)ABS(getData(entity1)->entityPosition - getData(entity2)->entityPosition) <= distance
2502
&& (getData(entity1)->location != kLocationOutsideTrain || getData(entity2)->location != kLocationOutsideTrain);
2505
bool Entities::checkFields10(EntityIndex entity) const {
2506
return getData(entity)->location <= kLocationOutsideTrain;
2509
bool Entities::isSomebodyInsideRestaurantOrSalon() const {
2510
for (uint i = 1; i < _entities.size(); i++) {
2511
EntityIndex index = (EntityIndex)i;
2513
if (getData(index)->location == kLocationOutsideCompartment && (isInSalon(index) || isInRestaurant(index)))
2520
bool Entities::isInSalon(EntityIndex entity) const {
2521
return isInsideTrainCar(entity, kCarRestaurant)
2522
&& getData(entity)->entityPosition >= kPosition_1540
2523
&& getData(entity)->entityPosition <= kPosition_3650;
2526
bool Entities::isInRestaurant(EntityIndex entity) const {
2527
return isInsideTrainCar(entity, kCarRestaurant)
2528
&& getData(entity)->entityPosition >= kPosition_3650
2529
&& getData(entity)->entityPosition <= kPosition_5800;
2532
bool Entities::isInKronosSalon(EntityIndex entity) const {
2533
return isInsideTrainCar(entity, kCarKronos)
2534
&& getData(entity)->entityPosition >= kPosition_5500
2535
&& getData(entity)->entityPosition <= kPosition_7500;
2538
bool Entities::isOutsideAlexeiWindow() const {
2539
return (getData(kEntityPlayer)->entityPosition == kPosition_7500 || getData(kEntityPlayer)->entityPosition == kPosition_8200)
2540
&& getData(kEntityPlayer)->location == kLocationOutsideTrain
2541
&& getData(kEntityPlayer)->car == kCarGreenSleeping;
2544
bool Entities::isOutsideAnnaWindow() const {
2545
return (getData(kEntityPlayer)->entityPosition == kPosition_4070 || getData(kEntityPlayer)->entityPosition == kPosition_4840)
2546
&& getData(kEntityPlayer)->location == kLocationOutsideTrain
2547
&& getData(kEntityPlayer)->car == kCarRedSleeping;
2550
bool Entities::isInKitchen(EntityIndex entity) const {
2551
return isInsideTrainCar(entity, kCarRestaurant) && getData(entity)->entityPosition > kPosition_5800;
2554
bool Entities::isNobodyInCompartment(CarIndex car, EntityPosition position) const {
2555
for (uint i = 1; i < _entities.size(); i++) {
2556
if (isInsideCompartment((EntityIndex)i, car, position))
2562
bool Entities::checkFields19(EntityIndex entity, CarIndex car, EntityPosition position) const {
2564
if (getData(entity)->car != car || getData(entity)->location != kLocationInsideCompartment)
2567
EntityPosition entityPosition = getData(entity)->entityPosition;
2570
if (position == kPosition_4455) {
2571
if (entityPosition == kPosition_4070 || entityPosition == kPosition_4455 || entityPosition == kPosition_4840)
2577
if (position == kPosition_6130) {
2578
if (entityPosition == kPosition_5790 || entityPosition == kPosition_6130 || entityPosition == kPosition_6470)
2584
if (position != kPosition_7850
2585
|| (entityPosition != kPosition_7500 && entityPosition != kPosition_7850 && entityPosition != kPosition_8200))
2591
bool Entities::isInBaggageCarEntrance(EntityIndex entity) const {
2592
return isInsideTrainCar(entity, kCarBaggage)
2593
&& getData(entity)->entityPosition >= kPosition_4500
2594
&& getData(entity)->entityPosition <= kPosition_5500;
2597
bool Entities::isInBaggageCar(EntityIndex entity) const {
2598
return isInsideTrainCar(entity, kCarBaggage) && getData(entity)->entityPosition < kPosition_4500;
2601
bool Entities::isInKronosSanctum(EntityIndex entity) const {
2602
return isInsideTrainCar(entity, kCarKronos)
2603
&& getData(entity)->entityPosition >= kPosition_3500
2604
&& getData(entity)->entityPosition <= kPosition_5500;
2607
bool Entities::isInKronosCarEntrance(EntityIndex entity) const {
2608
return isInsideTrainCar(entity, kCarKronos) && getData(entity)->entityPosition > kPosition_7900;
2611
bool Entities::checkDistanceFromPosition(EntityIndex entity, EntityPosition position, int distance) const {
2612
return distance >= ABS(getData(entity)->entityPosition - position);
2615
bool Entities::isWalkingOppositeToPlayer(EntityIndex entity) const {
2616
if (getData(entity)->direction == kDirectionUp && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
2619
return (getData(entity)->direction == kDirectionDown && getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp));
2622
bool Entities::isFemale(EntityIndex entity) {
2623
return (entity == kEntityAnna
2624
|| entity == kEntityTatiana
2625
|| entity == kEntityVesna
2626
|| entity == kEntityKahina
2627
|| entity == kEntityMmeBoutarel
2628
|| entity == kEntityRebecca
2629
|| entity == kEntitySophie
2630
|| entity == kEntityYasmin
2631
|| entity == kEntityHadija
2632
|| entity == kEntityAlouan);
2635
bool Entities::isMarried(EntityIndex entity) {
2636
return (entity != kEntityTatiana
2637
&& entity != kEntityRebecca
2638
&& entity != kEntitySophie);
2641
bool Entities::checkPosition(EntityPosition position) const {
2642
Position position1 = 0;
2643
Position position2 = 0;
2649
case kPosition_1500:
2654
case kPosition_2740:
2659
case kPosition_3050:
2664
case kPosition_4070:
2669
case kPosition_4840:
2674
case kPosition_5790:
2679
case kPosition_6470:
2684
case kPosition_7500:
2689
case kPosition_8200:
2695
if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp) && entityPositions[position1] >= getEntityData(kEntityPlayer)->entityPosition)
2698
return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown) && entityPositions[position2] <= getEntityData(kEntityPlayer)->entityPosition);
2701
bool Entities::checkSequenceFromPosition(EntityIndex entity) const {
2702
FrameInfo *info = getEntityData(entity)->sequence->getFrameInfo((uint16)getEntityData(entity)->currentFrame);
2704
if (getEntityData(entity)->direction == kDirectionUp)
2705
return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp)
2706
&& info->entityPosition + getEntityPositionFromCurrentPosition() > kPosition_8513);
2708
if (getEntityData(entity)->direction == kDirectionDown)
2709
return (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown)
2710
&& info->entityPosition + getEntityPositionFromCurrentPosition() < kPosition_2087);
2715
EntityPosition Entities::getEntityPositionFromCurrentPosition() const {
2716
// Get the scene position first
2717
Position position = getScenes()->get(getState()->scene)->position;
2719
if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingUp))
2720
return (EntityPosition)(entityPositions[position] - kPosition_1430);
2722
if (getScenes()->checkPosition(kSceneNone, SceneManager::kCheckPositionLookingDown))
2723
return (EntityPosition)(entityPositions[position] - kPosition_9020);
2725
return kPositionNone;
2728
void Entities::clearEntitySequenceData(EntityData::EntityCallData *data, EntityDirection direction) const {
2729
getScenes()->removeAndRedraw(&data->frame, false);
2730
getScenes()->removeAndRedraw(&data->frame1, false);
2732
SAFE_DELETE(data->sequence);
2733
SAFE_DELETE(data->sequence2);
2735
data->sequenceName = "";
2736
data->sequenceName2 = "";
2738
data->field_4A9 = false;
2739
data->field_4AA = false;
2740
data->directionSwitch = kDirectionNone;
2742
data->currentFrame = -1;
2743
data->currentFrame2 = 0;
2745
data->direction = direction;
2748
} // End of namespace LastExpress