diff options
Diffstat (limited to 'engines/lastexpress/game')
-rw-r--r-- | engines/lastexpress/game/action.cpp | 72 | ||||
-rw-r--r-- | engines/lastexpress/game/beetle.cpp | 14 | ||||
-rw-r--r-- | engines/lastexpress/game/entities.cpp | 28 | ||||
-rw-r--r-- | engines/lastexpress/game/fight.cpp | 1583 | ||||
-rw-r--r-- | engines/lastexpress/game/fight.h | 266 | ||||
-rw-r--r-- | engines/lastexpress/game/inventory.cpp | 19 | ||||
-rw-r--r-- | engines/lastexpress/game/logic.cpp | 29 | ||||
-rw-r--r-- | engines/lastexpress/game/menu.cpp | 1541 | ||||
-rw-r--r-- | engines/lastexpress/game/menu.h | 207 | ||||
-rw-r--r-- | engines/lastexpress/game/object.cpp | 2 | ||||
-rw-r--r-- | engines/lastexpress/game/savegame.cpp | 81 | ||||
-rw-r--r-- | engines/lastexpress/game/savepoint.cpp | 6 | ||||
-rw-r--r-- | engines/lastexpress/game/scenes.cpp | 24 | ||||
-rw-r--r-- | engines/lastexpress/game/sound.cpp | 1951 | ||||
-rw-r--r-- | engines/lastexpress/game/sound.h | 389 | ||||
-rw-r--r-- | engines/lastexpress/game/state.cpp | 2 | ||||
-rw-r--r-- | engines/lastexpress/game/state.h | 2 |
17 files changed, 148 insertions, 6068 deletions
diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp index 7540d18ed8..2ef4c20d70 100644 --- a/engines/lastexpress/game/action.cpp +++ b/engines/lastexpress/game/action.cpp @@ -39,9 +39,11 @@ #include "lastexpress/game/savegame.h" #include "lastexpress/game/savepoint.h" #include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" #include "lastexpress/game/state.h" +#include "lastexpress/sound/queue.h" +#include "lastexpress/sound/sound.h" + #include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -405,7 +407,7 @@ SceneIndex Action::processHotspot(const SceneHotspot &hotspot) { ////////////////////////////////////////////////////////////////////////// // Action 0 IMPLEMENT_ACTION(dummy) - warning("Action::action_dummy: Dummy action function called (hotspot action: %d)!", hotspot.action); + warning("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action); return kSceneInvalid; } @@ -453,7 +455,7 @@ IMPLEMENT_ACTION(savePoint) IMPLEMENT_ACTION(playSound) // Check that the file is not already buffered - if (hotspot.param2 || !getSound()->isBuffered(Common::String::format("LIB%03d", hotspot.param1), true)) + if (hotspot.param2 || !getSoundQueue()->isBuffered(Common::String::format("LIB%03d", hotspot.param1), true)) getSound()->playSoundEvent(kEntityPlayer, hotspot.param1, hotspot.param2); return kSceneInvalid; @@ -465,8 +467,8 @@ IMPLEMENT_ACTION(playMusic) // Check that the file is not already buffered Common::String filename = Common::String::format("MUS%03d", hotspot.param1); - if (!getSound()->isBuffered(filename) && (hotspot.param1 != 50 || getProgress().chapter == kChapter5)) - getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault, hotspot.param2); + if (!getSoundQueue()->isBuffered(filename) && (hotspot.param1 != 50 || getProgress().chapter == kChapter5)) + getSound()->playSound(kEntityPlayer, filename, kFlagDefault, hotspot.param2); return kSceneInvalid; } @@ -481,7 +483,7 @@ IMPLEMENT_ACTION(knock) if (getObjects()->get(object).entity) { getSavePoints()->push(kEntityPlayer, getObjects()->get(object).entity, kActionKnock, object); } else { - if (!getSound()->isBuffered("LIB012", true)) + if (!getSoundQueue()->isBuffered("LIB012", true)) getSound()->playSoundEvent(kEntityPlayer, 12); } @@ -516,7 +518,7 @@ IMPLEMENT_ACTION(compartment) && (compartment != kObjectCompartment1 || !getInventory()->hasItem(kItemKey) || (getInventory()->getSelectedItem() != kItemFirebird && getInventory()->getSelectedItem() != kItemBriefcase)))) { - if (!getSound()->isBuffered("LIB13")) + if (!getSoundQueue()->isBuffered("LIB13")) getSound()->playSoundEvent(kEntityPlayer, 13); // Stop processing further @@ -621,7 +623,7 @@ IMPLEMENT_ACTION(updateObjetLocation2) getObjects()->updateLocation2(object, location); - if (object != kObject112 || getSound()->isBuffered("LIB096")) { + if (object != kObject112 || getSoundQueue()->isBuffered("LIB096")) { if (object == 1) getSound()->playSoundEvent(kEntityPlayer, 73); } else { @@ -805,8 +807,8 @@ IMPLEMENT_ACTION(enterCompartment) getSound()->playSoundEvent(kEntityPlayer, 14); getSound()->playSoundEvent(kEntityPlayer, 15, 22); - if (getProgress().field_78 && !getSound()->isBuffered("MUS003")) { - getSound()->playSound(kEntityPlayer, "MUS003", SoundManager::kFlagDefault); + if (getProgress().field_78 && !getSoundQueue()->isBuffered("MUS003")) { + getSound()->playSound(kEntityPlayer, "MUS003", kFlagDefault); getProgress().field_78 = 0; } @@ -1083,8 +1085,8 @@ IMPLEMENT_ACTION(25) break; case 2: - if (!getSound()->isBuffered("MUS021")) - getSound()->playSound(kEntityPlayer, "MUS021", SoundManager::kFlagDefault); + if (!getSoundQueue()->isBuffered("MUS021")) + getSound()->playSound(kEntityPlayer, "MUS021", kFlagDefault); break; case 3: @@ -1134,7 +1136,7 @@ IMPLEMENT_ACTION(26) ////////////////////////////////////////////////////////////////////////// // Action 27 IMPLEMENT_ACTION(27) - if (!getSound()->isBuffered("LIB031", true)) + if (!getSoundQueue()->isBuffered("LIB031", true)) getSound()->playSoundEvent(kEntityPlayer, 31); switch (getEntityData(kEntityPlayer)->car) { @@ -1182,8 +1184,8 @@ IMPLEMENT_ACTION(29) getSound()->playSoundEvent(kEntityPlayer, hotspot.param1, hotspot.param2); Common::String filename = Common::String::format("MUS%03d", hotspot.param3); - if (!getSound()->isBuffered(filename)) - getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault); + if (!getSoundQueue()->isBuffered(filename)) + getSound()->playSound(kEntityPlayer, filename, kFlagDefault); return kSceneInvalid; } @@ -1345,7 +1347,7 @@ IMPLEMENT_ACTION(openBed) ////////////////////////////////////////////////////////////////////////// // Action 37 IMPLEMENT_ACTION(dialog) - getSound()->playDialog(kEntityTables4, (EntityIndex)hotspot.param1, SoundManager::kFlagDefault, 0); + getSound()->playDialog(kEntityTables4, (EntityIndex)hotspot.param1, kFlagDefault, 0); return kSceneInvalid; } @@ -1354,8 +1356,8 @@ IMPLEMENT_ACTION(dialog) // Action 38 IMPLEMENT_ACTION(eggBox) getSound()->playSoundEvent(kEntityPlayer, 43); - if (getProgress().field_7C && !getSound()->isBuffered("MUS003")) { - getSound()->playSound(kEntityPlayer, "MUS003", SoundManager::kFlagDefault); + if (getProgress().field_7C && !getSoundQueue()->isBuffered("MUS003")) { + getSound()->playSound(kEntityPlayer, "MUS003", kFlagDefault); getProgress().field_7C = 0; } @@ -1366,8 +1368,8 @@ IMPLEMENT_ACTION(eggBox) // Action 39 IMPLEMENT_ACTION(39) getSound()->playSoundEvent(kEntityPlayer, 24); - if (getProgress().field_80 && !getSound()->isBuffered("MUS003")) { - getSound()->playSound(kEntityPlayer, "MUS003", SoundManager::kFlagDefault); + if (getProgress().field_80 && !getSoundQueue()->isBuffered("MUS003")) { + getSound()->playSound(kEntityPlayer, "MUS003", kFlagDefault); getProgress().field_80 = 0; } @@ -1408,8 +1410,8 @@ IMPLEMENT_ACTION(playMusicChapter) if (id) { Common::String filename = Common::String::format("MUS%03d", id); - if (!getSound()->isBuffered(filename)) - getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault); + if (!getSoundQueue()->isBuffered(filename)) + getSound()->playSound(kEntityPlayer, filename, kFlagDefault); } return kSceneInvalid; @@ -1440,8 +1442,8 @@ IMPLEMENT_ACTION(playMusicChapterSetupTrain) Common::String filename = Common::String::format("MUS%03d", hotspot.param1); - if (!getSound()->isBuffered(filename) && hotspot.param3 & id) { - getSound()->playSound(kEntityPlayer, filename, SoundManager::kFlagDefault); + if (!getSoundQueue()->isBuffered(filename) && hotspot.param3 & id) { + getSound()->playSound(kEntityPlayer, filename, kFlagDefault); getSavePoints()->call(kEntityPlayer, kEntityTrain, kAction203863200, filename.c_str()); getSavePoints()->push(kEntityPlayer, kEntityTrain, kAction222746496, hotspot.param2); @@ -1612,7 +1614,7 @@ bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool d if (doPlaySound) playCompartmentSoundEvents(object); - if (!getSound()->isBuffered(kEntityMertens)) + if (!getSoundQueue()->isBuffered(kEntityMertens)) getSound()->playWarningCompartment(kEntityMertens, object); getSavePoints()->push(kEntityPlayer, kEntityMertens, kAction305159806); @@ -1628,7 +1630,7 @@ bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool d if (doPlaySound) playCompartmentSoundEvents(object); - if (!getSound()->isBuffered(kEntityMertens)) + if (!getSoundQueue()->isBuffered(kEntityMertens)) getSound()->playSound(kEntityMertens, (rnd(2)) ? "JAC1000" : "JAC1000A"); if (doLoadScene) @@ -1640,7 +1642,7 @@ bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool d if (doPlaySound) playCompartmentSoundEvents(object); - if (!getSound()->isBuffered(kEntityMertens)) + if (!getSoundQueue()->isBuffered(kEntityMertens)) getSound()->playSound(kEntityMertens, (rnd(2)) ? "JAC1000" : "JAC1000A"); if (doLoadScene) @@ -1667,7 +1669,7 @@ bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool d if (doPlaySound) playCompartmentSoundEvents(object); - if (!getSound()->isBuffered(kEntityCoudert)) + if (!getSoundQueue()->isBuffered(kEntityCoudert)) getSound()->playWarningCompartment(kEntityCoudert, object); getSavePoints()->push(kEntityPlayer, kEntityCoudert, kAction305159806); @@ -1684,7 +1686,7 @@ bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool d if (doPlaySound) playCompartmentSoundEvents(object); - if (!getSound()->isBuffered(kEntityCoudert)) + if (!getSoundQueue()->isBuffered(kEntityCoudert)) getSound()->playSound(kEntityCoudert, (rnd(2)) ? "JAC1000" : "JAC1000A"); if (doLoadScene) @@ -1699,7 +1701,7 @@ bool Action::handleOtherCompartment(ObjectIndex object, bool doPlaySound, bool d if (doPlaySound) playCompartmentSoundEvents(object); - if (!getSound()->isBuffered(kEntityCoudert)) + if (!getSoundQueue()->isBuffered(kEntityCoudert)) getSound()->playSound(kEntityCoudert, (rnd(2)) ? "JAC1000" : "JAC1000A"); if (doLoadScene) @@ -1908,7 +1910,7 @@ LABEL_KEY: // Play an animation and add delta time to global game time void Action::playAnimation(EventIndex index, bool debugMode) const { if (index >= _animationListSize) - error("Action::playAnimation: invalid event index (value=%i, max=%i)", index, _animationListSize); + error("[Action::playAnimation] Invalid event index (value=%i, max=%i)", index, _animationListSize); // In debug mode, just show the animation if (debugMode) { @@ -1930,8 +1932,8 @@ void Action::playAnimation(EventIndex index, bool debugMode) const { if (!getFlags()->mouseRightClick) { if (getGlobalTimer()) { - if (getSound()->isBuffered("TIMER")) { - getSound()->processEntry("TIMER"); + if (getSoundQueue()->isBuffered("TIMER")) { + getSoundQueue()->processEntry("TIMER"); setGlobalTimer(105); } } @@ -1948,8 +1950,8 @@ void Action::playAnimation(EventIndex index, bool debugMode) const { if (animation.load(getArchive(Common::String(_animationList[index].filename) + ".nis") , processSound ? Animation::kFlagDefault : Animation::kFlagProcess)) animation.play(); - if (getSound()->isBuffered("TIMER")) - getSound()->removeFromQueue("TIMER"); + if (getSoundQueue()->isBuffered("TIMER")) + getSoundQueue()->removeFromQueue("TIMER"); } // Show cursor diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp index cb6f0a3306..ab707ddae9 100644 --- a/engines/lastexpress/game/beetle.cpp +++ b/engines/lastexpress/game/beetle.cpp @@ -131,7 +131,7 @@ bool Beetle::isLoaded() const { bool Beetle::catchBeetle() { if (!_data) - error("Beetle::catchBeetle: sequences have not been loaded!"); + error("[Beetle::catchBeetle] Sequences have not been loaded"); if (getInventory()->getSelectedItem() == kItemMatchBox && getInventory()->hasItem(kItemMatch) @@ -148,14 +148,14 @@ bool Beetle::catchBeetle() { bool Beetle::isCatchable() const { if (!_data) - error("Beetle::isCatchable: sequences have not been loaded!"); + error("[Beetle::isCatchable] Sequences have not been loaded"); return (_data->indexes[_data->offset] >= 30); } void Beetle::update() { if (!_data) - error("Beetle::update: sequences have not been loaded!"); + error("[Beetle::update] Sequences have not been loaded"); if (!_data->isLoaded) return; @@ -194,7 +194,7 @@ void Beetle::update() { void Beetle::drawUpdate() { if (!_data) - error("Beetle::drawUpdate: sequences have not been loaded!"); + error("[Beetle::drawUpdate] Sequences have not been loaded"); if (_data->frame != NULL) { getScenes()->setCoordinates(_data->frame); @@ -366,7 +366,7 @@ void Beetle::drawUpdate() { void Beetle::move() { if (!_data) - error("Beetle::move: sequences have not been loaded!"); + error("[Beetle::move] Sequences have not been loaded"); if (_data->indexes[_data->offset] >= 24 && _data->indexes[_data->offset] <= 29) return; @@ -444,7 +444,7 @@ update_data: // Update the beetle sequence to show the correct frames in the correct place void Beetle::updateFrame(SequenceFrame *frame) const { if (!_data) - error("Beetle::updateSequence: sequences have not been loaded!"); + error("[Beetle::updateFrame] Sequences have not been loaded"); if (!frame) return; @@ -459,7 +459,7 @@ void Beetle::updateFrame(SequenceFrame *frame) const { void Beetle::updateData(uint32 index) { if (!_data) - error("Beetle::updateData: sequences have not been loaded!"); + error("[Beetle::updateData] Sequences have not been loaded"); if (!_data->isLoaded) return; diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index 513ad114b0..f6bb2030f0 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -68,9 +68,11 @@ #include "lastexpress/game/logic.h" #include "lastexpress/game/savepoint.h" #include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" #include "lastexpress/game/state.h" +#include "lastexpress/sound/queue.h" +#include "lastexpress/sound/sound.h" + #include "lastexpress/graphics.h" #include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" @@ -200,7 +202,7 @@ Entity *Entities::get(EntityIndex entity) { assert((uint)entity < _entities.size()); if (entity == kEntityPlayer) - error("Cannot get entity for index == 0!"); + error("[Entities::get] Cannot get entity for kEntityPlayer"); return _entities[entity]; } @@ -218,24 +220,24 @@ int Entities::getPosition(CarIndex car, Position position) const { int index = 100 * car + position; if (car > 10) - error("Entities::getPosition: trying to access an invalid car (was: %d, valid:0-9)", car); + error("[Entities::getPosition] Trying to access an invalid car (was: %d, valid:0-9)", car); if (position > 100) - error("Entities::getPosition: trying to access an invalid position (was: %d, valid:0-100)", position); + error("[Entities::getPosition] Trying to access an invalid position (was: %d, valid:0-100)", position); return _positions[index]; } int Entities::getCompartments(int index) const { if (index >= _compartmentsCount) - error("Entities::getCompartments: trying to access an invalid compartment (was: %d, valid:0-15)", index); + error("[Entities::getCompartments] Trying to access an invalid compartment (was: %d, valid:0-15)", index); return _compartments[index]; } int Entities::getCompartments1(int index) const { if (index >= _compartmentsCount) - error("Entities::getCompartments: trying to access an invalid compartment (was: %d, valid:0-15)", index); + error("[Entities::getCompartments] Trying to access an invalid compartment (was: %d, valid:0-15)", index); return _compartments1[index]; } @@ -299,7 +301,7 @@ void Entities::setupChapter(ChapterIndex chapter) { memset(&_compartments1, 0, sizeof(_compartments1)); memset(&_positions, 0, sizeof(_positions)); - getSound()->resetQueue(SoundManager::kSoundType13); + getSoundQueue()->resetQueue(kSoundType13); } // we skip the header when doing entity setup @@ -369,8 +371,8 @@ void Entities::resetState(EntityIndex entityIndex) { getData(entityIndex)->currentCall = 0; getData(entityIndex)->inventoryItem = kItemNone; - if (getSound()->isBuffered(entityIndex)) - getSound()->removeFromQueue(entityIndex); + if (getSoundQueue()->isBuffered(entityIndex)) + getSoundQueue()->removeFromQueue(entityIndex); clearSequences(entityIndex); @@ -1780,7 +1782,7 @@ void Entities::enterCompartment(EntityIndex entity, ObjectIndex compartment, boo // Update compartments int index = (compartment < 32 ? compartment - 1 : compartment - 24); if (index >= 16) - error("Entities::exitCompartment: invalid compartment index!"); + error("[Entities::enterCompartment] Invalid compartment index"); if (useCompartment1) _compartments1[index] |= STORE_VALUE(entity); @@ -1866,7 +1868,7 @@ void Entities::exitCompartment(EntityIndex entity, ObjectIndex compartment, bool // Update compartments int index = (compartment < 32 ? compartment - 1 : compartment - 24); if (index >= 16) - error("Entities::exitCompartment: invalid compartment index!"); + error("[Entities::exitCompartment] Invalid compartment index"); if (useCompartment1) _compartments1[index] &= ~STORE_VALUE(entity); @@ -2355,7 +2357,7 @@ bool Entities::changeCar(EntityData::EntityCallData *data, EntityIndex entity, C if (data->car == newCar) { if (isInGreenCarEntrance(kEntityPlayer)) { getSound()->playSoundEvent(kEntityPlayer, 14); - getSound()->excuseMe(entity, kEntityPlayer, SoundManager::kFlagDefault); + getSound()->excuseMe(entity, kEntityPlayer, kFlagDefault); getScenes()->loadSceneFromPosition(kCarGreenSleeping, 1); getSound()->playSound(kEntityPlayer, "CAT1127A"); getSound()->playSoundEvent(kEntityPlayer, 15); @@ -2374,7 +2376,7 @@ bool Entities::changeCar(EntityData::EntityCallData *data, EntityIndex entity, C if (data->car == newCar) { if (isInKronosCarEntrance(kEntityPlayer)) { getSound()->playSoundEvent(kEntityPlayer, 14); - getSound()->excuseMe(entity, kEntityPlayer, SoundManager::kFlagDefault); + getSound()->excuseMe(entity, kEntityPlayer, kFlagDefault); getScenes()->loadSceneFromPosition(kCarGreenSleeping, 62); getSound()->playSound(kEntityPlayer, "CAT1127A"); getSound()->playSoundEvent(kEntityPlayer, 15); diff --git a/engines/lastexpress/game/fight.cpp b/engines/lastexpress/game/fight.cpp deleted file mode 100644 index ecc43bed2b..0000000000 --- a/engines/lastexpress/game/fight.cpp +++ /dev/null @@ -1,1583 +0,0 @@ -/* 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/game/fight.h" - -#include "lastexpress/data/cursor.h" -#include "lastexpress/data/scene.h" -#include "lastexpress/data/sequence.h" - -#include "lastexpress/game/entities.h" -#include "lastexpress/game/inventory.h" -#include "lastexpress/game/logic.h" -#include "lastexpress/game/object.h" -#include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" -#include "lastexpress/game/state.h" - -#include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" -#include "lastexpress/lastexpress.h" -#include "lastexpress/resource.h" - -#include "common/func.h" - -namespace LastExpress { - -#define CALL_FUNCTION0(fighter, name) \ - (*fighter->name)(fighter) - -#define CALL_FUNCTION1(fighter, name, a) \ - (*fighter->name)(fighter, a) - -#define REGISTER_PLAYER_FUNCTIONS(name) \ - if (!_data) \ - error("Fight::load##namePlayer - invalid data!"); \ - _data->player->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleAction##name); \ - _data->player->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::update##name); \ - _data->player->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract##name); - -#define REGISTER_OPPONENT_FUNCTIONS(name) \ - if (!_data) \ - error("Fight::load##nameOpponent - invalid data!"); \ - _data->opponent->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleOpponentAction##name); \ - _data->opponent->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::updateOpponent##name); \ - _data->opponent->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract); - -#define CHECK_SEQUENCE2(fighter, value) \ - (fighter->frame->getInfo()->field_33 & value) - -Fight::Fight(LastExpressEngine *engine) : _engine(engine), _data(NULL), _endType(kFightEndLost), _state(0), _handleTimer(false) {} - -Fight::~Fight() { - clearData(); - _data = NULL; - - // Zero passed pointers - _engine = NULL; -} - -////////////////////////////////////////////////////////////////////////// -// Events -////////////////////////////////////////////////////////////////////////// - -void Fight::eventMouse(const Common::Event &ev) { - if (!_data || _data->index) - return; - - // TODO move all the egg handling to inventory functions - - getFlags()->mouseLeftClick = false; - getFlags()->shouldRedraw = false; - getFlags()->mouseRightClick = false; - - if (ev.mouse.x < 608 || ev.mouse.y < 448 || ev.mouse.x >= 640 || ev.mouse.x >= 480) { - - // Handle right button click - if (ev.type == Common::EVENT_RBUTTONUP) { - getSound()->removeFromQueue(kEntityTables0); - setStopped(); - - getGlobalTimer() ? _state = 0 : ++_state; - - getFlags()->mouseRightClick = true; - } - - if (_handleTimer) { - // Timer expired => show with full brightness - if (!getGlobalTimer()) - getInventory()->drawBlinkingEgg(); - - _handleTimer = false; - } - - // Check hotspots - Scene *scene = getScenes()->get(getState()->scene); - SceneHotspot *hotspot = NULL; - - if (!scene->checkHotSpot(ev.mouse, &hotspot)) { - _engine->getCursor()->setStyle(kCursorNormal); - } else { - _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor); - - // Call player function - if (CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) { - if (ev.type == Common::EVENT_LBUTTONUP) - CALL_FUNCTION1(_data->player, handleAction, (FightAction)hotspot->action); - } else { - _engine->getCursor()->setStyle(kCursorNormal); - } - } - } else { - // Handle clicks on menu icon - - if (!_handleTimer) { - // Timer expired => show with full brightness - if (!getGlobalTimer()) - getInventory()->drawBlinkingEgg(); - - _handleTimer = true; - } - - // Stop fight if clicked - if (ev.type == Common::EVENT_LBUTTONUP) { - _handleTimer = false; - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndExit); - } - - // Reset timer on right click - if (ev.type == Common::EVENT_RBUTTONUP) { - if (getGlobalTimer()) { - if (getSound()->isBuffered("TIMER")) - getSound()->removeFromQueue("TIMER"); - - setGlobalTimer(900); - } - } - } - - getFlags()->shouldRedraw = true; -} - -void Fight::eventTick(const Common::Event &ev) { - handleTick(ev, true); -} - -void Fight::handleTick(const Common::Event &ev, bool isProcessing) { - // TODO move all the egg handling to inventory functions - - // Blink egg - if (getGlobalTimer()) { - warning("Fight::handleMouseMove - egg blinking not implemented!"); - } - - if (!_data || _data->index) - return; - - SceneHotspot *hotspot = NULL; - if (!getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot) || !CALL_FUNCTION1(_data->player, canInteract, (FightAction)hotspot->action)) { - _engine->getCursor()->setStyle(kCursorNormal); - } else { - _engine->getCursor()->setStyle((CursorStyle)hotspot->cursor); - } - - CALL_FUNCTION0(_data->player, update); - CALL_FUNCTION0(_data->opponent, update); - - // Draw sequences - if (!_data->isRunning) - return; - - if (isProcessing) - getScenes()->drawFrames(true); - - if (_data->index) { - // Set next sequence name index - _data->index--; - _data->sequences[_data->index] = loadSequence(_data->names[_data->index]); - } -} - -////////////////////////////////////////////////////////////////////////// -// Setup -////////////////////////////////////////////////////////////////////////// - -Fight::FightEndType Fight::setup(FightType type) { - if (_data) - error("Fight::setup - calling fight setup again while a fight is already in progress!"); - - ////////////////////////////////////////////////////////////////////////// - // Prepare UI & state - if (_state >= 5 && (type == kFightSalko || type == kFightVesna)) { - _state = 0; - return kFightEndWin; - } - - getInventory()->showHourGlass(); - // TODO events function - getFlags()->flag_0 = false; - getFlags()->mouseRightClick = false; - getEntities()->reset(); - - // Compute scene to use - SceneIndex sceneIndex; - switch(type) { - default: - sceneIndex = kSceneFightDefault; - break; - - case kFightMilos: - sceneIndex = (getObjects()->get(kObjectCompartment1).location2 < kObjectLocation3) ? kSceneFightMilos : kSceneFightMilosBedOpened; - break; - - case kFightAnna: - sceneIndex = kSceneFightAnna; - break; - - case kFightIvo: - sceneIndex = kSceneFightIvo; - break; - - case kFightSalko: - sceneIndex = kSceneFightSalko; - break; - - case kFightVesna: - sceneIndex = kSceneFightVesna; - break; - } - - if (getFlags()->shouldRedraw) { - getFlags()->shouldRedraw = false; - askForRedraw(); - //redrawScreen(); - } - - // Load the scene object - Scene *scene = getScenes()->get(sceneIndex); - - // Update game entities and state - getEntityData(kEntityPlayer)->entityPosition = scene->entityPosition; - getEntityData(kEntityPlayer)->location = scene->location; - - getState()->scene = sceneIndex; - - getFlags()->flag_3 = true; - - // Draw the scene - _engine->getGraphicsManager()->draw(scene, GraphicsManager::kBackgroundC); - // FIXME move to start of fight? - askForRedraw(); - redrawScreen(); - - ////////////////////////////////////////////////////////////////////////// - // Setup the fight - _data = new FightData; - loadData(type); - - // Show opponents & egg button - Common::Event emptyEvent; - handleTick(emptyEvent, false); - getInventory()->drawEgg(); - - // Start fight - _endType = kFightEndLost; - while (_data->isRunning) { - if (_engine->handleEvents()) - continue; - - getSound()->updateQueue(); - } - - // Cleanup after fight is over - clearData(); - - return _endType; -} - -////////////////////////////////////////////////////////////////////////// -// Status -////////////////////////////////////////////////////////////////////////// - -void Fight::setStopped() { - if (_data) - _data->isRunning = false; -} - -void Fight::bailout(FightEndType type) { - _state = 0; - _endType = type; - setStopped(); -} - -////////////////////////////////////////////////////////////////////////// -// Cleanup -////////////////////////////////////////////////////////////////////////// - -void Fight::clearData() { - if (!_data) - return; - - // Clear data - clearSequences(_data->player); - clearSequences(_data->opponent); - - SAFE_DELETE(_data->player); - SAFE_DELETE(_data->opponent); - - SAFE_DELETE(_data); - - _engine->restoreEventHandlers(); -} - -void Fight::clearSequences(Fighter *combatant) const { - if (!combatant) - return; - - // The original game resets the function pointers to default values, just before deleting the struct - getScenes()->removeAndRedraw(&combatant->frame, false); - - // Free sequences - for (int i = 0; i < (int)combatant->sequences.size(); i++) - SAFE_DELETE(combatant->sequences[i]); -} - -////////////////////////////////////////////////////////////////////////// -// Drawing -////////////////////////////////////////////////////////////////////////// - -void Fight::setSequenceAndDraw(Fighter *combatant, uint32 sequenceIndex, FightSequenceType type) const { - if (combatant->sequences.size() < sequenceIndex) - return; - - switch (type) { - default: - break; - - case kFightSequenceType0: - if (combatant->sequenceIndex) - return; - - combatant->sequence = combatant->sequences[sequenceIndex]; - combatant->sequenceIndex = sequenceIndex; - draw(combatant); - break; - - case kFightSequenceType1: - combatant->sequence = combatant->sequences[sequenceIndex]; - combatant->sequenceIndex = sequenceIndex; - combatant->sequenceIndex2 = 0; - draw(combatant); - break; - - case kFightSequenceType2: - combatant->sequenceIndex2 = sequenceIndex; - break; - } -} - -void Fight::draw(Fighter *combatant) const { - getScenes()->removeAndRedraw(&combatant->frame, false); - - combatant->frameIndex = 0; - combatant->field_24 = 0; -} - -////////////////////////////////////////////////////////////////////////// -// Loading -////////////////////////////////////////////////////////////////////////// - -void Fight::loadData(FightType type) { - if (!_data) - error("Fight::loadData - invalid data!"); - - switch (type) { - default: - break; - - case kFightMilos: - loadMilosPlayer(); - loadMilosOpponent(); - break; - - case kFightAnna: - loadAnnaPlayer(); - loadAnnaOpponent(); - break; - - case kFightIvo: - loadIvoPlayer(); - loadIvoOpponent(); - break; - - case kFightSalko: - loadSalkoPlayer(); - loadSalkoOpponent(); - break; - - case kFightVesna: - loadVesnaPlayer(); - loadVesnaOpponent(); - break; - } - - if (!_data->player || !_data->opponent) - error("Fight::loadData - error loading fight data (type=%d)", type); - - ////////////////////////////////////////////////////////////////////////// - // Start running the fight - _data->isRunning = true; - - if (_state < 5) { - setSequenceAndDraw(_data->player, 0, kFightSequenceType0); - setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0); - goto end_load; - } - - switch(type) { - default: - break; - - case kFightMilos: - _data->opponent->countdown = 1; - setSequenceAndDraw(_data->player, 4, kFightSequenceType0); - setSequenceAndDraw(_data->opponent, 0, kFightSequenceType0); - break; - - case kFightIvo: - _data->opponent->countdown = 1; - setSequenceAndDraw(_data->player, 3, kFightSequenceType0); - setSequenceAndDraw(_data->opponent, 6, kFightSequenceType0); - break; - - case kFightVesna: - _data->opponent->countdown = 1; - setSequenceAndDraw(_data->player, 0, kFightSequenceType0); - setSequenceAndDraw(_data->player, 3, kFightSequenceType2); - setSequenceAndDraw(_data->opponent, 5, kFightSequenceType0); - break; - } - -end_load: - // Setup event handlers - _engine->backupEventHandlers(); - SET_EVENT_HANDLERS(Fight, this); -} - -////////////////////////////////////////////////////////////////////////// -// Shared -////////////////////////////////////////////////////////////////////////// -void Fight::processFighter(Fighter *fighter) { - if (!_data) - error("Fight::processFighter - invalid data!"); - - if (!fighter->sequence) { - if (fighter->frame) { - getScenes()->removeFromQueue(fighter->frame); - getScenes()->setCoordinates(fighter->frame); - } - SAFE_DELETE(fighter->frame); - return; - } - - if (fighter->sequence->count() <= fighter->frameIndex) { - switch(fighter->action) { - default: - break; - - case kFightAction101: - setSequenceAndDraw(fighter, fighter->sequenceIndex2, kFightSequenceType1); - fighter->sequenceIndex2 = 0; - break; - - case kFightActionResetFrame: - fighter->frameIndex = 0; - break; - - case kFightAction103: - setSequenceAndDraw(fighter, 0, kFightSequenceType1); - CALL_FUNCTION1(fighter, handleAction, kFightAction101); - setSequenceAndDraw(fighter->opponent, 0, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction101); - CALL_FUNCTION0(fighter->opponent, update); - break; - - case kFightActionWin: - bailout(kFightEndWin); - break; - - case kFightActionLost: - bailout(kFightEndLost); - break; - } - } - - if (_data->isRunning) { - - // Get the current sequence frame - SequenceFrame *frame = new SequenceFrame(fighter->sequence, (uint16)fighter->frameIndex); - frame->getInfo()->location = 1; - - if (fighter->frame == frame) { - delete frame; - return; - } - - getSound()->playFightSound(frame->getInfo()->soundAction, frame->getInfo()->field_31); - - // Add current frame to queue and advance - getScenes()->addToQueue(frame); - fighter->frameIndex++; - - if (fighter->frame) { - getScenes()->removeFromQueue(fighter->frame); - - if (!frame->getInfo()->field_2E) - getScenes()->setCoordinates(fighter->frame); - } - - // Replace by new frame - delete fighter->frame; - fighter->frame = frame; - } -} - -void Fight::handleAction(Fighter *fighter, FightAction action) { - switch (action) { - default: - return; - - case kFightAction101: - break; - - case kFightActionResetFrame: - fighter->countdown--; - break; - - case kFightAction103: - CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); - break; - - case kFightActionWin: - _endType = kFightEndWin; - CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); - break; - - case kFightActionLost: - _endType = kFightEndLost; - CALL_FUNCTION1(fighter->opponent, handleAction, kFightActionResetFrame); - break; - } - - // Update action - fighter->action = action; -} - -bool Fight::canInteract(Fighter const *fighter, FightAction /*= (FightAction)0*/ ) { - return (fighter->action == kFightAction101 && !fighter->sequenceIndex); -} - -void Fight::update(Fighter *fighter) { - - processFighter(fighter); - - if (fighter->frame) - fighter->frame->getInfo()->location = (fighter->action == kFightActionResetFrame ? 2 : 0); -} - -void Fight::updateOpponent(Fighter *fighter) { - - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - processFighter(opponent); - - if (opponent->field_38 && !opponent->sequenceIndex) - opponent->field_38--; - - if (fighter->frame) - fighter->frame->getInfo()->location = 1; -} - -////////////////////////////////////////////////////////////////////////// -// Milos -////////////////////////////////////////////////////////////////////////// - -void Fight::loadMilosPlayer() { - REGISTER_PLAYER_FUNCTIONS(Milos) - - _data->player->sequences.push_back(loadSequence("2001cr.seq")); - _data->player->sequences.push_back(loadSequence("2001cdl.seq")); - _data->player->sequences.push_back(loadSequence("2001cdr.seq")); - _data->player->sequences.push_back(loadSequence("2001cdm.seq")); - _data->player->sequences.push_back(loadSequence("2001csgr.seq")); - _data->player->sequences.push_back(loadSequence("2001csgl.seq")); - _data->player->sequences.push_back(loadSequence("2001dbk.seq")); -} - -void Fight::loadMilosOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Milos) - - _data->opponent->sequences.push_back(loadSequence("2001or.seq")); - _data->opponent->sequences.push_back(loadSequence("2001oal.seq")); - _data->opponent->sequences.push_back(loadSequence("2001oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2001okl.seq")); - _data->opponent->sequences.push_back(loadSequence("2001okm.seq")); - _data->opponent->sequences.push_back(loadSequence("2001dbk.seq")); - _data->opponent->sequences.push_back(loadSequence("2001wbk.seq")); - - getSound()->playSound(kEntityTables0, "MUS027", SoundManager::kFlagDefault); - - _data->opponent->field_38 = 35; -} - -void Fight::handleActionMilos(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 6, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 3, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction2: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 6, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction128: - if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4) || fighter->opponent->sequenceIndex != 1) { - switch (fighter->opponent->sequenceIndex) { - default: - setSequenceAndDraw(fighter, rnd(3) + 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(fighter, 3, kFightSequenceType0); - break; - } - } else { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - CALL_FUNCTION0(fighter, update); - } - break; - } -} - -void Fight::updateMilos(Fighter *fighter) { - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - // Draw sequences - if (fighter->opponent->countdown <= 0) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1); - - getSound()->removeFromQueue(kEntityTables0); - getSound()->playSound(kEntityTrain, "MUS029", SoundManager::kFlagDefault); - - CALL_FUNCTION1(fighter, handleAction, kFightActionWin); - } - - if (fighter->sequenceIndex == 4) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction4); - _endType = kFightEndLost; - } - } - - update(fighter); -} - -bool Fight::canInteractMilos(Fighter const *fighter, FightAction action) { - if (!_data) - error("Fight::canInteractMilos - invalid data!"); - - if (action != kFightAction128 - || _data->player->sequenceIndex != 1 - || !fighter->frame - || CHECK_SEQUENCE2(fighter, 4) - || fighter->opponent->sequenceIndex != 1) { - return canInteract(fighter); - } - - _engine->getCursor()->setStyle(kCursorHand); - - return true; -} - -void Fight::handleOpponentActionMilos(Fighter *fighter, FightAction action) { - if (action == kFightAction4) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - } else { - if (action != kFightAction131) - handleAction(fighter, action); - } -} - -void Fight::updateOpponentMilos(Fighter *fighter) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 >= 2) { - switch (rnd(5)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType1); - break; - - case 3: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - } else { - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - } - - // Update field_38 - if (opponent->opponent->field_34 < 5) - opponent->field_38 = 6 * (5 - opponent->opponent->field_34); - else - opponent->field_38 = 0; - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - - if (opponent->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - CALL_FUNCTION1(opponent, handleAction, kFightActionLost); - } - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Anna -////////////////////////////////////////////////////////////////////////// - -void Fight::loadAnnaPlayer() { - if (!_data) - error("Fight::loadAnnaPlayer - invalid data!"); - - // Special case: we are using some shared functions directly - _data->player->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleActionAnna); - _data->player->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::update); - _data->player->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract); - - _data->player->sequences.push_back(loadSequence("2002cr.seq")); - _data->player->sequences.push_back(loadSequence("2002cdl.seq")); - _data->player->sequences.push_back(loadSequence("2002cdr.seq")); - _data->player->sequences.push_back(loadSequence("2002cdm.seq")); - _data->player->sequences.push_back(loadSequence("2002lbk.seq")); -} - -void Fight::loadAnnaOpponent() { - if (!_data) - error("Fight::loadAnnaOpponent - invalid data!"); - - // Special case: we are using some shared functions directly - _data->opponent->handleAction = new Common::Functor2Mem<Fighter *, FightAction, void, Fight>(this, &Fight::handleAction); - _data->opponent->update = new Common::Functor1Mem<Fighter *, void, Fight>(this, &Fight::updateOpponentAnna); - _data->opponent->canInteract = new Common::Functor2Mem<Fighter const *, FightAction, bool, Fight>(this, &Fight::canInteract); - - _data->opponent->sequences.push_back(loadSequence("2002or.seq")); - _data->opponent->sequences.push_back(loadSequence("2002oal.seq")); - _data->opponent->sequences.push_back(loadSequence("2002oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2002oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2002okr.seq")); - _data->opponent->sequences.push_back(loadSequence("2002okml.seq")); - _data->opponent->sequences.push_back(loadSequence("2002okm.seq")); - - getSound()->playSound(kEntityTables0, "MUS030", SoundManager::kFlagDefault); - - _data->opponent->field_38 = 30; -} - -void Fight::handleActionAnna(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if ((fighter->sequenceIndex != 1 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction2: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction3: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 1) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 4, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 6, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction128: - switch (fighter->opponent->sequenceIndex) { - default: - setSequenceAndDraw(fighter, 3, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(fighter, 3, kFightSequenceType0); - break; - - case 3: - setSequenceAndDraw(fighter, 2, kFightSequenceType0); - break; - } - break; - } - - if (fighter->field_34 > 4) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndWin); - } -} - -void Fight::updateOpponentAnna(Fighter *fighter) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 >= 2) { - switch (rnd(6)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 3, kFightSequenceType0); - break; - - case 3: - setSequenceAndDraw(opponent, 3, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 5: - setSequenceAndDraw(opponent, 3, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - } - } - - // Update field_38 - opponent->field_38 = (int32)rnd(15); - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 3) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - - if (opponent->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - CALL_FUNCTION1(opponent, handleAction, kFightActionLost); - } - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Ivo -////////////////////////////////////////////////////////////////////////// - -void Fight::loadIvoPlayer() { - REGISTER_PLAYER_FUNCTIONS(Ivo) - - _data->player->sequences.push_back(loadSequence("2003cr.seq")); - _data->player->sequences.push_back(loadSequence("2003car.seq")); - _data->player->sequences.push_back(loadSequence("2003cal.seq")); - _data->player->sequences.push_back(loadSequence("2003cdr.seq")); - _data->player->sequences.push_back(loadSequence("2003cdm.seq")); - _data->player->sequences.push_back(loadSequence("2003chr.seq")); - _data->player->sequences.push_back(loadSequence("2003chl.seq")); - _data->player->sequences.push_back(loadSequence("2003ckr.seq")); - _data->player->sequences.push_back(loadSequence("2003lbk.seq")); - _data->player->sequences.push_back(loadSequence("2003fbk.seq")); - - _data->player->countdown = 5; -} - -void Fight::loadIvoOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Ivo) - - _data->opponent->sequences.push_back(loadSequence("2003or.seq")); - _data->opponent->sequences.push_back(loadSequence("2003oal.seq")); - _data->opponent->sequences.push_back(loadSequence("2003oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2003odm.seq")); - _data->opponent->sequences.push_back(loadSequence("2003okl.seq")); - _data->opponent->sequences.push_back(loadSequence("2003okj.seq")); - _data->opponent->sequences.push_back(loadSequence("blank.seq")); - _data->opponent->sequences.push_back(loadSequence("csdr.seq")); - _data->opponent->sequences.push_back(loadSequence("2003l.seq")); - - getSound()->playSound(kEntityTables0, "MUS032", SoundManager::kFlagDefault); - - _data->opponent->countdown = 5; - _data->opponent->field_38 = 15; -} - -void Fight::handleActionIvo(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if (fighter->sequenceIndex != 1 || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 7, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction2: - if ((fighter->sequenceIndex != 2 && fighter->sequenceIndex != 3) || CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 7, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction128: - switch (fighter->opponent->sequenceIndex) { - default: - case 1: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(fighter, 2, kFightSequenceType0); - break; - } - break; - - case kFightAction129: - setSequenceAndDraw(fighter, (fighter->opponent->countdown > 1) ? 4 : 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0); - break; - - case kFightAction130: - setSequenceAndDraw(fighter, 3, fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0); - break; - } -} - -void Fight::updateIvo(Fighter *fighter) { - - if ((fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) && !fighter->frameIndex) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction131); - - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - // Draw sequences - if (fighter->opponent->countdown <= 0) { - setSequenceAndDraw(fighter, 9, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, 8, kFightSequenceType1); - getSound()->removeFromQueue(kEntityTables0); - - CALL_FUNCTION1(fighter, handleAction, kFightActionWin); - return; - } - - if (fighter->sequenceIndex == 3 || fighter->sequenceIndex == 4) - CALL_FUNCTION1(fighter->opponent, handleAction, (FightAction)fighter->sequenceIndex); - } - - update(fighter); -} - -bool Fight::canInteractIvo(Fighter const *fighter, FightAction action) { - if (action == kFightAction129 || action == kFightAction130) - return (fighter->sequenceIndex >= 8); - - return canInteract(fighter); -} - -void Fight::handleOpponentActionIvo(Fighter *fighter, FightAction action) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - switch (action) { - default: - handleAction(fighter, action); - break; - - case kFightAction3: - if ((opponent->sequenceIndex != 1 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) { - setSequenceAndDraw(opponent, 6, kFightSequenceType1); - setSequenceAndDraw(opponent->opponent, 6, kFightSequenceType1); - CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103); - } - break; - - case kFightAction4: - if ((opponent->sequenceIndex != 2 && opponent->sequenceIndex != 3) || CHECK_SEQUENCE2(opponent, 4)) { - setSequenceAndDraw(opponent, 6, kFightSequenceType1); - setSequenceAndDraw(opponent->opponent, 5, kFightSequenceType1); - CALL_FUNCTION1(opponent->opponent, handleAction, kFightAction103); - } - break; - - case kFightAction131: - if (opponent->sequenceIndex) - break; - - if (rnd(100) <= (unsigned int)(opponent->countdown > 2 ? 60 : 75)) { - setSequenceAndDraw(opponent, 3 , kFightSequenceType1); - if (opponent->opponent->sequenceIndex == 4) - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - } - break; - } -} - -void Fight::updateOpponentIvo(Fighter *fighter) { - // This is an opponent struct! - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 >= 2) { - switch (rnd(5)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 3: - setSequenceAndDraw(opponent, 0, kFightSequenceType2); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 0, kFightSequenceType1); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - } - - // Update field_38 - opponent->field_38 = 3 * opponent->countdown + (int32)rnd(10); - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - - if (opponent->opponent->countdown <= 0) { - setSequenceAndDraw(opponent, 7, kFightSequenceType1); - setSequenceAndDraw(opponent->opponent, 8, kFightSequenceType1); - getSound()->removeFromQueue(kEntityTables0); - - CALL_FUNCTION1(opponent->opponent, handleAction, kFightActionWin); - - return; - } - - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Salko -////////////////////////////////////////////////////////////////////////// - -void Fight::loadSalkoPlayer() { - REGISTER_PLAYER_FUNCTIONS(Salko) - - _data->player->sequences.push_back(loadSequence("2004cr.seq")); - _data->player->sequences.push_back(loadSequence("2004cdr.seq")); - _data->player->sequences.push_back(loadSequence("2004chj.seq")); - _data->player->sequences.push_back(loadSequence("2004bk.seq")); - - _data->player->countdown = 2; -} - -void Fight::loadSalkoOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Salko) - - _data->opponent->sequences.push_back(loadSequence("2004or.seq")); - _data->opponent->sequences.push_back(loadSequence("2004oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2004oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2004okr.seq")); - _data->opponent->sequences.push_back(loadSequence("2004ohm.seq")); - _data->opponent->sequences.push_back(loadSequence("blank.seq")); - - getSound()->playSound(kEntityTables0, "MUS035", SoundManager::kFlagDefault); - - _data->opponent->countdown = 3; - _data->opponent->field_38 = 30; -} - -void Fight::handleActionSalko(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - case kFightAction2: - if (fighter->sequenceIndex != 1 && CHECK_SEQUENCE2(fighter, 4)) { - fighter->field_34 = 0; - - setSequenceAndDraw(fighter, 3, kFightSequenceType1); - setSequenceAndDraw(fighter->opponent, (action == kFightAction1 ? 3 : 4), kFightSequenceType1); - - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - - if (action == kFightAction2) - fighter->countdown= 0; - - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction5: - if (fighter->sequenceIndex != 3) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction128: - setSequenceAndDraw(fighter, 1, kFightSequenceType0); - fighter->field_34 = 0; - break; - - case kFightAction131: - setSequenceAndDraw(fighter, 2, (fighter->sequenceIndex ? kFightSequenceType2 : kFightSequenceType0)); - break; - } -} - -void Fight::updateSalko(Fighter *fighter) { - update(fighter); - - // The original doesn't check for currentSequence2 != NULL (might not happen when everything is working properly, but crashes with our current implementation) - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - if (fighter->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndWin); - - return; - } - - if (fighter->sequenceIndex == 2) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction2); - } -} - -bool Fight::canInteractSalko(Fighter const *fighter, FightAction action) { - if (action == kFightAction131) { - if (fighter->sequenceIndex == 1) { - if (fighter->opponent->countdown <= 0) - _engine->getCursor()->setStyle(kCursorHand); - - return true; - } - - return false; - } - - return canInteract(fighter); -} - -void Fight::handleOpponentActionSalko(Fighter *fighter, FightAction action) { - if (action == kFightAction2) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - } else { - handleAction(fighter, action); - } -} - -void Fight::updateOpponentSalko(Fighter *fighter) { - // This is an opponent struct - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - switch (rnd(5)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 2: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 3: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - - // Update field_38 - opponent->field_38 = 4 * opponent->countdown; - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndLost); - - // Stop processing - return; - } - - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - } - - updateOpponent(opponent); -} - -////////////////////////////////////////////////////////////////////////// -// Vesna -////////////////////////////////////////////////////////////////////////// - -void Fight::loadVesnaPlayer() { - REGISTER_PLAYER_FUNCTIONS(Vesna) - - _data->player->sequences.push_back(loadSequence("2005cr.seq")); - _data->player->sequences.push_back(loadSequence("2005cdr.seq")); - _data->player->sequences.push_back(loadSequence("2005cbr.seq")); - _data->player->sequences.push_back(loadSequence("2005bk.seq")); - _data->player->sequences.push_back(loadSequence("2005cdm1.seq")); - _data->player->sequences.push_back(loadSequence("2005chl.seq")); -} - -void Fight::loadVesnaOpponent() { - REGISTER_OPPONENT_FUNCTIONS(Vesna) - - _data->opponent->sequences.push_back(loadSequence("2005or.seq")); - _data->opponent->sequences.push_back(loadSequence("2005oam.seq")); - _data->opponent->sequences.push_back(loadSequence("2005oar.seq")); - _data->opponent->sequences.push_back(loadSequence("2005okml.seq")); - _data->opponent->sequences.push_back(loadSequence("2005okr.seq")); - _data->opponent->sequences.push_back(loadSequence("2005odm1.seq")); - _data->opponent->sequences.push_back(loadSequence("2005csbm.seq")); - _data->opponent->sequences.push_back(loadSequence("2005oam4.seq")); - - getSound()->playSound(kEntityTables0, "MUS038", SoundManager::kFlagDefault); - - _data->opponent->countdown = 4; - _data->opponent->field_38 = 30; -} - -void Fight::handleActionVesna(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - return; - - case kFightAction1: - if (fighter->sequenceIndex != 1) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction2: - if (fighter->sequenceIndex != 2) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } else { - fighter->field_34++; - } - break; - - case kFightAction5: - if (fighter->sequenceIndex != 3) { - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - CALL_FUNCTION0(fighter, update); - } - break; - - case kFightAction128: - if (fighter->sequenceIndex == 1 && fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) { - setSequenceAndDraw(fighter, 5, kFightSequenceType1); - } else { - setSequenceAndDraw(fighter, (fighter->opponent->sequenceIndex == 5) ? 3 : 1, kFightSequenceType0); - } - break; - - case kFightAction132: - setSequenceAndDraw(fighter, 2, kFightSequenceType0); - break; - } - - if (fighter->field_34 > 10) { - setSequenceAndDraw(fighter->opponent, 5, kFightSequenceType2); - fighter->opponent->countdown = 1; - fighter->field_34 = 0; - } -} - -void Fight::updateVesna(Fighter *fighter) { - if (fighter->frame && CHECK_SEQUENCE2(fighter, 2)) { - - if (fighter->sequenceIndex == 3) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction3); - - if (fighter->opponent->countdown <= 0) { - getSound()->removeFromQueue(kEntityTables0); - bailout(kFightEndWin); - return; - } - - if (fighter->sequenceIndex == 5) - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction5); - } - - update(fighter); -} - -bool Fight::canInteractVesna(Fighter const *fighter, FightAction action) { - if (action != kFightAction128) - return canInteract(fighter); - - if (fighter->sequenceIndex != 1) { - - if (fighter->opponent->sequenceIndex == 5) { - _engine->getCursor()->setStyle(kCursorDown); - return true; - } - - return canInteract(fighter); - } - - if (fighter->opponent->sequenceIndex == 1 && CHECK_SEQUENCE2(fighter, 4)) { - _engine->getCursor()->setStyle(kCursorPunchLeft); - return true; - } - - return false; -} - -void Fight::handleOpponentActionVesna(Fighter *fighter, FightAction action) { - switch (action) { - default: - handleAction(fighter, action); - break; - - case kFightAction3: - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - break; - - case kFightAction5: - setSequenceAndDraw(fighter, 7, kFightSequenceType1); - CALL_FUNCTION1(fighter->opponent, handleAction, kFightAction103); - if (fighter->countdown <= 1) - fighter->countdown = 1; - break; - - case kFightAction131: - break; - } -} - -void Fight::updateOpponentVesna(Fighter *fighter) { - // This is an opponent struct - Opponent *opponent = (Opponent *)fighter; - - if (!opponent->field_38 && CALL_FUNCTION1(opponent, canInteract, kFightAction1) && !opponent->sequenceIndex2) { - - if (opponent->opponent->field_34 == 1) { - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - } else { - switch (rnd(6)) { - default: - break; - - case 0: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - break; - - case 1: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - - case 2: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - break; - - case 3: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 4: - setSequenceAndDraw(opponent, 1, kFightSequenceType0); - setSequenceAndDraw(opponent, 2, kFightSequenceType2); - break; - - case 5: - setSequenceAndDraw(opponent, 2, kFightSequenceType0); - setSequenceAndDraw(opponent, 1, kFightSequenceType2); - break; - } - } - - // Update field_38 - opponent->field_38 = 4 * opponent->countdown; - } - - if (opponent->frame && CHECK_SEQUENCE2(opponent, 2)) { - if (opponent->sequenceIndex == 1 || opponent->sequenceIndex == 2 || opponent->sequenceIndex == 5) - CALL_FUNCTION1(opponent->opponent, handleAction, (FightAction)opponent->sequenceIndex); - - if (opponent->opponent->countdown <= 0) { - - switch (opponent->sequenceIndex) { - default: - break; - - case 1: - setSequenceAndDraw(opponent, 3, kFightSequenceType1); - break; - - case 2: - setSequenceAndDraw(opponent, 4, kFightSequenceType1); - break; - - case 5: - setSequenceAndDraw(opponent, 6, kFightSequenceType1); - break; - } - - setSequenceAndDraw(opponent->opponent, 4, kFightSequenceType1); - - CALL_FUNCTION1(opponent, handleAction, kFightActionLost); - CALL_FUNCTION0(opponent->opponent, update); - CALL_FUNCTION0(opponent, update); - - getSound()->removeFromQueue(kEntityTables0); - - // Stop processing - return; - } - } - - updateOpponent(opponent); -} - -} // End of namespace LastExpress diff --git a/engines/lastexpress/game/fight.h b/engines/lastexpress/game/fight.h deleted file mode 100644 index a33cc93a29..0000000000 --- a/engines/lastexpress/game/fight.h +++ /dev/null @@ -1,266 +0,0 @@ -/* 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. - * - */ - -#ifndef LASTEXPRESS_FIGHT_H -#define LASTEXPRESS_FIGHT_H - -/* - Fight structure - --------------- - uint32 {4} - player struct - uint32 {4} - opponent struct - uint32 {4} - hasLost flag - - byte {1} - isRunning - - Fight participant structure - --------------------------- - uint32 {4} - function pointer - uint32 {4} - pointer to fight structure - uint32 {4} - pointer to opponent (fight participant structure) - uint32 {4} - array of sequences - uint32 {4} - number of sequences - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint16 {2} - ?? - uint16 {2} - ?? - only for opponent structure - uint32 {4} - ?? - only for opponent structure - -*/ - -#include "lastexpress/shared.h" - -#include "lastexpress/eventhandler.h" - -#include "common/array.h" - -namespace LastExpress { - -class LastExpressEngine; -class Sequence; -class SequenceFrame; - -////////////////////////////////////////////////////////////////////////// -// TODO : objectify! -class Fight : public EventHandler { -public: - enum FightEndType { - kFightEndWin = 0, - kFightEndLost = 1, - kFightEndExit = 2 - }; - - Fight(LastExpressEngine *engine); - ~Fight(); - - FightEndType setup(FightType type); - - void eventMouse(const Common::Event &ev); - void eventTick(const Common::Event &ev); - - void setStopped(); - void resetState() { _state = 0; } - -private: - enum FightSequenceType { - kFightSequenceType0 = 0, - kFightSequenceType1 = 1, - kFightSequenceType2 = 2 - }; - - enum FightAction { - kFightAction1 = 1, - kFightAction2 = 2, - kFightAction3 = 3, - kFightAction4 = 4, - kFightAction5 = 5, - kFightAction101 = 101, - kFightActionResetFrame = 102, - kFightAction103 = 103, - kFightActionWin = 104, - kFightActionLost = 105, - kFightAction128 = 128, - kFightAction129 = 129, - kFightAction130 = 130, - kFightAction131 = 131, - kFightAction132 = 132 - }; - - struct Fighter { - Common::Functor2<Fighter *, FightAction, void> *handleAction; - Common::Functor1<Fighter *, void> *update; - Common::Functor2<Fighter const *, FightAction, bool> *canInteract; - Fighter *opponent; - Common::Array<Sequence *> sequences; - uint32 sequenceIndex; - Sequence *sequence; - SequenceFrame *frame; - uint32 frameIndex; - uint32 field_24; - FightAction action; - uint32 sequenceIndex2; - int32 countdown; // countdown before loosing ? - uint32 field_34; - - Fighter() { - handleAction = NULL; - update = NULL; - canInteract = NULL; - - opponent = NULL; - - sequenceIndex = 0; - sequence = NULL; - frame = NULL; - frameIndex = 0; - - field_24 = 0; - - action = kFightAction101; - sequenceIndex2 = 0; - - countdown = 1; - - field_34 = 0; - } - }; - - // Opponent struct - struct Opponent : Fighter { - int32 field_38; - - Opponent() : Fighter() { - field_38 = 0; - } - }; - - struct FightData { - Fighter *player; - Opponent *opponent; - int32 index; - - Sequence *sequences[20]; - Common::String names[20]; - - bool isRunning; - - FightData() { - player = new Fighter(); - opponent = new Opponent(); - - // Set opponents - player->opponent = opponent; - opponent->opponent = player; - - index = 0; - - isRunning = false; - } - }; - - LastExpressEngine *_engine; - FightData *_data; - FightEndType _endType; - int _state; - - bool _handleTimer; - - // Events - void handleTick(const Common::Event &ev, bool unknown); - - // State - void bailout(FightEndType type); - - - // Drawing - void setSequenceAndDraw(Fighter *fighter, uint32 sequenceIndex, FightSequenceType type) const; - void draw(Fighter *fighter) const; - - // Cleanup - void clearData(); - void clearSequences(Fighter *fighter) const; - - ////////////////////////////////////////////////////////////////////////// - // Loading - void loadData(FightType type); - - // Shared - void processFighter(Fighter *fighter); - - // Default functions - void handleAction(Fighter *fighter, FightAction action); - void update(Fighter *fighter); - bool canInteract(Fighter const *fighter, FightAction = (FightAction)0); - void updateOpponent(Fighter *fighter); - - // Milos - void loadMilosPlayer(); - void loadMilosOpponent(); - void handleActionMilos(Fighter *fighter, FightAction action); - void updateMilos(Fighter *fighter); - bool canInteractMilos(Fighter const *fighter, FightAction action); - void handleOpponentActionMilos(Fighter *fighter, FightAction action); - void updateOpponentMilos(Fighter *fighter); - - // Anna - void loadAnnaPlayer(); - void loadAnnaOpponent(); - void handleActionAnna(Fighter *fighter, FightAction action); - void updateOpponentAnna(Fighter *fighter); - - // Ivo - void loadIvoPlayer(); - void loadIvoOpponent(); - void handleActionIvo(Fighter *fighter, FightAction action); - void updateIvo(Fighter *fighter); - bool canInteractIvo(Fighter const *fighter, FightAction action); - void handleOpponentActionIvo(Fighter *fighter, FightAction action); - void updateOpponentIvo(Fighter *fighter); - - // Salko - void loadSalkoPlayer(); - void loadSalkoOpponent(); - void handleActionSalko(Fighter *fighter, FightAction action); - void updateSalko(Fighter *fighter); - bool canInteractSalko(Fighter const *fighter, FightAction action); - void handleOpponentActionSalko(Fighter *fighter, FightAction action); - void updateOpponentSalko(Fighter *fighter); - - // Vesna - void loadVesnaPlayer(); - void loadVesnaOpponent(); - void handleActionVesna(Fighter *fighter, FightAction action); - void updateVesna(Fighter *fighter); - bool canInteractVesna(Fighter const *fighter, FightAction action); - void handleOpponentActionVesna(Fighter *fighter, FightAction action); - void updateOpponentVesna(Fighter *fighter); -}; - -} // End of namespace LastExpress - -#endif // LASTEXPRESS_FIGHT_H diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index adf6ff772e..e417b1ec0d 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -27,11 +27,14 @@ #include "lastexpress/data/snd.h" #include "lastexpress/game/logic.h" -#include "lastexpress/game/menu.h" #include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" #include "lastexpress/game/state.h" +#include "lastexpress/menu/menu.h" + +#include "lastexpress/sound/queue.h" +#include "lastexpress/sound/sound.h" + #include "lastexpress/graphics.h" #include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" @@ -155,14 +158,14 @@ void Inventory::handleMouseEvent(const Common::Event &ev) { _portraitHighlighted = false; _isOpened = false; - getSound()->playSoundWithSubtitles("LIB039.SND", SoundManager::kFlagMenuClock, kEntityPlayer); + getSound()->playSoundWithSubtitles("LIB039.SND", kFlagMenuClock, kEntityPlayer); getMenu()->show(true, kSavegameTypeIndex, 0); } else if (ev.type == Common::EVENT_RBUTTONDOWN) { if (getGlobalTimer()) { - if (getSound()->isBuffered("TIMER")) - getSound()->removeFromQueue("TIMER"); + if (getSoundQueue()->isBuffered("TIMER")) + getSoundQueue()->removeFromQueue("TIMER"); setGlobalTimer(900); } @@ -436,7 +439,7 @@ void Inventory::showHourGlass(){ ////////////////////////////////////////////////////////////////////////// Inventory::InventoryEntry *Inventory::get(InventoryItem item) { if (item >= kPortraitOriginal) - error("Inventory::getEntry: Invalid inventory item!"); + error("[Inventory::get] Invalid inventory item"); return &_entries[item]; } @@ -620,7 +623,7 @@ void Inventory::drawEgg() { // Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit. void Inventory::drawBlinkingEgg() { - warning("Inventory::drawEgg - blinking not implemented!"); + warning("[Inventory::drawBlinkingEgg] Blinking not implemented"); //// TODO show egg (with or without mouseover) @@ -629,7 +632,7 @@ void Inventory::drawBlinkingEgg() { // if (getGlobalTimer() + ticks >= 90) // getSound()->playSoundWithSubtitles("TIMER.SND", 50331664, kEntityPlayer); - // if (getSound()->isBuffered("TIMER")) + // if (getSoundQueue()->isBuffered("TIMER")) // setGlobalTimer(0); //} diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp index 0911c60de0..aeac8cff98 100644 --- a/engines/lastexpress/game/logic.cpp +++ b/engines/lastexpress/game/logic.cpp @@ -30,20 +30,25 @@ // Entities #include "lastexpress/entities/chapters.h" +// Fight +#include "lastexpress/fight/fight.h" + // Game #include "lastexpress/game/action.h" #include "lastexpress/game/beetle.h" #include "lastexpress/game/entities.h" -#include "lastexpress/game/fight.h" #include "lastexpress/game/inventory.h" -#include "lastexpress/game/menu.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savegame.h" #include "lastexpress/game/savepoint.h" #include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" #include "lastexpress/game/state.h" +#include "lastexpress/menu/menu.h" + +#include "lastexpress/sound/queue.h" +#include "lastexpress/sound/sound.h" + #include "lastexpress/graphics.h" #include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" @@ -149,7 +154,7 @@ void Logic::eventMouse(const Common::Event &ev) { _engine->getCursor()->setStyle(getInventory()->get(kItemWhistle)->cursor); // Check if clicked - if (ev.type == Common::EVENT_LBUTTONUP && !getSound()->isBuffered("LIB045")) { + if (ev.type == Common::EVENT_LBUTTONUP && !getSoundQueue()->isBuffered("LIB045")) { getSound()->playSoundEvent(kEntityPlayer, 45); @@ -408,7 +413,7 @@ void Logic::eventTick(const Common::Event &) { void Logic::resetState() { getState()->scene = kSceneDefault; - warning("Logic::resetState: not implemented! You need to restart the engine until this is implemented."); + warning("[Logic::resetState] Not implemented! You need to restart the engine until this is implemented."); } /** @@ -421,7 +426,7 @@ void Logic::resetState() { */ void Logic::gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, bool showScene) const { - getSound()->processEntries(); + getSoundQueue()->processEntries(); getEntities()->reset(); getFlags()->isGameRunning = false; getSavePoints()->reset(); @@ -429,16 +434,16 @@ void Logic::gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, boo if (showScene) { - getSound()->processEntry(SoundManager::kSoundType11); + getSoundQueue()->processEntry(kSoundType11); if (sceneIndex && !getFlags()->mouseRightClick) { getScenes()->loadScene(sceneIndex); - while (getSound()->isBuffered(kEntityTables4)) { + while (getSoundQueue()->isBuffered(kEntityTables4)) { if (getFlags()->mouseRightClick) break; - getSound()->updateQueue(); + getSoundQueue()->updateQueue(); } } } @@ -448,7 +453,7 @@ void Logic::gameOver(SavegameType type, uint32 value, SceneIndex sceneIndex, boo } void Logic::switchChapter() const { - getSound()->clearStatus(); + getSoundQueue()->clearStatus(); switch(getState()->progress.chapter) { default: @@ -488,7 +493,7 @@ void Logic::switchChapter() const { } void Logic::playFinalSequence() const { - getSound()->processEntries(); + getSoundQueue()->processEntries(); _action->playAnimation(kEventFinalSequence); showCredits(); @@ -501,7 +506,7 @@ void Logic::playFinalSequence() const { } void Logic::showCredits() const { - error("Logic::showCredits: not implemented!"); + error("[Logic::showCredits] Not implemented"); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/menu.cpp b/engines/lastexpress/game/menu.cpp deleted file mode 100644 index f9eef26326..0000000000 --- a/engines/lastexpress/game/menu.cpp +++ /dev/null @@ -1,1541 +0,0 @@ -/* 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/game/menu.h" - -// Data -#include "lastexpress/data/animation.h" -#include "lastexpress/data/cursor.h" -#include "lastexpress/data/snd.h" -#include "lastexpress/data/scene.h" - -#include "lastexpress/game/fight.h" -#include "lastexpress/game/inventory.h" -#include "lastexpress/game/logic.h" -#include "lastexpress/game/savegame.h" -#include "lastexpress/game/savepoint.h" -#include "lastexpress/game/scenes.h" -#include "lastexpress/game/sound.h" -#include "lastexpress/game/state.h" - -#include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" -#include "lastexpress/lastexpress.h" -#include "lastexpress/resource.h" - -#include "common/rational.h" - -#define getNextGameId() (GameId)((_gameId + 1) % 6) - -namespace LastExpress { - -// Bottom-left buttons (quit.seq) -enum StartMenuButtons { - kButtonVolumeDownPushed, - kButtonVolumeDown, - kButtonVolume, - kButtonVolumeUp, - kButtonVolumeUpPushed, - kButtonBrightnessDownPushed, // 5 - kButtonBrightnessDown, - kButtonBrightness, - kButtonBrightnessUp, - kButtonBrightnessUpPushed, - kButtonQuit, // 10 - kButtonQuitPushed -}; - -// Egg buttons (buttns.seq) -enum StartMenuEggButtons { - kButtonShield, - kButtonRewind, - kButtonRewindPushed, - kButtonForward, - kButtonForwardPushed, - kButtonCredits, // 5 - kButtonCreditsPushed, - kButtonContinue -}; - -// Tooltips sequence (helpnewr.seq) -enum StartMenuTooltips { - kTooltipInsertCd1, - kTooltipInsertCd2, - kTooltipInsertCd3, - kTooltipContinueGame, - kTooltipReplayGame, - kTooltipContinueRewoundGame, // 5 - kTooltipViewGameEnding, - kTooltipStartAnotherGame, - kTooltipVolumeUp, - kTooltipVolumeDown, - kTooltipBrightnessUp, // 10 - kTooltipBrightnessDown, - kTooltipQuit, - kTooltipRewindParis, - kTooltipForwardStrasbourg, - kTooltipRewindStrasbourg, // 15 - kTooltipRewindMunich, - kTooltipForwardMunich, - kTooltipForwardVienna, - kTooltipRewindVienna, - kTooltipRewindBudapest, // 20 - kTooltipForwardBudapest, - kTooltipForwardBelgrade, - kTooltipRewindBelgrade, - kTooltipForwardConstantinople, - kTooltipSwitchBlueGame, // 25 - kTooltipSwitchRedGame, - kTooltipSwitchGoldGame, - kTooltipSwitchGreenGame, - kTooltipSwitchTealGame, - kTooltipSwitchPurpleGame, // 30 - kTooltipPlayNewGame, - kTooltipCredits, - kTooltipFastForward, - kTooltipRewind -}; - -////////////////////////////////////////////////////////////////////////// -// DATA -////////////////////////////////////////////////////////////////////////// - -// Information about the cities on the train line -static const struct { - uint8 frame; - TimeValue time; -} _trainCities[31] = { - {0, kTimeCityParis}, - {9, kTimeCityEpernay}, - {11, kTimeCityChalons}, - {16, kTimeCityBarLeDuc}, - {21, kTimeCityNancy}, - {25, kTimeCityLuneville}, - {35, kTimeCityAvricourt}, - {37, kTimeCityDeutschAvricourt}, - {40, kTimeCityStrasbourg}, - {53, kTimeCityBadenOos}, - {56, kTimeCityKarlsruhe}, - {60, kTimeCityStuttgart}, - {63, kTimeCityGeislingen}, - {66, kTimeCityUlm}, - {68, kTimeCityAugsburg}, - {73, kTimeCityMunich}, - {84, kTimeCitySalzbourg}, - {89, kTimeCityAttnangPuchheim}, - {97, kTimeCityWels}, - {100, kTimeCityLinz}, - {104, kTimeCityAmstetten}, - {111, kTimeCityVienna}, - {120, kTimeCityPoszony}, - {124, kTimeCityGalanta}, - {132, kTimeCityBudapest}, - {148, kTimeCityBelgrade}, - /* Line 1 ends at 150 - line 2 begins at 0 */ - {157, kTimeCityNish}, - {165, kTimeCityTzaribrod}, - {174, kTimeCitySofia}, - {198, kTimeCityAdrianople}, - {210, kTimeCityConstantinople}}; - -static const struct { - TimeValue time; - uint index; - StartMenuTooltips rewind; - StartMenuTooltips forward; -} _cityButtonsInfo[7] = { - {kTimeCityParis, 64, kTooltipRewindParis, kTooltipRewindParis}, - {kTimeCityStrasbourg, 128, kTooltipRewindStrasbourg, kTooltipForwardStrasbourg}, - {kTimeCityMunich, 129, kTooltipRewindMunich, kTooltipForwardMunich}, - {kTimeCityVienna, 130, kTooltipRewindVienna, kTooltipForwardVienna}, - {kTimeCityBudapest, 131, kTooltipRewindBudapest, kTooltipForwardBudapest}, - {kTimeCityBelgrade, 132, kTooltipRewindBelgrade, kTooltipForwardBelgrade}, - {kTimeCityConstantinople, 192, kTooltipForwardConstantinople, kTooltipForwardConstantinople} -}; - -////////////////////////////////////////////////////////////////////////// -// Clock -////////////////////////////////////////////////////////////////////////// -class Clock { -public: - explicit Clock(LastExpressEngine *engine); - ~Clock(); - - void draw(uint32 time); - void clear(); - -private: - LastExpressEngine *_engine; - - // Frames - SequenceFrame *_frameMinutes; - SequenceFrame *_frameHour; - SequenceFrame *_frameSun; - SequenceFrame *_frameDate; -}; - -Clock::Clock(LastExpressEngine *engine) : _engine(engine), _frameMinutes(NULL), _frameHour(NULL), _frameSun(NULL), _frameDate(NULL) { - _frameMinutes = new SequenceFrame(loadSequence("eggmin.seq"), 0, true); - _frameHour = new SequenceFrame(loadSequence("egghour.seq"), 0, true); - _frameSun = new SequenceFrame(loadSequence("sun.seq"), 0, true); - _frameDate = new SequenceFrame(loadSequence("datenew.seq"), 0, true); -} - -Clock::~Clock() { - SAFE_DELETE(_frameMinutes); - SAFE_DELETE(_frameHour); - SAFE_DELETE(_frameSun); - SAFE_DELETE(_frameDate); - - // Zero passed pointers - _engine = NULL; -} - -void Clock::clear() { - getScenes()->removeFromQueue(_frameMinutes); - getScenes()->removeFromQueue(_frameHour); - getScenes()->removeFromQueue(_frameSun); - getScenes()->removeFromQueue(_frameDate); -} - -void Clock::draw(uint32 time) { - assert(time >= kTimeCityParis && time <= kTimeCityConstantinople); - - // Check that sequences have been loaded - if (!_frameMinutes || !_frameHour || !_frameSun || !_frameDate) - error("Clock::process: clock sequences have not been loaded correctly!"); - - // Clear existing frames - clear(); - - // Game starts at: 1037700 = 7:13 p.m. on July 24, 1914 - // Game ends at: 4941000 = 7:30 p.m. on July 26, 1914 - // Game lasts for: 3903300 = 2 days + 17 mins = 2897 mins - - // 15 = 1 second - // 15 * 60 = 900 = 1 minute - // 900 * 60 = 54000 = 1 hour - // 54000 * 24 = 1296000 = 1 day - - // Calculate each sequence index from the current time - - uint8 hour = 0; - uint8 minute = 0; - State::getHourMinutes(time, &hour, &minute); - uint32 index_date = 18 * time / 1296000; - if (hour == 23) - index_date += 18 * minute / 60; - - // Set sequences frames - _frameMinutes->setFrame(minute); - _frameHour->setFrame((5 * hour + minute / 12) % 60); - _frameSun->setFrame((5 * hour + minute / 12) % 120); - _frameDate->setFrame((uint16)index_date); - - // Adjust z-order and queue - _frameMinutes->getInfo()->location = 1; - _frameHour->getInfo()->location = 1; - _frameSun->getInfo()->location = 1; - _frameDate->getInfo()->location = 1; - - getScenes()->addToQueue(_frameMinutes); - getScenes()->addToQueue(_frameHour); - getScenes()->addToQueue(_frameSun); - getScenes()->addToQueue(_frameDate); -} - -////////////////////////////////////////////////////////////////////////// -// TrainLine -////////////////////////////////////////////////////////////////////////// -class TrainLine { -public: - explicit TrainLine(LastExpressEngine *engine); - ~TrainLine(); - - void draw(uint32 time); - void clear(); - -private: - LastExpressEngine *_engine; - - // Frames - SequenceFrame *_frameLine1; - SequenceFrame *_frameLine2; -}; - -TrainLine::TrainLine(LastExpressEngine *engine) : _engine(engine), _frameLine1(NULL), _frameLine2(NULL) { - _frameLine1 = new SequenceFrame(loadSequence("line1.seq"), 0, true); - _frameLine2 = new SequenceFrame(loadSequence("line2.seq"), 0, true); -} - -TrainLine::~TrainLine() { - SAFE_DELETE(_frameLine1); - SAFE_DELETE(_frameLine2); - - // Zero passed pointers - _engine = NULL; -} - -void TrainLine::clear() { - getScenes()->removeFromQueue(_frameLine1); - getScenes()->removeFromQueue(_frameLine2); -} - -// Draw the train line at the time -// line1: 150 frames (=> Belgrade) -// line2: 61 frames (=> Constantinople) -void TrainLine::draw(uint32 time) { - assert(time >= kTimeCityParis && time <= kTimeCityConstantinople); - - // Check that sequences have been loaded - if (!_frameLine1 || !_frameLine2) - error("TrainLine::process: Line sequences have not been loaded correctly!"); - - // Clear existing frames - clear(); - - // Get the index of the last city the train has visited - uint index = 0; - for (uint i = 0; i < ARRAYSIZE(_trainCities); i++) - if ((uint32)_trainCities[i].time <= time) - index = i; - - uint16 frame; - if (time > (uint32)_trainCities[index].time) { - // Interpolate linearly to use a frame between the cities - uint8 diffFrames = _trainCities[index + 1].frame - _trainCities[index].frame; - uint diffTimeCities = (uint)(_trainCities[index + 1].time - _trainCities[index].time); - uint traveledTime = (time - (uint)_trainCities[index].time); - frame = (uint16)(_trainCities[index].frame + (traveledTime * diffFrames) / diffTimeCities); - } else { - // Exactly on the city - frame = _trainCities[index].frame; - } - - // Set frame, z-order and queue - if (frame < 150) { - _frameLine1->setFrame(frame); - - _frameLine1->getInfo()->location = 1; - getScenes()->addToQueue(_frameLine1); - } else { - // We passed Belgrade - _frameLine1->setFrame(149); - _frameLine2->setFrame(frame - 150); - - _frameLine1->getInfo()->location = 1; - _frameLine2->getInfo()->location = 1; - - getScenes()->addToQueue(_frameLine1); - getScenes()->addToQueue(_frameLine2); - } -} - - -////////////////////////////////////////////////////////////////////////// -// Menu -////////////////////////////////////////////////////////////////////////// -Menu::Menu(LastExpressEngine *engine) : _engine(engine), - _seqTooltips(NULL), _seqEggButtons(NULL), _seqButtons(NULL), _seqAcorn(NULL), _seqCity1(NULL), _seqCity2(NULL), _seqCity3(NULL), _seqCredits(NULL), - _gameId(kGameBlue), _hasShownStartScreen(false), _hasShownIntro(false), - _isShowingCredits(false), _isGameStarted(false), _isShowingMenu(false), - _creditsSequenceIndex(0), _checkHotspotsTicks(15), _mouseFlags(Common::EVENT_INVALID), _lastHotspot(NULL), - _currentTime(kTimeNone), _lowerTime(kTimeNone), _time(kTimeNone), _currentIndex(0), _index(0), _lastIndex(0), _delta(0), _handleTimeDelta(false) { - - _clock = new Clock(_engine); - _trainLine = new TrainLine(_engine); -} - -Menu::~Menu() { - SAFE_DELETE(_clock); - SAFE_DELETE(_trainLine); - - SAFE_DELETE(_seqTooltips); - SAFE_DELETE(_seqEggButtons); - SAFE_DELETE(_seqButtons); - SAFE_DELETE(_seqAcorn); - SAFE_DELETE(_seqCity1); - SAFE_DELETE(_seqCity2); - SAFE_DELETE(_seqCity3); - SAFE_DELETE(_seqCredits); - - _lastHotspot = NULL; - - // Cleanup frames - for (MenuFrames::iterator it = _frames.begin(); it != _frames.end(); it++) - SAFE_DELETE(it->_value); - - _frames.clear(); - - // Zero passed pointers - _engine = NULL; -} - -////////////////////////////////////////////////////////////////////////// -// Setup -void Menu::setup() { - - // Clear drawing queue - getScenes()->removeAndRedraw(&_frames[kOverlayAcorn], false); - SAFE_DELETE(_seqAcorn); - - // Load Menu scene - // + 1 = normal menu with open egg / clock - // + 2 = shield menu, when no savegame exists (no game has been started) - _isGameStarted = _lowerTime >= kTimeStartGame; - getScenes()->loadScene((SceneIndex)(_isGameStarted ? _gameId * 5 + 1 : _gameId * 5 + 2)); - getFlags()->shouldRedraw = true; - getLogic()->updateCursor(); - - ////////////////////////////////////////////////////////////////////////// - // Load Acorn sequence - _seqAcorn = loadSequence(getAcornSequenceName(_isGameStarted ? getNextGameId() : kGameBlue)); - - ////////////////////////////////////////////////////////////////////////// - // Check if we loaded sequences before - if (_seqTooltips && _seqTooltips->count() > 0) - return; - - // Load all static data - _seqTooltips = loadSequence("helpnewr.seq"); - _seqEggButtons = loadSequence("buttns.seq"); - _seqButtons = loadSequence("quit.seq"); - _seqCity1 = loadSequence("jlinetl.seq"); - _seqCity2 = loadSequence("jlinecen.seq"); - _seqCity3 = loadSequence("jlinebr.seq"); - _seqCredits = loadSequence("credits.seq"); - - _frames[kOverlayTooltip] = new SequenceFrame(_seqTooltips); - _frames[kOverlayEggButtons] = new SequenceFrame(_seqEggButtons); - _frames[kOverlayButtons] = new SequenceFrame(_seqButtons); - _frames[kOverlayAcorn] = new SequenceFrame(_seqAcorn); - _frames[kOverlayCity1] = new SequenceFrame(_seqCity1); - _frames[kOverlayCity2] = new SequenceFrame(_seqCity2); - _frames[kOverlayCity3] = new SequenceFrame(_seqCity3); - _frames[kOverlayCredits] = new SequenceFrame(_seqCredits); -} - -////////////////////////////////////////////////////////////////////////// -// Handle events -void Menu::eventMouse(const Common::Event &ev) { - if (!getFlags()->shouldRedraw) - return; - - bool redraw = true; - getFlags()->shouldRedraw = false; - - // Update coordinates - setCoords(ev.mouse); - //_mouseFlags = (Common::EventType)(ev.type & Common::EVENT_LBUTTONUP); - - if (_isShowingCredits) { - if (ev.type == Common::EVENT_RBUTTONUP) { - showFrame(kOverlayCredits, -1, true); - _isShowingCredits = false; - } - - if (ev.type == Common::EVENT_LBUTTONUP) { - // Last frame of the credits - if (_seqCredits && _creditsSequenceIndex == _seqCredits->count() - 1) { - showFrame(kOverlayCredits, -1, true); - _isShowingCredits = false; - } else { - ++_creditsSequenceIndex; - showFrame(kOverlayCredits, _creditsSequenceIndex, true); - } - } - } else { - // Check for hotspots - SceneHotspot *hotspot = NULL; - getScenes()->get(getState()->scene)->checkHotSpot(ev.mouse, &hotspot); - - if (_lastHotspot != hotspot || ev.type == Common::EVENT_LBUTTONUP) { - _lastHotspot = hotspot; - - if (ev.type == Common::EVENT_MOUSEMOVE) { /* todo check event type */ - if (!_handleTimeDelta && hasTimeDelta()) - setTime(); - } - - if (hotspot) { - redraw = handleEvent((StartMenuAction)hotspot->action, ev.type); - getFlags()->mouseRightClick = false; - getFlags()->mouseLeftClick = false; - } else { - hideOverlays(); - } - } - } - - if (redraw) { - getFlags()->shouldRedraw = true; - askForRedraw(); - } -} - -void Menu::eventTick(const Common::Event&) { - if (hasTimeDelta()) - adjustTime(); - else if (_handleTimeDelta) - _handleTimeDelta = false; - - // Check hotspots - if (!--_checkHotspotsTicks) { - checkHotspots(); - _checkHotspotsTicks = 15; - } -} - -////////////////////////////////////////////////////////////////////////// -// Show the intro and load the main menu scene -void Menu::show(bool doSavegame, SavegameType type, uint32 value) { - - if (_isShowingMenu) - return; - - _isShowingMenu = true; - getEntities()->reset(); - - // If no blue savegame exists, this might be the first time we start the game, so we show the full intro - if (!getFlags()->mouseRightClick) { - if (!SaveLoad::isSavegameValid(kGameBlue) && _engine->getResourceManager()->loadArchive(kArchiveCd1)) { - - if (!_hasShownIntro) { - // Show Broderbrund logo - Animation animation; - if (animation.load(getArchive("1930.nis"))) - animation.play(); - - getFlags()->mouseRightClick = false; - - // Play intro music - getSound()->playSoundWithSubtitles("MUS001.SND", SoundManager::kFlagMusic, kEntityPlayer); - - // Show The Smoking Car logo - if (animation.load(getArchive("1931.nis"))) - animation.play(); - - _hasShownIntro = true; - } - } else { - // Only show the quick intro - if (!_hasShownStartScreen) { - getSound()->playSoundWithSubtitles("MUS018.SND", SoundManager::kFlagMusic, kEntityPlayer); - getScenes()->loadScene(kSceneStartScreen); - - // Original game waits 60 frames and loops Sound::unknownFunction1 unless the right button is pressed - uint32 nextFrameCount = getFrameCount() + 60; - while (getFrameCount() < nextFrameCount) { - _engine->pollEvents(); - - if (getFlags()->mouseRightClick) - break; - - getSound()->updateQueue(); - } - } - } - } - - _hasShownStartScreen = true; - - // Init Menu - init(doSavegame, type, value); - - // Setup sound - getSound()->unknownFunction4(); - getSound()->resetQueue(SoundManager::kSoundType11, SoundManager::kSoundType13); - if (getSound()->isBuffered("TIMER")) - getSound()->removeFromQueue("TIMER"); - - // Init flags & misc - _isShowingCredits = false; - _handleTimeDelta = hasTimeDelta(); - getInventory()->unselectItem(); - - // Set Cursor type - _engine->getCursor()->setStyle(kCursorNormal); - _engine->getCursor()->show(true); - - setup(); - checkHotspots(); - - // Set event handlers - SET_EVENT_HANDLERS(Menu, this); -} - -bool Menu::handleEvent(StartMenuAction action, Common::EventType type) { - bool clicked = (type == Common::EVENT_LBUTTONUP); - - switch(action) { - default: - hideOverlays(); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuCredits: - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - if (clicked) { - showFrame(kOverlayEggButtons, kButtonCreditsPushed, true); - showFrame(kOverlayTooltip, -1, true); - - getSound()->playSound(kEntityPlayer, "LIB046"); - - hideOverlays(); - - _isShowingCredits = true; - _creditsSequenceIndex = 0; - - showFrame(kOverlayCredits, 0, true); - } else { - // TODO check flags ? - - showFrame(kOverlayEggButtons, kButtonCredits, true); - showFrame(kOverlayTooltip, kTooltipCredits, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuQuitGame: - showFrame(kOverlayTooltip, kTooltipQuit, true); - - if (clicked) { - showFrame(kOverlayButtons, kButtonQuitPushed, true); - - getSound()->clearStatus(); - getSound()->updateQueue(); - getSound()->playSound(kEntityPlayer, "LIB046"); - - // FIXME uncomment when sound queue is properly implemented - /*while (getSound()->isBuffered("LIB046")) - getSound()->updateQueue();*/ - - getFlags()->shouldRedraw = false; - - Engine::quitGame(); - - return false; - } else { - showFrame(kOverlayButtons, kButtonQuit, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuCase4: - if (clicked) - _index = 0; - // fall down to kMenuContinue - - ////////////////////////////////////////////////////////////////////////// - case kMenuContinue: { - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - // Determine the proper CD archive - ArchiveIndex cd = kArchiveCd1; - if (getProgress().chapter > kChapter1) - cd = (getProgress().chapter > kChapter3) ? kArchiveCd3 : kArchiveCd2; - - // Show tooltips & buttons to start a game, continue a game or load the proper cd - if (ResourceManager::isArchivePresent(cd)) { - if (_isGameStarted) { - showFrame(kOverlayEggButtons, kButtonContinue, true); - - if (_lastIndex == _index) { - showFrame(kOverlayTooltip, getSaveLoad()->isGameFinished(_index, _lastIndex) ? kTooltipViewGameEnding : kTooltipContinueGame, true); - } else { - showFrame(kOverlayTooltip, kTooltipContinueRewoundGame, true); - } - - } else { - showFrame(kOverlayEggButtons, kButtonShield, true); - showFrame(kOverlayTooltip, kTooltipPlayNewGame, true); - } - } else { - showFrame(kOverlayEggButtons, -1, true); - showFrame(kOverlayTooltip, cd - 1, true); - } - - if (!clicked) - break; - - // Try loading the archive file - if (!_engine->getResourceManager()->loadArchive(cd)) - break; - - // Load the train data file and setup game - getScenes()->loadSceneDataFile(cd); - showFrame(kOverlayTooltip, -1, true); - getSound()->playSound(kEntityPlayer, "LIB046"); - - // Setup new game - getSavePoints()->reset(); - setLogicEventHandlers(); - - if (_index) { - getSound()->processEntry(SoundManager::kSoundType11); - } else { - if (!getFlags()->mouseRightClick) { - getScenes()->loadScene((SceneIndex)(5 * _gameId + 3)); - - if (!getFlags()->mouseRightClick) { - getScenes()->loadScene((SceneIndex)(5 * _gameId + 4)); - - if (!getFlags()->mouseRightClick) { - getScenes()->loadScene((SceneIndex)(5 * _gameId + 5)); - - if (!getFlags()->mouseRightClick) { - getSound()->processEntry(SoundManager::kSoundType11); - - // Show intro - Animation animation; - if (animation.load(getArchive("1601.nis"))) - animation.play(); - - getEvent(kEventIntro) = 1; - } - } - } - } - - if (!getEvent(kEventIntro)) { - getEvent(kEventIntro) = 1; - - getSound()->processEntry(SoundManager::kSoundType11); - } - } - - // Setup game - getFlags()->isGameRunning = true; - startGame(); - - if (!_isShowingMenu) - getInventory()->show(); - - return false; - } - - ////////////////////////////////////////////////////////////////////////// - case kMenuSwitchSaveGame: - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - if (clicked) { - showFrame(kOverlayAcorn, 1, true); - showFrame(kOverlayTooltip, -1, true); - getSound()->playSound(kEntityPlayer, "LIB047"); - - // Setup new menu screen - switchGame(); - setup(); - - // Set fight state to 0 - getFight()->resetState(); - - return true; - } - - // TODO Check for flag - - showFrame(kOverlayAcorn, 0, true); - - if (_isGameStarted) { - showFrame(kOverlayTooltip, kTooltipSwitchBlueGame, true); - break; - } - - if (_gameId == kGameGold) { - showFrame(kOverlayTooltip, kTooltipSwitchBlueGame, true); - break; - } - - if (!SaveLoad::isSavegameValid(getNextGameId())) { - showFrame(kOverlayTooltip, kTooltipStartAnotherGame, true); - break; - } - - // Stupid tooltips ids are not in order, so we can't just increment them... - switch(_gameId) { - default: - break; - - case kGameBlue: - showFrame(kOverlayTooltip, kTooltipSwitchRedGame, true); - break; - - case kGameRed: - showFrame(kOverlayTooltip, kTooltipSwitchGreenGame, true); - break; - - case kGameGreen: - showFrame(kOverlayTooltip, kTooltipSwitchPurpleGame, true); - break; - - case kGamePurple: - showFrame(kOverlayTooltip, kTooltipSwitchTealGame, true); - break; - - case kGameTeal: - showFrame(kOverlayTooltip, kTooltipSwitchGoldGame, true); - break; - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuRewindGame: - if (!_index || _currentTime < _time) { - hideOverlays(); - break; - } - - if (clicked) { - if (hasTimeDelta()) - _handleTimeDelta = false; - - showFrame(kOverlayEggButtons, kButtonRewindPushed, true); - showFrame(kOverlayTooltip, -1, true); - - getSound()->playSound(kEntityPlayer, "LIB046"); - - rewindTime(); - - _handleTimeDelta = false; - } else { - showFrame(kOverlayEggButtons, kButtonRewind, true); - showFrame(kOverlayTooltip, kTooltipRewind, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuForwardGame: - if (_lastIndex <= _index || _currentTime > _time) { - hideOverlays(); - break; - } - - if (clicked) { - if (hasTimeDelta()) - _handleTimeDelta = false; - - showFrame(kOverlayEggButtons, kButtonForwardPushed, true); - showFrame(kOverlayTooltip, -1, true); - - getSound()->playSound(kEntityPlayer, "LIB046"); - - forwardTime(); - - _handleTimeDelta = false; - } else { - showFrame(kOverlayEggButtons, kButtonForward, true); - showFrame(kOverlayTooltip, kTooltipFastForward, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuParis: - moveToCity(kParis, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuStrasBourg: - moveToCity(kStrasbourg, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuMunich: - moveToCity(kMunich, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuVienna: - moveToCity(kVienna, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuBudapest: - moveToCity(kBudapest, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuBelgrade: - moveToCity(kBelgrade, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuConstantinople: - moveToCity(kConstantinople, clicked); - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuDecreaseVolume: - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - // Cannot decrease volume further - if (getVolume() == 0) { - showFrame(kOverlayButtons, kButtonVolume, true); - showFrame(kOverlayTooltip, -1, true); - break; - } - - showFrame(kOverlayTooltip, kTooltipVolumeDown, true); - - // Show highlight on button & adjust volume if needed - if (clicked) { - showFrame(kOverlayButtons, kButtonVolumeDownPushed, true); - getSound()->playSound(kEntityPlayer, "LIB046"); - setVolume(getVolume() - 1); - - getSaveLoad()->saveVolumeBrightness(); - - uint32 nextFrameCount = getFrameCount() + 15; - while (nextFrameCount > getFrameCount()) { - _engine->pollEvents(); - - getSound()->updateQueue(); - } - } else { - showFrame(kOverlayButtons, kButtonVolumeDown, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuIncreaseVolume: - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - // Cannot increase volume further - if (getVolume() >= 7) { - showFrame(kOverlayButtons, kButtonVolume, true); - showFrame(kOverlayTooltip, -1, true); - break; - } - - showFrame(kOverlayTooltip, kTooltipVolumeUp, true); - - // Show highlight on button & adjust volume if needed - if (clicked) { - showFrame(kOverlayButtons, kButtonVolumeUpPushed, true); - getSound()->playSound(kEntityPlayer, "LIB046"); - setVolume(getVolume() + 1); - - getSaveLoad()->saveVolumeBrightness(); - - uint32 nextFrameCount = getFrameCount() + 15; - while (nextFrameCount > getFrameCount()) { - _engine->pollEvents(); - - getSound()->updateQueue(); - } - } else { - showFrame(kOverlayButtons, kButtonVolumeUp, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuDecreaseBrightness: - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - // Cannot increase brightness further - if (getBrightness() == 0) { - showFrame(kOverlayButtons, kButtonBrightness, true); - showFrame(kOverlayTooltip, -1, true); - break; - } - - showFrame(kOverlayTooltip, kTooltipBrightnessDown, true); - - // Show highlight on button & adjust brightness if needed - if (clicked) { - showFrame(kOverlayButtons, kButtonBrightnessDownPushed, true); - getSound()->playSound(kEntityPlayer, "LIB046"); - setBrightness(getBrightness() - 1); - - getSaveLoad()->saveVolumeBrightness(); - - // Reshow the background and frames (they will pick up the new brightness through the GraphicsManager) - _engine->getGraphicsManager()->draw(getScenes()->get((SceneIndex)(_isGameStarted ? _gameId * 5 + 1 : _gameId * 5 + 2)), GraphicsManager::kBackgroundC, true); - showFrame(kOverlayTooltip, kTooltipBrightnessDown, false); - showFrame(kOverlayButtons, kButtonBrightnessDownPushed, false); - } else { - showFrame(kOverlayButtons, kButtonBrightnessDown, true); - } - break; - - ////////////////////////////////////////////////////////////////////////// - case kMenuIncreaseBrightness: - if (hasTimeDelta()) { - hideOverlays(); - break; - } - - // Cannot increase brightness further - if (getBrightness() >= 6) { - showFrame(kOverlayButtons, kButtonBrightness, true); - showFrame(kOverlayTooltip, -1, true); - break; - } - - showFrame(kOverlayTooltip, kTooltipBrightnessUp, true); - - // Show highlight on button & adjust brightness if needed - if (clicked) { - showFrame(kOverlayButtons, kButtonBrightnessUpPushed, true); - getSound()->playSound(kEntityPlayer, "LIB046"); - setBrightness(getBrightness() + 1); - - getSaveLoad()->saveVolumeBrightness(); - - // Reshow the background and frames (they will pick up the new brightness through the GraphicsManager) - _engine->getGraphicsManager()->draw(getScenes()->get((SceneIndex)(_isGameStarted ? _gameId * 5 + 1 : _gameId * 5 + 2)), GraphicsManager::kBackgroundC, true); - showFrame(kOverlayTooltip, kTooltipBrightnessUp, false); - showFrame(kOverlayButtons, kButtonBrightnessUpPushed, false); - } else { - showFrame(kOverlayButtons, kButtonBrightnessUp, true); - } - break; - } - - return true; -} - -void Menu::setLogicEventHandlers() { - SET_EVENT_HANDLERS(Logic, getLogic()); - clear(); - _isShowingMenu = false; -} - -////////////////////////////////////////////////////////////////////////// -// Game-related -////////////////////////////////////////////////////////////////////////// -void Menu::init(bool doSavegame, SavegameType type, uint32 value) { - - bool useSameIndex = true; - - if (getGlobalTimer()) { - value = 0; - - // Check if the CD file is present - ArchiveIndex index = kArchiveCd1; - switch (getProgress().chapter) { - default: - case kChapter1: - break; - - case kChapter2: - case kChapter3: - index = kArchiveCd2; - break; - - case kChapter4: - case kChapter5: - index = kArchiveCd3; - break; - } - - if (ResourceManager::isArchivePresent(index)) { - setGlobalTimer(0); - useSameIndex = false; - - // TODO remove existing savegame and reset index & savegame name - warning("Menu::initGame: not implemented!"); - } - - doSavegame = false; - } else { - // TODO rename saves? - } - - // Create a new savegame if needed - if (!SaveLoad::isSavegamePresent(_gameId)) - getSaveLoad()->create(_gameId); - - if (doSavegame) - getSaveLoad()->saveGame(kSavegameTypeEvent2, kEntityPlayer, kEventNone); - - if (!getGlobalTimer()) { - // TODO: remove existing savegame temp file - } - - // Init savegame & menu values - _lastIndex = getSaveLoad()->init(_gameId, true); - _lowerTime = getSaveLoad()->getTime(_lastIndex); - - if (useSameIndex) - _index = _lastIndex; - - //if (!getGlobalTimer()) - // _index3 = 0; - - if (!getProgress().chapter) - getProgress().chapter = kChapter1; - - getState()->time = (TimeValue)getSaveLoad()->getTime(_index); - getProgress().chapter = getSaveLoad()->getChapter(_index); - - if (_lowerTime >= kTimeStartGame) { - _currentTime = (uint32)getState()->time; - _time = (uint32)getState()->time; - _clock->draw(_time); - _trainLine->draw(_time); - - initTime(type, value); - } -} - -// Start a game (or load an existing savegame) -void Menu::startGame() { - // Clear savegame headers - getSaveLoad()->clear(); - - // Hide menu elements - _clock->clear(); - _trainLine->clear(); - - if (_lastIndex == _index) { - setGlobalTimer(0); - if (_index) { - getSaveLoad()->loadGame(_gameId); - } else { - getLogic()->resetState(); - getEntities()->setup(true, kEntityPlayer); - } - } else { - getSaveLoad()->loadGame(_gameId, _index); - } -} - -// Switch to the next savegame -void Menu::switchGame() { - - // Switch back to blue game is the current game is not started - _gameId = SaveLoad::isSavegameValid(_gameId) ? getNextGameId() : kGameBlue; - - // Initialize savegame if needed - if (!SaveLoad::isSavegamePresent(_gameId)) - getSaveLoad()->create(_gameId); - - getState()->time = kTimeNone; - - // Clear menu elements - _clock->clear(); - _trainLine->clear(); - - // Clear loaded savegame data - getSaveLoad()->clear(true); - - init(false, kSavegameTypeIndex, 0); -} - -////////////////////////////////////////////////////////////////////////// -// Overlays & elements -////////////////////////////////////////////////////////////////////////// -void Menu::checkHotspots() { - if (!_isShowingMenu) - return; - - if (!getFlags()->shouldRedraw) - return; - - if (_isShowingCredits) - return; - - SceneHotspot *hotspot = NULL; - getScenes()->get(getState()->scene)->checkHotSpot(getCoords(), &hotspot); - - if (hotspot) - handleEvent((StartMenuAction)hotspot->action, _mouseFlags); - else - hideOverlays(); -} - -void Menu::hideOverlays() { - _lastHotspot = NULL; - - // Hide all menu overlays - for (MenuFrames::iterator it = _frames.begin(); it != _frames.end(); it++) - showFrame(it->_key, -1, false); - - getScenes()->drawFrames(true); -} - -void Menu::showFrame(StartMenuOverlay overlayType, int index, bool redraw) { - if (index == -1) { - getScenes()->removeFromQueue(_frames[overlayType]); - } else { - // Check that the overlay is valid - if (!_frames[overlayType]) - return; - - // Remove the frame and add a new one with the proper index - getScenes()->removeFromQueue(_frames[overlayType]); - _frames[overlayType]->setFrame((uint16)index); - getScenes()->addToQueue(_frames[overlayType]); - } - - if (redraw) - getScenes()->drawFrames(true); -} - -// Remove all frames from the queue -void Menu::clear() { - for (MenuFrames::iterator it = _frames.begin(); it != _frames.end(); it++) - getScenes()->removeAndRedraw(&it->_value, false); - - clearBg(GraphicsManager::kBackgroundOverlay); -} - -// Get the sequence name to use for the acorn highlight, depending of the currently loaded savegame -Common::String Menu::getAcornSequenceName(GameId id) const { - Common::String name = ""; - switch (id) { - default: - case kGameBlue: - name = "aconblu3.seq"; - break; - - case kGameRed: - name = "aconred.seq"; - break; - - case kGameGreen: - name = "acongren.seq"; - break; - - case kGamePurple: - name = "aconpurp.seq"; - break; - - case kGameTeal: - name = "aconteal.seq"; - break; - - case kGameGold: - name = "acongold.seq"; - break; - } - - return name; -} - -////////////////////////////////////////////////////////////////////////// -// Time -////////////////////////////////////////////////////////////////////////// -void Menu::initTime(SavegameType type, uint32 value) { - if (!value) - return; - - // The savegame entry index - uint32 entryIndex = 0; - - switch (type) { - default: - break; - - case kSavegameTypeIndex: - entryIndex = (_index <= value) ? 1 : _index - value; - break; - - case kSavegameTypeTime: - if (value < kTimeStartGame) - break; - - entryIndex = _index; - if (!entryIndex) - break; - - // Iterate through existing entries - do { - if (getSaveLoad()->getTime(entryIndex) <= value) - break; - - entryIndex--; - } while (entryIndex); - break; - - case kSavegameTypeEvent: - entryIndex = _index; - if (!entryIndex) - break; - - do { - if (getSaveLoad()->getValue(entryIndex) == value) - break; - - entryIndex--; - } while (entryIndex); - break; - - case kSavegameTypeEvent2: - // TODO rewrite in a more legible way - if (_index > 1) { - uint32 index = _index; - do { - if (getSaveLoad()->getValue(index) == value) - break; - - index--; - } while (index > 1); - - entryIndex = index - 1; - } else { - entryIndex = _index - 1; - } - break; - } - - if (entryIndex) { - _currentIndex = entryIndex; - updateTime(getSaveLoad()->getTime(entryIndex)); - } -} - -void Menu::updateTime(uint32 time) { - if (_currentTime == _time) - _delta = 0; - - _currentTime = time; - - if (_time != time) { - if (getSound()->isBuffered(kEntityChapters)) - getSound()->removeFromQueue(kEntityChapters); - - getSound()->playSoundWithSubtitles((_currentTime >= _time) ? "LIB042" : "LIB041", SoundManager::kFlagMenuClock, kEntityChapters); - adjustIndex(_currentTime, _time, false); - } -} - -void Menu::adjustIndex(uint32 time1, uint32 time2, bool searchEntry) { - uint32 index = 0; - int32 timeDelta = -1; - - if (time1 != time2) { - - index = _index; - - if (time2 >= time1) { - if (searchEntry) { - uint32 currentIndex = _index; - - if ((int32)_index >= 0) { - do { - // Calculate new delta - int32 newDelta = time1 - (uint32)getSaveLoad()->getTime(currentIndex); - - if (newDelta >= 0 && timeDelta >= newDelta) { - timeDelta = newDelta; - index = currentIndex; - } - - --currentIndex; - } while ((int32)currentIndex >= 0); - } - } else { - index = _index - 1; - } - } else { - if (searchEntry) { - uint32 currentIndex = _index; - - if (_lastIndex >= _index) { - do { - // Calculate new delta - int32 newDelta = (uint32)getSaveLoad()->getTime(currentIndex) - time1; - - if (newDelta >= 0 && timeDelta > newDelta) { - timeDelta = newDelta; - index = currentIndex; - } - - ++currentIndex; - } while (currentIndex <= _lastIndex); - } - } else { - index = _index + 1; - } - } - - _index = index; - checkHotspots(); - } - - if (_index == _currentIndex) { - if (getProgress().chapter != getSaveLoad()->getChapter(index)) - getProgress().chapter = getSaveLoad()->getChapter(_index); - } -} - -void Menu::goToTime(uint32 time) { - - uint32 entryIndex = 0; - uint32 deltaTime = (uint32)ABS((int32)(getSaveLoad()->getTime(0) - time)); - uint32 index = 0; - - do { - uint32 deltaTime2 = (uint32)ABS((int32)(getSaveLoad()->getTime(index) - time)); - if (deltaTime2 < deltaTime) { - deltaTime = deltaTime2; - entryIndex = index; - } - - ++index; - } while (_lastIndex >= index); - - _currentIndex = entryIndex; - updateTime(getSaveLoad()->getTime(entryIndex)); -} - -void Menu::setTime() { - _currentIndex = _index; - _currentTime = getSaveLoad()->getTime(_currentIndex); - - if (_time == _currentTime) - adjustTime(); -} - -void Menu::forwardTime() { - if (_lastIndex <= _index) - return; - - _currentIndex = _lastIndex; - updateTime(getSaveLoad()->getTime(_currentIndex)); -} - -void Menu::rewindTime() { - if (!_index) - return; - - _currentIndex = 0; - updateTime(getSaveLoad()->getTime(_currentIndex)); -} - -void Menu::adjustTime() { - uint32 originalTime = _time; - - // Adjust time delta - Common::Rational timeDelta(_delta >= 90 ? 9 : (9 * _delta + 89), _delta >= 90 ? 1 : 90); - - if (_currentTime < _time) { - timeDelta *= 900; - _time -= (uint)timeDelta.toInt(); - - if (_currentTime > _time) - _time = _currentTime; - } else { - timeDelta *= 900; - _time += (uint)timeDelta.toInt(); - - if (_currentTime < _time) - _time = _currentTime; - } - - if (_currentTime == _time && getSound()->isBuffered(kEntityChapters)) - getSound()->removeFromQueue(kEntityChapters); - - _clock->draw(_time); - _trainLine->draw(_time); - getScenes()->drawFrames(true); - - adjustIndex(_time, originalTime, true); - - ++_delta; -} - -void Menu::moveToCity(CityButton city, bool clicked) { - uint32 time = (uint32)_cityButtonsInfo[city].time; - - // TODO Check if we have access (there seems to be more checks on some internal times) - probably : current_time (menu only) / game time / some other? - if (_lowerTime < time || _time == time || _currentTime == time) { - hideOverlays(); - return; - } - - // Show city overlay - showFrame((StartMenuOverlay)((_cityButtonsInfo[city].index >> 6) + 3), _cityButtonsInfo[city].index & 63, true); - - if (clicked) { - showFrame(kOverlayTooltip, -1, true); - getSound()->playSound(kEntityPlayer, "LIB046"); - goToTime(time); - - _handleTimeDelta = true; - - return; - } - - // Special case of first and last cities - if (city == kParis || city == kConstantinople) { - showFrame(kOverlayTooltip, (city == kParis) ? kTooltipRewindParis : kTooltipForwardConstantinople, true); - return; - } - - showFrame(kOverlayTooltip, (_time <= time) ? _cityButtonsInfo[city].forward : _cityButtonsInfo[city].rewind, true); -} - -////////////////////////////////////////////////////////////////////////// -// Sound / Brightness -////////////////////////////////////////////////////////////////////////// - -// Get current volume (converted internal ScummVM value) -uint32 Menu::getVolume() const { - return getState()->volume; -} - -// Set the volume (converts to ScummVM values) -void Menu::setVolume(uint32 volume) const { - getState()->volume = volume; - - // Clamp volume - uint32 value = volume * Audio::Mixer::kMaxMixerVolume / 7; - - if (value > Audio::Mixer::kMaxMixerVolume) - value = Audio::Mixer::kMaxMixerVolume; - - _engine->_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, (int32)value); -} - -uint32 Menu::getBrightness() const { - return getState()->brightness; -} - -void Menu::setBrightness(uint32 brightness) const { - getState()->brightness = brightness; - - // TODO reload cursor & font with adjusted brightness -} - -} // End of namespace LastExpress diff --git a/engines/lastexpress/game/menu.h b/engines/lastexpress/game/menu.h deleted file mode 100644 index 4b84c065cb..0000000000 --- a/engines/lastexpress/game/menu.h +++ /dev/null @@ -1,207 +0,0 @@ -/* 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. - * - */ - -#ifndef LASTEXPRESS_MENU_H -#define LASTEXPRESS_MENU_H - -#include "lastexpress/data/sequence.h" - -#include "lastexpress/eventhandler.h" - -#include "lastexpress/shared.h" - -#include "common/hashmap.h" - -namespace LastExpress { - -class LastExpressEngine; -class Scene; -class SceneHotspot; - -class Clock; -class TrainLine; - -class Menu : public EventHandler { -public: - Menu(LastExpressEngine *engine); - ~Menu(); - - void show(bool doSavegame, SavegameType type, uint32 value); - - // Event handling - void eventMouse(const Common::Event &ev); - void eventTick(const Common::Event &ev); - - bool isShown() const { return _isShowingMenu; } - - GameId getGameId() const { return _gameId; } - -private: - // Start menu events - enum StartMenuAction { - kMenuContinue = 1, - kMenuCredits = 2, - kMenuQuitGame = 3, - kMenuCase4 = 4, - kMenuSwitchSaveGame = 6, - kMenuRewindGame = 7, - kMenuForwardGame = 8, - kMenuParis = 10, - kMenuStrasBourg = 11, - kMenuMunich = 12, - kMenuVienna = 13, - kMenuBudapest = 14, - kMenuBelgrade = 15, - kMenuConstantinople = 16, - kMenuDecreaseVolume = 17, - kMenuIncreaseVolume = 18, - kMenuDecreaseBrightness = 19, - kMenuIncreaseBrightness = 20 - }; - - // City buttons - enum CityButton { - kParis = 0, - kStrasbourg = 1, - kMunich = 2, - kVienna = 3, - kBudapest = 4, - kBelgrade = 5, - kConstantinople = 6 - }; - - // Start menu overlay elements - enum StartMenuOverlay { - kOverlayTooltip, // 0 - kOverlayEggButtons, - kOverlayButtons, - kOverlayAcorn, - kOverlayCity1, - kOverlayCity2, // 5 - kOverlayCity3, - kOverlayCredits - }; - - LastExpressEngine *_engine; - - // Sequences - Sequence *_seqTooltips; - Sequence *_seqEggButtons; - Sequence *_seqButtons; - Sequence *_seqAcorn; - Sequence *_seqCity1; - Sequence *_seqCity2; - Sequence *_seqCity3; - Sequence *_seqCredits; - - GameId _gameId; - - // Indicator to know if we need to show the start animation when showMenu is called - bool _hasShownStartScreen; - bool _hasShownIntro; - - bool _isShowingCredits; - bool _isGameStarted; - bool _isShowingMenu; - - - uint16 _creditsSequenceIndex; - - ////////////////////////////////////////////////////////////////////////// - // Event handling - uint32 _checkHotspotsTicks; - Common::EventType _mouseFlags; - SceneHotspot *_lastHotspot; - - void init(bool doSavegame, SavegameType type, uint32 value); - void setup(); - bool handleEvent(StartMenuAction action, Common::EventType type); - void checkHotspots(); - void setLogicEventHandlers(); - - ////////////////////////////////////////////////////////////////////////// - // Game-related - void startGame(); - void switchGame(); - - ////////////////////////////////////////////////////////////////////////// - // Overlays & elements - Clock *_clock; - TrainLine *_trainLine; - - struct MenuOverlays_EqualTo { - bool operator()(const StartMenuOverlay &x, const StartMenuOverlay &y) const { return x == y; } - }; - - struct MenuOverlays_Hash { - uint operator()(const StartMenuOverlay &x) const { return x; } - }; - - typedef Common::HashMap<StartMenuOverlay, SequenceFrame *, MenuOverlays_Hash, MenuOverlays_EqualTo> MenuFrames; - - MenuFrames _frames; - - void hideOverlays(); - void showFrame(StartMenuOverlay overlay, int index, bool redraw); - - void clear(); - - // TODO: remove? - void moveToCity(CityButton city, bool clicked); - - ////////////////////////////////////////////////////////////////////////// - // Misc - Common::String getAcornSequenceName(GameId id) const; - - ////////////////////////////////////////////////////////////////////////// - // Time - uint32 _currentTime; // current game time - uint32 _lowerTime; // lower time value - uint32 _time; - - uint32 _currentIndex; // current savegame entry - uint32 _index; - uint32 _lastIndex; - uint32 _delta; - bool _handleTimeDelta; - - void initTime(SavegameType type, uint32 val); - void updateTime(uint32 time); - void adjustTime(); - void adjustIndex(uint32 time1, uint32 time2, bool searchEntry); - void goToTime(uint32 time); - void setTime(); - void forwardTime(); - void rewindTime(); - bool hasTimeDelta() { return (_currentTime - _time) >= 1; } - - ////////////////////////////////////////////////////////////////////////// - // Sound/Brightness related - uint32 getVolume() const; - void setVolume(uint32 volume) const; - uint32 getBrightness() const; - void setBrightness(uint32 brightness) const; -}; - -} // End of namespace LastExpress - -#endif // LASTEXPRESS_MENU_H diff --git a/engines/lastexpress/game/object.cpp b/engines/lastexpress/game/object.cpp index a600075953..d9e9e4279a 100644 --- a/engines/lastexpress/game/object.cpp +++ b/engines/lastexpress/game/object.cpp @@ -39,7 +39,7 @@ Objects::Objects(LastExpressEngine *engine) : _engine(engine) {} const Objects::Object Objects::get(ObjectIndex index) const { if (index >= kObjectMax) - error("Objects::get - internal error: invalid object index (%d)", index); + error("[Objects::get] Invalid object index (%d)", index); return _objects[index]; } diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 5d06ecab13..57c18b5697 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -24,11 +24,14 @@ #include "lastexpress/game/inventory.h" #include "lastexpress/game/logic.h" -#include "lastexpress/game/menu.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savepoint.h" #include "lastexpress/game/state.h" +#include "lastexpress/menu/menu.h" + +#include "lastexpress/sound/queue.h" + #include "lastexpress/debug.h" #include "lastexpress/lastexpress.h" #include "lastexpress/helpers.h" @@ -42,12 +45,12 @@ namespace LastExpress { static const struct { const char *saveFile; } gameInfo[6] = { - {"blue.egg"}, - {"red.egg"}, - {"green.egg"}, - {"purple.egg"}, - {"teal.egg"}, - {"gold.egg"} + {"lastexpress-blue.egg"}, + {"lastexpress-red.egg"}, + {"lastexpress-green.egg"}, + {"lastexpress-purple.egg"}, + {"lastexpress-teal.egg"}, + {"lastexpress-gold.egg"} }; ////////////////////////////////////////////////////////////////////////// @@ -72,10 +75,10 @@ void SaveLoad::initStream() { void SaveLoad::flushStream(GameId id) { Common::OutSaveFile *save = openForSaving(id); if (!save) - error("SaveLoad::flushStream: cannot open savegame (%s)!", getFilename(id).c_str()); + error("[SaveLoad::flushStream] Cannot open savegame (%s)", getFilename(id).c_str()); if (!_savegame) - error("SaveLoad::flushStream: savegame stream is invalid"); + error("[SaveLoad::flushStream] Savegame stream is invalid"); save->write(_savegame->getData(), (uint32)_savegame->size()); @@ -106,7 +109,7 @@ uint32 SaveLoad::init(GameId id, bool resetHeaders) { SavegameMainHeader mainHeader; mainHeader.saveLoadWithSerializer(ser); if (!mainHeader.isValid()) - error("SaveLoad::init - Savegame seems to be corrupted (invalid header)"); + error("[SaveLoad::init] Savegame seems to be corrupted (invalid header)"); // Reset cached entry headers if needed if (resetHeaders) { @@ -124,7 +127,7 @@ uint32 SaveLoad::init(GameId id, bool resetHeaders) { while (_savegame->pos() < _savegame->size() && !_savegame->eos() && !_savegame->err()) { // Update sound queue while we go through the savegame - getSound()->updateQueue(); + getSoundQueue()->updateQueue(); SavegameEntryHeader *entry = new SavegameEntryHeader(); entry->saveLoadWithSerializer(ser); @@ -145,10 +148,10 @@ uint32 SaveLoad::init(GameId id, bool resetHeaders) { void SaveLoad::loadStream(GameId id) { Common::InSaveFile *save = openForLoading(id); if (save->size() < 32) - error("SaveLoad::init - Savegame seems to be corrupted (not enough data: %i bytes)", save->size()); + error("[SaveLoad::loadStream] Savegame seems to be corrupted (not enough data: %i bytes)", save->size()); if (!_savegame) - error("SaveLoad::loadStream: savegame stream is invalid"); + error("[SaveLoad::loadStream] Savegame stream is invalid"); // Load all savegame data uint8* buf = new uint8[8192]; @@ -189,7 +192,7 @@ void SaveLoad::clear(bool clearStream) { // Load game void SaveLoad::loadGame(GameId id) { if (!_savegame) - error("SaveLoad::loadGame: No savegame stream present!"); + error("[SaveLoad::loadGame] No savegame stream present"); // Rewind current savegame _savegame->seek(0); @@ -197,12 +200,12 @@ void SaveLoad::loadGame(GameId id) { // Validate main header SavegameMainHeader header; if (!loadMainHeader(_savegame, &header)) { - debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str()); + debugC(2, kLastExpressDebugSavegame, "Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str()); return; } if (!_savegame) - error("SaveLoad::loadGame: No savegame stream present!"); + error("[SaveLoad::loadGame] No savegame stream present"); // Load the last entry _savegame->seek(header.offsetEntry); @@ -216,7 +219,7 @@ void SaveLoad::loadGame(GameId id) { _gameTicksLastSavegame = getState()->timeTicks; if (header.keepIndex) { - getSound()->clearQueue(); + getSoundQueue()->clearQueue(); readEntry(&type, &entity, &val, false); } @@ -227,7 +230,7 @@ void SaveLoad::loadGame(GameId id) { // Load a specific game entry void SaveLoad::loadGame(GameId id, uint32 index) { - error("SaveLoad::loadGame: not implemented! (only loading the last entry is working for now)"); + error("[SaveLoad::loadGame] Not implemented! (only loading the last entry is working for now)"); } // Save game @@ -238,12 +241,12 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { // Validate main header SavegameMainHeader header; if (!loadMainHeader(_savegame, &header)) { - debugC(2, kLastExpressDebugSavegame, "SaveLoad::saveGame - Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str()); + debugC(2, kLastExpressDebugSavegame, "Cannot load main header: %s", getFilename(getMenu()->getGameId()).c_str()); return; } if (!_savegame) - error("SaveLoad::saveGame: savegame stream is invalid"); + error("[SaveLoad::saveGame] Savegame stream is invalid"); // Validate the current entry if it exists if (header.count > 0) { @@ -255,7 +258,7 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { entry.saveLoadWithSerializer(ser); if (!entry.isValid()) { - warning("SaveLoad::saveGame: Invalid entry. This savegame might be corrupted!"); + warning("[SaveLoad::saveGame] Invalid entry. This savegame might be corrupted"); _savegame->seek(header.offset); } else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) { // Not ready to save a game, skipping! @@ -293,7 +296,7 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { // Validate the main header if (!header.isValid()) - error("SaveLoad::saveGame: main game header is invalid!"); + error("[SaveLoad::saveGame] Main game header is invalid"); // Write the main header _savegame->seek(0); @@ -304,7 +307,7 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { } void SaveLoad::saveVolumeBrightness() { - warning("SaveLoad::saveVolumeBrightness: not implemented!"); + warning("[SaveLoad::saveVolumeBrightness] Not implemented"); } ////////////////////////////////////////////////////////////////////////// @@ -316,7 +319,7 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he // Check there is enough data (32 bytes) if (stream->size() < 32) { - debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Savegame seems to be corrupted (not enough data: %i bytes)!", stream->size()); + debugC(2, kLastExpressDebugSavegame, "Savegame seems to be corrupted (not enough data: %i bytes)", stream->size()); return false; } @@ -328,7 +331,7 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he // Validate the header if (!header->isValid()) { - debugC(2, kLastExpressDebugSavegame, "SaveLoad::loadMainHeader - Cannot validate main header!"); + debugC(2, kLastExpressDebugSavegame, "Cannot validate main header"); return false; } @@ -345,11 +348,11 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { uint32 _count = (uint32)_savegame->pos() - _prevPosition; \ debugC(kLastExpressDebugSavegame, "Savegame: Writing " #name ": %d bytes", _count); \ if (_count != val)\ - error("SaveLoad::writeEntry: Number of bytes written (%d) differ from expected count (%d)", _count, val); \ + error("[SaveLoad::writeEntry] Number of bytes written (%d) differ from expected count (%d)", _count, val); \ } if (!_savegame) - error("SaveLoad::writeEntry: savegame stream is invalid"); + error("[SaveLoad::writeEntry] Savegame stream is invalid"); SavegameEntryHeader header; @@ -376,7 +379,7 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { WRITE_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32); WRITE_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128); WRITE_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40); - WRITE_ENTRY("sound", getSound()->saveLoadWithSerializer(ser), 3 * 4 + getSound()->count() * 64); + WRITE_ENTRY("sound", getSoundQueue()->saveLoadWithSerializer(ser), 3 * 4 + getSoundQueue()->count() * 64); WRITE_ENTRY("savepoints", getSavePoints()->saveLoadWithSerializer(ser), 128 * 16 + 4 + getSavePoints()->count() * 16); header.offset = (uint32)_savegame->pos() - (originalPosition + 32); @@ -392,7 +395,7 @@ void SaveLoad::writeEntry(SavegameType type, EntityIndex entity, uint32 value) { // Validate entry header if (!header.isValid()) - error("SaveLoad::writeEntry: entry header is invalid"); + error("[SaveLoad::writeEntry] Entry header is invalid"); // Save the header with the updated info _savegame->seek(originalPosition); @@ -409,7 +412,7 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b uint32 _count = (uint32)_savegame->pos() - _prevPosition; \ debugC(kLastExpressDebugSavegame, "Savegame: Reading " #name ": %d bytes", _count); \ if (_count != val) \ - error("SaveLoad::readEntry: Number of bytes read (%d) differ from expected count (%d)", _count, val); \ + error("[SaveLoad::readEntry] Number of bytes read (%d) differ from expected count (%d)", _count, val); \ } #define LOAD_ENTRY_ONLY(name, func) { \ @@ -420,10 +423,10 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b } if (!type || !entity || !val) - error("SaveLoad::readEntry: Invalid parameters passed!"); + error("[SaveLoad::readEntry] Invalid parameters passed"); if (!_savegame) - error("SaveLoad::readEntry: No savegame stream present!"); + error("[SaveLoad::readEntry] No savegame stream present"); // Load entry header SavegameEntryHeader entry; @@ -431,7 +434,7 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b entry.saveLoadWithSerializer(ser); if (!entry.isValid()) - error("SaveLoad::readEntry: entry header is invalid!"); + error("[SaveLoad::readEntry] Entry header is invalid"); // Init type, entity & value *type = entry.type; @@ -451,7 +454,7 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b LOAD_ENTRY("inventory", getInventory()->saveLoadWithSerializer(ser), 7 * 32); LOAD_ENTRY("objects", getObjects()->saveLoadWithSerializer(ser), 5 * 128); LOAD_ENTRY("entities", getEntities()->saveLoadWithSerializer(ser), 1262 * 40); - LOAD_ENTRY_ONLY("sound", getSound()->saveLoadWithSerializer(ser)); + LOAD_ENTRY_ONLY("sound", getSoundQueue()->saveLoadWithSerializer(ser)); LOAD_ENTRY_ONLY("savepoints", getSavePoints()->saveLoadWithSerializer(ser)); // Update chapter @@ -466,7 +469,7 @@ void SaveLoad::readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, b SaveLoad::SavegameEntryHeader *SaveLoad::getEntry(uint32 index) { if (index >= _gameHeaders.size()) - error("SaveLoad::getEntry: invalid index (was:%d, max:%d)", index, _gameHeaders.size() - 1); + error("[SaveLoad::getEntry] Invalid index (was:%d, max:%d)", index, _gameHeaders.size() - 1); return _gameHeaders[index]; } @@ -486,7 +489,7 @@ bool SaveLoad::isSavegamePresent(GameId id) { // Check if the game has been started in the specific savegame bool SaveLoad::isSavegameValid(GameId id) { if (!isSavegamePresent(id)) { - debugC(2, kLastExpressDebugSavegame, "SaveLoad::isSavegameValid - Savegame does not exist: %s", getFilename(id).c_str()); + debugC(2, kLastExpressDebugSavegame, "Savegame does not exist: %s", getFilename(id).c_str()); return false; } @@ -549,7 +552,7 @@ bool SaveLoad::isGameFinished(uint32 menuIndex, uint32 savegameIndex) { // Get the file name from the savegame ID Common::String SaveLoad::getFilename(GameId id) { if (id >= 6) - error("SaveLoad::getName - attempting to use an invalid game id. Valid values: 0 - 5, was %d", id); + error("[SaveLoad::getFilename] Attempting to use an invalid game id. Valid values: 0 - 5, was %d", id); return gameInfo[id].saveFile; } @@ -558,7 +561,7 @@ Common::InSaveFile *SaveLoad::openForLoading(GameId id) { Common::InSaveFile *load = g_system->getSavefileManager()->openForLoading(getFilename(id)); if (!load) - debugC(2, kLastExpressDebugSavegame, "SaveLoad::openForLoading - Cannot open savegame for loading: %s", getFilename(id).c_str()); + debugC(2, kLastExpressDebugSavegame, "Cannot open savegame for loading: %s", getFilename(id).c_str()); return load; } @@ -567,7 +570,7 @@ Common::OutSaveFile *SaveLoad::openForSaving(GameId id) { Common::OutSaveFile *save = g_system->getSavefileManager()->openForSaving(getFilename(id)); if (!save) - debugC(2, kLastExpressDebugSavegame, "SaveLoad::openForSaving - Cannot open savegame for writing: %s", getFilename(id).c_str()); + debugC(2, kLastExpressDebugSavegame, "Cannot open savegame for writing: %s", getFilename(id).c_str()); return save; } diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp index 7ec7c241e9..64ae26c2be 100644 --- a/engines/lastexpress/game/savepoint.cpp +++ b/engines/lastexpress/game/savepoint.cpp @@ -128,17 +128,17 @@ void SavePoints::addData(EntityIndex entity, ActionIndex action, uint32 param) { ////////////////////////////////////////////////////////////////////////// void SavePoints::setCallback(EntityIndex index, Entity::Callback *callback) { if (index >= 40) - error("SavePoints::setCallback - attempting to use an invalid entity index. Valid values 0-39, was %d", index); + error("[SavePoints::setCallback] Attempting to use an invalid entity index. Valid values 0-39, was %d", index); if (!callback || !callback->isValid()) - error("SavePoints::setCallback - attempting to set an invalid callback for entity %s", ENTITY_NAME(index)); + error("[SavePoints::setCallback] Attempting to set an invalid callback for entity %s", ENTITY_NAME(index)); _callbacks[index] = callback; } Entity::Callback *SavePoints::getCallback(EntityIndex index) const { if (index >= 40) - error("SavePoints::getCallback - attempting to use an invalid entity index. Valid values 0-39, was %d", index); + error("[SavePoints::getCallback] Attempting to use an invalid entity index. Valid values 0-39, was %d", index); return _callbacks[index]; } diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp index e830b1d128..b886951e0b 100644 --- a/engines/lastexpress/game/scenes.cpp +++ b/engines/lastexpress/game/scenes.cpp @@ -31,9 +31,11 @@ #include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savepoint.h" -#include "lastexpress/game/sound.h" #include "lastexpress/game/state.h" +#include "lastexpress/sound/queue.h" +#include "lastexpress/sound/sound.h" + #include "lastexpress/graphics.h" #include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" @@ -79,12 +81,12 @@ void SceneManager::loadSceneDataFile(ArchiveIndex archive) { case kArchiveCd2: case kArchiveCd3: if (!_sceneLoader->load(getArchive(Common::String::format("CD%iTRAIN.DAT", archive)))) - error("SceneManager::loadSceneDataFile: cannot load data file CD%iTRAIN.DAT", archive); + error("[SceneManager::loadSceneDataFile] Cannot load data file CD%iTRAIN.DAT", archive); break; default: case kArchiveAll: - error("SceneManager::loadSceneDataFile: Invalid archive index (must be [1-3], was %d", archive); + error("[SceneManager::loadSceneDataFile] Invalid archive index (must be [1-3], was %d", archive); break; } } @@ -462,7 +464,7 @@ bool SceneManager::checkPosition(SceneIndex index, CheckPositionType type) const switch (type) { default: - error("SceneManager::checkPosition: Invalid position type: %d", type); + error("[SceneManager::checkPosition] Invalid position type: %d", type); case kCheckPositionLookingUp: return isInSleepingCar && (position >= 1 && position <= 19); @@ -1057,9 +1059,9 @@ void SceneManager::preProcessScene(SceneIndex *index) { // Sound processing Scene *newScene = getScenes()->get(*index); - if (getSound()->isBuffered(kEntityTables4)) { + if (getSoundQueue()->isBuffered(kEntityTables4)) { if (newScene->type != Scene::kTypeReadText || newScene->param1) - getSound()->processEntry(kEntityTables4); + getSoundQueue()->processEntry(kEntityTables4); } // Cleanup beetle sequences @@ -1089,8 +1091,8 @@ void SceneManager::postProcessScene() { if (getFlags()->mouseRightClick) break; - getSound()->updateQueue(); - getSound()->updateSubtitles(); + getSoundQueue()->updateQueue(); + getSoundQueue()->updateSubtitles(); } } @@ -1132,7 +1134,7 @@ void SceneManager::postProcessScene() { } if (progress) - getSound()->excuseMe((progress == 1) ? entities[0] : entities[rnd(progress)], kEntityPlayer, SoundManager::kFlagDefault); + getSound()->excuseMe((progress == 1) ? entities[0] : entities[rnd(progress)], kEntityPlayer, kFlagDefault); } if (hotspot->scene) @@ -1157,8 +1159,8 @@ void SceneManager::postProcessScene() { if (getState()->time >= kTimeCityGalanta || getProgress().field_18 == 4) break; - getSound()->processEntry(SoundManager::kSoundType7); - getSound()->playSound(kEntityTrain, "LIB050", SoundManager::kFlagDefault); + getSoundQueue()->processEntry(kSoundType7); + getSound()->playSound(kEntityTrain, "LIB050", kFlagDefault); switch (getProgress().chapter) { default: diff --git a/engines/lastexpress/game/sound.cpp b/engines/lastexpress/game/sound.cpp deleted file mode 100644 index 3f98ac79ea..0000000000 --- a/engines/lastexpress/game/sound.cpp +++ /dev/null @@ -1,1951 +0,0 @@ -/* 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/game/sound.h" - -#include "lastexpress/game/action.h" -#include "lastexpress/game/entities.h" -#include "lastexpress/game/inventory.h" -#include "lastexpress/game/logic.h" -#include "lastexpress/game/savepoint.h" -#include "lastexpress/game/state.h" - -#include "lastexpress/helpers.h" -#include "lastexpress/graphics.h" -#include "lastexpress/lastexpress.h" -#include "lastexpress/resource.h" - -namespace LastExpress { - -#define SOUNDCACHE_ENTRY_SIZE 92160 -#define SOUNDCACHE_MAX_SIZE 6 - -// Letters & messages -const char *messages[24] = { - "", - "TXT1001", // 1 - "TXT1001A", // 2 - "TXT1011", // 3 - "TXT1012", // 4 - "TXT1013", // 5 - "TXT1014", // 6 - "TXT1020", // 7 - "TXT1030", // 8 - "END1009B", // 50 - "END1046", // 51 - "END1047", // 52 - "END1112", // 53 - "END1112A", // 54 - "END1503", // 55 - "END1505A", // 56 - "END1505B", // 57 - "END1610", // 58 - "END1612A", // 59 - "END1612C", // 61 - "END1612D", // 62 - "ENDALRM1", // 63 - "ENDALRM2", // 64 - "ENDALRM3" // 65 -}; - -const char *cities[17] = { - "EPERNAY", - "CHALONS", - "BARLEDUC", - "NANCY", - "LUNEVILL", - "AVRICOUR", - "DEUTSCHA", - "STRASBOU", - "BADENOOS", - "SALZBURG", - "ATTNANG", - "WELS", - "LINZ", - "VIENNA", - "POZSONY", - "GALANTA", - "POLICE" -}; - -const char *locomotiveSounds[5] = { - "ZFX1005", - "ZFX1006", - "ZFX1007", - "ZFX1007A", - "ZFX1007B" -}; - -static const SoundManager::FlagType soundFlags[32] = { - SoundManager::kFlagDefault, SoundManager::kFlag15, SoundManager::kFlag14, SoundManager::kFlag13, SoundManager::kFlag12, - SoundManager::kFlag11, SoundManager::kFlag11, SoundManager::kFlag10, SoundManager::kFlag10, SoundManager::kFlag9, SoundManager::kFlag9, SoundManager::kFlag8, SoundManager::kFlag8, - SoundManager::kFlag7, SoundManager::kFlag7, SoundManager::kFlag7, SoundManager::kFlag6, SoundManager::kFlag6, SoundManager::kFlag6, - SoundManager::kFlag5, SoundManager::kFlag5, SoundManager::kFlag5, SoundManager::kFlag5, SoundManager::kFlag4, SoundManager::kFlag4, SoundManager::kFlag4, SoundManager::kFlag4, - SoundManager::kFlag3, SoundManager::kFlag3, SoundManager::kFlag3, SoundManager::kFlag3, SoundManager::kFlag3 -}; - -SoundManager::SoundManager(LastExpressEngine *engine) : _engine(engine), _state(0), _currentType(kSoundType16), _flag(0) { - // Initialize unknown data - _data0 = 0; - _data1 = 0; - _data2 = 0; - - memset(&_buffer, 0, sizeof(_buffer)); - memset(&_lastWarning, 0, sizeof(_lastWarning)); - - // Sound cache - _soundCacheData = malloc(6 * SOUNDCACHE_ENTRY_SIZE); - - _drawSubtitles = 0; - _currentSubtitle = NULL; -} - -SoundManager::~SoundManager() { - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - SAFE_DELETE(*i); - _soundList.clear(); - - // Entries in the cache are just pointers to sound list entries - _soundCache.clear(); - - for (Common::List<SubtitleEntry *>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) - SAFE_DELETE(*i); - _subtitles.clear(); - - _currentSubtitle = NULL; - - free(_soundCacheData); - - // Zero passed pointers - _engine = NULL; -} - -////////////////////////////////////////////////////////////////////////// -// Timer -////////////////////////////////////////////////////////////////////////// -void SoundManager::handleTimer() { - Common::StackLock locker(_mutex); - - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - SoundEntry *entry = (*i); - if (entry->stream == NULL) { - SAFE_DELETE(*i); - i = _soundList.reverse_erase(i); - continue; - } else if (!entry->soundStream) { - entry->soundStream = new StreamedSound(); - - // TODO: stream any sound in the queue after filtering - entry->soundStream->load(entry->stream); - } - } -} - -////////////////////////////////////////////////////////////////////////// -// Sound queue management -////////////////////////////////////////////////////////////////////////// -void SoundManager::updateQueue() { - // TODO add mutex lock! - warning("Sound::updateQueue: not implemented!"); -} - -void SoundManager::resetQueue(SoundType type1, SoundType type2) { - if (!type2) - type2 = type1; - - Common::StackLock locker(_mutex); - - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - if ((*i)->type != type1 && (*i)->type != type2) - resetEntry(*i); - } -} - -void SoundManager::removeFromQueue(EntityIndex entity) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(entity); - if (entry) - resetEntry(entry); -} - -void SoundManager::removeFromQueue(Common::String filename) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(filename); - if (entry) - resetEntry(entry); -} - -void SoundManager::clearQueue() { - _flag |= 4; - - // FIXME: Wait a while for a flag to be set - //for (int i = 0; i < 3000000; i++) - // if (_flag & 8) - // break; - - _flag |= 8; - - Common::StackLock locker(_mutex); - - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - SoundEntry *entry = (*i); - - // Delete entry - removeEntry(entry); - SAFE_DELETE(entry); - - i = _soundList.reverse_erase(i); - } - - updateSubtitles(); -} - -bool SoundManager::isBuffered(EntityIndex entity) { - Common::StackLock locker(_mutex); - - return (getEntry(entity) != NULL); -} - -bool SoundManager::isBuffered(Common::String filename, bool testForEntity) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(filename); - - if (testForEntity) - return entry != NULL && !entry->entity; - - return (entry != NULL); -} - -////////////////////////////////////////////////////////////////////////// -// Entry -////////////////////////////////////////////////////////////////////////// -void SoundManager::setupEntry(SoundEntry *entry, Common::String name, FlagType flag, int a4) { - if (!entry) - error("SoundManager::setupEntry: Invalid entry!"); - - entry->field_4C = a4; - setEntryType(entry, flag); - setEntryStatus(entry, flag); - - // Add entry to sound list - _soundList.push_back(entry); - - // TODO Add entry to cache and load sound data - //setupCache(entry); - loadSoundData(entry, name); -} - -void SoundManager::setEntryType(SoundEntry *entry, FlagType flag) { - switch (flag & kFlagType9) { - default: - case kFlagNone: - entry->type = _currentType; - _currentType = (SoundType)(_currentType + 1); - break; - - case kFlagType1_2: { - SoundEntry *previous2 = getEntry(kSoundType2); - if (previous2) - updateEntry(previous2, 0); - - SoundEntry *previous = getEntry(kSoundType1); - if (previous) { - previous->type = kSoundType2; - updateEntry(previous, 0); - } - - entry->type = kSoundType1; - } - break; - - case kFlagType3: { - SoundEntry *previous = getEntry(kSoundType3); - if (previous) { - previous->type = kSoundType4; - updateEntry(previous, 0); - } - - entry->type = kSoundType11; - } - break; - - case kFlagType7: { - SoundEntry *previous = getEntry(kSoundType7); - if (previous) - previous->type = kSoundType8; - - entry->type = kSoundType7; - } - break; - - case kFlagType9: { - SoundEntry *previous = getEntry(kSoundType9); - if (previous) - previous->type = kSoundType10; - - entry->type = kSoundType9; - } - break; - - case kFlagType11: { - SoundEntry *previous = getEntry(kSoundType11); - if (previous) - previous->type = kSoundType14; - - entry->type = kSoundType11; - } - break; - - case kFlagType13: { - SoundEntry *previous = getEntry(kSoundType13); - if (previous) - previous->type = kSoundType14; - - entry->type = kSoundType13; - } - break; - } -} - -void SoundManager::setEntryStatus(SoundEntry *entry, FlagType flag) const { - SoundStatus status = (SoundStatus)flag; - if (!((status & 0xFF) & kSoundStatusClear1)) - status = (SoundStatus)(status | kSoundStatusClear2); - - if (((status & 0xFF00) >> 8) & kSoundStatusClear0) - entry->status.status = (uint32)status; - else - entry->status.status = (status | kSoundStatusClear4); -} - -void SoundManager::setInCache(SoundEntry *entry) { - entry->status.status |= kSoundStatusClear2; -} - -bool SoundManager::setupCache(SoundEntry *entry) { - if (entry->soundData) - return true; - - if (_soundCache.size() >= SOUNDCACHE_MAX_SIZE) { - - SoundEntry *cacheEntry = NULL; - uint32 size = 1000; - - for (Common::List<SoundEntry *>::iterator i = _soundCache.begin(); i != _soundCache.end(); ++i) { - if (!((*i)->status.status & kSoundStatus_180)) { - uint32 newSize = (*i)->field_4C + ((*i)->status.status & kSoundStatusClear1); - - if (newSize < size) { - cacheEntry = (*i); - size = newSize; - } - } - } - - if (entry->field_4C <= size) - return false; - - if (cacheEntry) - setInCache(cacheEntry); - - // TODO: Wait until the cache entry is ready to be removed - while (!(cacheEntry->status.status1 & 1)) - ; - - if (cacheEntry->soundData) - removeFromCache(cacheEntry); - - _soundCache.push_back(entry); - entry->soundData = (char *)_soundCacheData + SOUNDCACHE_ENTRY_SIZE * (_soundCache.size() - 1); - } else { - _soundCache.push_back(entry); - entry->soundData = (char *)_soundCacheData + SOUNDCACHE_ENTRY_SIZE * (_soundCache.size() - 1); - } - - return true; -} - -void SoundManager::removeFromCache(SoundEntry *entry) { - for (Common::List<SoundEntry *>::iterator i = _soundCache.begin(); i != _soundCache.end(); ++i) { - if ((*i) == entry) { - // Remove sound buffer - entry->soundData = NULL; - - // Remove entry from sound cache - i = _soundCache.reverse_erase(i); - } - } -} - -void SoundManager::clearStatus() { - Common::StackLock locker(_mutex); - - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - (*i)->status.status |= kSoundStatusClear3; -} - -void SoundManager::loadSoundData(SoundEntry *entry, Common::String name) { - entry->name2 = name; - - // Load sound data - entry->stream = getArchive(name); - - if (!entry->stream) - entry->stream = getArchive("DEFAULT.SND"); - - if (entry->stream) { - warning("Sound::loadSoundData: not implemented!"); - } else { - entry->status.status = kSoundStatusRemoved; - } -} - -void SoundManager::resetEntry(SoundEntry *entry) const { - entry->status.status |= kSoundStatusRemoved; - entry->entity = kEntityPlayer; - - if (entry->stream) { - if (!entry->soundStream) { - SAFE_DELETE(entry->stream); - } else { - entry->soundStream->stop(); - SAFE_DELETE(entry->soundStream); - } - - entry->stream = NULL; - } -} - - -void SoundManager::removeEntry(SoundEntry *entry) { - entry->status.status |= kSoundStatusRemoved; - - // Loop until ready - while (!(entry->status.status1 & 4) && !(_flag & 8) && (_flag & 1)) - ; // empty loop body - - // The original game remove the entry from the cache here, - // but since we are called from within an iterator loop - // we will remove the entry there - // removeFromCache(entry); - - if (entry->subtitle) { - drawSubtitle(entry->subtitle); - SAFE_DELETE(entry->subtitle); - } - - if (entry->entity) { - if (entry->entity == kEntitySteam) - playLoopingSound(); - else if (entry->entity != kEntityTrain) - getSavePoints()->push(kEntityPlayer, entry->entity, kActionEndSound); - } -} - -void SoundManager::updateEntry(SoundEntry *entry, uint value) const { - if (!(entry->status.status3 & 64)) { - int value2 = value; - - entry->status.status |= kSoundStatus_100000; - - if (value) { - if (_flag & 32) { - entry->field_40 = value; - value2 = value * 2 + 1; - } - - entry->field_3C = value2; - } else { - entry->field_3C = 0; - entry->status.status |= kSoundStatus_40000000; - } - } -} - -void SoundManager::updateEntryState(SoundEntry *entry) const { - if (_flag & 32) { - if (entry->type != kSoundType9 && entry->type != kSoundType7 && entry->type != kSoundType5) { - uint32 status = entry->status.status & kSoundStatusClear1; - - entry->status.status &= kSoundStatusClearAll; - - entry->field_40 = status; - entry->status.status |= status * 2 + 1; - } - } - - entry->status.status |= kSoundStatus_20; -} - -void SoundManager::processEntry(EntityIndex entity) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(entity); - if (entry) { - updateEntry(entry, 0); - entry->entity = kEntityPlayer; - } -} - -void SoundManager::processEntry(SoundType type) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(type); - if (entry) - updateEntry(entry, 0); -} - -void SoundManager::setupEntry(SoundType type, EntityIndex index) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(type); - if (entry) - entry->entity = index; -} - -void SoundManager::processEntry(Common::String filename) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(filename); - if (entry) { - updateEntry(entry, 0); - entry->entity = kEntityPlayer; - } -} - -void SoundManager::processEntries() { - _state = 0; - - processEntry(kSoundType1); - processEntry(kSoundType2); -} - -uint32 SoundManager::getEntryTime(EntityIndex index) { - Common::StackLock locker(_mutex); - - SoundEntry *entry = getEntry(index); - if (entry) - return entry->time; - - return 0; -} - -////////////////////////////////////////////////////////////////////////// -// Misc -////////////////////////////////////////////////////////////////////////// - -void SoundManager::unknownFunction4() { - // TODO: Add mutex ? - warning("Sound::unknownFunction4: not implemented!"); -} - -////////////////////////////////////////////////////////////////////////// -// Entry search -////////////////////////////////////////////////////////////////////////// -SoundManager::SoundEntry *SoundManager::getEntry(EntityIndex index) { - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - if ((*i)->entity == index) - return *i; - } - - return NULL; -} - -SoundManager::SoundEntry *SoundManager::getEntry(Common::String name) { - if (!name.contains('.')) - name += ".SND"; - - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - if ((*i)->name2 == name) - return *i; - } - - return NULL; -} - -SoundManager::SoundEntry *SoundManager::getEntry(SoundType type) { - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - if ((*i)->type == type) - return *i; - } - - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -// Savegame -////////////////////////////////////////////////////////////////////////// -void SoundManager::saveLoadWithSerializer(Common::Serializer &s) { - s.syncAsUint32LE(_state); - s.syncAsUint32LE(_currentType); - - // Compute the number of entries to save - uint32 numEntries = count(); - s.syncAsUint32LE(numEntries); - - Common::StackLock locker(_mutex); - - // Save or load each entry data - if (s.isSaving()) { - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { - SoundEntry *entry = *i; - if (entry->name2.matchString("NISSND?") && (entry->status.status & kFlagType7) != kFlag3) { - s.syncAsUint32LE(entry->status.status); // status; - s.syncAsUint32LE(entry->type); // type; - s.syncAsUint32LE(entry->field_1C); // field_8; - s.syncAsUint32LE(entry->time); // time; - s.syncAsUint32LE(entry->field_34); // field_10; - s.syncAsUint32LE(entry->field_38); // field_14; - s.syncAsUint32LE(entry->entity); // entity; - - uint32 field_1C = (uint32)entry->field_48 - _data2; - if (field_1C > kFlag8) - field_1C = 0; - s.syncAsUint32LE(field_1C); // field_1C; - - s.syncAsUint32LE(entry->field_4C); // field_20; - - char name1[16]; - strcpy((char *)&name1, entry->name1.c_str()); - s.syncBytes((byte *)&name1, 16); - - char name2[16]; - strcpy((char *)&name2, entry->name2.c_str()); - s.syncBytes((byte *)&name2, 16); - } - } - } else { - warning("Sound::saveLoadWithSerializer: not implemented!"); - s.skip(numEntries * 64); - } -} - - -// FIXME: We probably need another mutex here to protect during the whole savegame process -// as we could have removed an entry between the time we check the count and the time we -// save the entries -uint32 SoundManager::count() { - Common::StackLock locker(_mutex); - - uint32 numEntries = 0; - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - if ((*i)->name2.matchString("NISSND?")) - ++numEntries; - - return numEntries; -} - -////////////////////////////////////////////////////////////////////////// -// Game-related functions -////////////////////////////////////////////////////////////////////////// -void SoundManager::playSound(EntityIndex entity, Common::String filename, FlagType flag, byte a4) { - if (isBuffered(entity) && entity) - removeFromQueue(entity); - - FlagType currentFlag = (flag == -1) ? getSoundFlag(entity) : (FlagType)(flag | 0x80000); - - // Add .SND at the end of the filename if needed - if (!filename.contains('.')) - filename += ".SND"; - - if (!playSoundWithSubtitles(filename, currentFlag, entity, a4)) - if (entity) - getSavePoints()->push(kEntityPlayer, entity, kActionEndSound); -} - -bool SoundManager::playSoundWithSubtitles(Common::String filename, FlagType flag, EntityIndex entity, byte a4) { - SoundEntry *entry = new SoundEntry(); - - Common::StackLock locker(_mutex); - - setupEntry(entry, filename, flag, 30); - entry->entity = entity; - - if (a4) { - entry->field_48 = _data2 + 2 * a4; - entry->status.status |= kSoundStatus_8000; - } else { - // Get subtitles name - while (filename.size() > 4) - filename.deleteLastChar(); - - showSubtitle(entry, filename); - updateEntryState(entry); - } - - return (entry->type != kSoundTypeNone); -} - -void SoundManager::playSoundEvent(EntityIndex entity, byte action, byte a3) { - int values[5]; - - if (getEntityData(entity)->car != getEntityData(kEntityPlayer)->car) - return; - - if (getEntities()->isInSalon(entity) != getEntities()->isInSalon(kEntityPlayer)) - return; - - int _action = (int)action; - FlagType flag = getSoundFlag(entity); - - switch (action) { - case 36: { - int _param3 = (flag <= 9) ? flag + 7 : 16; - - if (_param3 > 7) { - _data0 = (uint)_param3; - _data1 = _data2 + 2 * a3; - } - break; - } - - case 37: - _data0 = 7; - _data1 = _data2 + 2 * a3; - break; - - case 150: - case 156: - case 162: - case 168: - case 188: - case 198: - _action += 1 + (int)rnd(5); - break; - - case 174: - case 184: - case 194: - _action += 1 + (int)rnd(3); - break; - - case 180: - _action += 1 + (int)rnd(4); - break; - - case 246: - values[0] = 0; - values[1] = 104; - values[2] = 105; - values[3] = 106; - values[4] = 116; - _action = values[rnd(5)]; - break; - - case 247: - values[0] = 11; - values[1] = 123; - values[2] = 124; - _action = values[rnd(3)]; - break; - - case 248: - values[0] = 0; - values[1] = 103; - values[2] = 108; - values[3] = 109; - _action = values[rnd(4)]; - break; - - case 249: - values[0] = 0; - values[1] = 56; - values[2] = 112; - values[3] = 113; - _action = values[rnd(4)]; - break; - - case 250: - values[0] = 0; - values[1] = 107; - values[2] = 115; - values[3] = 117; - _action = values[rnd(4)]; - break; - - case 251: - values[0] = 0; - values[1] = 11; - values[2] = 56; - values[3] = 113; - _action = values[rnd(4)]; - break; - - case 252: - values[0] = 0; - values[1] = 6; - values[2] = 109; - values[3] = 121; - _action = values[rnd(4)]; - break; - - case 254: - values[0] = 0; - values[1] = 104; - values[2] = 120; - values[3] = 121; - _action = values[rnd(4)]; - break; - - case 255: - values[0] = 0; - values[1] = 106; - values[2] = 115; - _action = values[rnd(3)]; - break; - - default: - break; - } - - if (_action && flag) - playSoundWithSubtitles(Common::String::format("LIB%03d.SND", _action), flag, kEntityPlayer, a3); -} - -void SoundManager::playSteam(CityIndex index) { - if (index >= ARRAYSIZE(cities)) - error("SoundManager::playSteam: invalid city index (was %d, max %d)", index, ARRAYSIZE(cities)); - - _state |= kSoundState2; - - if (!getEntry(kSoundType1)) - playSoundWithSubtitles("STEAM.SND", kFlagSteam, kEntitySteam); - - // Get the new sound entry and show subtitles - SoundEntry *entry = getEntry(kSoundType1); - if (entry) - showSubtitle(entry, cities[index]); -} - -void SoundManager::playFightSound(byte action, byte a4) { - int _action = (int)action; - int values[5]; - - switch (action) { - default: - break; - - case 174: - case 184: - case 194: - values[0] = action + 1; - values[1] = action + 2; - values[2] = action + 3; - _action = values[rnd(3)]; - break; - - case 180: - values[0] = action + 1; - values[1] = action + 2; - values[2] = action + 3; - values[3] = action + 4; - _action = values[rnd(4)]; - break; - - case 150: - case 156: - case 162: - case 168: - case 188: - case 198: - values[0] = action + 1; - values[1] = action + 2; - values[2] = action + 3; - values[3] = action + 4; - values[4] = action + 5; - _action = values[rnd(5)]; - break; - } - - if (_action) - playSound(kEntityTrain, Common::String::format("LIB%03d.SND", _action), kFlagDefault, a4); -} - -void SoundManager::playDialog(EntityIndex entity, EntityIndex entityDialog, FlagType flag, byte a4) { - if (isBuffered(getDialogName(entityDialog))) - removeFromQueue(getDialogName(entityDialog)); - - playSound(entity, getDialogName(entityDialog), flag, a4); -} - -void SoundManager::playLocomotiveSound() { - playSound(kEntityPlayer, locomotiveSounds[rnd(5)], (FlagType)(rnd(15) + 2)); -} - -const char *SoundManager::getDialogName(EntityIndex entity) const { - switch (entity) { - case kEntityAnna: - if (getEvent(kEventAnnaDialogGoToJerusalem)) - return "XANN12"; - - if (getEvent(kEventLocomotiveRestartTrain)) - return "XANN11"; - - if (getEvent(kEventAnnaBaggageTies) || getEvent(kEventAnnaBaggageTies2) || getEvent(kEventAnnaBaggageTies3) || getEvent(kEventAnnaBaggageTies4)) - return "XANN10"; - - if (getEvent(kEventAnnaTired) || getEvent(kEventAnnaTiredKiss)) - return "XANN9"; - - if (getEvent(kEventAnnaBaggageArgument)) - return "XANN8"; - - if (getEvent(kEventKronosVisit)) - return "XANN7"; - - if (getEvent(kEventAbbotIntroduction)) - return "XANN6A"; - - if (getEvent(kEventVassiliSeizure)) - return "XANN6"; - - if (getEvent(kEventAugustPresentAnna) || getEvent(kEventAugustPresentAnnaFirstIntroduction)) - return "XANN5"; - - if (getProgress().field_60) - return "XANN4"; - - if (getEvent(kEventAnnaGiveScarf) || getEvent(kEventAnnaGiveScarfDiner) || getEvent(kEventAnnaGiveScarfSalon) - || getEvent(kEventAnnaGiveScarfMonogram) || getEvent(kEventAnnaGiveScarfDinerMonogram) || getEvent(kEventAnnaGiveScarfSalonMonogram)) - return "XANN3"; - - if (getEvent(kEventDinerMindJoin)) - return "XANN2"; - - if (getEvent(kEventGotALight) || getEvent(kEventGotALightD)) - return "XANN1"; - - break; - - case kEntityAugust: - if (getEvent(kEventAugustTalkCigar)) - return "XAUG6"; - - if (getEvent(kEventAugustBringBriefcase)) - return "XAUG5"; - - // Getting closer to Vienna... - if (getState()->time > kTime2200500 && !getEvent(kEventAugustMerchandise)) - return "XAUG4A"; - - if (getEvent(kEventAugustMerchandise)) - return "XAUG4"; - - if (getEvent(kEventDinerAugust) || getEvent(kEventDinerAugustAlexeiBackground) || getEvent(kEventMeetAugustTylerCompartment) - || getEvent(kEventMeetAugustTylerCompartmentBed) || getEvent(kEventMeetAugustHisCompartment) || getEvent(kEventMeetAugustHisCompartmentBed)) - return "XAUG3"; - - if (getEvent(kEventAugustPresentAnnaFirstIntroduction)) - return "XAUG2"; - - if (getProgress().eventMertensAugustWaiting) - return "XAUG1"; - - break; - - case kEntityTatiana: - if (getEvent(kEventTatianaTylerCompartment)) - return "XTAT6"; - - if (getEvent(kEventTatianaCompartmentStealEgg)) - return "XTAT5"; - - if (getEvent(kEventTatianaGivePoem)) - return "XTAT3"; - - if (getProgress().field_64) - return "XTAT1"; - - break; - - case kEntityVassili: - if (getEvent(kEventCathFreePassengers)) - return "XVAS4"; - - if (getEvent(kEventVassiliCompartmentStealEgg)) - return "XVAS3"; - - if (getEvent(kEventAbbotIntroduction)) - return "XVAS2"; - - if (getEvent(kEventVassiliSeizure)) - return "XVAS1A"; - - if (getProgress().field_64) - return "XVAS1"; - - break; - - case kEntityAlexei: - if (getProgress().field_88) - return "XALX6"; - - if (getProgress().field_8C) - return "XALX5"; - - if (getProgress().field_90) - return "XALX4A"; - - if (getProgress().field_68) - return "XALX4"; - - if (getEvent(kEventAlexeiSalonPoem)) - return "XALX3"; - - if (getEvent(kEventAlexeiSalonVassili)) - return "XALX2"; - - if (getEvent(kEventAlexeiDiner) || getEvent(kEventAlexeiDinerOriginalJacket)) - return "XALX1"; - - break; - - case kEntityAbbot: - if (getEvent(kEventAbbotDrinkDefuse)) - return "XABB4"; - - if (getEvent(kEventAbbotInvitationDrink) || getEvent(kEventDefuseBomb)) - return "XABB3"; - - if (getEvent(kEventAbbotWrongCompartment) || getEvent(kEventAbbotWrongCompartmentBed)) - return "XABB2"; - - if (getEvent(kEventAbbotIntroduction)) - return "XABB1"; - - break; - - case kEntityMilos: - if (getEvent(kEventLocomotiveMilosDay) || getEvent(kEventLocomotiveMilosNight)) - return "XMIL5"; - - if (getEvent(kEventMilosCompartmentVisitTyler) && (getProgress().chapter == kChapter3 || getProgress().chapter == kChapter4)) - return "XMIL4"; - - if (getEvent(kEventMilosCorridorThanks) || getProgress().chapter == kChapter5) - return "XMIL3"; - - if (getEvent(kEventMilosCompartmentVisitAugust)) - return "XMIL2"; - - if (getEvent(kEventMilosTylerCompartmentDefeat)) - return "XMIL1"; - - break; - - case kEntityVesna: - if (getProgress().field_94) - return "XVES2"; - - if (getProgress().field_98) - return "XVES1"; - - break; - - case kEntityKronos: - if (getEvent(kEventKronosReturnBriefcase)) - return "XKRO6"; - - if (getEvent(kEventKronosBringEggCeiling) || getEvent(kEventKronosBringEgg)) - return "XKRO5"; - - if (getEvent(kEventKronosConversation) || getEvent(kEventKronosConversationFirebird)) { - ObjectLocation location = getInventory()->get(kItemFirebird)->location; - if (location != kObjectLocation6 && location != kObjectLocation5 && location != kObjectLocation2 && location != kObjectLocation1) - return "XKRO4A"; - } - - if (getEvent(kEventKronosConversationFirebird)) - return "XKRO4"; - - if (getEvent(kEventKronosConversation)) { - if (!getEvent(kEventMilosCompartmentVisitAugust)) - return "XKRO3"; - else - return "XKRO2"; - } - - if (getProgress().eventMertensKronosInvitation) - return "XKRO1"; - - break; - - case kEntityFrancois: - if (getProgress().field_9C) - return "XFRA3"; - - if (getProgress().field_A0 - || getEvent(kEventFrancoisWhistle) || getEvent(kEventFrancoisWhistleD) - || getEvent(kEventFrancoisWhistleNight) || getEvent(kEventFrancoisWhistleNightD)) - return "XFRA2"; - - if (getState()->time > kTimeParisEpernay) // Between Paris and Epernay - return "XFRA1"; - - break; - - case kEntityMmeBoutarel: - if (getProgress().field_A4) - return "XMME4"; - - if (getProgress().field_A8) - return "XMME3"; - - if (getProgress().field_A0) - return "XMME2"; - - if (getProgress().field_AC) - return "XMME1"; - - break; - - case kEntityBoutarel: - if (getProgress().eventMetBoutarel) - return "XMRB1"; - - break; - - case kEntityRebecca: - if (getProgress().field_B4) - return "XREB1A"; - - if (getProgress().field_B8) - return "XREB1"; - - break; - - case kEntitySophie: - if (getProgress().field_B0) - return "XSOP2"; - - if (getProgress().field_BC) - return "XSOP1B"; - - if (getProgress().field_B4) - return "XSOP1A"; - - if (getProgress().field_B8) - return "XSOP1"; - - break; - - case kEntityMahmud: - if (getProgress().field_C4) - return "XMAH1"; - - break; - - case kEntityYasmin: - if (getProgress().eventMetYasmin) - return "XHAR2"; - - break; - - case kEntityHadija: - if (getProgress().eventMetHadija) - return "XHAR1"; - - break; - - case kEntityAlouan: - if (getProgress().field_DC) - return "XHAR3"; - - break; - - case kEntityGendarmes: - if (getProgress().field_E0) - return "XHAR4"; - - break; - - case kEntityChapters: - if (getEvent(kEventCathDream) || getEvent(kEventCathWakingUp)) - return "XTYL3"; - - return "XTYL1"; - - default: - break; - } - - return NULL; -} - -////////////////////////////////////////////////////////////////////////// -// Letters & Messages -////////////////////////////////////////////////////////////////////////// -void SoundManager::readText(int id){ - if (!isBuffered(kEntityTables4)) - return; - - if (id < 0 || (id > 8 && id < 50) || id > 64) - error("Sound::readText - attempting to use invalid id. Valid values [1;8] - [50;64], was %d", id); - - // Get proper message file (names are stored in sequence in the array but id is [1;8] - [50;64]) - const char *text = messages[id <= 8 ? id : id - 41]; - - // Check if file is in cache for id [1;8] - if (id <= 8) - if (isBuffered(text)) - removeFromQueue(text); - - playSound(kEntityTables4, text, kFlagDefault); -} - -////////////////////////////////////////////////////////////////////////// -// Sound bites -////////////////////////////////////////////////////////////////////////// -void SoundManager::playWarningCompartment(EntityIndex entity, ObjectIndex compartment) { - -#define PLAY_WARNING(index, sound1, sound2, sound3, sound4, sound5, sound6) { \ - if (_lastWarning[index] + 450 >= getState()->timeTicks) { \ - if (rnd(2)) \ - playSound(kEntityMertens, sound1, kFlagDefault); \ - else \ - playSound(kEntityMertens, rnd(2) ? sound2 : sound3, kFlagDefault); \ - } else { \ - if (rnd(2)) \ - playSound(kEntityMertens, sound4, kFlagDefault); \ - else \ - playSound(kEntityMertens, rnd(2) ? sound5 : sound6, kFlagDefault); \ - } \ - _lastWarning[index] = getState()->timeTicks; \ -} - - if (entity != kEntityMertens && entity != kEntityCoudert) - return; - - ////////////////////////////////////////////////////////////////////////// - // Mertens - if (entity == kEntityMertens) { - - switch (compartment) { - default: - break; - - case kObjectCompartment2: - PLAY_WARNING(0, "Con1502A", "Con1500B", "Con1500C", "Con1502", "Con1500", "Con1500A"); - break; - - case kObjectCompartment3: - PLAY_WARNING(1, "Con1501A", "Con1500B", "Con1500C", "Con1501", "Con1500", "Con1500A"); - break; - - case kObjectCompartment4: - PLAY_WARNING(2, "Con1503", "Con1500B", "Con1500C", "Con1503", "Con1500", "Con1500A"); - break; - - case kObjectCompartment5: - case kObjectCompartment6: - case kObjectCompartment7: - case kObjectCompartment8: - ++_lastWarning[3]; - - switch (_lastWarning[3]) { - default: - break; - - case 1: - getSound()->playSound(kEntityMertens, "Con1503C", kFlagDefault); - break; - - case 2: - getSound()->playSound(kEntityMertens, rnd(2) ? "Con1503E" : "Con1503A", kFlagDefault); - break; - - case 3: - getSound()->playSound(kEntityMertens, rnd(2) ? "Con1503B" : "Con1503D", kFlagDefault); - _lastWarning[3] = 0; - break; - } - } - - return; - } - - ////////////////////////////////////////////////////////////////////////// - // Coudert - switch (compartment) { - default: - break; - - case kObjectCompartmentA: - if (_lastWarning[4] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1508" : "Jac1508A", kFlagDefault); - break; - - case kObjectCompartmentB: - if (_lastWarning[5] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - if (getProgress().field_40 || (getState()->time > kTimeCityLinz && getState()->time < kTime2133000)) - getSound()->playSound(kEntityCoudert, "Jac1507A", kFlagDefault); - else - getSound()->playSound(kEntityCoudert, "Jac1507", kFlagDefault); - break; - - case kObjectCompartmentC: - if (_lastWarning[6] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - if (getProgress().chapter < kChapter3) - getSound()->playSound(kEntityCoudert, "Jac1506", kFlagDefault); - else - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1506A" : "Jac1506B", kFlagDefault); - break; - - case kObjectCompartmentD: - if (_lastWarning[7] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - getSound()->playSound(kEntityCoudert, "Jac1505", kFlagDefault); - break; - - case kObjectCompartmentE: - if (_lastWarning[8] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - if (getProgress().field_40 || (getState()->time > kTime2115000 && getState()->time < kTime2133000)) { - getSound()->playSound(kEntityCoudert, "Jac1504B", kFlagDefault); - break; - } - - if (getEntities()->isInsideCompartment(kEntityRebecca, kCarRedSleeping, kPosition_4840)) - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - else - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1504" : "Jac1504A", kFlagDefault); - break; - - case kObjectCompartmentF: - if (_lastWarning[9] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - if (getProgress().field_40 || (getState()->time > kTime2083500 && getState()->time < kTime2133000)) { - getSound()->playSound(kEntityCoudert, "Jac1503B", kFlagDefault); - break; - } - - if (rnd(2) || getEntities()->isInsideCompartment(kEntityAnna, kCarRedSleeping, kPosition_4070)) - getSound()->playSound(kEntityCoudert, "Jac1503", kFlagDefault); - else - getSound()->playSound(kEntityCoudert, "Jac1503A", kFlagDefault); - break; - - case kObjectCompartmentG: - if (_lastWarning[10] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - if (rnd(2) || getEntities()->isInsideCompartment(kEntityMilos, kCarRedSleeping, kPosition_3050)) - getSound()->playSound(kEntityCoudert, "Jac1502", kFlagDefault); - else - getSound()->playSound(kEntityCoudert, "Jac1502A", kFlagDefault); - break; - - case kObjectCompartmentH: - if (_lastWarning[11] + 450 >= getState()->timeTicks) { - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - break; - } - - if (getEntities()->isInsideCompartment(kEntityIvo, kCarRedSleeping, kPosition_2740)) - getSound()->playSound(kEntityCoudert, rnd(2) ? "Jac1500" : "Jac1500A", kFlagDefault); - else - getSound()->playSound(kEntityCoudert, "Jac1501", kFlagDefault); - break; - } - - // Update ticks (Compartments A - H are indexes 4 - 11) - _lastWarning[compartment - 28] = getState()->timeTicks; -} - -void SoundManager::excuseMe(EntityIndex entity, EntityIndex entity2, FlagType flag) { - if (isBuffered(entity) && entity != kEntityPlayer && entity != kEntityChapters && entity != kEntityTrain) - return; - - if (entity2 == kEntityFrancois || entity2 == kEntityMax) - return; - - if (entity == kEntityFrancois && getEntityData(kEntityFrancois)->field_4A3 != 30) - return; - - if (flag == kFlagNone) - flag = getSoundFlag(entity); - - switch (entity) { - default: - break; - - case kEntityAnna: - playSound(kEntityPlayer, "ANN1107A", flag); - break; - - case kEntityAugust: - switch(rnd(4)) { - default: - break; - - case 0: - playSound(kEntityPlayer, "AUG1100A", flag); - break; - - case 1: - playSound(kEntityPlayer, "AUG1100B", flag); - break; - - case 2: - playSound(kEntityPlayer, "AUG1100C", flag); - break; - - case 3: - playSound(kEntityPlayer, "AUG1100D", flag); - break; - } - break; - - case kEntityMertens: - if (Entities::isFemale(entity2)) { - playSound(kEntityPlayer, (rnd(2) ? "CON1111" : "CON1111A"), flag); - } else { - if (entity2 || getProgress().jacket != kJacketGreen || !rnd(2)) { - switch(rnd(3)) { - default: - break; - - case 0: - playSound(kEntityPlayer, "CON1110A", flag); - break; - - case 1: - playSound(kEntityPlayer, "CON1110C", flag); - break; - - case 2: - playSound(kEntityPlayer, "CON1110", flag); - break; - } - } else { - if (isNight()) { - playSound(kEntityPlayer, (getProgress().field_18 == 2 ? "CON1110F" : "CON1110E")); - } else { - playSound(kEntityPlayer, "CON1110D"); - } - } - } - break; - - case kEntityCoudert: - if (Entities::isFemale(entity2)) { - playSound(kEntityPlayer, "JAC1111D", flag); - } else { - if (entity2 || getProgress().jacket != kJacketGreen || !rnd(2)) { - switch(rnd(4)) { - default: - break; - - case 0: - playSound(kEntityPlayer, "JAC1111", flag); - break; - - case 1: - playSound(kEntityPlayer, "JAC1111A", flag); - break; - - case 2: - playSound(kEntityPlayer, "JAC1111B", flag); - break; - - case 3: - playSound(kEntityPlayer, "JAC1111C", flag); - break; - } - } else { - playSound(kEntityPlayer, "JAC1113B", flag); - } - } - break; - - case kEntityPascale: - playSound(kEntityPlayer, (rnd(2) ? "HDE1002" : "HED1002A"), flag); - break; - - case kEntityServers0: - case kEntityServers1: - switch(rnd(3)) { - default: - break; - - case 0: - playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002" : "WAT1003", flag); - break; - - case 1: - playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002A" : "WAT1003A", flag); - break; - - case 2: - playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002B" : "WAT1003B", flag); - break; - } - break; - - case kEntityVerges: - if (Entities::isFemale(entity2)) { - playSound(kEntityPlayer, (rnd(2) ? "TRA1113A" : "TRA1113B")); - } else { - playSound(kEntityPlayer, "TRA1112", flag); - } - break; - - case kEntityTatiana: - playSound(kEntityPlayer, (rnd(2) ? "TAT1102A" : "TAT1102B"), flag); - break; - - case kEntityAlexei: - playSound(kEntityPlayer, (rnd(2) ? "ALX1099C" : "ALX1099D"), flag); - break; - - case kEntityAbbot: - if (Entities::isFemale(entity2)) { - playSound(kEntityPlayer, "ABB3002C", flag); - } else { - switch(rnd(3)) { - default: - break; - - case 0: - playSound(kEntityPlayer, "ABB3002", flag); - break; - - case 1: - playSound(kEntityPlayer, "ABB3002A", flag); - break; - - case 2: - playSound(kEntityPlayer, "ABB3002B", flag); - break; - } - } - break; - - case kEntityVesna: - switch(rnd(3)) { - default: - break; - - case 0: - playSound(kEntityPlayer, "VES1109A", flag); - break; - - case 1: - playSound(kEntityPlayer, "VES1109B", flag); - break; - - case 2: - playSound(kEntityPlayer, "VES1109C", flag); - break; - } - break; - - case kEntityKahina: - playSound(kEntityPlayer, (rnd(2) ? "KAH1001" : "KAH1001A"), flag); - break; - - case kEntityFrancois: - case kEntityMmeBoutarel: - switch(rnd(4)) { - default: - break; - - case 0: - playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001" : "MME1103A", flag); - break; - - case 1: - playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001A" : "MME1103B", flag); - break; - - case 2: - playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001B" : "MME1103C", flag); - break; - - case 3: - playSound(kEntityPlayer, (entity == kEntityFrancois) ? "FRA1001C" : "MME1103D", flag); - break; - } - break; - - case kEntityBoutarel: - playSound(kEntityPlayer, "MRB1104", flag); - if (flag > 2) - getProgress().eventMetBoutarel = true; - break; - - case kEntityRebecca: - playSound(kEntityPlayer, (rnd(2) ? "REB1106" : "REB110A"), flag); - break; - - case kEntitySophie: { - switch(rnd(3)) { - default: - break; - - case 0: - playSound(kEntityPlayer, "SOP1105", flag); - break; - - case 1: - playSound(kEntityPlayer, Entities::isFemale(entity2) ? "SOP1105C" : "SOP1105A", flag); - break; - - case 2: - playSound(kEntityPlayer, Entities::isFemale(entity2) ? "SOP1105D" : "SOP1105B", flag); - break; - } - break; - } - - case kEntityMahmud: - playSound(kEntityPlayer, "MAH1101", flag); - break; - - case kEntityYasmin: - playSound(kEntityPlayer, "HAR1002", flag); - if (flag > 2) - getProgress().eventMetYasmin = true; - break; - - case kEntityHadija: - playSound(kEntityPlayer, (rnd(2) ? "HAR1001" : "HAR1001A"), flag); - if (flag > 2) - getProgress().eventMetHadija = true; - break; - - case kEntityAlouan: - playSound(kEntityPlayer, "HAR1004", flag); - break; - } -} - -void SoundManager::excuseMeCath() { - switch(rnd(3)) { - default: - playSound(kEntityPlayer, "CAT1126B"); - break; - - case 1: - playSound(kEntityPlayer, "CAT1126C"); - break; - - case 2: - playSound(kEntityPlayer, "CAT1126D"); - break; - } -} - -const char *SoundManager::justCheckingCath() const { - switch(rnd(4)) { - default: - break; - - case 0: - return "CAT5001"; - - case 1: - return "CAT5001A"; - - case 2: - return "CAT5001B"; - - case 3: - return "CAT5001C"; - } - - return "CAT5001"; -} - -const char *SoundManager::wrongDoorCath() const { - switch(rnd(5)) { - default: - break; - - case 0: - return "CAT1125"; - - case 1: - return "CAT1125A"; - - case 2: - return "CAT1125B"; - - case 3: - return "CAT1125C"; - - case 4: - return "CAT1125D"; - } - - return "CAT1125"; -} - -const char *SoundManager::justAMinuteCath() const { - switch(rnd(3)) { - default: - break; - - case 0: - return "CAT1520"; - - case 1: - return "CAT1521"; - - case 2: - return "CAT1125"; // ?? is this a bug in the original? - } - - return "CAT1520"; -} - -////////////////////////////////////////////////////////////////////////// -// Sound flags -////////////////////////////////////////////////////////////////////////// -SoundManager::FlagType SoundManager::getSoundFlag(EntityIndex entity) const { - if (entity == kEntityPlayer) - return kFlagDefault; - - if (getEntityData(entity)->car != getEntityData(kEntityPlayer)->car) - return kFlagNone; - - // Compute sound value - FlagType ret = kFlag2; - - // Get default value if valid - int index = ABS(getEntityData(entity)->entityPosition - getEntityData(kEntityPlayer)->entityPosition) / 230; - if (index < 32) - ret = soundFlags[index]; - - if (getEntityData(entity)->location == kLocationOutsideTrain) { - if (getEntityData(entity)->car != kCarKronos - && !getEntities()->isOutsideAlexeiWindow() - && !getEntities()->isOutsideAnnaWindow()) - return kFlagNone; - - return (FlagType)(ret / 6); - } - - switch (getEntityData(entity)->car) { - default: - break; - - case kCarKronos: - if (getEntities()->isInKronosSalon(entity) != getEntities()->isInKronosSalon(kEntityPlayer)) - ret = (FlagType)(ret * 2); - break; - - case kCarGreenSleeping: - case kCarRedSleeping: - if (getEntities()->isInGreenCarEntrance(kEntityPlayer) && !getEntities()->isInKronosSalon(entity)) - ret = (FlagType)(ret * 2); - - if (getEntityData(kEntityPlayer)->location - && (getEntityData(entity)->entityPosition != kPosition_1 || !getEntities()->isDistanceBetweenEntities(kEntityPlayer, entity, 400))) - ret = (FlagType)(ret * 2); - break; - - case kCarRestaurant: - if (getEntities()->isInSalon(entity) == getEntities()->isInSalon(kEntityPlayer) - && (getEntities()->isInRestaurant(entity) != getEntities()->isInRestaurant(kEntityPlayer))) - ret = (FlagType)(ret * 2); - else - ret = (FlagType)(ret * 4); - break; - } - - return ret; -} - -////////////////////////////////////////////////////////////////////////// -// Subtitles -////////////////////////////////////////////////////////////////////////// -void SoundManager::updateSubtitles() { - Common::StackLock locker(_mutex); - - uint32 index = 0; - SubtitleEntry *subtitle = NULL; - - for (Common::List<SubtitleEntry *>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) { - uint32 current_index = 0; - SoundEntry *soundEntry = (*i)->sound; - SoundStatus status = (SoundStatus)soundEntry->status.status; - - if (!(status & kSoundStatus_40) - || status & 0x180 - || soundEntry->time == 0 - || (status & 0x1F) < 6 - || ((getFlags()->nis & 0x8000) && soundEntry->field_4C < 90)) { - current_index = 0; - } else { - current_index = soundEntry->field_4C + (status & 0x1F); - - if (_currentSubtitle == (*i)) - current_index += 4; - } - - if (index < current_index) { - index = current_index; - subtitle = (*i); - } - } - - if (_currentSubtitle == subtitle) { - if (subtitle) - setupSubtitleAndDraw(subtitle); - - return; - } - - if (_drawSubtitles & 1) - drawSubtitleOnScreen(subtitle); - - if (subtitle) { - loadSubtitleData(subtitle); - setupSubtitleAndDraw(subtitle); - } -} - -void SoundManager::showSubtitle(SoundEntry *entry, Common::String filename) { - entry->subtitle = loadSubtitle(filename, entry); - - if (entry->subtitle->status.status2 & 4) { - drawSubtitle(entry->subtitle); - SAFE_DELETE(entry->subtitle); - } else { - entry->status.status |= kSoundStatus_20000; - } -} - -SoundManager::SubtitleEntry *SoundManager::loadSubtitle(Common::String filename, SoundEntry *soundEntry) { - SubtitleEntry *entry = new SubtitleEntry(); - _subtitles.push_back(entry); - - // Set sound entry and filename - entry->filename = filename + ".SBE"; - entry->sound = soundEntry; - - // Load subtitle data - if (_engine->getResourceManager()->hasFile(filename)) { - if (_drawSubtitles & 2) - return entry; - - loadSubtitleData(entry); - } else { - entry->status.status = kSoundStatus_400; - } - - return entry; -} - -void SoundManager::loadSubtitleData(SubtitleEntry * entry) { - entry->data = new SubtitleManager(_engine->getFont()); - entry->data->load(getArchive(entry->filename)); - - _drawSubtitles |= 2; - _currentSubtitle = entry; -} - -void SoundManager::setupSubtitleAndDraw(SubtitleEntry *subtitle) { - if (!subtitle->data) { - subtitle->data = new SubtitleManager(_engine->getFont()); - subtitle->data->load(getArchive(subtitle->filename)); - } - - if (subtitle->data->getMaxTime() > subtitle->sound->time) { - subtitle->status.status = kSoundStatus_400; - } else { - subtitle->data->setTime((uint16)subtitle->sound->time); - - if (_drawSubtitles & 1) - drawSubtitleOnScreen(subtitle); - } - - _currentSubtitle = subtitle; -} - -void SoundManager::drawSubtitle(SubtitleEntry *subtitle) { - // Remove subtitle from queue - _subtitles.remove(subtitle); - - if (subtitle == _currentSubtitle) { - drawSubtitleOnScreen(subtitle); - - _currentSubtitle = NULL; - _drawSubtitles = 0; - } -} - -void SoundManager::drawSubtitleOnScreen(SubtitleEntry *subtitle) { - if (!subtitle) - error("SoundManager::drawSubtitleOnScreen: Invalid subtitle entry!"); - - _drawSubtitles &= ~1; - - if (subtitle->data == NULL) - return; - - if (_drawSubtitles & 1) - _engine->getGraphicsManager()->draw(subtitle->data, GraphicsManager::kBackgroundOverlay); -} - -////////////////////////////////////////////////////////////////////////// -// Misc -////////////////////////////////////////////////////////////////////////// -void SoundManager::playLoopingSound() { - warning("SoundManager::playLoopingSound: not implemented!"); -} - -void SoundManager::stopAllSound() { - Common::StackLock locker(_mutex); - - for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - (*i)->soundStream->stop(); -} - -} // End of namespace LastExpress diff --git a/engines/lastexpress/game/sound.h b/engines/lastexpress/game/sound.h deleted file mode 100644 index ddafc21829..0000000000 --- a/engines/lastexpress/game/sound.h +++ /dev/null @@ -1,389 +0,0 @@ -/* 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. - * - */ - -#ifndef LASTEXPRESS_SOUND_H -#define LASTEXPRESS_SOUND_H - -/* - - Sound entry: 68 bytes (this is what appears in the savegames) - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - entity - uint32 {4} - ?? - uint32 {4} - ?? - char {16} - name 1 - char {16} - name 2 - - Sound queue entry: 120 bytes - uint16 {2} - status - byte {1} - ?? - byte {1} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - file data pointer - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - archive structure pointer - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - ?? - uint32 {4} - entity - uint32 {4} - ?? - uint32 {4} - ?? - char {16} - name 1 - char {16} - name 2 - uint32 {4} - pointer to next entry in the queue - uint32 {4} - subtitle data pointer - -*/ - -#include "lastexpress/data/snd.h" -#include "lastexpress/data/subtitle.h" - -#include "lastexpress/shared.h" - -#include "lastexpress/helpers.h" - -#include "common/list.h" -#include "common/mutex.h" -#include "common/system.h" -#include "common/serializer.h" - -namespace LastExpress { - -class LastExpressEngine; -class SubtitleManager; - -class SoundManager : Common::Serializable { -public: - enum SoundType { - kSoundTypeNone = 0, - kSoundType1, - kSoundType2, - kSoundType3, - kSoundType4, - kSoundType5, - kSoundType6, - kSoundType7, - kSoundType8, - kSoundType9, - kSoundType10, - kSoundType11, - kSoundType12, - kSoundType13, - kSoundType14, - kSoundType15, - kSoundType16 - }; - - enum FlagType { - kFlagInvalid = -1, - kFlagNone = 0x0, - kFlag2 = 0x2, - kFlag3 = 0x3, - kFlag4 = 0x4, - kFlag5 = 0x5, - kFlag6 = 0x6, - kFlag7 = 0x7, - kFlag8 = 0x8, - kFlag9 = 0x9, - kFlag10 = 0xA, - kFlag11 = 0xB, - kFlag12 = 0xC, - kFlag13 = 0xD, - kFlag14 = 0xE, - kFlag15 = 0xF, - kFlagDefault = 0x10, - - kFlagType1_2 = 0x1000000, - kFlagSteam = 0x1001007, - kFlagType13 = 0x3000000, - kFlagMenuClock = 0x3080010, - kFlagType7 = 0x4000000, - kFlagType11 = 0x5000000, - kFlagMusic = 0x5000010, - kFlagType3 = 0x6000000, - kFlagLoop = 0x6001008, - kFlagType9 = 0x7000000 - }; - - SoundManager(LastExpressEngine *engine); - ~SoundManager(); - - // Timer - void handleTimer(); - - // State - void resetState() { _state |= kSoundType1; } - - // Sound queue - void updateQueue(); - void resetQueue(SoundType type1, SoundType type2 = kSoundTypeNone); - void clearQueue(); - - // Subtitles - void updateSubtitles(); - - // Entry - bool isBuffered(Common::String filename, bool testForEntity = false); - bool isBuffered(EntityIndex entity); - void setupEntry(SoundType type, EntityIndex index); - void processEntry(EntityIndex entity); - void processEntry(SoundType type); - void processEntry(Common::String filename); - void processEntries(); - void removeFromQueue(Common::String filename); - void removeFromQueue(EntityIndex entity); - uint32 getEntryTime(EntityIndex index); - - // Misc - void unknownFunction4(); - void clearStatus(); - - // Sound playing - void playSound(EntityIndex entity, Common::String filename, FlagType flag = kFlagInvalid, byte a4 = 0); - bool playSoundWithSubtitles(Common::String filename, FlagType flag, EntityIndex entity, byte a4 = 0); - void playSoundEvent(EntityIndex entity, byte action, byte a3 = 0); - void playDialog(EntityIndex entity, EntityIndex entityDialog, FlagType flag, byte a4); - void playSteam(CityIndex index); - void playFightSound(byte action, byte a4); - void playLocomotiveSound(); - void playWarningCompartment(EntityIndex entity, ObjectIndex compartment); - - // Dialog & Letters - void readText(int id); - const char *getDialogName(EntityIndex entity) const; - - // Sound bites - void excuseMe(EntityIndex entity, EntityIndex entity2 = kEntityPlayer, FlagType flag = kFlagNone); - void excuseMeCath(); - const char *justCheckingCath() const; - const char *wrongDoorCath() const; - const char *justAMinuteCath() const; - - // FLags - SoundManager::FlagType getSoundFlag(EntityIndex index) const; - - // Debug - void stopAllSound(); - - // Serializable - void saveLoadWithSerializer(Common::Serializer &ser); - uint32 count(); - -private: - typedef int32 *SoundBuffer; - - enum SoundStatus { - kSoundStatus_20 = 0x20, - kSoundStatus_40 = 0x40, - kSoundStatus_180 = 0x180, - kSoundStatusRemoved = 0x200, - kSoundStatus_400 = 0x400, - - kSoundStatus_8000 = 0x8000, - kSoundStatus_20000 = 0x20000, - kSoundStatus_100000 = 0x100000, - kSoundStatus_40000000 = 0x40000000, - - kSoundStatusClear0 = 0x10, - kSoundStatusClear1 = 0x1F, - kSoundStatusClear2 = 0x80, - kSoundStatusClear3 = 0x200, - kSoundStatusClear4 = 0x800, - kSoundStatusClearAll = 0xFFFFFFE0 - }; - - enum SoundState { - kSoundState0 = 0, - kSoundState1 = 1, - kSoundState2 = 2 - }; - - union SoundStatusUnion { - uint32 status; - byte status1; - byte status2; - byte status3; - byte status4; - - SoundStatusUnion() { - status = 0; - } - }; - - struct SubtitleEntry; - - struct SoundEntry { - SoundStatusUnion status; - SoundType type; // int - //int field_8; - //int field_C; - int processedFrameCount; - void *soundData; - //int field_18; - int field_1C; - uint32 time; - //int field_24; - //int field_28; - Common::SeekableReadStream *stream; // int - //int field_30; - int field_34; - int field_38; - int field_3C; - int field_40; - EntityIndex entity; - int field_48; - uint32 field_4C; - Common::String name1; //char[16]; - Common::String name2; //char[16]; - //int next; // offset to the next structure in the list (not used) - SubtitleEntry *subtitle; - - // Sound stream - StreamedSound *soundStream; - - SoundEntry() { - status.status = 0; - type = kSoundTypeNone; - - processedFrameCount = 0; - soundData = NULL; - - field_1C = 0; - time = 0; - - stream = NULL; - - field_34 = 0; - field_38 = 0; - field_3C = 0; - field_40 = 0; - entity = kEntityPlayer; - field_48 = 0; - field_4C = 0; - - subtitle = NULL; - - soundStream = NULL; - } - - ~SoundEntry() { - // Entries that have been queued would have their streamed disposed automatically - if (!soundStream) - SAFE_DELETE(stream); - - delete soundStream; - } - }; - - struct SubtitleEntry { - Common::String filename; - SoundStatusUnion status; - SoundEntry *sound; - SubtitleManager *data; - - SubtitleEntry() { - status.status = 0; - sound = NULL; - data = NULL; - } - - ~SubtitleEntry() { - SAFE_DELETE(data); - } - }; - - // Engine - LastExpressEngine *_engine; - - // State flag - int _state; - SoundType _currentType; - - Common::Mutex _mutex; - - // Unknown data - uint32 _data0; - uint32 _data1; - uint32 _data2; - uint32 _flag; - - // Filters - int32 _buffer[2940]; ///< Static sound buffer - - // Compartment warnings by Mertens or Coudert - uint32 _lastWarning[12]; - - // Looping sound - void playLoopingSound(); - - // Sound entries - Common::List<SoundEntry *> _soundList; ///< List of all sound entries - Common::List<SoundEntry *> _soundCache; ///< List of entries with a data buffer - void *_soundCacheData; - - SoundEntry *getEntry(EntityIndex index); - SoundEntry *getEntry(Common::String name); - SoundEntry *getEntry(SoundType type); - - void setupEntry(SoundEntry *entry, Common::String name, FlagType flag, int a4); - void setEntryType(SoundEntry *entry, FlagType flag); - void setEntryStatus(SoundEntry *entry, FlagType flag) const; - void setInCache(SoundEntry *entry); - bool setupCache(SoundEntry *entry); - void removeFromCache(SoundEntry *entry); - void loadSoundData(SoundEntry *entry, Common::String name); - - void updateEntry(SoundEntry *entry, uint value) const; - void updateEntryState(SoundEntry *entry) const; - void resetEntry(SoundEntry *entry) const; - void removeEntry(SoundEntry *entry); - - // Subtitles - int _drawSubtitles; - Common::List<SubtitleEntry *> _subtitles; - SubtitleEntry *_currentSubtitle; - void showSubtitle(SoundEntry *entry, Common::String filename); - SubtitleEntry *loadSubtitle(Common::String filename, SoundEntry *soundEntry); - void loadSubtitleData(SubtitleEntry * entry); - void setupSubtitleAndDraw(SubtitleEntry *subtitle); - void drawSubtitle(SubtitleEntry *subtitle); - void drawSubtitleOnScreen(SubtitleEntry *subtitle); - - // Sound filter - void applyFilter(SoundEntry *entry, SoundBuffer buffer); -}; - -} // End of namespace LastExpress - -#endif // LASTEXPRESS_SOUND_H diff --git a/engines/lastexpress/game/state.cpp b/engines/lastexpress/game/state.cpp index 0cf2ddba40..f3fd9720b1 100644 --- a/engines/lastexpress/game/state.cpp +++ b/engines/lastexpress/game/state.cpp @@ -57,7 +57,7 @@ bool State::isNightTime() const { void State::getHourMinutes(uint32 time, uint8 *hours, uint8 *minutes) { if (hours == NULL || minutes == NULL) - error("State::getHourMinutes: invalid parameters passed!"); + error("[State::getHourMinutes] Invalid parameters passed"); *hours = (uint8)((time % 1296000) / 54000); *minutes = (uint8)((time % 54000) / 900); diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h index 8f71e7d424..c937fdce9f 100644 --- a/engines/lastexpress/game/state.h +++ b/engines/lastexpress/game/state.h @@ -325,7 +325,7 @@ public: switch (index) { default: - error("GameProgress::isEqual: invalid index value (was: %d, max:127)", index); + error("[GameProgress::getValueName] Invalid index value (was: %d, max:127)", index); break; EXPOSE_VALUE(0, field_0); |