~ubuntu-branches/ubuntu/raring/scummvm/raring

« back to all changes in this revision

Viewing changes to engines/lastexpress/game/entities.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Moritz Muehlenhoff
  • Date: 2011-05-25 19:02:23 UTC
  • mto: (21.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20110525190223-fiqm0oaec714xk31
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

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