scummvm/engines/lastexpress/entities/chapters.cpp
2018-09-11 23:14:30 +03:00

1921 lines
60 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "lastexpress/entities/chapters.h"
#include "lastexpress/entities/abbot.h"
#include "lastexpress/entities/alexei.h"
#include "lastexpress/entities/alouan.h"
#include "lastexpress/entities/anna.h"
#include "lastexpress/entities/august.h"
#include "lastexpress/entities/boutarel.h"
#include "lastexpress/entities/coudert.h"
#include "lastexpress/entities/cooks.h"
#include "lastexpress/entities/francois.h"
#include "lastexpress/entities/gendarmes.h"
#include "lastexpress/entities/hadija.h"
#include "lastexpress/entities/ivo.h"
#include "lastexpress/entities/kahina.h"
#include "lastexpress/entities/kronos.h"
#include "lastexpress/entities/mahmud.h"
#include "lastexpress/entities/max.h"
#include "lastexpress/entities/mertens.h"
#include "lastexpress/entities/milos.h"
#include "lastexpress/entities/mmeboutarel.h"
#include "lastexpress/entities/pascale.h"
#include "lastexpress/entities/rebecca.h"
#include "lastexpress/entities/salko.h"
#include "lastexpress/entities/sophie.h"
#include "lastexpress/entities/tatiana.h"
#include "lastexpress/entities/vassili.h"
#include "lastexpress/entities/verges.h"
#include "lastexpress/entities/vesna.h"
#include "lastexpress/entities/waiter1.h"
#include "lastexpress/entities/waiter2.h"
#include "lastexpress/entities/yasmin.h"
#include "lastexpress/game/action.h"
#include "lastexpress/game/entities.h"
#include "lastexpress/game/inventory.h"
#include "lastexpress/game/logic.h"
#include "lastexpress/game/object.h"
#include "lastexpress/game/savepoint.h"
#include "lastexpress/game/scenes.h"
#include "lastexpress/game/state.h"
#include "lastexpress/menu/menu.h"
#include "lastexpress/sound/queue.h"
#include "lastexpress/lastexpress.h"
#include "lastexpress/resource.h"
namespace LastExpress {
Chapters::Chapters(LastExpressEngine *engine) : Entity(engine, kEntityChapters) {
ADD_CALLBACK_FUNCTION_II(Chapters, savegame);
ADD_CALLBACK_FUNCTION_SI(Chapters, enterStation);
ADD_CALLBACK_FUNCTION_S(Chapters, exitStation);
ADD_CALLBACK_FUNCTION(Chapters, chapter1);
ADD_CALLBACK_FUNCTION(Chapters, resetMainEntities);
ADD_CALLBACK_FUNCTION(Chapters, firstDream);
ADD_CALLBACK_FUNCTION(Chapters, chapter1Init);
ADD_CALLBACK_FUNCTION(Chapters, chapter1Handler);
ADD_CALLBACK_FUNCTION(Chapters, chapter1Next);
ADD_CALLBACK_FUNCTION(Chapters, chapter2);
ADD_CALLBACK_FUNCTION(Chapters, chapter2Init);
ADD_CALLBACK_FUNCTION(Chapters, chapter2Handler);
ADD_CALLBACK_FUNCTION(Chapters, chapter3);
ADD_CALLBACK_FUNCTION(Chapters, chapter3Init);
ADD_CALLBACK_FUNCTION(Chapters, chapter3Handler);
ADD_CALLBACK_FUNCTION(Chapters, viennaEvents);
ADD_CALLBACK_FUNCTION(Chapters, chapter4);
ADD_CALLBACK_FUNCTION(Chapters, chapter4Init);
ADD_CALLBACK_FUNCTION(Chapters, chapter4Handler);
ADD_CALLBACK_FUNCTION(Chapters, chapter5);
ADD_CALLBACK_FUNCTION(Chapters, chapter5Init);
ADD_CALLBACK_FUNCTION(Chapters, chapter5Handler);
}
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION_II(1, Chapters, savegame, SavegameType, uint32)
Entity::savegame(savepoint);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION_SI(2, Chapters, enterStation, CityIndex)
enterExitStation(savepoint, true);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION_S(3, Chapters, exitStation)
enterExitStation(savepoint, false);
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(4, Chapters, chapter1)
if (savepoint.action == kActionDefault) {
getSavePoints()->addData(kEntityChapters, kAction171843264, 0);
setup_chapter1Init();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(5, Chapters, resetMainEntities)
if (savepoint.action != kActionDefault)
return;
RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_reset);
RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_reset);
RESET_ENTITY_STATE(kEntityAlouan, Alouan, setup_reset);
RESET_ENTITY_STATE(kEntityAnna, Anna, setup_reset);
RESET_ENTITY_STATE(kEntityAugust, August, setup_reset);
RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_reset);
RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_reset);
RESET_ENTITY_STATE(kEntityFrancois, Francois, setup_reset);
RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_reset);
RESET_ENTITY_STATE(kEntityIvo, Ivo, setup_reset);
RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_reset);
RESET_ENTITY_STATE(kEntityKronos, Kronos, setup_reset);
RESET_ENTITY_STATE(kEntityMmeBoutarel, MmeBoutarel, setup_reset);
RESET_ENTITY_STATE(kEntityMahmud, Mahmud, setup_reset);
RESET_ENTITY_STATE(kEntityMax, Max, setup_reset);
RESET_ENTITY_STATE(kEntityMilos, Milos, setup_reset);
RESET_ENTITY_STATE(kEntityBoutarel, Boutarel, setup_reset);
RESET_ENTITY_STATE(kEntityGendarmes, Gendarmes, setup_reset);
RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_reset);
RESET_ENTITY_STATE(kEntitySalko, Salko, setup_reset);
RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_reset);
RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_reset);
RESET_ENTITY_STATE(kEntityVerges, Verges, setup_reset);
RESET_ENTITY_STATE(kEntityVassili, Vassili, setup_reset);
RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_reset);
RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_reset);
callbackAction();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(6, Chapters, firstDream)
// Chapter 1 end
switch (savepoint.action) {
default:
break;
case kActionEndSound:
getSound()->playSound(kEntityChapters, "MUS009", kFlagDefault);
break;
case kActionKnock:
if (!getSoundQueue()->isBuffered("LIB012", true))
getSound()->playSound(kEntityPlayer, "LIB012");
break;
case kActionOpenDoor:
if (params->param1) {
getEntities()->clearSequences(kEntityChapters);
getSoundQueue()->processEntry(kEntityChapters);
getSound()->playSound(kEntityPlayer, "LIB014");
getSoundQueue()->resetState();
ENTITY_PARAM(0, 4) = 7;
getSound()->playSteam(kCityPolice);
getAction()->playAnimation(kEventCathDream);
getState()->timeDelta = 3;
getProgress().field_18 = 1;
getProgress().field_84 = 0;
getObjects()->update(kObject63, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getScenes()->loadScene(kScene41);
callbackAction();
} else {
getSound()->playSound(kEntityPlayer, "LIB014");
getSound()->playSound(kEntityPlayer, "LIB015", kFlagDefault, 15);
if (!getSoundQueue()->isBuffered(kEntityChapters))
getSound()->playSound(kEntityChapters, "MUS009", kFlagDefault);
getScenes()->loadSceneFromPosition(kCarLocomotive, 38);
getObjects()->update(kObject63, kEntityChapters, kObjectLocationNone, kCursorHandKnock, kCursorHand);
params->param1 = 1;
}
break;
case kActionDefault:
RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_function19);
RESET_ENTITY_STATE(kEntityWaiter1, Waiter1, setup_function22);
RESET_ENTITY_STATE(kEntityWaiter2, Waiter2, setup_function16);
RESET_ENTITY_STATE(kEntityCooks, Cooks, setup_lockUp);
RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function42);
RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_chapter1Handler);
RESET_ENTITY_STATE(kEntityVerges, Verges, setup_chapter1Handler);
getSavePoints()->push(kEntityChapters, kEntityMertens, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
RESET_ENTITY_STATE(kEntityKronos, Kronos, setup_function10);
RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_cathDone);
RESET_ENTITY_STATE(kEntityAnna, Anna, setup_asleep);
RESET_ENTITY_STATE(kEntityAugust, August, setup_function34);
RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function24);
RESET_ENTITY_STATE(kEntityVassili, Vassili, setup_function7);
RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function26);
RESET_ENTITY_STATE(kEntityMilos, Milos, setup_function18);
RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_function15);
RESET_ENTITY_STATE(kEntityIvo, Ivo, setup_function17);
RESET_ENTITY_STATE(kEntitySalko, Salko, setup_function11);
RESET_ENTITY_STATE(kEntityFrancois, Francois, setup_function20);
RESET_ENTITY_STATE(kEntityMmeBoutarel, MmeBoutarel, setup_function16);
RESET_ENTITY_STATE(kEntityBoutarel, Boutarel, setup_function22);
RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_function27);
RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_function5);
RESET_ENTITY_STATE(kEntityMahmud, Mahmud, setup_resetChapter);
RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_function10);
RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_function12);
RESET_ENTITY_STATE(kEntityHadija, Alouan, setup_function12);
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
getSoundQueue()->processEntries();
if (getSoundQueue()->isBuffered("CON1505"))
getSoundQueue()->processEntry("CON1505");
if (getSoundQueue()->isBuffered("AUG1057"))
getSoundQueue()->processEntry("AUG1057");
if (getSoundQueue()->isBuffered("ZFX1005"))
getSoundQueue()->processEntry("ZFX1005");
else if (getSoundQueue()->isBuffered("ZFX1006"))
getSoundQueue()->processEntry("ZFX1006");
else if (getSoundQueue()->isBuffered("ZFX1007"))
getSoundQueue()->processEntry("ZFX1007");
else if (getSoundQueue()->isBuffered("ZFX1007A"))
getSoundQueue()->processEntry("ZFX1007A");
else if (getSoundQueue()->isBuffered("ZFX1007B"))
getSoundQueue()->processEntry("ZFX1007B");
getSound()->playSound(kEntityPlayer, "MUS008", kFlagDefault);
getInventory()->unselectItem();
// TODO: fade to black screen
// FIXME add event pump ?
while (getSoundQueue()->isBuffered("MUS008"))
getSoundQueue()->updateQueue();
getProgress().field_84 = true;
getScenes()->loadSceneFromPosition(kCarLocomotive, 75);
getInventory()->show();
getState()->time = kTime1492200;
getProgress().field_18 = 4;
getState()->timeDelta = 0;
getObjects()->update(kObject63, kEntityChapters, kObjectLocationNone, kCursorNormal, kCursorHand);
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
getProgress().isTrainRunning = false;
setCallback(1);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kAction225358684:
params->param2++;
if (params->param2 >= 3) {
if (!getSoundQueue()->isBuffered("LIB031", true))
getSound()->playSound(kEntityPlayer, "LIB031");
if (params->param2 == 3) {
getData()->car = kCarLocomotive;
getEntities()->drawSequenceLeft(kEntityChapters, "JUGL");
}
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(7, Chapters, chapter1Init)
if (savepoint.action != kActionDefault)
return;
getProgress().chapter = kChapter1;
getSoundQueue()->resetState();
getState()->time = kTimeStartGame;
getState()->timeDelta = 0;
getProgress().isTrainRunning = true;
getProgress().portrait = kPortraitOriginal;
getProgress().field_18 = 1;
// Setup inventory & items location
getInventory()->addItem(kItemTelegram);
getInventory()->addItem(kItemArticle);
getInventory()->setLocationAndProcess(kItemScarf, kObjectLocation1);
getInventory()->setLocationAndProcess(kItemParchemin, kObjectLocation1);
getInventory()->setLocationAndProcess(kItemGreenJacket, kObjectLocation1);
getInventory()->setLocationAndProcess(kItemCorpse, kObjectLocation1);
getInventory()->setLocationAndProcess(kItemPassengerList, kObjectLocation1);
getInventory()->setLocationAndProcess(kItem5, kObjectLocation1);
getInventory()->setLocationAndProcess(kItem7, kObjectLocation1);
getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
getInventory()->setLocationAndProcess(kItemMatch, kObjectLocation1);
getInventory()->setLocationAndProcess(kItem22, kObjectLocation1);
getInventory()->setLocationAndProcess(kItemPaper, kObjectLocation1);
getProgress().field_7C = 1;
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
for (uint i = kObjectCompartment1; i <= kObjectCompartment8; i++) {
getObjects()->updateModel((ObjectIndex) i, kObjectModel2);
}
for (uint i = kObjectCompartmentA; i <= kObjectCompartmentH; i++) {
getObjects()->updateModel((ObjectIndex) i, kObjectModel2);
}
params->param1 = 40;
getObjects()->updateModel(kObject25, kObjectModel1);
getObjects()->updateModel(kObjectTrainTimeTable, kObjectModel1);
getObjects()->updateModel(kObject98, kObjectModel1);
getObjects()->updateModel(kObjectRestaurantCar, kObjectModel1);
getObjects()->update(kObject25, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObjectTrainTimeTable, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObjectRedSleepingCar, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject28, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject56, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject54, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObjectRestaurantCar, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject59, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject66, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject64, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject65, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject69, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObject98, kEntityPlayer, kObjectLocationNone, kCursorNormal, kCursorForward);
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObject101, kEntityPlayer, kObjectLocation1, kCursorHandKnock, kCursorHand);
setup_chapter1Handler();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler)
// Moving at night
switch (savepoint.action) {
default:
break;
case kActionNone:
if (!getProgress().isTrainRunning || getState()->time >= kTime1458000)
goto label_processStations;
if (Entity::updateParameter(params->param6, getState()->timeTicks, params->param2)) {
// Play sound FX
getSound()->playLocomotiveSound();
params->param2 = 225 * (4 * rnd(5) + 20);
params->param6 = 0;
}
label_processStations:
// Process stations
if (getState()->time > kTime1039500 && !params->param7) {
params->param7 = 1;
setCallback(1);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
}
label_enter_epernay:
// Entering Epernay station
if (timeCheckEnterStation(kTimeEnterEpernay, params->param8, 2, "Epernay", kCityEpernay))
break;
label_exit_epernay:
// Exiting Epernay station
if (getState()->time > kTimeExitEpernay && !CURRENT_PARAM(1, 1)) {
CURRENT_PARAM(1, 1) = 1;
params->param4 = 1;
setCallback(3);
setup_exitStation("Epernay");
break;
}
label_epernay_police:
if (params->param5 && !ENTITY_PARAM(0, 2)) {
setCallback(4);
setup_exitStation("Unschedu");
break;
}
label_enter_chalons:
if (getState()->time > kTimeEnterChalons && !CURRENT_PARAM(1, 2)) {
CURRENT_PARAM(1, 2) = 1;
getProgress().field_18 = 2;
}
// Skip to callback 18 checks
if (params->param1)
goto label_exit_strasbourg;
// Entering Chalons station
if (timeCheckEnterStation(kTimeEnterChalons, CURRENT_PARAM(1, 3), 5, "Chalons", kCityChalons))
break;
label_exit_chalons:
// Exiting Chalons station
if (timeCheckExitStation(kTimeExitChalons, CURRENT_PARAM(1, 4), 6, "Chalons"))
break;
label_enter_barleduc:
// Entering Bar-Le-Duc station
if (timeCheckEnterStation(kTimeCityBarLeDuc, CURRENT_PARAM(1, 5), 7, "BarLeDuc", kCityBarleduc))
break;
label_exit_barleduc:
// Exiting Bar-Le-Duc station
if (timeCheckExitStation(kTimeExitBarLeDuc, CURRENT_PARAM(1, 6), 8, "BarLeDuc"))
break;
label_enter_nancy:
if (getState()->time > kTime1260000 && !CURRENT_PARAM(1, 7)) {
CURRENT_PARAM(1, 7) = 1;
getState()->timeDelta = 1;
}
// Entering Nancy station
if (timeCheckEnterStation(kTimeCityNancy, CURRENT_PARAM(1, 8), 9, "Nancy", kCityNancy))
break;
label_exit_nancy:
// Exiting Nancy station
if (timeCheckExitStation(kTimeExitNancy, CURRENT_PARAM(2, 1), 10, "Nancy"))
break;
label_enter_luneville:
// Entering Luneville station
if (timeCheckEnterStation(kTimeCityLuneville, CURRENT_PARAM(2, 2), 11, "Luneville", kCityLuneville))
break;
label_exit_luneville:
// Exiting Luneville station
if (timeCheckExitStation(kTimeExitLuneville, CURRENT_PARAM(2, 3), 12, "Luneville"))
break;
label_enter_avricourt:
// Entering Avricourt station
if (timeCheckEnterStation(kTimeCityAvricourt, CURRENT_PARAM(2, 4), 13, "Avricourt", kCityAvricourt))
break;
label_exit_avricourt:
// Exiting Avricourt station
if (timeCheckExitStation(kTimeExitAvricourt, CURRENT_PARAM(2, 5), 14, "Avricourt"))
break;
label_enter_deutschavricourt:
// Entering Deutsch-Avricourt station
if (timeCheckEnterStation(kTimeCityDeutschAvricourt, CURRENT_PARAM(2, 6), 15, "DeutschA", kCityDeutschAvricourt))
break;
label_exit_deutschavricourt:
// Exiting Avricourt station
if (timeCheckExitStation(kTimeExitDeutschAvricourt, CURRENT_PARAM(2, 7), 16, "DeutschA"))
break;
label_enter_strasbourg:
if (getState()->time > kTimeCityStrasbourg && !CURRENT_PARAM(2, 8)) {
CURRENT_PARAM(2, 8) = 1;
setCallback(17);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
}
label_exit_strasbourg:
// Exiting Strasbourg station
if (timeCheckExitStation(kTimeExitStrasbourg, CURRENT_PARAM(3, 1), 19, "Strasbou"))
break;
label_enter_badenoos:
// Entering Baden Oos station
if (timeCheckEnterStation(kTimeCityBadenOos, CURRENT_PARAM(3, 2), 20, "BadenOos", kCityBadenOos))
break;
label_exit_badenoos:
// Exiting Baden Oos station
if (timeCheckExitStation(kTimeExitBadenOos, CURRENT_PARAM(3, 3), 21, "BadenOos"))
break;
label_chapter1_next:
if (getState()->time > kTimeChapter1End3 && ! CURRENT_PARAM(3, 4)) {
CURRENT_PARAM(3, 4) = 1;
setup_chapter1Next();
}
break;
case kActionEndSound:
if (ENTITY_PARAM(0, 2)) {
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
playSteam();
break;
}
if (getEntities()->isOutsideAlexeiWindow()) {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
playSteam();
break;
}
if (getEntities()->isOutsideAnnaWindow()) {
getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
playSteam();
break;
}
CarIndex car = getEntityData(kEntityPlayer)->car;
if (car < kCarRedSleeping || car > kCarCoalTender) {
if (car < kCarBaggageRear || car > kCarGreenSleeping) {
playSteam();
break;
}
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
playSteam();
break;
}
if (ENTITY_PARAM(0, 3)) {
getSoundQueue()->resetState();
ENTITY_PARAM(0, 3) = 0;
if (params->param4) {
getSavePoints()->push(kEntityChapters, getProgress().field_24 ? kEntityVerges : kEntityMertens, getProgress().field_24 ? kAction168187490 : kAction224122407);
params->param4 = 0;
}
}
break;
case kActionDefault:
params->param2 = 225 * (4 * rnd(5) + 20);
break;
case kActionDrawScene:
if (!params->param3) {
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 1)) {
getState()->time = kTimeChapter1;
getState()->timeDelta = 3;
params->param3 = 1;
}
}
break;
case kActionCallback:
switch (getCallback()) {
default:
break;
case 1:
goto label_enter_epernay;
case 2:
goto label_exit_epernay;
case 3:
goto label_epernay_police;
case 4:
params->param5 = 0;
goto label_enter_chalons;
case 5:
goto label_exit_chalons;
case 6:
goto label_enter_barleduc;
case 7:
goto label_exit_barleduc;
case 8:
goto label_enter_nancy;
case 9:
goto label_exit_nancy;
case 10:
goto label_enter_luneville;
case 11:
goto label_exit_luneville;
case 12:
goto label_enter_avricourt;
case 13:
goto label_exit_avricourt;
case 14:
goto label_enter_deutschavricourt;
case 15:
goto label_exit_deutschavricourt;
case 16:
getState()->time = kTimeEnterStrasbourg;
goto label_enter_strasbourg;
case 17:
getProgress().field_18 = 1;
setCallback(18);
setup_enterStation("Strasbou", kCityStrasbourg);
break;
case 18:
goto label_exit_strasbourg;
case 19:
getState()->timeDelta = 1;
goto label_enter_badenoos;
case 20:
goto label_exit_badenoos;
case 21:
goto label_chapter1_next;
case 22:
params->param5 = 1;
break;
case 23:
params->param1 = 1;
break;
}
break;
case kAction169629818:
setCallback(22);
setup_enterStation("Unschedu", kCityPolice);
break;
case kActionEndChapter:
getProgress().field_18 = 3;
if (getState()->time >= kTimeChapter1End) {
setup_chapter1Next();
} else {
setCallback(23);
setup_firstDream();
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(9, Chapters, chapter1Next)
if (savepoint.action == kActionDefault) {
// Reset sound cache
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
getSound()->playSound(kEntityPlayer, "MUS008", kFlagDefault);
getInventory()->unselectItem();
// TODO: fade to black screen
while (getSoundQueue()->isBuffered("MUS008"))
getSoundQueue()->updateQueue();
setup_chapter2();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(10, Chapters, chapter2)
switch (savepoint.action) {
default:
break;
case kActionDefault:
// Setup for chapter 2 in case it hasn't been done before
if (getProgress().chapter != kChapter2) {
getProgress().chapter = kChapter2;
getEntities()->setupChapter(kChapter2);
}
// Set game time & delta
getState()->time = kTimeChapter2;
getState()->timeDelta = 5;
// Save game
setCallback(1);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kActionCallback:
if (getCallback() == 1) {
if (!_engine->getResourceManager()->loadArchive(kArchiveCd2)) {
getMenu()->show(false, kSavegameTypeIndex, 0);
return;
}
// Load scene data
getScenes()->loadSceneDataFile(kArchiveCd2);
setup_chapter2Init();
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(11, Chapters, chapter2Init)
if (savepoint.action != kActionDefault)
return;
getProgress().eventCorpseMovedFromFloor = true;
getProgress().field_18 = 1;
getProgress().isTrainRunning = true;
getProgress().eventCorpseFound = true;
// Switch to green jacket/portrait
getProgress().jacket = kJacketGreen;
getProgress().portrait = kPortraitGreen;
// Setup inventory & items location
getInventory()->addItem(kItemGreenJacket);
getInventory()->get(kItemCorpse)->location = kObjectLocationNone;
getInventory()->get(kItemCorpse)->inPocket = false;
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getInventory()->setLocationAndProcess(kItemBeetle, kObjectLocation3);
getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
for (uint i = 1; i < 9; i++) {
getObjects()->updateModel((ObjectIndex) i, kObjectModel2);
}
for (uint i = 33; i < 40; i++) {
getObjects()->updateModel((ObjectIndex) i, kObjectModel2);
}
params->param1 = 40;
getSavePoints()->push(kEntityChapters, kEntityTables0, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables1, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables2, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables3, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables4, kActionDrawTablesWithChairs);
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectOutsideTylerCompartment, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
// Reset sound cache
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
getAction()->playAnimation(kEventTrainPassing);
if (getInventory()->hasItem(kItemScarf))
getScenes()->loadScene(kScene41);
else
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 79);
setup_chapter2Handler();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(12, Chapters, chapter2Handler)
switch (savepoint.action) {
default:
break;
case kActionNone:
if (!getProgress().isTrainRunning)
break;
if (!Entity::updateParameter(params->param2, getState()->timeTicks, params->param1))
break;
getSound()->playLocomotiveSound();
params->param1 = 225 * (4 * rnd(5) + 20);
params->param2 = 0;
break;
case kActionDefault:
params->param1 = 225 * (4 * rnd(5) + 20);
break;
case kActionChapter3:
setup_chapter3();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(13, Chapters, chapter3)
if (savepoint.action == kActionDefault) {
// Setup for chapter 3 in case it hasn't been done before
if (getProgress().chapter != kChapter3) {
getProgress().chapter = kChapter3;
getEntities()->setupChapter(kChapter3);
}
// Set game time & delta
getState()->time = kTimeChapter3;
getState()->timeDelta = 5;
setup_chapter3Init();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(14, Chapters, chapter3Init)
switch (savepoint.action) {
default:
break;
case kActionDefault:
getSavePoints()->push(kEntityChapters, kEntityTables0, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables1, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables2, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables3, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables4, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables5, kActionDrawTablesWithChairs);
getProgress().isTrainRunning = true;
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getInventory()->setLocationAndProcess(kItemBriefcase, kObjectLocation1);
getInventory()->setLocationAndProcess(kItem3, kObjectLocation1);
getObjects()->updateModel(kObjectCompartment1, kObjectModel2);
getObjects()->update(kObject107, kEntityPlayer, kObjectLocation3, kCursorKeepValue, kCursorKeepValue);
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
// TODO: fade to black screen
getScenes()->loadSceneFromPosition(kCarRestaurant, 60);
getInventory()->show();
setCallback(1);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kActionCallback:
if (getCallback() == 1)
setup_chapter3Handler();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler)
// Moving during the afternoon
switch (savepoint.action) {
default:
break;
case kActionNone:
if (getProgress().isTrainRunning) {
if (Entity::updateParameter(params->param4, getState()->timeTicks, params->param1)) {
getSound()->playLocomotiveSound();
params->param1 = 225 * (4 * rnd(5) + 20);
params->param4 = 0;
}
}
if (Entity::updateParameter(params->param5, getState()->timeTicks, params->param2)) {
switch (rnd(2)) {
default:
break;
case 0:
getSound()->playSound(kEntityPlayer, "ZFX1008", (SoundFlag)(rnd(15) + 2));
break;
case 1:
getSound()->playSound(kEntityPlayer, "ZFX1009", (SoundFlag)(rnd(15) + 2));
break;
}
params->param2 = 225 * (4 * rnd(6) + 8);
params->param5 = 0;
}
if (timeCheckEnterStation(kTimeEnterSalzbourg, params->param6, 1, "Salzburg", kCitySalzbourg))
break;
label_callback_1:
if (timeCheckExitStation(kTimeExitSalzbourg, params->param7, 2, "Salzburg"))
break;
label_callback_2:
if (timeCheckEnterStation(kTimeEnterAttnangPuchheim, params->param8, 3, "Attnang", kCityAttnangPuchheim))
break;
label_callback_3:
if (timeCheckExitStation(kTimeExitAttnangPuchheim, CURRENT_PARAM(1, 1), 4, "Attnang"))
break;
label_callback_4:
if (timeCheckEnterStation(kTimeEnterWels, CURRENT_PARAM(1, 2), 5, "Wels", kCityWels))
break;
label_callback_5:
if (timeCheckExitStation(kTimeExitWels, CURRENT_PARAM(1, 3), 6, "Wels"))
break;
label_callback_6:
if (timeCheckEnterStation(kTimeEnterLinz, CURRENT_PARAM(1, 4), 7, "Linz", kCityLinz))
break;
label_callback_7:
if (timeCheckExitStation(kTimeExitLinz, CURRENT_PARAM(1, 5), 8, "Linz"))
break;
label_callback_8:
if (getState()->time > kTime2187000 && !CURRENT_PARAM(1, 6)) {
CURRENT_PARAM(1, 6) = 1;
getState()->timeDelta = 5;
}
timeCheckEnterStation(kTimeCityVienna, CURRENT_PARAM(1, 7), 9, "Vienna", kCityVienna);
break;
case kActionEndSound:
if (ENTITY_PARAM(0, 2)) {
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
if (getEntityData(kEntityPlayer)->location == kLocationOutsideTrain) {
if (getEntities()->isOutsideAlexeiWindow()) {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
} else if (getEntities()->isOutsideAnnaWindow()) {
getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
} else {
CarIndex car = getEntityData(kEntityPlayer)->car;
if (car < kCarRedSleeping || car > kCarCoalTender) {
if (car >= kCarBaggageRear && car <= kCarGreenSleeping) {
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
} else {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
}
}
} else {
getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
}
}
}
getSoundQueue()->resetState();
getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4));
ENTITY_PARAM(0, 2) = 0;
if (params->param3)
setup_viennaEvents();
break;
}
if (ENTITY_PARAM(0, 3)) {
getSoundQueue()->resetState();
ENTITY_PARAM(0, 3) = 0;
}
break;
case kActionDefault:
params->param1 = 225 * (4 * rnd(5) + 20);
params->param2 = 225 * (4 * rnd(6) + 8);
break;
case kActionCallback:
switch (getCallback()) {
default:
break;
case 1:
goto label_callback_1;
case 2:
goto label_callback_2;
case 3:
goto label_callback_3;
case 4:
goto label_callback_4;
case 5:
goto label_callback_5;
case 6:
goto label_callback_6;
case 7:
goto label_callback_7;
case 8:
goto label_callback_8;
case 9:
params->param3 = 1;
break;
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(16, Chapters, viennaEvents)
// End in Vienna
switch (savepoint.action) {
default:
break;
case kActionDefault:
getEntityData(kEntityPlayer)->car = kCarLocomotive;
if (getSoundQueue()->isBuffered(kEntityAbbot))
getSoundQueue()->processEntry(kEntityAbbot);
if (!getEvent(kEventAugustBringBriefcase)) {
setCallback(1);
setup_savegame(kSavegameTypeEvent, kEventViennaAugustUnloadGuns);
break;
}
if (getInventory()->get(kItemFirebird)->location == kObjectLocation5) {
setCallback(2);
setup_savegame(kSavegameTypeEvent, kEventViennaKronosFirebird);
break;
}
if (ENTITY_PARAM(0, 1)) {
setCallback(3);
setup_savegame(kSavegameTypeEvent, kEventVergesAnnaDead);
break;
}
setCallback(4);
setup_savegame(kSavegameTypeEvent, kEventViennaContinueGame);
break;
case kActionCallback:
switch (getCallback()) {
default:
break;
case 1:
getAction()->playAnimation(kEventViennaAugustUnloadGuns);
if (getEvent(kEventConcertLeaveWithBriefcase))
getLogic()->gameOver(kSavegameTypeTime, kTime2187000, kSceneNone, true);
else if (getEvent(kEventCathJumpDownCeiling))
getLogic()->gameOver(kSavegameTypeEvent, kEventCathJumpDownCeiling, kSceneNone, true);
else
getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneNone, true);
break;
case 2:
getAction()->playAnimation(kEventViennaKronosFirebird);
if (getEvent(kEventKronosBringEggCeiling))
getLogic()->gameOver(kSavegameTypeEvent2, kEventKronosBringEggCeiling, kSceneGameOverVienna1, true);
else if (getEvent(kEventKronosBringEgg)) {
getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneGameOverVienna1, true);
} else {
if (getProgress().field_C0) {
if (getEvent(kEventKronosReturnBriefcase))
getLogic()->gameOver(kSavegameTypeTime, getProgress().field_C0, kSceneGameOverVienna2, true);
else
getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneGameOverVienna2, true);
} else {
if (getEvent(kEventKronosReturnBriefcase))
getLogic()->gameOver(kSavegameTypeEvent, kEventKronosReturnBriefcase, kSceneGameOverVienna, true);
else
getLogic()->gameOver(kSavegameTypeTime, kTime2155500, kSceneGameOverVienna, true);
}
}
break;
case 3:
getAction()->playAnimation(kEventVergesAnnaDead);
getLogic()->gameOver(kSavegameTypeTime, kTime2250000, kSceneGameOverAnnaDied, true);
break;
case 4:
getAction()->playAnimation(kEventViennaContinueGame);
setup_chapter4();
break;
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(17, Chapters, chapter4)
switch (savepoint.action) {
default:
break;
case kActionDefault:
// Setup for chapter 4 in case it hasn't been done before
if (getProgress().chapter != kChapter4) {
getProgress().chapter = kChapter4;
getEntities()->setupChapter(kChapter4);
}
// Set game time & delta
getState()->time = kTimeChapter4;
getState()->timeDelta = 5;
// Save game
setCallback(1);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kActionCallback:
if (getCallback() == 1) {
if (!_engine->getResourceManager()->loadArchive(kArchiveCd3)) {
getMenu()->show(false, kSavegameTypeIndex, 0);
return;
}
// Load scene data
getScenes()->loadSceneDataFile(kArchiveCd3);
setup_chapter4Init();
}
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(18, Chapters, chapter4Init)
if (savepoint.action != kActionDefault)
return;
getSoundQueue()->processEntries();
getSoundQueue()->resetState();
getProgress().isTrainRunning = true;
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStartRunning);
getSavePoints()->push(kEntityChapters, kEntityTables0, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables1, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables2, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables3, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables4, kActionDrawTablesWithChairs);
getSavePoints()->push(kEntityChapters, kEntityTables5, kActionDrawTablesWithChairs);
getScenes()->loadSceneFromItemPosition(kItem3);
getInventory()->setLocationAndProcess(kItemBomb, kObjectLocation1);
if (getInventory()->get(kItemBeetle)->location == kObjectLocation3)
getScenes()->loadSceneFromItemPosition(kItemBeetle);
getObjects()->updateModel(kObject25, kObjectModel2);
getObjects()->update(kObject107, kEntityPlayer, kObjectLocation3, kCursorKeepValue, kCursorKeepValue);
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
// TODO: fade to black screen
if (getInventory()->hasItem(kItemFirebird))
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 76);
else
getScenes()->loadSceneFromPosition(kCarRestaurant, 69);
getInventory()->show();
setup_chapter4Handler();
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler)
// Moving during the second night
switch (savepoint.action) {
default:
break;
case kActionNone:
if (getProgress().isTrainRunning) {
if (Entity::updateParameter(params->param6, getState()->timeTicks, params->param4)) {
getSound()->playLocomotiveSound();
params->param4 = 225 * (4 * rnd(5) + 20);
params->param6 = 0;
}
}
if (Entity::updateParameter(params->param7, getState()->timeTicks, params->param5)) {
switch (rnd(2)) {
default:
break;
case 0:
getSound()->playSound(kEntityPlayer, "ZFX1008", (SoundFlag)(rnd(15) + 2));
break;
case 1:
getSound()->playSound(kEntityPlayer, "ZFX1009", (SoundFlag)(rnd(15) + 2));
break;
}
params->param5 = 225 * (4 * rnd(6) + 8);
params->param7 = 0;
}
if (timeCheckEnterStation(kTimeEnterPoszony, params->param8, 1, "Pozsony", kCityPoszony))
break;
label_exitPozsony:
if (timeCheckExitStation(kTimeExitPoszony, CURRENT_PARAM(1, 1), 2, "Pozsony"))
break;
label_enterGalanta:
if (getObjects()->get(kObjectCompartment1).model == kObjectModel1) {
if (getState()->time > kTime2403000 && !CURRENT_PARAM(1, 2)) {
CURRENT_PARAM(1, 2) = 1;
getProgress().field_18 = 2;
}
}
if (params->param1)
goto label_callback_4;
if (timeCheckEnterStation(kTimeEnterGalanta, CURRENT_PARAM(1, 3), 3, "Galanta", kCityGalanta))
break;
label_exitGalanta:
if (timeCheckExitStation(kTimeExitGalanta, CURRENT_PARAM(1, 4), 4, "Galanta"))
break;
label_callback_4:
if (getState()->time > kTime2470500 && !CURRENT_PARAM(1, 5)) {
CURRENT_PARAM(1, 5) = 1;
if (getProgress().field_18 == 2)
getState()->timeDelta = 1;
}
if (getState()->time > kTime2506500 && !CURRENT_PARAM(1, 6)) {
CURRENT_PARAM(1, 6) = 1;
if (getProgress().field_18 == 2)
getProgress().field_18 = 1;
}
if (getState()->time > kTime2520000 && !CURRENT_PARAM(1, 7)) {
CURRENT_PARAM(1, 7) = 1;
if (!params->param2 && !params->param3) {
setCallback(5);
setup_savegame(kSavegameTypeEvent, kEventTrainExplosionBridge);
}
}
break;
case kActionEndSound:
if (ENTITY_PARAM(0, 2)) {
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
playSteam();
break;
}
if (getEntities()->isOutsideAlexeiWindow()) {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
playSteam();
break;
}
if (getEntities()->isOutsideAnnaWindow()) {
getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
playSteam();
break;
}
CarIndex car = getEntityData(kEntityPlayer)->car;
if (car < kCarRedSleeping || car > kCarCoalTender) {
if (car < kCarBaggageRear || car > kCarGreenSleeping) {
playSteam();
break;
}
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
playSteam();
break;
}
getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
playSteam();
break;
}
if (ENTITY_PARAM(0, 3)) {
getSoundQueue()->resetState();
ENTITY_PARAM(0, 3) = 0;
} else if (!params->param2 && !params->param3) {
getSound()->playSound(kEntityChapters, "ZFX1001");
}
break;
case kActionExitCompartment:
getEntities()->clearSequences(kEntityChapters);
setCallback(11);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kActionDefault:
params->param4 = 225 * (4 * rnd(5) + 20);
params->param5 = 225 * (4 * rnd(6) + 8);
break;
case kActionCallback:
switch (getCallback()) {
default:
break;
case 1:
goto label_exitPozsony;
case 2:
goto label_enterGalanta;
case 3:
goto label_exitGalanta;
case 4:
goto label_callback_4;
case 5:
if (getSoundQueue()->isBuffered(kEntityChapters))
getSoundQueue()->removeFromQueue(kEntityChapters);
getAction()->playAnimation(kEventTrainExplosionBridge);
getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
break;
case 6:
getSoundQueue()->processEntries();
getAction()->playAnimation(kEventTylerCastleDream);
getSoundQueue()->resetState();
getProgress().field_18 = 1;
getScenes()->loadScene(kScene41);
getSavePoints()->push(kEntityChapters, kEntityTatiana, kAction169360385);
getState()->timeDelta = 1;
getState()->time = kTime2511900;
getInventory()->setLocationAndProcess(kItem2, kObjectLocation1);
getScenes()->loadSceneFromItemPosition(kItem22);
getData()->car = kCarRedSleeping;
getData()->entityPosition = kPosition_1500;
getData()->location = kLocationInsideCompartment;
getSound()->playSound(kEntityChapters, "ZFX1001");
break;
case 7:
getAction()->playAnimation(kEventTrainExplosionBridge);
getLogic()->gameOver(kSavegameTypeTime, kTime2430000, kSceneNone, true);
break;
case 8:
getSound()->playSound(kEntityPlayer, "MUS022");
if (getState()->time < kTime2517300)
getState()->time = kTime2517300;
break;
case 9:
getAction()->playAnimation(kEventCathDefusingBomb);
getScenes()->loadSceneFromPosition(kCarRedSleeping, 73);
break;
case 10:
getAction()->playAnimation(kEventDefuseBomb);
RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_afterBomb);
getSavePoints()->push(kEntityChapters, kEntityAnna, kAction191001984);
getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction191001984);
getScenes()->loadSceneFromItemPosition(kItem2);
getInventory()->get(kItem2)->location = kObjectLocationNone;
params->param2 = 1;
getScenes()->loadSceneFromPosition(kCarRedSleeping, 2);
break;
case 11:
getScenes()->loadSceneFromPosition(kCarRedSleeping, 74);
getSound()->playSound(kEntityTrain, "ZFX4001", kFlagDefault);
getLogic()->gameOver(kSavegameTypeIndex, 1, kSceneNone, true);
break;
}
break;
case kActionChapter5:
setup_chapter5();
break;
case kAction156435676:
getSavePoints()->push(kEntityChapters, kEntityTatiana, kAction169360385);
getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
getState()->timeDelta = 1;
getState()->time = kTime2511900;
getInventory()->setLocationAndProcess(kItem2, kObjectLocation1);
getData()->car = kCarRedSleeping;
getData()->entityPosition = kPosition_1500;
getData()->location = kLocationInsideCompartment;
getSound()->playSound(kEntityChapters, "ZFX1001");
break;
case kAction158610240:
setCallback(8);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kAction169300225:
if (getState()->time < kTime2519100)
getState()->time = kTime2519100;
params->param3 = 1;
getEntities()->drawSequenceRight(kEntityChapters, "BOMB");
break;
case kAction190346110:
getProgress().field_18 = 3;
params->param1 = 1;
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
// BUG: the original game fades to black screen twice, before MUS008 starts playing
// (the second call just makes a delay)
getSound()->playSound(kEntityPlayer, "MUS008", kFlagDefault);
getInventory()->unselectItem();
// TODO: fade to black screen
while (getSoundQueue()->isBuffered("MUS008"))
getSoundQueue()->updateQueue();
if (getInventory()->hasItem(kItemBomb)) {
RESET_ENTITY_STATE(kEntityAlexei, Alexei, setup_function47);
RESET_ENTITY_STATE(kEntityAnna, Anna, setup_sulking);
RESET_ENTITY_STATE(kEntityAugust, August, setup_function65);
RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function48);
RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_function53);
RESET_ENTITY_STATE(kEntityWaiter1, Waiter1, setup_serving4);
RESET_ENTITY_STATE(kEntityWaiter2, Waiter2, setup_serving4);
RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_chapter4Handler);
RESET_ENTITY_STATE(kEntityVerges, Verges, setup_chapter4Handler);
RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function49);
RESET_ENTITY_STATE(kEntityAbbot, Abbot, setup_function44);
RESET_ENTITY_STATE(kEntityMilos, Milos, setup_function32);
RESET_ENTITY_STATE(kEntityVesna, Vesna, setup_function27);
RESET_ENTITY_STATE(kEntityIvo, Ivo, setup_function29);
RESET_ENTITY_STATE(kEntitySalko, Salko, setup_function22);
RESET_ENTITY_STATE(kEntityMmeBoutarel, MmeBoutarel, setup_function25);
RESET_ENTITY_STATE(kEntityBoutarel, Boutarel, setup_function35);
RESET_ENTITY_STATE(kEntityRebecca, Rebecca, setup_function45);
RESET_ENTITY_STATE(kEntitySophie, Sophie, setup_function9);
RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_function17);
RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_function19);
RESET_ENTITY_STATE(kEntityAlouan, Alouan, setup_function19);
RESET_ENTITY_STATE(kEntityMax, Max, setup_inCageFriendly);
getSavePoints()->push(kEntityChapters, kEntityAnna, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityMertens, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityWaiter1, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityWaiter2, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityPascale, kAction201431954);
getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954);
setCallback(6);
setup_savegame(kSavegameTypeEvent, kEventTylerCastleDream);
} else {
getState()->time = kTime2520000;
setCallback(7);
setup_savegame(kSavegameTypeEvent, kEventTrainExplosionBridge);
}
break;
case kAction191001984:
getState()->time = kTime2520000;
if (getSoundQueue()->isBuffered(kEntityChapters))
getSoundQueue()->removeFromQueue(kEntityChapters);
getEntities()->clearSequences(kEntityChapters);
getInventory()->removeItem(kItemTelegram);
getState()->timeDelta = 5;
setCallback(10);
setup_savegame(kSavegameTypeEvent, kEventDefuseBomb);
break;
case kAction201959744:
if (getSoundQueue()->isBuffered(kEntityChapters))
getSoundQueue()->removeFromQueue(kEntityChapters);
getSound()->playSound(kEntityTrain, "ZFX4001", kFlagDefault);
getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, true);
break;
case kAction225367984:
setCallback(9);
setup_savegame(kSavegameTypeEvent, kEventCathDefusingBomb);
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(20, Chapters, chapter5)
if (savepoint.action == kActionDefault) {
// Setup for chapter 5 in case it hasn't been done before
if (getProgress().chapter != kChapter5) {
getProgress().chapter = kChapter5;
getEntities()->setupChapter(kChapter5);
}
// Set game time & delta
getState()->time = kTimeChapter5;
getState()->timeDelta = 2;
setup_chapter5Init();
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(21, Chapters, chapter5Init)
switch (savepoint.action) {
default:
break;
case kActionDefault:
getEntities()->clearSequences(kEntityTables0);
getEntities()->clearSequences(kEntityTables1);
getEntities()->clearSequences(kEntityTables2);
getEntities()->clearSequences(kEntityTables3);
getEntities()->clearSequences(kEntityTables4);
getEntities()->clearSequences(kEntityTables5);
getProgress().isTrainRunning = true;
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, kCursorHand);
getObjects()->update(kObjectCompartment1, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment2, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment4, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment5, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment6, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment7, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartment8, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentA, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentB, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentC, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentD, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentE, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentF, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentG, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectCompartmentH, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectHandleBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectHandleInsideBathroom, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectKitchen, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject20, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject21, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject22, kEntityPlayer, kObjectLocation3, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject48, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject49, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject50, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject51, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject52, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObject53, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getProgress().field_18 = 1;
getProgress().field_84 = 1;
getProgress().portrait = kCursorPortraitYellow;
getInventory()->unselectItem();
getInventory()->removeItem(kItemKey);
getInventory()->removeItem(kItemBomb);
getInventory()->removeItem(kItemMatch);
if (getInventory()->hasItem(kItemFirebird)) {
getInventory()->removeItem(kItemFirebird);
getInventory()->setLocationAndProcess(kItemFirebird, kObjectLocation3);
if (getInventory()->hasItem(kItemWhistle)) {
getInventory()->removeItem(kItemWhistle);
getInventory()->setLocationAndProcess(kItemWhistle, kObjectLocation3);
}
}
getObjects()->update(kObject93, kEntityPlayer, kObjectLocation2, kCursorKeepValue, kCursorKeepValue);
getObjects()->update(kObject94, kEntityPlayer, kObjectLocationNone, kCursorKeepValue, kCursorKeepValue);
getObjects()->update(kObject101, kEntityPlayer, kObjectLocationNone, kCursorHandKnock, kCursorHand);
getObjects()->updateModel(kObject98, kObjectModel2);
getObjects()->updateModel(kObjectRestaurantCar, kObjectModel2);
if (ENTITY_PARAM(0, 2) || ENTITY_PARAM(0, 3)) {
getSoundQueue()->removeFromQueue(kEntityChapters);
ENTITY_PARAM(0, 2) = 0;
ENTITY_PARAM(0, 3) = 0;
}
// TODO: fade to black screen
getScenes()->loadSceneFromPosition(kCarBaggageRear, 95);
getInventory()->show();
setCallback(1);
setup_savegame(kSavegameTypeTime, kTimeNone);
break;
case kActionCallback:
if (getCallback() == 1)
setup_chapter5Handler();
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_FUNCTION(22, Chapters, chapter5Handler)
switch (savepoint.action) {
default:
break;
case kActionNone:
if (getState()->time > kTime2907000 && !params->param2) {
params->param2 = 1;
if (!getProgress().isNightTime) {
getSound()->playSound(kEntityChapters, "ARRIVE", kFlag8);
getSoundQueue()->processEntries();
}
}
if (getState()->time > kTimeTrainStopped2 && !params->param3) {
params->param3 = 1;
if (!getEvent(kEventLocomotiveMilosDay) && !getEvent(kEventLocomotiveMilosNight)) {
getSound()->playSound(kEntityChapters, "ARRIVE", kFlag8);
getSoundQueue()->processEntries();
}
}
break;
case kActionEndSound:
if (getState()->time <= kTimeTrainStopped2) {
setCallback(1);
setup_savegame(kSavegameTypeEvent, kEventTrainStopped);
} else {
getLogic()->gameOver(kSavegameTypeTime, kTime2934000, kSceneGameOverTrainStopped, true);
}
break;
case kActionDefault:
params->param1 = 225 * (4 * rnd(10) + 20);
break;
case kActionCallback:
if (getCallback() == 1) {
getAction()->playAnimation(kEventTrainStopped);
getLogic()->gameOver(kSavegameTypeTime, kTimeTrainStopped, kSceneGameOverTrainStopped, true);
}
break;
case kAction135800432:
getProgress().isNightTime = true;
getState()->time = kTime2916000;
if (getSoundQueue()->isBuffered(kEntityChapters))
getSoundQueue()->removeFromQueue(kEntityChapters);
break;
}
IMPLEMENT_FUNCTION_END
//////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////
void Chapters::enterExitStation(const SavePoint &savepoint, bool isEnteringStation) {
if (savepoint.action == kActionDefault) {
if (!ENTITY_PARAM(0, 2) && !ENTITY_PARAM(0, 3)) {
enterExitHelper(isEnteringStation);
return;
}
getSoundQueue()->removeFromQueue(kEntityChapters);
if (!ENTITY_PARAM(0, 2)) {
if (ENTITY_PARAM(0, 3))
ENTITY_PARAM(0, 3) = 0;
enterExitHelper(isEnteringStation);
return;
}
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStopRunning);
if (getEntityData(kEntityPlayer)->location != kLocationOutsideTrain) {
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
return;
}
// Green sleeping car
if (getEntities()->isOutsideAlexeiWindow()) {
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 49);
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
return;
}
// Red sleeping car
if (getEntities()->isOutsideAnnaWindow()) {
getScenes()->loadSceneFromPosition(kCarRedSleeping, 49);
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
return;
}
// Other cars
if (getEntityData(kEntityPlayer)->car < kCarRedSleeping || getEntityData(kEntityPlayer)->car > kCarCoalTender) {
if (getEntityData(kEntityPlayer)->car < kCarBaggageRear || getEntityData(kEntityPlayer)->car > kCarGreenSleeping) {
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
return;
}
if (getEntities()->isPlayerPosition(kCarGreenSleeping, 98)) {
getSound()->playSound(kEntityPlayer, "LIB015");
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 71);
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
return;
}
getScenes()->loadSceneFromPosition(kCarGreenSleeping, 82);
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
return;
}
getScenes()->loadSceneFromPosition(kCarRestaurant, 82);
ENTITY_PARAM(0, 2) = 0;
enterExitHelper(isEnteringStation);
}
}
//////////////////////////////////////////////////////////////////////////
void Chapters::enterExitHelper(bool isEnteringStation) {
EXPOSE_PARAMS(EntityData::EntityParametersSIIS);
getSound()->playSound(kEntityChapters, isEnteringStation ? "ARRIVE" : "DEPART", kFlag8);
getSoundQueue()->processEntries();
getObjects()->update(kObjectHandleOutsideLeft, kEntityPlayer, kObjectLocation1, kCursorNormal, isEnteringStation ? kCursorNormal : kCursorHand);
getObjects()->update(kObjectHandleOutsideRight, kEntityPlayer, kObjectLocation1, kCursorNormal, isEnteringStation ? kCursorNormal : kCursorHand);
getProgress().isTrainRunning = !isEnteringStation;
if (isEnteringStation) {
ENTITY_PARAM(0, 2) = 1;
ENTITY_PARAM(0, 4) = params->param4;
} else {
getSavePoints()->push(kEntityChapters, kEntityTrain, kActionTrainStartRunning);
ENTITY_PARAM(0, 3) = 1;
}
callbackAction();
}
void Chapters::playSteam() const {
getSoundQueue()->resetState();
getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4));
ENTITY_PARAM(0, 2) = 0;
}
bool Chapters::timeCheckEnterStation(TimeValue timeValue, uint &parameter, byte callback, const char *sequence, CityIndex cityIndex) {
if (getState()->time > timeValue && !parameter) {
parameter = 1;
setCallback(callback);
setup_enterStation(sequence, cityIndex);
return true;
}
return false;
}
bool Chapters::timeCheckExitStation(TimeValue timeValue, uint &parameter, byte callback, const char *sequence) {
if (getState()->time > timeValue && !parameter) {
parameter = 1;
setCallback(callback);
setup_exitStation(sequence);
return true;
}
return false;
}
} // End of namespace LastExpress