diff options
378 files changed, 8997 insertions, 2250 deletions
diff --git a/backends/events/androidsdl/androidsdl-events.cpp b/backends/events/androidsdl/androidsdl-events.cpp index bd8045ec62..7ea8ff1dc1 100644 --- a/backends/events/androidsdl/androidsdl-events.cpp +++ b/backends/events/androidsdl/androidsdl-events.cpp @@ -43,17 +43,16 @@ bool AndroidSdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event & else if (ev.button.button == SDL_BUTTON_MIDDLE) { event.type = Common::EVENT_MBUTTONDOWN; - static int show_onscreen=0; - if (show_onscreen==0) { - SDL_ANDROID_SetScreenKeyboardShown(0); - show_onscreen++; + static int show_onscreen = 0; + if (show_onscreen == 0) { + SDL_ANDROID_SetScreenKeyboardShown(0); + show_onscreen++; + } else if (show_onscreen==1) { + SDL_ANDROID_SetScreenKeyboardShown(1); + show_onscreen++; } - else if (show_onscreen==1) { - SDL_ANDROID_SetScreenKeyboardShown(1); - show_onscreen++; - } - if (show_onscreen==2) - show_onscreen=0; + if (show_onscreen == 2) + show_onscreen = 0; } #endif else @@ -68,7 +67,9 @@ bool AndroidSdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) { if (false) {} if (ev.key.keysym.sym == SDLK_LCTRL) { - ev.key.keysym.sym = SDLK_F5; + event.type = Common::EVENT_KEYDOWN; + event.kbd.keycode = Common::KEYCODE_F5; + return true; } else { // Let the events fall through if we didn't change them, this may not be the best way to // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though. diff --git a/devtools/create_titanic/create_titanic_dat.cpp b/devtools/create_titanic/create_titanic_dat.cpp index 9186c1ce20..61e5de1149 100644 --- a/devtools/create_titanic/create_titanic_dat.cpp +++ b/devtools/create_titanic/create_titanic_dat.cpp @@ -285,6 +285,136 @@ static const FrameRange BARBOT_FRAME_RANGES[60] = { { 202, 281 }, { 182, 202 }, { 165, 182 }, { 96, 165 }, { 0, 95 } }; +static const char *const MISSIVEOMAT_MESSAGES[3] = { + "Welcome, Leovinus.\n" + "\n" + "This is your Missive-O-Mat.\n" + "\n" + "You have received 1827 Electric Missives.\n" + "\n" + "For your convenience I have deleted:\n" + " 453 things that people you don't know thought it would be " + "terribly witty to forward to you,\n" + " 63 Missives containing double or triple exclamation marks,\n" + " 846 Missives from mailing-lists you once thought might be quite " + "interesting and now can't figure out how to cancel,\n" + " 962 Chain Missives,\n" + " 1034 instructions on how to become a millionaire using butter,\n" + " 3 Yassaccan Death Threats (slightly down on last week which is" + " pleasing news),\n" + " and a Missive from your Mother which I have answered reassuringly.\n" + "\n" + "I have selected the following Missives for your particular attention. " + "You will not need to run Fib-Finder to see why. Something Is Up and I " + "suspect those two slippery urchins Brobostigon and Scraliontis are behind it.", + + "Hello Droot. I have evaluated your recent missives.\n" + "Contents break down as follows:\n" + "\n" + "Good news 49%\n" + "Bad news 48%\n" + "Indifferent news 4%\n" + "Petty mailings and Family Missives 5%\n" + "Special Offers from the Blerontin Sand Society 1% (note - there's" + " a rather pretty dune for hire on p4)\n" + "\n" + "In general terms you Thrive. You continue to Prosper. Your shares are" + " Secure. Your hair, as always, looks Good. Carpet 14 needs cleaning. \n" + "\n" + "I am pleased to report there have been no further comments about " + "foot odor.\n" + "\n" + "Recommend urgently you sell all fish paste shares as Market jittery.\n" + "\n" + "As your Great Scheme nears completion I have taken the liberty of" + " replying to all non-urgent Missives and list below only communic" + "ations with Manager Brobostigon and His Pain in the Ass Loftiness" + " Leovinus. \n" + "\n" + "Beware - Leovinus grows suspicious. Don't take your eye off B" + "robostigon. \n" + "\n" + "Weather for the Launch tomorrow is bright and sunny. Hazy clouds" + " will be turned on at eleven. I suggest the red suit with the st" + "reamers.\n" + "\n" + "All money transfers will be completed through alias accounts by m" + "oonsup.\n" + "\n" + "Eat well. Your fish levels are down and you may suffer indecisio" + "n flutters mid-morning.\n" + "\n" + "Here are your Missives...", + + "Hello Antar, this is your Missive-o-Mat.\n" + "Not that you need reminding but today is the Glorious Dawning of " + "a New Age in Luxury Space Travel.\n" + "\n" + "Generally my assessment of your position this morning is that you" + " are well, albeit not as rich as you would like to be. I hope yo" + "ur interesting collaboration with Mr Scraliontis will soon bear f" + "ruit. \n" + "\n" + "I trust your flatulence has eased during the night. Such a distr" + "essing condition for a man in your position.\n" + "\n" + "Most of your Missives are routine construction matters which I ha" + "ve dealt with and deleted. All Missives from Mr Scraliontis and " + "His Loftiness Leovinus are here." +}; + +struct BedheadEntry { + const char *_name1; + const char *_name2; + const char *_name3; + const char *_name4; + int _startFrame; + int _endFrame; +}; + +static const BedheadEntry ON_CLOSED[4] = { + { "Closed", "Closed", "Open", "Open", 0, 12 }, + { "Open", "Any", "Any", "RestingUTV", 0, 4 }, + { "Closed", "Open", "Any", "RestingV", 0, 6 }, + { "Closed", "Closed", "Closed", "RestingG", 0, 21 } +}; +static const BedheadEntry ON_RESTING_TV[2] = { + { "Any", "Closed", "Open", "Open", 6, 12 }, + { "Any", "Closed", "Closed", "RestingG", 6, 21 } +}; +static const BedheadEntry ON_RESTING_UV[2] = { + { "Any", "Any", "Open", "Open", 8, 12 }, + { "Any", "Any", "Closed", "RestingG", 8, 21 } +}; +static const BedheadEntry ON_CLOSED_WRONG[2] = { + { "Any", "Any", "Closed", "OpenWrong", 42, 56 }, + { "Any", "Any", "Open", "RestingDWrong", 42, 52 } +}; + +static const BedheadEntry OFF_OPEN[3] = { + { "Closed", "Closed", "Open", "Closed", 27, 41 }, + { "Any", "Open", "Any", "RestingUV", 27, 29 }, + { "Open", "Closed", "Any", "RestingTV", 27, 33 } +}; +static const BedheadEntry OFF_RESTING_UTV[1] = { + { "Any", "Any", "Any", "Closed", 36, 41 } +}; +static const BedheadEntry OFF_RESTING_V[1] = { + { "Closed", "Any", "Any", "Closed", 32, 41 } +}; +static const BedheadEntry OFF_RESTING_G[3] = { + { "Closed", "Closed", "Closed", "Closed", 21, 41 }, + { "Any", "Open", "Closed", "RestingUV", 21, 29 }, + { "Open", "Closed", "Closed", "RestingTV", 21, 33 } +}; +static const BedheadEntry OFF_OPEN_WRONG[1] = { + { "Any", "Any", "Any", "ClosedWrong", 56, 70 } +}; +static const BedheadEntry OFF_RESTING_D_WRONG[1] = { + { "Any", "Any", "Any", "ClosedWrong", 59, 70 } +}; + + void NORETURN_PRE error(const char *s, ...) { printf("%s\n", s); exit(1); @@ -619,6 +749,86 @@ void writeBarbotFrameRanges() { dataOffset += size; } +void writeMissiveOMatMessages() { + outputFile.seek(dataOffset); + + for (int idx = 0; idx < 3; ++idx) + outputFile.writeString(MISSIVEOMAT_MESSAGES[idx]); + + uint size = outputFile.size() - dataOffset; + writeEntryHeader("TEXT/MISSIVEOMAT/WELCOME", dataOffset, size); + dataOffset += size; + + static const int MESSAGES[3] = { 0x5A63C0, 0x5A5BA8, 0x5A4A18 }; + writeStringArray("TEXT/MISSIVEOMAT/MESSAGES", MESSAGES[_version], 58); + static const int FROM[3] = { 0x5A61F0, 0x5A59D8, 0x5A4BE8 }; + writeStringArray("TEXT/MISSIVEOMAT/FROM", FROM[_version], 58); + static const int TO[3] = { 0x5A62D8, 0x5A5AC0, 0x5A4B00 }; + writeStringArray("TEXT/MISSIVEOMAT/TO", TO[_version], 58); +} + +void writeBedheadGroup(const BedheadEntry *data, int count) { + for (int idx = 0; idx < count; ++idx, ++data) { + outputFile.writeString(data->_name1); + outputFile.writeString(data->_name2); + outputFile.writeString(data->_name3); + outputFile.writeString(data->_name4); + outputFile.writeLong(data->_startFrame); + outputFile.writeLong(data->_endFrame); + } +} + +void writeBedheadData() { + outputFile.seek(dataOffset); + + writeBedheadGroup(ON_CLOSED, 4); + writeBedheadGroup(ON_RESTING_TV, 2); + writeBedheadGroup(ON_RESTING_UV, 2); + writeBedheadGroup(ON_CLOSED_WRONG, 2); + writeBedheadGroup(OFF_OPEN, 3); + writeBedheadGroup(OFF_RESTING_UTV, 1); + writeBedheadGroup(OFF_RESTING_V, 1); + writeBedheadGroup(OFF_RESTING_G, 3); + writeBedheadGroup(OFF_OPEN_WRONG, 1); + writeBedheadGroup(OFF_RESTING_D_WRONG, 1); + + uint size = outputFile.size() - dataOffset; + writeEntryHeader("DATA/BEDHEAD", dataOffset, size); + dataOffset += size; +} + +void writeParrotLobbyLinkUpdaterEntries() { + static const int OFFSETS[3] = { 0x5A5B38, 0x5A5320, 0x5A4360 }; + static const int COUNTS[5] = { 7, 5, 6, 9, 1 }; + static const int SKIP[5] = { 36, 36, 40, 36, 0 }; + uint recordOffset = OFFSETS[_version], linkOffset; + byte vals[8]; + + outputFile.seek(dataOffset); + + for (int groupNum = 0; groupNum < 4; ++groupNum) { + for (int entryNum = 0; entryNum < COUNTS[groupNum]; + ++entryNum, recordOffset += 36) { + inputFile.seek(recordOffset - FILE_DIFF[_version]); + linkOffset = inputFile.readUint32LE(); + for (int idx = 0; idx < 8; ++idx) + vals[idx] = inputFile.readUint32LE(); + + // Write out the entry + inputFile.seek(linkOffset - FILE_DIFF[_version]); + outputFile.writeString(inputFile); + outputFile.write(vals, 8); + } + + // Skip space between groups + recordOffset += SKIP[groupNum]; + } + + uint size = outputFile.size() - dataOffset; + writeEntryHeader("DATA/PARROT_LOBBY_LINK_UPDATOR", dataOffset, size); + dataOffset += size; +} + void writeHeader() { // Write out magic string const char *MAGIC_STR = "SVTN"; @@ -789,6 +999,9 @@ void writeData() { writeAllUpdateStates(); writeAllScriptPreResponses(); writeBarbotFrameRanges(); + writeMissiveOMatMessages(); + writeBedheadData(); + writeParrotLobbyLinkUpdaterEntries(); } void createScriptMap() { diff --git a/dists/msvc10/create_msvc10.bat b/dists/msvc10/create_msvc10.bat index be0434fc50..53acbff42e 100644 --- a/dists/msvc10/create_msvc10.bat +++ b/dists/msvc10/create_msvc10.bat @@ -55,14 +55,14 @@ goto done echo. echo Creating project files with all engines enabled (stable and unstable) echo. -create_project ..\.. --enable-all-engines --msvc --msvc-version 10 --build-events +create_project ..\.. --enable-all-engines --disable-fluidsynth --msvc --msvc-version 10 --build-events goto done :stable echo. echo Creating normal project files, with only the stable engines enabled echo. -create_project ..\.. --msvc --msvc-version 10 +create_project ..\.. --disable-fluidsynth --msvc --msvc-version 10 goto done :tools diff --git a/dists/msvc11/create_msvc11.bat b/dists/msvc11/create_msvc11.bat index fc5471f46f..3c3052a5b0 100644 --- a/dists/msvc11/create_msvc11.bat +++ b/dists/msvc11/create_msvc11.bat @@ -55,14 +55,14 @@ goto done echo. echo Creating project files with all engines enabled (stable and unstable) echo. -create_project ..\.. --enable-all-engines --msvc --msvc-version 11 --build-events +create_project ..\.. --enable-all-engines --disable-fluidsynth --msvc --msvc-version 11 --build-events goto done :stable echo. echo Creating normal project files, with only the stable engines enabled echo. -create_project ..\.. --msvc --msvc-version 11 +create_project ..\.. --disable-fluidsynth --msvc --msvc-version 11 goto done :tools diff --git a/dists/msvc12/create_msvc12.bat b/dists/msvc12/create_msvc12.bat index d99001edb1..449b50ea54 100644 --- a/dists/msvc12/create_msvc12.bat +++ b/dists/msvc12/create_msvc12.bat @@ -55,14 +55,14 @@ goto done echo. echo Creating project files with all engines enabled (stable and unstable) echo. -create_project ..\.. --enable-all-engines --msvc --msvc-version 12 --build-events +create_project ..\.. --enable-all-engines --disable-fluidsynth --msvc --msvc-version 12 --build-events goto done :stable echo. echo Creating normal project files, with only the stable engines enabled echo. -create_project ..\.. --msvc --msvc-version 12 +create_project ..\.. --disable-fluidsynth --msvc --msvc-version 12 goto done :tools diff --git a/dists/msvc9/create_msvc9.bat b/dists/msvc9/create_msvc9.bat index 34bcccdd7b..005bc084db 100644 --- a/dists/msvc9/create_msvc9.bat +++ b/dists/msvc9/create_msvc9.bat @@ -55,14 +55,14 @@ goto done echo. echo Creating project files with all engines enabled (stable and unstable) echo. -create_project ..\.. --enable-all-engines --msvc --msvc-version 9 +create_project ..\.. --enable-all-engines --disable-fluidsynth --msvc --msvc-version 9 goto done :stable echo. echo Creating normal project files, with only the stable engines enabled echo. -create_project ..\.. --msvc --msvc-version 9 +create_project ..\.. --disable-fluidsynth --msvc --msvc-version 9 goto done :tools diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 19595606e1..9afb2c6700 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -402,6 +402,15 @@ byte AdlEngine::roomArg(byte room) const { return room; } +void AdlEngine::loadDroppedItemOffsets(Common::ReadStream &stream, byte count) { + for (uint i = 0; i < count; ++i) { + Common::Point p; + p.x = stream.readByte(); + p.y = stream.readByte(); + _itemOffsets.push_back(p); + } +} + void AdlEngine::clearScreen() const { _display->setMode(DISPLAY_MODE_MIXED); _display->clear(0x00); @@ -1263,16 +1272,17 @@ Common::String AdlEngine::toAscii(const Common::String &str) { } Common::String AdlEngine::itemStr(uint i) const { - byte desc = getItem(i).description; - byte noun = getItem(i).noun; + const Item &item(getItem(i)); + Common::String name = Common::String::format("%d", i); - if (noun > 0) { + if (item.noun > 0) { name += "/"; - name += _priNouns[noun - 1]; + name += _priNouns[item.noun - 1]; } - if (desc > 0) { + Common::String desc = getItemDescription(item); + if (!desc.empty()) { name += "/"; - name += toAscii(loadMessage(desc)); + name += toAscii(desc); } return name; } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 89cdabe384..971336ef50 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -247,6 +247,7 @@ protected: virtual void initState(); virtual byte roomArg(byte room) const; virtual void advanceClock() { } + void loadDroppedItemOffsets(Common::ReadStream &stream, byte count); // Opcodes int o1_isItemInRoom(ScriptEnv &e); diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp index e18f3339f8..979d794146 100644 --- a/engines/adl/adl_v2.cpp +++ b/engines/adl/adl_v2.cpp @@ -359,9 +359,83 @@ DataBlockPtr AdlEngine_v2::readDataBlockPtr(Common::ReadStream &f) const { if (track == 0 && sector == 0 && offset == 0 && size == 0) return DataBlockPtr(); + adjustDataBlockPtr(track, sector, offset, size); + return _disk->getDataBlock(track, sector, offset, size); } +void AdlEngine_v2::loadItems(Common::ReadStream &stream) { + byte id; + while ((id = stream.readByte()) != 0xff && !stream.eos() && !stream.err()) { + Item item = Item(); + item.id = id; + item.noun = stream.readByte(); + item.room = stream.readByte(); + item.picture = stream.readByte(); + item.isLineArt = stream.readByte(); // Disk number in later games + item.position.x = stream.readByte(); + item.position.y = stream.readByte(); + item.state = stream.readByte(); + item.description = stream.readByte(); + + stream.readByte(); // Struct size + + byte picListSize = stream.readByte(); + + // Flag to keep track of what has been drawn on the screen + stream.readByte(); + + for (uint i = 0; i < picListSize; ++i) + item.roomPictures.push_back(stream.readByte()); + + _state.items.push_back(item); + } + + if (stream.eos() || stream.err()) + error("Error loading items"); +} + +void AdlEngine_v2::loadRooms(Common::ReadStream &stream, byte count) { + for (uint i = 0; i < count; ++i) { + Room room; + + stream.readByte(); // number + for (uint j = 0; j < 6; ++j) + room.connections[j] = stream.readByte(); + room.data = readDataBlockPtr(stream); + room.picture = stream.readByte(); + room.curPicture = stream.readByte(); + room.isFirstTime = stream.readByte(); + + _state.rooms.push_back(room); + } + + if (stream.eos() || stream.err()) + error("Error loading rooms"); +} + +void AdlEngine_v2::loadMessages(Common::ReadStream &stream, byte count) { + for (uint i = 0; i < count; ++i) + _messages.push_back(readDataBlockPtr(stream)); +} + +void AdlEngine_v2::loadPictures(Common::ReadStream &stream) { + byte picNr; + while ((picNr = stream.readByte()) != 0xff) { + if (stream.eos() || stream.err()) + error("Error reading global pic list"); + + _pictures[picNr] = readDataBlockPtr(stream); + } +} + +void AdlEngine_v2::loadItemPictures(Common::ReadStream &stream, byte count) { + for (uint i = 0; i < count; ++i) { + stream.readByte(); // number + _itemPics.push_back(readDataBlockPtr(stream)); + } +} + int AdlEngine_v2::o2_isFirstTime(ScriptEnv &e) { OP_DEBUG_0("\t&& IS_FIRST_TIME()"); diff --git a/engines/adl/adl_v2.h b/engines/adl/adl_v2.h index 4a473e9b1f..8f36b5cdb8 100644 --- a/engines/adl/adl_v2.h +++ b/engines/adl/adl_v2.h @@ -25,9 +25,6 @@ #include "adl/adl.h" -// Note: this version of ADL redraws only when necessary, but -// this is not currently implemented. - namespace Common { class RandomSource; } @@ -55,6 +52,12 @@ protected: void takeItem(byte noun); virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const; + virtual void adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const { } + void loadItems(Common::ReadStream &stream); + void loadRooms(Common::ReadStream &stream, byte count); + void loadMessages(Common::ReadStream &stream, byte count); + void loadPictures(Common::ReadStream &stream); + void loadItemPictures(Common::ReadStream &stream, byte count); void checkTextOverflow(char c); diff --git a/engines/adl/adl_v3.cpp b/engines/adl/adl_v3.cpp index 005478c376..ba9e4a063e 100644 --- a/engines/adl/adl_v3.cpp +++ b/engines/adl/adl_v3.cpp @@ -20,162 +20,50 @@ * */ -#include "common/random.h" -#include "common/error.h" - #include "adl/adl_v3.h" -#include "adl/display.h" -#include "adl/graphics.h" namespace Adl { AdlEngine_v3::AdlEngine_v3(OSystem *syst, const AdlGameDescription *gd) : - AdlEngine_v2(syst, gd), - _curDisk(0) { -} - -Common::String AdlEngine_v3::loadMessage(uint idx) const { - Common::String str = AdlEngine_v2::loadMessage(idx); - - for (uint i = 0; i < str.size(); ++i) { - const char *xorStr = "AVISDURGAN"; - str.setChar(str[i] ^ xorStr[i % strlen(xorStr)], i); - } - - return str; + AdlEngine_v2(syst, gd) { } Common::String AdlEngine_v3::getItemDescription(const Item &item) const { - return _itemDesc[item.id - 1]; + return _itemDesc[item.description - 1]; } -void AdlEngine_v3::applyDiskOffset(byte &track, byte §or) const { - sector += _diskOffsets[_curDisk].sector; - if (sector >= 16) { - sector -= 16; - ++track; - } +void AdlEngine_v3::loadItemDescriptions(Common::SeekableReadStream &stream, byte count) { + int32 startPos = stream.pos(); + uint16 baseAddr = stream.readUint16LE(); - track += _diskOffsets[_curDisk].track; -} - -DataBlockPtr AdlEngine_v3::readDataBlockPtr(Common::ReadStream &f) const { - byte track = f.readByte(); - byte sector = f.readByte(); - byte offset = f.readByte(); - byte size = f.readByte(); - - if (f.eos() || f.err()) - error("Error reading DataBlockPtr"); + // This code assumes that the first pointer points to a string that + // directly follows the pointer table + assert(baseAddr != 0); + baseAddr -= count * 2; - if (track == 0 && sector == 0 && offset == 0 && size == 0) - return DataBlockPtr(); + for (uint i = 0; i < count; ++i) { + stream.seek(startPos + i * 2); + uint16 offset = stream.readUint16LE(); - applyDiskOffset(track, sector); + if (offset > 0) { + stream.seek(startPos + offset - baseAddr); + _itemDesc.push_back(readString(stream, 0xff)); + } else + _itemDesc.push_back(Common::String()); + } - return _disk->getDataBlock(track, sector, offset, size); + if (stream.eos() || stream.err()) + error("Error loading item descriptions"); } typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine_v3> OpcodeV3; -#define SetOpcodeTable(x) table = &x; -#define Opcode(x) table->push_back(new OpcodeV3(this, &AdlEngine_v3::x)) -#define OpcodeUnImpl() table->push_back(new OpcodeV3(this, 0)) void AdlEngine_v3::setupOpcodeTables() { - Common::Array<const Opcode *> *table = 0; - - SetOpcodeTable(_condOpcodes); - // 0x00 - OpcodeUnImpl(); - Opcode(o2_isFirstTime); - Opcode(o2_isRandomGT); - Opcode(o3_isItemInRoom); - // 0x04 - Opcode(o3_isNounNotInRoom); - Opcode(o1_isMovesGT); - Opcode(o1_isVarEQ); - Opcode(o2_isCarryingSomething); - // 0x08 - Opcode(o3_isVarGT); - Opcode(o1_isCurPicEQ); - Opcode(o3_skipOneCommand); - - SetOpcodeTable(_actOpcodes); - // 0x00 - OpcodeUnImpl(); - Opcode(o1_varAdd); - Opcode(o1_varSub); - Opcode(o1_varSet); - // 0x04 - Opcode(o1_listInv); - Opcode(o3_moveItem); - Opcode(o1_setRoom); - Opcode(o2_setCurPic); - // 0x08 - Opcode(o2_setPic); - Opcode(o1_printMsg); - Opcode(o3_dummy); - Opcode(o3_setTextMode); - // 0x0c - Opcode(o2_moveAllItems); - Opcode(o1_quit); - Opcode(o3_dummy); - Opcode(o2_save); - // 0x10 - Opcode(o2_restore); - Opcode(o1_restart); - Opcode(o3_setDisk); - Opcode(o3_dummy); - // 0x14 - Opcode(o1_resetPic); - Opcode(o1_goDirection<IDI_DIR_NORTH>); - Opcode(o1_goDirection<IDI_DIR_SOUTH>); - Opcode(o1_goDirection<IDI_DIR_EAST>); - // 0x18 - Opcode(o1_goDirection<IDI_DIR_WEST>); - Opcode(o1_goDirection<IDI_DIR_UP>); - Opcode(o1_goDirection<IDI_DIR_DOWN>); - Opcode(o1_takeItem); - // 0x1c - Opcode(o1_dropItem); - Opcode(o1_setRoomPic); - Opcode(o3_sound); - OpcodeUnImpl(); - // 0x20 - Opcode(o2_initDisk); -} - -int AdlEngine_v3::o3_isVarGT(ScriptEnv &e) { - OP_DEBUG_2("\t&& VARS[%d] > %d", e.arg(1), e.arg(2)); - - if (getVar(e.arg(1)) > e.arg(2)) - return 2; - - return -1; -} - -int AdlEngine_v3::o3_skipOneCommand(ScriptEnv &e) { - OP_DEBUG_0("\t&& SKIP_ONE_COMMAND()"); - - _skipOneCommand = true; - setVar(2, 0); - - return -1; -} - -// FIXME: Rename "isLineArt" and look at code duplication -int AdlEngine_v3::o3_isItemInRoom(ScriptEnv &e) { - OP_DEBUG_2("\t&& GET_ITEM_ROOM(%s) == %s", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str()); - - const Item &item = getItem(e.arg(1)); - - if (e.arg(2) != IDI_ANY && item.isLineArt != _curDisk) - return -1; - - if (item.room == roomArg(e.arg(2))) - return 2; - - return -1; + AdlEngine_v2::setupOpcodeTables(); + delete _condOpcodes[0x04]; + _condOpcodes[0x04] = new OpcodeV3(this, &AdlEngine_v3::o3_isNounNotInRoom); + delete _actOpcodes[0x04]; + _actOpcodes[0x04] = new OpcodeV3(this, &AdlEngine_v3::o3_listInv); } int AdlEngine_v3::o3_isNounNotInRoom(ScriptEnv &e) { @@ -183,75 +71,28 @@ int AdlEngine_v3::o3_isNounNotInRoom(ScriptEnv &e) { Common::List<Item>::const_iterator item; - setVar(24, 0); + bool isAnItem = false; - for (item = _state.items.begin(); item != _state.items.end(); ++item) + for (item = _state.items.begin(); item != _state.items.end(); ++item) { if (item->noun == e.getNoun()) { - setVar(24, 1); + isAnItem = true; if (item->room == roomArg(e.arg(1))) return -1; } - - return 1; -} - -int AdlEngine_v3::o3_moveItem(ScriptEnv &e) { - OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str()); - - byte room = roomArg(e.arg(2)); - - Item &item = getItem(e.arg(1)); - - if (item.room == _roomOnScreen) - _picOnScreen = 0; - - // Set items that move from inventory to a room to state "dropped" - if (item.room == IDI_ANY && room != IDI_VOID_ROOM) - item.state = IDI_ITEM_DROPPED; - - item.room = room; - item.isLineArt = _curDisk; - return 2; -} - -int AdlEngine_v3::o3_dummy(ScriptEnv &e) { - OP_DEBUG_0("\tDUMMY()"); - - return 0; -} - -int AdlEngine_v3::o3_setTextMode(ScriptEnv &e) { - OP_DEBUG_1("\tSET_TEXT_MODE(%d)", e.arg(1)); - - // TODO - // 1: 4-line mode - // 2: 24-line mode - - switch (e.arg(1)) { - case 3: - // We re-use the restarting flag here, to simulate a long jump - _isRestarting = true; - return -1; } - return 1; + return (isAnItem ? 1 : -1); } -int AdlEngine_v3::o3_setDisk(ScriptEnv &e) { - OP_DEBUG_2("\tSET_DISK(%d, %d)", e.arg(1), e.arg(2)); - - // TODO - // Arg 1: disk - // Arg 2: room - - return 2; -} +int AdlEngine_v3::o3_listInv(ScriptEnv &e) { + OP_DEBUG_0("\tLIST_INVENTORY()"); -int AdlEngine_v3::o3_sound(ScriptEnv &e) { - OP_DEBUG_0("\tSOUND()"); + Common::List<Item>::const_iterator item; - // TODO + for (item = _state.items.begin(); item != _state.items.end(); ++item) + if (item->room == IDI_ANY) + printString(_itemDesc[item->description - 1]); return 0; } diff --git a/engines/adl/adl_v3.h b/engines/adl/adl_v3.h index 61dd5852e7..b0d40f3993 100644 --- a/engines/adl/adl_v3.h +++ b/engines/adl/adl_v3.h @@ -25,18 +25,6 @@ #include "adl/adl_v2.h" -// Note: this version of ADL redraws only when necessary, but -// this is not currently implemented. - -namespace Common { -class RandomSource; -} - -struct DiskOffset { - byte track; - byte sector; -}; - namespace Adl { class AdlEngine_v3 : public AdlEngine_v2 { @@ -48,27 +36,14 @@ protected: // AdlEngine virtual void setupOpcodeTables(); - virtual Common::String loadMessage(uint idx) const; Common::String getItemDescription(const Item &item) const; - // AdlEngine_v2 - virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const; - - void applyDiskOffset(byte &track, byte §or) const; + void loadItemDescriptions(Common::SeekableReadStream &stream, byte count); - int o3_isVarGT(ScriptEnv &e); - int o3_isItemInRoom(ScriptEnv &e); int o3_isNounNotInRoom(ScriptEnv &e); - int o3_skipOneCommand(ScriptEnv &e); - int o3_moveItem(ScriptEnv &e); - int o3_dummy(ScriptEnv &e); - int o3_setTextMode(ScriptEnv &e); - int o3_setDisk(ScriptEnv &e); - int o3_sound(ScriptEnv &e); + int o3_listInv(ScriptEnv &e); Common::Array<Common::String> _itemDesc; - byte _curDisk; - Common::Array<DiskOffset> _diskOffsets; }; } // End of namespace Adl diff --git a/engines/adl/adl_v4.cpp b/engines/adl/adl_v4.cpp new file mode 100644 index 0000000000..ed20c82513 --- /dev/null +++ b/engines/adl/adl_v4.cpp @@ -0,0 +1,258 @@ +/* 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 "common/random.h" +#include "common/error.h" + +#include "adl/adl_v4.h" +#include "adl/display.h" +#include "adl/graphics.h" + +namespace Adl { + +AdlEngine_v4::AdlEngine_v4(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine_v3(syst, gd), + _curDisk(0) { +} + +Common::String AdlEngine_v4::loadMessage(uint idx) const { + Common::String str = AdlEngine_v2::loadMessage(idx); + + for (uint i = 0; i < str.size(); ++i) { + const char *xorStr = "AVISDURGAN"; + str.setChar(str[i] ^ xorStr[i % strlen(xorStr)], i); + } + + return str; +} + +Common::String AdlEngine_v4::getItemDescription(const Item &item) const { + return _itemDesc[item.id - 1]; +} + +void AdlEngine_v4::applyDiskOffset(byte &track, byte §or) const { + sector += _diskOffsets[_curDisk].sector; + if (sector >= 16) { + sector -= 16; + ++track; + } + + track += _diskOffsets[_curDisk].track; +} + +void AdlEngine_v4::adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const { + applyDiskOffset(track, sector); +} + +typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine_v4> OpcodeV4; +#define SetOpcodeTable(x) table = &x; +#define Opcode(x) table->push_back(new OpcodeV4(this, &AdlEngine_v4::x)) +#define OpcodeUnImpl() table->push_back(new OpcodeV4(this, 0)) + +void AdlEngine_v4::setupOpcodeTables() { + Common::Array<const Opcode *> *table = 0; + + SetOpcodeTable(_condOpcodes); + // 0x00 + OpcodeUnImpl(); + Opcode(o2_isFirstTime); + Opcode(o2_isRandomGT); + Opcode(o4_isItemInRoom); + // 0x04 + Opcode(o4_isNounNotInRoom); + Opcode(o1_isMovesGT); + Opcode(o1_isVarEQ); + Opcode(o2_isCarryingSomething); + // 0x08 + Opcode(o4_isVarGT); + Opcode(o1_isCurPicEQ); + Opcode(o4_skipOneCommand); + + SetOpcodeTable(_actOpcodes); + // 0x00 + OpcodeUnImpl(); + Opcode(o1_varAdd); + Opcode(o1_varSub); + Opcode(o1_varSet); + // 0x04 + Opcode(o4_listInv); + Opcode(o4_moveItem); + Opcode(o1_setRoom); + Opcode(o2_setCurPic); + // 0x08 + Opcode(o2_setPic); + Opcode(o1_printMsg); + Opcode(o4_dummy); + Opcode(o4_setTextMode); + // 0x0c + Opcode(o2_moveAllItems); + Opcode(o1_quit); + Opcode(o4_dummy); + Opcode(o2_save); + // 0x10 + Opcode(o2_restore); + Opcode(o1_restart); + Opcode(o4_setDisk); + Opcode(o4_dummy); + // 0x14 + Opcode(o1_resetPic); + Opcode(o1_goDirection<IDI_DIR_NORTH>); + Opcode(o1_goDirection<IDI_DIR_SOUTH>); + Opcode(o1_goDirection<IDI_DIR_EAST>); + // 0x18 + Opcode(o1_goDirection<IDI_DIR_WEST>); + Opcode(o1_goDirection<IDI_DIR_UP>); + Opcode(o1_goDirection<IDI_DIR_DOWN>); + Opcode(o1_takeItem); + // 0x1c + Opcode(o1_dropItem); + Opcode(o1_setRoomPic); + Opcode(o4_sound); + OpcodeUnImpl(); + // 0x20 + Opcode(o2_initDisk); +} + +int AdlEngine_v4::o4_isVarGT(ScriptEnv &e) { + OP_DEBUG_2("\t&& VARS[%d] > %d", e.arg(1), e.arg(2)); + + if (getVar(e.arg(1)) > e.arg(2)) + return 2; + + return -1; +} + +int AdlEngine_v4::o4_skipOneCommand(ScriptEnv &e) { + OP_DEBUG_0("\t&& SKIP_ONE_COMMAND()"); + + _skipOneCommand = true; + setVar(2, 0); + + return -1; +} + +// FIXME: Rename "isLineArt" and look at code duplication +int AdlEngine_v4::o4_isItemInRoom(ScriptEnv &e) { + OP_DEBUG_2("\t&& GET_ITEM_ROOM(%s) == %s", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str()); + + const Item &item = getItem(e.arg(1)); + + if (e.arg(2) != IDI_ANY && item.isLineArt != _curDisk) + return -1; + + if (item.room == roomArg(e.arg(2))) + return 2; + + return -1; +} + +int AdlEngine_v4::o4_isNounNotInRoom(ScriptEnv &e) { + OP_DEBUG_1("\t&& NO_SUCH_ITEMS_IN_ROOM(%s)", itemRoomStr(e.arg(1)).c_str()); + + Common::List<Item>::const_iterator item; + + setVar(24, 0); + + for (item = _state.items.begin(); item != _state.items.end(); ++item) + if (item->noun == e.getNoun()) { + setVar(24, 1); + + if (item->room == roomArg(e.arg(1))) + return -1; + } + + return 1; +} + +int AdlEngine_v4::o4_listInv(ScriptEnv &e) { + OP_DEBUG_0("\tLIST_INVENTORY()"); + + Common::List<Item>::const_iterator item; + + for (item = _state.items.begin(); item != _state.items.end(); ++item) + if (item->room == IDI_ANY) + printString(_itemDesc[item->id - 1]); + + return 0; +} + +int AdlEngine_v4::o4_moveItem(ScriptEnv &e) { + OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str()); + + byte room = roomArg(e.arg(2)); + + Item &item = getItem(e.arg(1)); + + if (item.room == _roomOnScreen) + _picOnScreen = 0; + + // Set items that move from inventory to a room to state "dropped" + if (item.room == IDI_ANY && room != IDI_VOID_ROOM) + item.state = IDI_ITEM_DROPPED; + + item.room = room; + item.isLineArt = _curDisk; + return 2; +} + +int AdlEngine_v4::o4_dummy(ScriptEnv &e) { + OP_DEBUG_0("\tDUMMY()"); + + return 0; +} + +int AdlEngine_v4::o4_setTextMode(ScriptEnv &e) { + OP_DEBUG_1("\tSET_TEXT_MODE(%d)", e.arg(1)); + + // TODO + // 1: 4-line mode + // 2: 24-line mode + + switch (e.arg(1)) { + case 3: + // We re-use the restarting flag here, to simulate a long jump + _isRestarting = true; + return -1; + } + + return 1; +} + +int AdlEngine_v4::o4_setDisk(ScriptEnv &e) { + OP_DEBUG_2("\tSET_DISK(%d, %d)", e.arg(1), e.arg(2)); + + // TODO + // Arg 1: disk + // Arg 2: room + + return 2; +} + +int AdlEngine_v4::o4_sound(ScriptEnv &e) { + OP_DEBUG_0("\tSOUND()"); + + // TODO + + return 0; +} + +} // End of namespace Adl diff --git a/engines/adl/hires2.h b/engines/adl/adl_v4.h index 50016725d6..79aa824d92 100644 --- a/engines/adl/hires2.h +++ b/engines/adl/adl_v4.h @@ -20,45 +20,52 @@ * */ -#ifndef ADL_HIRES2_H -#define ADL_HIRES2_H +#ifndef ADL_ADL_V4_H +#define ADL_ADL_V4_H -#include "common/str.h" - -#include "adl/adl_v2.h" -#include "adl/disk.h" +#include "adl/adl_v3.h" namespace Common { -class ReadStream; -struct Point; +class RandomSource; } +struct DiskOffset { + byte track; + byte sector; +}; + namespace Adl { -#define IDS_HR2_DISK_IMAGE "WIZARD.DSK" +class AdlEngine_v4 : public AdlEngine_v3 { +public: + virtual ~AdlEngine_v4() { } -#define IDI_HR2_NUM_ROOMS 135 -#define IDI_HR2_NUM_MESSAGES 255 -#define IDI_HR2_NUM_VARS 40 -#define IDI_HR2_NUM_ITEM_PICS 38 -#define IDI_HR2_NUM_ITEM_OFFSETS 16 +protected: + AdlEngine_v4(OSystem *syst, const AdlGameDescription *gd); -// Messages used outside of scripts -#define IDI_HR2_MSG_CANT_GO_THERE 123 -#define IDI_HR2_MSG_DONT_UNDERSTAND 19 -#define IDI_HR2_MSG_ITEM_DOESNT_MOVE 242 -#define IDI_HR2_MSG_ITEM_NOT_HERE 4 -#define IDI_HR2_MSG_THANKS_FOR_PLAYING 239 + // AdlEngine + virtual void setupOpcodeTables(); + virtual Common::String loadMessage(uint idx) const; + Common::String getItemDescription(const Item &item) const; -class HiRes2Engine : public AdlEngine_v2 { -public: - HiRes2Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v2(syst, gd) { } + // AdlEngine_v2 + virtual void adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const; -private: - // AdlEngine - void runIntro() const; - void init(); - void initGameState(); + void applyDiskOffset(byte &track, byte §or) const; + + int o4_isVarGT(ScriptEnv &e); + int o4_isItemInRoom(ScriptEnv &e); + int o4_isNounNotInRoom(ScriptEnv &e); + int o4_skipOneCommand(ScriptEnv &e); + int o4_listInv(ScriptEnv &e); + int o4_moveItem(ScriptEnv &e); + int o4_dummy(ScriptEnv &e); + int o4_setTextMode(ScriptEnv &e); + int o4_setDisk(ScriptEnv &e); + int o4_sound(ScriptEnv &e); + + byte _curDisk; + Common::Array<DiskOffset> _diskOffsets; }; } // End of namespace Adl diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp index af51f95fe7..10812d79ea 100644 --- a/engines/adl/detection.cpp +++ b/engines/adl/detection.cpp @@ -76,6 +76,7 @@ static const PlainGameDescriptor adlGames[] = { { "hires0", "Hi-Res Adventure #0: Mission Asteroid" }, { "hires1", "Hi-Res Adventure #1: Mystery House" }, { "hires2", "Hi-Res Adventure #2: Wizard and the Princess" }, + { "hires4", "Hi-Res Adventure #4: Ulysses and the Golden Fleece" }, { "hires6", "Hi-Res Adventure #6: The Dark Crystal" }, { 0, 0 } }; @@ -92,7 +93,7 @@ static const AdlGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformApple2, - ADGF_UNSTABLE, + ADGF_TESTING, GUIO2(GAMEOPTION_COLOR_DEFAULT_OFF, GAMEOPTION_SCANLINES) }, GAME_TYPE_HIRES1 @@ -106,7 +107,7 @@ static const AdlGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformApple2, - ADGF_UNSTABLE, + ADGF_TESTING, GUIO2(GAMEOPTION_COLOR_DEFAULT_OFF, GAMEOPTION_SCANLINES) }, GAME_TYPE_HIRES1 @@ -120,7 +121,7 @@ static const AdlGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformApple2, - ADGF_UNSTABLE, + ADGF_TESTING, GUIO2(GAMEOPTION_COLOR_DEFAULT_ON, GAMEOPTION_SCANLINES) }, GAME_TYPE_HIRES2 @@ -134,11 +135,26 @@ static const AdlGameDescription gameDescriptions[] = { }, Common::EN_ANY, Common::kPlatformApple2, - ADGF_UNSTABLE, + ADGF_TESTING, GUIO2(GAMEOPTION_COLOR_DEFAULT_ON, GAMEOPTION_SCANLINES) }, GAME_TYPE_HIRES0 }, + { // Hi-Res Adventure #4: Ulysses and the Golden Fleece - Atari 8-bit - Re-release + { + "hires4", 0, + { + { "ULYS1A.XFD", 0, "26365d2b06509fd21e7a7919e33f7199", 92160 }, + // FIXME: Add sides 1B and 2C + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformAtariST, // FIXME + ADGF_UNSTABLE, + GUIO2(GAMEOPTION_COLOR_DEFAULT_ON, GAMEOPTION_SCANLINES) + }, + GAME_TYPE_HIRES4 + }, { // Hi-Res Adventure #6: The Dark Crystal - Apple II - Roberta Williams Anthology { "hires6", 0, @@ -298,6 +314,7 @@ void AdlMetaEngine::removeSaveState(const char *target, int slot) const { Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd); Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd); Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd); +Engine *HiRes4Engine_create(OSystem *syst, const AdlGameDescription *gd); Engine *HiRes6Engine_create(OSystem *syst, const AdlGameDescription *gd); bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { @@ -316,6 +333,9 @@ bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD case GAME_TYPE_HIRES0: *engine = HiRes0Engine_create(syst, adlGd); break; + case GAME_TYPE_HIRES4: + *engine = HiRes4Engine_create(syst, adlGd); + break; case GAME_TYPE_HIRES6: *engine = HiRes6Engine_create(syst, adlGd); break; diff --git a/engines/adl/detection.h b/engines/adl/detection.h index 533466c094..b4dc3c430f 100644 --- a/engines/adl/detection.h +++ b/engines/adl/detection.h @@ -35,6 +35,7 @@ enum GameType { GAME_TYPE_HIRES0, GAME_TYPE_HIRES1, GAME_TYPE_HIRES2, + GAME_TYPE_HIRES4, GAME_TYPE_HIRES6 }; diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp index 49e01f9d0f..d429556670 100644 --- a/engines/adl/disk.cpp +++ b/engines/adl/disk.cpp @@ -28,15 +28,7 @@ namespace Adl { -#define TRACKS 35 -// The Apple II uses either 13- or 16-sector disks. We currently pad out -// 13-sector disks, so we set SECTORS_PER_TRACK to 16 here. -#define SECTORS_PER_TRACK 16 -#define BYTES_PER_SECTOR 256 -#define RAW_IMAGE_SIZE(S) (TRACKS * (S) * BYTES_PER_SECTOR) -#define NIB_IMAGE_SIZE (RAW_IMAGE_SIZE(13) * 2) - -static Common::SeekableReadStream *readImage_DSK(const Common::String &filename) { +static Common::SeekableReadStream *readImage(const Common::String &filename) { Common::File *f = new Common::File; if (!f->open(filename)) { @@ -44,9 +36,6 @@ static Common::SeekableReadStream *readImage_DSK(const Common::String &filename) return nullptr; } - if (f->size() != RAW_IMAGE_SIZE(16)) - error("Unrecognized DSK image '%s' of size %d bytes", filename.c_str(), f->size()); - return f; } @@ -63,7 +52,7 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename) if (!f.open(filename)) return nullptr; - if (f.size() != NIB_IMAGE_SIZE) + if (f.size() != 232960) error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), f.size()); // starting at 0xaa, 32 is invalid (see below) @@ -73,7 +62,9 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename) // we always pad it out const uint sectorsPerTrack = 16; - byte *diskImage = (byte *)calloc(RAW_IMAGE_SIZE(sectorsPerTrack), 1); + const uint bytesPerSector = 256; + const uint imageSize = 35 * sectorsPerTrack * bytesPerSector; + byte *const diskImage = (byte *)calloc(imageSize, 1); bool sawAddress = false; uint8 volNo, track, sector; @@ -120,13 +111,13 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename) // We should always find the data field after an address field. // TODO: we ignore volNo? - byte *output = diskImage + (track * sectorsPerTrack + sector) * BYTES_PER_SECTOR; + byte *output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector; if (newStyle) { // We hardcode the DOS 3.3 mapping here. TODO: Do we also need raw/prodos? int raw2dos[16] = { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 }; sector = raw2dos[sector]; - output = diskImage + (track * sectorsPerTrack + sector) * BYTES_PER_SECTOR; + output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector; // 6-and-2 uses 342 on-disk bytes byte inbuffer[342]; @@ -216,42 +207,65 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename) } } - return new Common::MemoryReadStream(diskImage, RAW_IMAGE_SIZE(sectorsPerTrack), DisposeAfterUse::YES); + return new Common::MemoryReadStream(diskImage, imageSize, DisposeAfterUse::YES); } bool DiskImage::open(const Common::String &filename) { Common::String lcName(filename); lcName.toLowercase(); - if (lcName.hasSuffix(".dsk")) - _stream = readImage_DSK(filename); - else if (lcName.hasSuffix(".nib")) + if (lcName.hasSuffix(".dsk")) { + _stream = readImage(filename); + _tracks = 35; + _sectorsPerTrack = 16; + _bytesPerSector = 256; + } else if (lcName.hasSuffix(".nib")) { _stream = readImage_NIB(filename); + _tracks = 35; + _sectorsPerTrack = 16; + _bytesPerSector = 256; + } else if (lcName.hasSuffix(".xfd")) { + _stream = readImage(filename); + _tracks = 40; + _sectorsPerTrack = 18; + _bytesPerSector = 128; + } + + int expectedSize = _tracks * _sectorsPerTrack * _bytesPerSector; + + if (!_stream) + return false; + + if (_stream->size() != expectedSize) + error("Unrecognized disk image '%s' of size %d bytes (expected %d bytes)", filename.c_str(), _stream->size(), expectedSize); - return _stream != nullptr; + return true; } const DataBlockPtr DiskImage::getDataBlock(uint track, uint sector, uint offset, uint size) const { - return DataBlockPtr(new DiskImage::DataBlock(this, track, sector, offset, size, _mode13)); + return DataBlockPtr(new DiskImage::DataBlock(this, track, sector, offset, size, _sectorLimit)); } -Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector, uint offset, uint size, uint sectorsPerTrackToRead) const { - const uint bytesToRead = size * BYTES_PER_SECTOR + BYTES_PER_SECTOR - offset; +Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector, uint offset, uint size, uint sectorLimit) const { + const uint bytesToRead = size * _bytesPerSector + _bytesPerSector - offset; byte *const data = (byte *)malloc(bytesToRead); uint dataOffset = 0; - if (sector > sectorsPerTrackToRead - 1) - error("Sector %i is out of bounds for %i-sector reading", sector, sectorsPerTrackToRead); + if (sectorLimit == 0) + sectorLimit = _sectorsPerTrack; + + if (sector >= sectorLimit) + error("Sector %i is out of bounds for %i-sector reading", sector, sectorLimit); while (dataOffset < bytesToRead) { - uint bytesRemInTrack = (sectorsPerTrackToRead - 1 - sector) * BYTES_PER_SECTOR + BYTES_PER_SECTOR - offset; - _stream->seek((track * SECTORS_PER_TRACK + sector) * BYTES_PER_SECTOR + offset); + uint bytesRemInTrack = (sectorLimit - 1 - sector) * _bytesPerSector + _bytesPerSector - offset; + _stream->seek((track * _sectorsPerTrack + sector) * _bytesPerSector + offset); if (bytesToRead - dataOffset < bytesRemInTrack) bytesRemInTrack = bytesToRead - dataOffset; if (_stream->read(data + dataOffset, bytesRemInTrack) < bytesRemInTrack) - error("Error reading disk image"); + error("Error reading disk image at track %d; sector %d", track, sector); ++track; diff --git a/engines/adl/disk.h b/engines/adl/disk.h index 1041f0cebd..653d76ff10 100644 --- a/engines/adl/disk.h +++ b/engines/adl/disk.h @@ -74,7 +74,10 @@ class DiskImage { public: DiskImage() : _stream(nullptr), - _mode13(false) { } + _tracks(0), + _sectorsPerTrack(0), + _bytesPerSector(0), + _sectorLimit(0) { } ~DiskImage() { delete _stream; @@ -82,32 +85,33 @@ public: bool open(const Common::String &filename); const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const; - Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsPerTrackToRead = 16) const; - void setMode13(bool enable) { _mode13 = enable; } + Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsUsed = 0) const; + void setSectorLimit(uint sectorLimit) { _sectorLimit = sectorLimit; } // Maximum number of sectors to read per track before stepping protected: class DataBlock : public Adl::DataBlock { public: - DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, bool mode13) : + DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, uint sectorLimit) : _track(track), _sector(sector), _offset(offset), _size(size), - _mode13(mode13), + _sectorLimit(sectorLimit), _disk(disk) { } Common::SeekableReadStream *createReadStream() const { - return _disk->createReadStream(_track, _sector, _offset, _size, (_mode13 ? 13 : 16)); + return _disk->createReadStream(_track, _sector, _offset, _size, _sectorLimit); } private: uint _track, _sector, _offset, _size; - bool _mode13; + uint _sectorLimit; const DiskImage *_disk; }; Common::SeekableReadStream *_stream; - bool _mode13; // Older 13-sector format + uint _tracks, _sectorsPerTrack, _bytesPerSector; + uint _sectorLimit; }; // Data in plain files diff --git a/engines/adl/hires0.cpp b/engines/adl/hires0.cpp index 316f77a9b6..9a0af05d20 100644 --- a/engines/adl/hires0.cpp +++ b/engines/adl/hires0.cpp @@ -1,168 +1,143 @@ -/* 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 "common/textconsole.h"
-
-#include "adl/hires0.h"
-#include "adl/graphics.h"
-#include "adl/disk.h"
-
-namespace Adl {
-
-void HiRes0Engine::init() {
- _graphics = new Graphics_v2(*_display);
-
- _disk = new DiskImage();
- if (!_disk->open(IDS_HR0_DISK_IMAGE))
- error("Failed to open disk image '" IDS_HR0_DISK_IMAGE "'");
-
- _disk->setMode13(true);
-
- StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 2));
-
- // TODO: all these strings/offsets/etc are the same as hires2
-
- for (uint i = 0; i < IDI_HR0_NUM_MESSAGES; ++i)
- _messages.push_back(readDataBlockPtr(*stream));
-
- // Read parser messages
- stream.reset(_disk->createReadStream(0x1a, 0x1));
- _strings.verbError = readStringAt(*stream, 0x4f);
- _strings.nounError = readStringAt(*stream, 0x8e);
- _strings.enterCommand = readStringAt(*stream, 0xbc);
-
- // Read time string
- stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7));
- _strings_v2.time = readString(*stream, 0xff);
-
- // Read line feeds
- stream.reset(_disk->createReadStream(0x19, 0xb, 0xf8, 1));
- _strings.lineFeeds = readString(*stream);
-
- // Read opcode strings
- stream.reset(_disk->createReadStream(0x1a, 0x6, 0x00, 2));
- _strings_v2.saveInsert = readStringAt(*stream, 0x5f);
- _strings_v2.saveReplace = readStringAt(*stream, 0xe5);
- _strings_v2.restoreInsert = readStringAt(*stream, 0x132);
- _strings_v2.restoreReplace = readStringAt(*stream, 0x1c2);
- _strings.playAgain = readStringAt(*stream, 0x225);
- _strings.pressReturn = readStringAt(*stream, 0x25f);
-
- _messageIds.cantGoThere = IDI_HR0_MSG_CANT_GO_THERE;
- _messageIds.dontUnderstand = IDI_HR0_MSG_DONT_UNDERSTAND;
- _messageIds.itemDoesntMove = IDI_HR0_MSG_ITEM_DOESNT_MOVE;
- _messageIds.itemNotHere = IDI_HR0_MSG_ITEM_NOT_HERE;
- _messageIds.thanksForPlaying = IDI_HR0_MSG_THANKS_FOR_PLAYING;
-
- // Load global picture data
- stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0));
- byte picNr;
- while ((picNr = stream->readByte()) != 0xff) {
- if (stream->eos() || stream->err())
- error("Error reading global pic list");
-
- _pictures[picNr] = readDataBlockPtr(*stream);
- }
-
- // Load item picture data
- stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05));
- for (uint i = 0; i < IDI_HR0_NUM_ITEM_PICS; ++i) {
- stream->readByte(); // number
- _itemPics.push_back(readDataBlockPtr(*stream));
- }
-
- // Load commands from executable
- stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 2));
- readCommands(*stream, _roomCommands);
-
- stream.reset(_disk->createReadStream(0x1f, 0x7, 0x00, 3));
- readCommands(*stream, _globalCommands);
-
- // Load dropped item offsets
- stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15));
- for (uint i = 0; i < IDI_HR0_NUM_ITEM_OFFSETS; ++i) {
- Common::Point p;
- p.x = stream->readByte();
- p.y = stream->readByte();
- _itemOffsets.push_back(p);
- }
-
- // Load verbs
- stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3));
- loadWords(*stream, _verbs, _priVerbs);
-
- // Load nouns
- stream.reset(_disk->createReadStream(0x22, 0x2, 0x00, 2));
- loadWords(*stream, _nouns, _priNouns);
-}
-
-void HiRes0Engine::initGameState() {
- _state.vars.resize(IDI_HR0_NUM_VARS);
-
- StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 2));
-
- for (uint i = 0; i < IDI_HR0_NUM_ROOMS; ++i) {
- Room room;
- stream->readByte(); // number
- for (uint j = 0; j < 6; ++j)
- room.connections[j] = stream->readByte();
- room.data = readDataBlockPtr(*stream);
- room.picture = stream->readByte();
- room.curPicture = stream->readByte();
- room.isFirstTime = stream->readByte();
- _state.rooms.push_back(room);
- }
-
- stream.reset(_disk->createReadStream(0x21, 0x0));
-
- byte id;
- while ((id = stream->readByte()) != 0xff) {
- Item item = Item();
- item.id = id;
- item.noun = stream->readByte();
- item.room = stream->readByte();
- item.picture = stream->readByte();
- item.isLineArt = stream->readByte();
- item.position.x = stream->readByte();
- item.position.y = stream->readByte();
- item.state = stream->readByte();
- item.description = stream->readByte();
-
- stream->readByte(); // Struct size
-
- byte picListSize = stream->readByte();
-
- // Flag to keep track of what has been drawn on the screen
- stream->readByte();
-
- for (uint i = 0; i < picListSize; ++i)
- item.roomPictures.push_back(stream->readByte());
-
- _state.items.push_back(item);
- }
-}
-
-Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd) {
- return new HiRes0Engine(syst, gd);
-}
-
-} // End of namespace Adl
+/* 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 "common/textconsole.h" + +#include "adl/adl_v2.h" +#include "adl/graphics.h" +#include "adl/disk.h" + +namespace Adl { + +#define IDS_HR0_DISK_IMAGE "MISSION.NIB" + +#define IDI_HR0_NUM_ROOMS 43 +#define IDI_HR0_NUM_MESSAGES 142 +#define IDI_HR0_NUM_VARS 40 +#define IDI_HR0_NUM_ITEM_PICS 2 +#define IDI_HR0_NUM_ITEM_OFFSETS 16 + +// Messages used outside of scripts +#define IDI_HR0_MSG_CANT_GO_THERE 110 +#define IDI_HR0_MSG_DONT_UNDERSTAND 112 +#define IDI_HR0_MSG_ITEM_DOESNT_MOVE 114 +#define IDI_HR0_MSG_ITEM_NOT_HERE 115 +#define IDI_HR0_MSG_THANKS_FOR_PLAYING 113 + +class HiRes0Engine : public AdlEngine_v2 { +public: + HiRes0Engine(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine_v2(syst, gd) { } + ~HiRes0Engine() { } + +private: + // AdlEngine + void init(); + void initGameState(); +}; + +void HiRes0Engine::init() { + _graphics = new Graphics_v2(*_display); + + _disk = new DiskImage(); + if (!_disk->open(IDS_HR0_DISK_IMAGE)) + error("Failed to open disk image '" IDS_HR0_DISK_IMAGE "'"); + + _disk->setSectorLimit(13); + + // TODO: all these strings/offsets/etc are the same as hires2 + + StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 2)); + loadMessages(*stream, IDI_HR0_NUM_MESSAGES); + + // Read parser messages + stream.reset(_disk->createReadStream(0x1a, 0x1)); + _strings.verbError = readStringAt(*stream, 0x4f); + _strings.nounError = readStringAt(*stream, 0x8e); + _strings.enterCommand = readStringAt(*stream, 0xbc); + + // Read time string + stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7)); + _strings_v2.time = readString(*stream, 0xff); + + // Read line feeds + stream.reset(_disk->createReadStream(0x19, 0xb, 0xf8, 1)); + _strings.lineFeeds = readString(*stream); + + // Read opcode strings + stream.reset(_disk->createReadStream(0x1a, 0x6, 0x00, 2)); + _strings_v2.saveInsert = readStringAt(*stream, 0x5f); + _strings_v2.saveReplace = readStringAt(*stream, 0xe5); + _strings_v2.restoreInsert = readStringAt(*stream, 0x132); + _strings_v2.restoreReplace = readStringAt(*stream, 0x1c2); + _strings.playAgain = readStringAt(*stream, 0x225); + _strings.pressReturn = readStringAt(*stream, 0x25f); + + _messageIds.cantGoThere = IDI_HR0_MSG_CANT_GO_THERE; + _messageIds.dontUnderstand = IDI_HR0_MSG_DONT_UNDERSTAND; + _messageIds.itemDoesntMove = IDI_HR0_MSG_ITEM_DOESNT_MOVE; + _messageIds.itemNotHere = IDI_HR0_MSG_ITEM_NOT_HERE; + _messageIds.thanksForPlaying = IDI_HR0_MSG_THANKS_FOR_PLAYING; + + // Load global picture data + stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0)); + loadPictures(*stream); + + // Load item picture data + stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05)); + loadItemPictures(*stream, IDI_HR0_NUM_ITEM_PICS); + + // Load commands from executable + stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 2)); + readCommands(*stream, _roomCommands); + + stream.reset(_disk->createReadStream(0x1f, 0x7, 0x00, 3)); + readCommands(*stream, _globalCommands); + + // Load dropped item offsets + stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15)); + loadDroppedItemOffsets(*stream, IDI_HR0_NUM_ITEM_OFFSETS); + + // Load verbs + stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3)); + loadWords(*stream, _verbs, _priVerbs); + + // Load nouns + stream.reset(_disk->createReadStream(0x22, 0x2, 0x00, 2)); + loadWords(*stream, _nouns, _priNouns); +} + +void HiRes0Engine::initGameState() { + _state.vars.resize(IDI_HR0_NUM_VARS); + + StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 2)); + loadRooms(*stream, IDI_HR0_NUM_ROOMS); + + stream.reset(_disk->createReadStream(0x21, 0x0)); + loadItems(*stream); +} + +Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd) { + return new HiRes0Engine(syst, gd); +} + +} // End of namespace Adl diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 26565c03c3..217a9013ba 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -27,11 +27,105 @@ #include "common/stream.h" #include "common/ptr.h" -#include "adl/hires1.h" +#include "adl/adl.h" +#include "adl/graphics.h" #include "adl/display.h" namespace Adl { +#define IDS_HR1_EXE_0 "AUTO LOAD OBJ" +#define IDS_HR1_EXE_1 "ADVENTURE" +#define IDS_HR1_LOADER "MYSTERY.HELLO" +#define IDS_HR1_MESSAGES "MESSAGES" + +#define IDI_HR1_NUM_ROOMS 41 +#define IDI_HR1_NUM_PICS 97 +#define IDI_HR1_NUM_VARS 20 +#define IDI_HR1_NUM_ITEM_OFFSETS 21 +#define IDI_HR1_NUM_MESSAGES 168 + +// Messages used outside of scripts +#define IDI_HR1_MSG_CANT_GO_THERE 137 +#define IDI_HR1_MSG_DONT_UNDERSTAND 37 +#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 +#define IDI_HR1_MSG_ITEM_NOT_HERE 152 +#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140 +#define IDI_HR1_MSG_DONT_HAVE_IT 127 +#define IDI_HR1_MSG_GETTING_DARK 7 + +#define IDI_HR1_OFS_STR_ENTER_COMMAND 0x5bbc +#define IDI_HR1_OFS_STR_VERB_ERROR 0x5b4f +#define IDI_HR1_OFS_STR_NOUN_ERROR 0x5b8e +#define IDI_HR1_OFS_STR_PLAY_AGAIN 0x5f1e +#define IDI_HR1_OFS_STR_CANT_GO_THERE 0x6c0a +#define IDI_HR1_OFS_STR_DONT_HAVE_IT 0x6c31 +#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51 +#define IDI_HR1_OFS_STR_GETTING_DARK 0x6c7c +#define IDI_HR1_OFS_STR_PRESS_RETURN 0x5f68 +#define IDI_HR1_OFS_STR_LINE_FEEDS 0x59d4 + +#define IDI_HR1_OFS_PD_TEXT_0 0x005d +#define IDI_HR1_OFS_PD_TEXT_1 0x012b +#define IDI_HR1_OFS_PD_TEXT_2 0x016d +#define IDI_HR1_OFS_PD_TEXT_3 0x0259 + +#define IDI_HR1_OFS_INTRO_TEXT 0x0066 +#define IDI_HR1_OFS_GAME_OR_HELP 0x000f + +#define IDI_HR1_OFS_LOGO_0 0x1003 +#define IDI_HR1_OFS_LOGO_1 0x1800 + +#define IDI_HR1_OFS_ITEMS 0x0100 +#define IDI_HR1_OFS_ROOMS 0x050a +#define IDI_HR1_OFS_PICS 0x4b03 +#define IDI_HR1_OFS_CMDS_0 0x3c00 +#define IDI_HR1_OFS_CMDS_1 0x3d00 +#define IDI_HR1_OFS_MSGS 0x4d00 + +#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff +#define IDI_HR1_OFS_CORNERS 0x4f00 + +#define IDI_HR1_OFS_VERBS 0x3800 +#define IDI_HR1_OFS_NOUNS 0x0f00 + +class HiRes1Engine : public AdlEngine { +public: + HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine(syst, gd), + _files(nullptr), + _messageDelay(true) { } + ~HiRes1Engine() { delete _files; } + +private: + // AdlEngine + void runIntro() const; + void init(); + void initGameState(); + void restartGame(); + void printString(const Common::String &str); + Common::String loadMessage(uint idx) const; + void printMessage(uint idx); + void drawItems(); + void drawItem(Item &item, const Common::Point &pos); + void loadRoom(byte roomNr); + void showRoom(); + + void wordWrap(Common::String &str) const; + + Files *_files; + Common::File _exe; + Common::Array<DataBlockPtr> _corners; + Common::Array<byte> _roomDesc; + bool _messageDelay; + + struct { + Common::String cantGoThere; + Common::String dontHaveIt; + Common::String dontUnderstand; + Common::String gettingDark; + } _gameStrings; +}; + void HiRes1Engine::runIntro() const { StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_0)); @@ -183,12 +277,7 @@ void HiRes1Engine::init() { // Load dropped item offsets stream->seek(IDI_HR1_OFS_ITEM_OFFSETS); - for (uint i = 0; i < IDI_HR1_NUM_ITEM_OFFSETS; ++i) { - Common::Point p; - p.x = stream->readByte(); - p.y = stream->readByte(); - _itemOffsets.push_back(p); - } + loadDroppedItemOffsets(*stream, IDI_HR1_NUM_ITEM_OFFSETS); // Load right-angle line art stream->seek(IDI_HR1_OFS_CORNERS); diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h deleted file mode 100644 index c060bc892e..0000000000 --- a/engines/adl/hires1.h +++ /dev/null @@ -1,134 +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 ADL_HIRES1_H -#define ADL_HIRES1_H - -#include "common/str.h" - -#include "adl/adl.h" -#include "adl/graphics.h" -#include "adl/disk.h" - -namespace Common { -class ReadStream; -struct Point; -} - -namespace Adl { - -#define IDS_HR1_EXE_0 "AUTO LOAD OBJ" -#define IDS_HR1_EXE_1 "ADVENTURE" -#define IDS_HR1_LOADER "MYSTERY.HELLO" -#define IDS_HR1_MESSAGES "MESSAGES" - -#define IDI_HR1_NUM_ROOMS 41 -#define IDI_HR1_NUM_PICS 97 -#define IDI_HR1_NUM_VARS 20 -#define IDI_HR1_NUM_ITEM_OFFSETS 21 -#define IDI_HR1_NUM_MESSAGES 168 - -// Messages used outside of scripts -#define IDI_HR1_MSG_CANT_GO_THERE 137 -#define IDI_HR1_MSG_DONT_UNDERSTAND 37 -#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151 -#define IDI_HR1_MSG_ITEM_NOT_HERE 152 -#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140 -#define IDI_HR1_MSG_DONT_HAVE_IT 127 -#define IDI_HR1_MSG_GETTING_DARK 7 - -#define IDI_HR1_OFS_STR_ENTER_COMMAND 0x5bbc -#define IDI_HR1_OFS_STR_VERB_ERROR 0x5b4f -#define IDI_HR1_OFS_STR_NOUN_ERROR 0x5b8e -#define IDI_HR1_OFS_STR_PLAY_AGAIN 0x5f1e -#define IDI_HR1_OFS_STR_CANT_GO_THERE 0x6c0a -#define IDI_HR1_OFS_STR_DONT_HAVE_IT 0x6c31 -#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51 -#define IDI_HR1_OFS_STR_GETTING_DARK 0x6c7c -#define IDI_HR1_OFS_STR_PRESS_RETURN 0x5f68 -#define IDI_HR1_OFS_STR_LINE_FEEDS 0x59d4 - -#define IDI_HR1_OFS_PD_TEXT_0 0x005d -#define IDI_HR1_OFS_PD_TEXT_1 0x012b -#define IDI_HR1_OFS_PD_TEXT_2 0x016d -#define IDI_HR1_OFS_PD_TEXT_3 0x0259 - -#define IDI_HR1_OFS_INTRO_TEXT 0x0066 -#define IDI_HR1_OFS_GAME_OR_HELP 0x000f - -#define IDI_HR1_OFS_LOGO_0 0x1003 -#define IDI_HR1_OFS_LOGO_1 0x1800 - -#define IDI_HR1_OFS_ITEMS 0x0100 -#define IDI_HR1_OFS_ROOMS 0x050a -#define IDI_HR1_OFS_PICS 0x4b03 -#define IDI_HR1_OFS_CMDS_0 0x3c00 -#define IDI_HR1_OFS_CMDS_1 0x3d00 -#define IDI_HR1_OFS_MSGS 0x4d00 - -#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff -#define IDI_HR1_OFS_CORNERS 0x4f00 - -#define IDI_HR1_OFS_VERBS 0x3800 -#define IDI_HR1_OFS_NOUNS 0x0f00 - -class HiRes1Engine : public AdlEngine { -public: - HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) : - AdlEngine(syst, gd), - _files(nullptr), - _messageDelay(true) { } - ~HiRes1Engine() { delete _files; } - -private: - // AdlEngine - void runIntro() const; - void init(); - void initGameState(); - void restartGame(); - void printString(const Common::String &str); - Common::String loadMessage(uint idx) const; - void printMessage(uint idx); - void drawItems(); - void drawItem(Item &item, const Common::Point &pos); - void loadRoom(byte roomNr); - void showRoom(); - - void wordWrap(Common::String &str) const; - - Files *_files; - Common::File _exe; - Common::Array<DataBlockPtr> _corners; - Common::Array<byte> _roomDesc; - bool _messageDelay; - - struct { - Common::String cantGoThere; - Common::String dontHaveIt; - Common::String dontUnderstand; - Common::String gettingDark; - } _gameStrings; -}; - -} // End of namespace Adl - -#endif diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp index 14db237d82..199f457b4f 100644 --- a/engines/adl/hires2.cpp +++ b/engines/adl/hires2.cpp @@ -26,18 +26,44 @@ #include "common/file.h" #include "common/stream.h" -#include "adl/hires2.h" +#include "adl/adl_v2.h" #include "adl/display.h" #include "adl/graphics.h" #include "adl/disk.h" namespace Adl { +#define IDS_HR2_DISK_IMAGE "WIZARD.DSK" + +#define IDI_HR2_NUM_ROOMS 135 +#define IDI_HR2_NUM_MESSAGES 255 +#define IDI_HR2_NUM_VARS 40 +#define IDI_HR2_NUM_ITEM_PICS 38 +#define IDI_HR2_NUM_ITEM_OFFSETS 16 + +// Messages used outside of scripts +#define IDI_HR2_MSG_CANT_GO_THERE 123 +#define IDI_HR2_MSG_DONT_UNDERSTAND 19 +#define IDI_HR2_MSG_ITEM_DOESNT_MOVE 242 +#define IDI_HR2_MSG_ITEM_NOT_HERE 4 +#define IDI_HR2_MSG_THANKS_FOR_PLAYING 239 + +class HiRes2Engine : public AdlEngine_v2 { +public: + HiRes2Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v2(syst, gd) { } + +private: + // AdlEngine + void runIntro() const; + void init(); + void initGameState(); +}; + void HiRes2Engine::runIntro() const { // This only works for the 16-sector re-release. The original // release is not supported at this time, because we don't have // access to it. - _disk->setMode13(false); + _disk->setSectorLimit(0); StreamPtr stream(_disk->createReadStream(0x00, 0xd, 0x17, 1)); _display->setMode(DISPLAY_MODE_TEXT); @@ -50,7 +76,7 @@ void HiRes2Engine::runIntro() const { _display->printString(str); delay(2000); - _disk->setMode13(true); + _disk->setSectorLimit(13); } void HiRes2Engine::init() { @@ -60,12 +86,10 @@ void HiRes2Engine::init() { if (!_disk->open(IDS_HR2_DISK_IMAGE)) error("Failed to open disk image '" IDS_HR2_DISK_IMAGE "'"); - _disk->setMode13(true); + _disk->setSectorLimit(13); StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 4)); - - for (uint i = 0; i < IDI_HR2_NUM_MESSAGES; ++i) - _messages.push_back(readDataBlockPtr(*stream)); + loadMessages(*stream, IDI_HR2_NUM_MESSAGES); // Read parser messages stream.reset(_disk->createReadStream(0x1a, 0x1)); @@ -98,20 +122,11 @@ void HiRes2Engine::init() { // Load global picture data stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0)); - byte picNr; - while ((picNr = stream->readByte()) != 0xff) { - if (stream->eos() || stream->err()) - error("Error reading global pic list"); - - _pictures[picNr] = readDataBlockPtr(*stream); - } + loadPictures(*stream); // Load item picture data stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05)); - for (uint i = 0; i < IDI_HR2_NUM_ITEM_PICS; ++i) { - stream->readByte(); // number - _itemPics.push_back(readDataBlockPtr(*stream)); - } + loadItemPictures(*stream, IDI_HR2_NUM_ITEM_PICS); // Load commands from executable stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 4)); @@ -122,12 +137,7 @@ void HiRes2Engine::init() { // Load dropped item offsets stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15)); - for (uint i = 0; i < IDI_HR2_NUM_ITEM_OFFSETS; ++i) { - Common::Point p; - p.x = stream->readByte(); - p.y = stream->readByte(); - _itemOffsets.push_back(p); - } + loadDroppedItemOffsets(*stream, IDI_HR2_NUM_ITEM_OFFSETS); // Load verbs stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3)); @@ -142,46 +152,10 @@ void HiRes2Engine::initGameState() { _state.vars.resize(IDI_HR2_NUM_VARS); StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 7)); - - for (uint i = 0; i < IDI_HR2_NUM_ROOMS; ++i) { - Room room; - stream->readByte(); // number - for (uint j = 0; j < 6; ++j) - room.connections[j] = stream->readByte(); - room.data = readDataBlockPtr(*stream); - room.picture = stream->readByte(); - room.curPicture = stream->readByte(); - room.isFirstTime = stream->readByte(); - _state.rooms.push_back(room); - } + loadRooms(*stream, IDI_HR2_NUM_ROOMS); stream.reset(_disk->createReadStream(0x21, 0x0, 0x00, 2)); - - byte id; - while ((id = stream->readByte()) != 0xff) { - Item item = Item(); - item.id = id; - item.noun = stream->readByte(); - item.room = stream->readByte(); - item.picture = stream->readByte(); - item.isLineArt = stream->readByte(); // Is this still used in this way? - item.position.x = stream->readByte(); - item.position.y = stream->readByte(); - item.state = stream->readByte(); - item.description = stream->readByte(); - - stream->readByte(); // Struct size - - byte picListSize = stream->readByte(); - - // Flag to keep track of what has been drawn on the screen - stream->readByte(); - - for (uint i = 0; i < picListSize; ++i) - item.roomPictures.push_back(stream->readByte()); - - _state.items.push_back(item); - } + loadItems(*stream); } Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd) { diff --git a/engines/adl/hires4.cpp b/engines/adl/hires4.cpp new file mode 100644 index 0000000000..ddfc868e9a --- /dev/null +++ b/engines/adl/hires4.cpp @@ -0,0 +1,271 @@ +/* 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 "common/system.h" +#include "common/debug.h" +#include "common/error.h" +#include "common/file.h" +#include "common/stream.h" + +#include "adl/adl_v3.h" +#include "adl/detection.h" +#include "adl/display.h" +#include "adl/graphics.h" +#include "adl/disk.h" + +namespace Adl { + +#define IDI_HR4_NUM_ROOMS 164 +#define IDI_HR4_NUM_MESSAGES 255 +#define IDI_HR4_NUM_VARS 40 +#define IDI_HR4_NUM_ITEM_DESCS 44 +#define IDI_HR4_NUM_ITEM_PICS 41 +#define IDI_HR4_NUM_ITEM_OFFSETS 40 + +// Messages used outside of scripts +#define IDI_HR4_MSG_CANT_GO_THERE 110 +#define IDI_HR4_MSG_DONT_UNDERSTAND 112 +#define IDI_HR4_MSG_ITEM_DOESNT_MOVE 114 +#define IDI_HR4_MSG_ITEM_NOT_HERE 115 +#define IDI_HR4_MSG_THANKS_FOR_PLAYING 113 + +class HiRes4Engine_Atari : public AdlEngine_v3 { +public: + HiRes4Engine_Atari(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine_v3(syst, gd), + _boot(nullptr), + _curDisk(0) { } + ~HiRes4Engine_Atari(); + +private: + // AdlEngine + void init(); + void initGameState(); + void loadRoom(byte roomNr); + Common::String formatVerbError(const Common::String &verb) const; + Common::String formatNounError(const Common::String &verb, const Common::String &noun) const; + + // AdlEngine_v2 + void adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const; + + Common::SeekableReadStream *createReadStream(DiskImage *disk, byte track, byte sector, byte offset = 0, byte size = 0) const; + void loadCommonData(); + void insertDisk(byte diskNr); + void rebindDisk(); + + DiskImage *_boot; + byte _curDisk; +}; + +static const char *const atariDisks[] = { "ULYS1A.XFD", "ULYS1B.XFD", "ULYS2C.XFD" }; + +HiRes4Engine_Atari::~HiRes4Engine_Atari() { + delete _boot; +} + +void HiRes4Engine_Atari::init() { + _graphics = new Graphics_v2(*_display); + + _boot = new DiskImage(); + if (!_boot->open(atariDisks[0])) + error("Failed to open disk image '%s'", atariDisks[0]); + + insertDisk(1); + loadCommonData(); + + StreamPtr stream(createReadStream(_boot, 0x06, 0x2)); + _strings.verbError = readStringAt(*stream, 0x4f); + _strings.nounError = readStringAt(*stream, 0x83); + _strings.enterCommand = readStringAt(*stream, 0xa6); + + stream.reset(createReadStream(_boot, 0x05, 0xb, 0xd7)); + _strings_v2.time = readString(*stream, 0xff); + + stream.reset(createReadStream(_boot, 0x06, 0x7, 0x00, 2)); + _strings_v2.saveInsert = readStringAt(*stream, 0x62); + _strings_v2.saveReplace = readStringAt(*stream, 0xdd); + _strings_v2.restoreInsert = readStringAt(*stream, 0x12a); + _strings_v2.restoreReplace = readStringAt(*stream, 0x1b8); + _strings.playAgain = readStringAt(*stream, 0x21b); + // TODO: restart sequence has "insert side a/b" strings + + _messageIds.cantGoThere = IDI_HR4_MSG_CANT_GO_THERE; + _messageIds.dontUnderstand = IDI_HR4_MSG_DONT_UNDERSTAND; + _messageIds.itemDoesntMove = IDI_HR4_MSG_ITEM_DOESNT_MOVE; + _messageIds.itemNotHere = IDI_HR4_MSG_ITEM_NOT_HERE; + _messageIds.thanksForPlaying = IDI_HR4_MSG_THANKS_FOR_PLAYING; + + stream.reset(createReadStream(_boot, 0x06, 0xd, 0x12, 2)); + loadItemDescriptions(*stream, IDI_HR4_NUM_ITEM_DESCS); + + stream.reset(createReadStream(_boot, 0x07, 0x1, 0xf4)); + loadDroppedItemOffsets(*stream, IDI_HR4_NUM_ITEM_OFFSETS); + + stream.reset(createReadStream(_boot, 0x08, 0xe, 0xa5, 5)); + readCommands(*stream, _roomCommands); + + stream.reset(createReadStream(_boot, 0x0a, 0x9, 0x00, 3)); + readCommands(*stream, _globalCommands); + + stream.reset(createReadStream(_boot, 0x05, 0x4, 0x00, 3)); + loadWords(*stream, _verbs, _priVerbs); + + stream.reset(createReadStream(_boot, 0x03, 0xb, 0x00, 6)); + loadWords(*stream, _nouns, _priNouns); +} + +void HiRes4Engine_Atari::loadRoom(byte roomNr) { + if (roomNr >= 59 && roomNr < 113) { + if (_curDisk != 2) { + insertDisk(2); + rebindDisk(); + } + } else if (_curDisk != 1) { + insertDisk(1); + rebindDisk(); + } + + if (roomNr == 121) { + // Room 121 is not present in the Atari version. This causes + // problems when we're dumping scripts with the debugger, so + // we intercept this room load here. + // FIXME: Find out if the Apple II version does have this room + // FIXME: Implement more generic handling of invalid rooms? + debug("Warning: attempt to load non-existent room 121"); + _roomData.description.clear(); + _roomData.pictures.clear(); + _roomData.commands.clear(); + return; + } + + AdlEngine_v3::loadRoom(roomNr); +} + +Common::String HiRes4Engine_Atari::formatVerbError(const Common::String &verb) const { + Common::String err = _strings.verbError; + for (uint i = 0; i < verb.size(); ++i) + err.setChar(verb[i], i + 8); + return err; +} + +Common::String HiRes4Engine_Atari::formatNounError(const Common::String &verb, const Common::String &noun) const { + Common::String err = _strings.nounError; + for (uint i = 0; i < verb.size(); ++i) + err.setChar(verb[i], i + 8); + for (uint i = 0; i < noun.size(); ++i) + err.setChar(noun[i], i + 19); + return err; +} + +void HiRes4Engine_Atari::insertDisk(byte diskNr) { + if (_curDisk == diskNr) + return; + + _curDisk = diskNr; + + delete _disk; + _disk = new DiskImage(); + if (!_disk->open(atariDisks[diskNr])) + error("Failed to open disk image '%s'", atariDisks[diskNr]); +} + +void HiRes4Engine_Atari::rebindDisk() { + // As room.data is bound to the DiskImage, we need to rebind them here + // We cannot simply reload the rooms as that would reset their state + + // FIXME: Remove DataBlockPtr-DiskImage coupling? + + StreamPtr stream(createReadStream(_boot, 0x03, 0x1, 0x0e, 9)); + for (uint i = 0; i < IDI_HR4_NUM_ROOMS; ++i) { + stream->skip(7); + _state.rooms[i].data = readDataBlockPtr(*stream); + stream->skip(3); + } + + // Rebind data that is on both side B and C + loadCommonData(); +} + +void HiRes4Engine_Atari::loadCommonData() { + _messages.clear(); + StreamPtr stream(createReadStream(_boot, 0x0a, 0x4, 0x00, 3)); + loadMessages(*stream, IDI_HR4_NUM_MESSAGES); + + _pictures.clear(); + stream.reset(createReadStream(_boot, 0x05, 0xe, 0x80)); + loadPictures(*stream); + + _itemPics.clear(); + stream.reset(createReadStream(_boot, 0x09, 0xe, 0x05)); + loadItemPictures(*stream, IDI_HR4_NUM_ITEM_PICS); +} + +void HiRes4Engine_Atari::initGameState() { + _state.vars.resize(IDI_HR4_NUM_VARS); + + StreamPtr stream(createReadStream(_boot, 0x03, 0x1, 0x0e, 9)); + loadRooms(*stream, IDI_HR4_NUM_ROOMS); + + stream.reset(createReadStream(_boot, 0x02, 0xc, 0x00, 12)); + loadItems(*stream); + + // FIXME + _display->moveCursorTo(Common::Point(0, 23)); +} + +Common::SeekableReadStream *HiRes4Engine_Atari::createReadStream(DiskImage *disk, byte track, byte sector, byte offset, byte size) const { + adjustDataBlockPtr(track, sector, offset, size); + return disk->createReadStream(track, sector, offset, size); +} + +void HiRes4Engine_Atari::adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const { + // Convert the Apple II disk offsets in the game, to Atari disk offsets + uint sectorIndex = (track * 16 + sector + 1) << 1; + + // Atari uses 128 bytes per sector vs. 256 on the Apple II + // Note that size indicates *additional* sectors to read after reading one sector + size *= 2; + + if (offset >= 128) { + // Offset in the second half of an Apple II sector, skip one sector and adjust offset + ++sectorIndex; + offset -= 128; + } else { + // Offset in the first half of an Apple II sector, we need to read one additional sector + ++size; + } + + // Compute track/sector for Atari's 18 sectors per track (sectorIndex is 1-based) + track = (sectorIndex - 1) / 18; + sector = (sectorIndex - 1) % 18; +} + +Engine *HiRes4Engine_create(OSystem *syst, const AdlGameDescription *gd) { + switch (gd->desc.platform) { + case Common::kPlatformAtariST: + return new HiRes4Engine_Atari(syst, gd); + default: + error("Unsupported platform"); + } +} + +} // End of namespace Adl diff --git a/engines/adl/hires6.cpp b/engines/adl/hires6.cpp index e9df7b513a..a1fea05f19 100644 --- a/engines/adl/hires6.cpp +++ b/engines/adl/hires6.cpp @@ -27,13 +27,65 @@ #include "common/stream.h" #include "common/memstream.h" -#include "adl/hires6.h" +#include "adl/adl_v4.h" #include "adl/display.h" #include "adl/graphics.h" #include "adl/disk.h" namespace Adl { +#define IDI_HR6_NUM_ROOMS 35 +#define IDI_HR6_NUM_MESSAGES 256 +#define IDI_HR6_NUM_VARS 40 +#define IDI_HR6_NUM_ITEM_DESCS 15 +#define IDI_HR6_NUM_ITEM_PICS 15 +#define IDI_HR6_NUM_ITEM_OFFSETS 16 + +// Messages used outside of scripts +#define IDI_HR6_MSG_CANT_GO_THERE 249 +#define IDI_HR6_MSG_DONT_UNDERSTAND 247 +#define IDI_HR6_MSG_ITEM_DOESNT_MOVE 253 +#define IDI_HR6_MSG_ITEM_NOT_HERE 254 +#define IDI_HR6_MSG_THANKS_FOR_PLAYING 252 + +struct DiskDataDesc { + byte track; + byte sector; + byte offset; + byte volume; +}; + +class HiRes6Engine : public AdlEngine_v4 { +public: + HiRes6Engine(OSystem *syst, const AdlGameDescription *gd) : + AdlEngine_v4(syst, gd), + _boot(nullptr), + _currVerb(0), + _currNoun(0) { + } + + ~HiRes6Engine() { delete _boot; } + +private: + // AdlEngine + void runIntro() const; + void init(); + void initGameState(); + void printRoomDescription(); + void showRoom(); + Common::String formatVerbError(const Common::String &verb) const; + Common::String formatNounError(const Common::String &verb, const Common::String &noun) const; + + // AdlEngine_v2 + void printString(const Common::String &str); + + void loadDisk(byte disk); + + DiskImage *_boot; + byte _currVerb, _currNoun; + Common::Array<DiskDataDesc> _diskDataDesc; +}; + static const char *disks[] = { "DARK1A.DSK", "DARK1B.NIB", "DARK2A.NIB", "DARK2B.NIB" }; #define SECTORS_PER_TRACK 16 @@ -141,18 +193,12 @@ void HiRes6Engine::init() { // Item descriptions stream.reset(loadSectors(_boot, 0x6, 0xb, 2)); - stream->seek(0x34); - for (uint i = 0; i < IDI_HR6_NUM_ITEM_DESCS; ++i) - _itemDesc.push_back(readString(*stream, 0xff)); + stream->seek(0x16); + loadItemDescriptions(*stream, IDI_HR6_NUM_ITEM_DESCS); // Load dropped item offsets stream.reset(_boot->createReadStream(0x8, 0x9, 0x16)); - for (uint i = 0; i < IDI_HR6_NUM_ITEM_OFFSETS; ++i) { - Common::Point p; - p.x = stream->readByte(); - p.y = stream->readByte(); - _itemOffsets.push_back(p); - } + loadDroppedItemOffsets(*stream, IDI_HR6_NUM_ITEM_OFFSETS); // Location of game data for each disc stream.reset(_boot->createReadStream(0x5, 0xa, 0x03)); @@ -187,10 +233,7 @@ void HiRes6Engine::loadDisk(byte disk) { // Load item picture data (indexed on boot disk) StreamPtr stream(_boot->createReadStream(0xb, 0xd, 0x08)); _itemPics.clear(); - for (uint i = 0; i < IDI_HR6_NUM_ITEM_PICS; ++i) { - stream->readByte(); - _itemPics.push_back(readDataBlockPtr(*stream)); - } + loadItemPictures(*stream, IDI_HR6_NUM_ITEM_PICS); _curDisk = disk; @@ -214,19 +257,13 @@ void HiRes6Engine::loadDisk(byte disk) { // Messages _messages.clear(); uint count = size / 4; - for (uint i = 0; i < count; ++i) - _messages.push_back(readDataBlockPtr(*stream)); + loadMessages(*stream, count); break; } case 0x4a80: { // Global pics _pictures.clear(); - byte picNr; - while ((picNr = stream->readByte()) != 0xff) { - if (stream->eos() || stream->err()) - error("Error reading global pic list"); - _pictures[picNr] = readDataBlockPtr(*stream); - } + loadPictures(*stream); break; } case 0x4000: @@ -243,17 +280,7 @@ void HiRes6Engine::loadDisk(byte disk) { stream->skip(14); // Skip invalid room 0 _state.rooms.clear(); - for (uint i = 0; i < count; ++i) { - Room room; - stream->readByte(); // number - for (uint j = 0; j < 6; ++j) - room.connections[j] = stream->readByte(); - room.data = readDataBlockPtr(*stream); - room.picture = stream->readByte(); - room.curPicture = stream->readByte(); - room.isFirstTime = stream->readByte(); - _state.rooms.push_back(room); - } + loadRooms(*stream, count); break; } case 0x7b00: @@ -287,31 +314,7 @@ void HiRes6Engine::initGameState() { StreamPtr stream(_boot->createReadStream(0x3, 0xe, 0x03)); - byte id; - while ((id = stream->readByte()) != 0xff) { - Item item = Item(); - item.id = id; - item.noun = stream->readByte(); - item.room = stream->readByte(); - item.picture = stream->readByte(); - item.isLineArt = stream->readByte(); // Now seems to be disk number - item.position.x = stream->readByte(); - item.position.y = stream->readByte(); - item.state = stream->readByte(); - item.description = stream->readByte(); - - stream->readByte(); // Struct size - - byte picListSize = stream->readByte(); - - // Flag to keep track of what has been drawn on the screen - stream->readByte(); - - for (uint i = 0; i < picListSize; ++i) - item.roomPictures.push_back(stream->readByte()); - - _state.items.push_back(item); - } + loadItems(*stream); _currVerb = _currNoun = 0; } diff --git a/engines/adl/hires6.h b/engines/adl/hires6.h deleted file mode 100644 index 0f604d848c..0000000000 --- a/engines/adl/hires6.h +++ /dev/null @@ -1,92 +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 ADL_HIRES6_H -#define ADL_HIRES6_H - -#include "common/str.h" - -#include "adl/adl_v3.h" -#include "adl/disk.h" - -namespace Common { -class ReadStream; -struct Point; -} - -namespace Adl { - -#define IDI_HR6_NUM_ROOMS 35 -#define IDI_HR6_NUM_MESSAGES 256 -#define IDI_HR6_NUM_VARS 40 -#define IDI_HR6_NUM_ITEM_DESCS 15 -#define IDI_HR6_NUM_ITEM_PICS 15 -#define IDI_HR6_NUM_ITEM_OFFSETS 16 - -// Messages used outside of scripts -#define IDI_HR6_MSG_CANT_GO_THERE 249 -#define IDI_HR6_MSG_DONT_UNDERSTAND 247 -#define IDI_HR6_MSG_ITEM_DOESNT_MOVE 253 -#define IDI_HR6_MSG_ITEM_NOT_HERE 254 -#define IDI_HR6_MSG_THANKS_FOR_PLAYING 252 - -struct DiskDataDesc { - byte track; - byte sector; - byte offset; - byte volume; -}; - -class HiRes6Engine : public AdlEngine_v3 { -public: - HiRes6Engine(OSystem *syst, const AdlGameDescription *gd) : - AdlEngine_v3(syst, gd), - _boot(nullptr), - _currVerb(0), - _currNoun(0) { - } - - ~HiRes6Engine() { delete _boot; } - -private: - // AdlEngine - void runIntro() const; - void init(); - void initGameState(); - void printRoomDescription(); - void showRoom(); - Common::String formatVerbError(const Common::String &verb) const; - Common::String formatNounError(const Common::String &verb, const Common::String &noun) const; - - // AdlEngine_v2 - void printString(const Common::String &str); - - void loadDisk(byte disk); - - DiskImage *_boot; - byte _currVerb, _currNoun; - Common::Array<DiskDataDesc> _diskDataDesc; -}; - -} // End of namespace Adl - -#endif diff --git a/engines/adl/module.mk b/engines/adl/module.mk index d17c8569b3..d1de2a6c02 100644 --- a/engines/adl/module.mk +++ b/engines/adl/module.mk @@ -4,6 +4,7 @@ MODULE_OBJS := \ adl.o \ adl_v2.o \ adl_v3.o \ + adl_v4.o \ console.o \ detection.o \ disk.o \ @@ -14,6 +15,7 @@ MODULE_OBJS := \ hires0.o \ hires1.o \ hires2.o \ + hires4.o \ hires6.o \ speaker.o diff --git a/engines/director/archive.cpp b/engines/director/archive.cpp new file mode 100644 index 0000000000..5b22b45734 --- /dev/null +++ b/engines/director/archive.cpp @@ -0,0 +1,248 @@ +/* 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 "common/macresman.h" + +#include "director/director.h" +#include "director/resource.h" +#include "director/lingo/lingo.h" + +namespace Director { + +Archive *DirectorEngine::createArchive() { + if (getPlatform() == Common::kPlatformMacintosh) { + if (getVersion() < 4) + return new MacArchive(); + else + return new RIFXArchive(); + } else { + return new RIFFArchive(); + } +} + +void DirectorEngine::loadMainArchive() { + if (getPlatform() == Common::kPlatformWindows) + loadEXE(); + else + loadMac(); +} + +void DirectorEngine::cleanupMainArchive() { + delete _mainArchive; + delete _macBinary; +} + +void DirectorEngine::loadEXE() { + Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(getEXEName()); + if (!exeStream) + error("Failed to open EXE '%s'", getEXEName().c_str()); + + _lingo->processEvent(kEventStart, 0); + + exeStream->seek(-4, SEEK_END); + exeStream->seek(exeStream->readUint32LE()); + + switch (getVersion()) { + case 3: + loadEXEv3(exeStream); + break; + case 4: + loadEXEv4(exeStream); + break; + case 5: + loadEXEv5(exeStream); + break; + case 7: + loadEXEv7(exeStream); + break; + default: + error("Unhandled Windows EXE version %d", getVersion()); + } +} + +void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) { + uint16 entryCount = stream->readUint16LE(); + if (entryCount != 1) + error("Unhandled multiple entry v3 EXE"); + + stream->skip(5); // unknown + + stream->readUint32LE(); // Main MMM size + Common::String mmmFileName = readPascalString(*stream); + Common::String directoryName = readPascalString(*stream); + + debugC(1, kDebugLoading, "Main MMM: '%s'", mmmFileName.c_str()); + debugC(1, kDebugLoading, "Directory Name: '%s'", directoryName.c_str()); + + _mainArchive = new RIFFArchive(); + + if (!_mainArchive->openFile(mmmFileName)) + error("Could not open '%s'", mmmFileName.c_str()); + + delete stream; +} + +void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) { + if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3')) + error("Invalid projector tag found in v4 EXE"); + + uint32 rifxOffset = stream->readUint32LE(); + /* uint32 fontMapOffset = */ stream->readUint32LE(); + /* uint32 resourceForkOffset1 = */ stream->readUint32LE(); + /* uint32 resourceForkOffset2 = */ stream->readUint32LE(); + stream->readUint32LE(); // graphics DLL offset + stream->readUint32LE(); // sound DLL offset + /* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset + + loadEXERIFX(stream, rifxOffset); +} + +void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) { + if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5')) + error("Invalid projector tag found in v5 EXE"); + + uint32 rifxOffset = stream->readUint32LE(); + stream->readUint32LE(); // unknown + stream->readUint32LE(); // unknown + stream->readUint32LE(); // unknown + /* uint16 screenWidth = */ stream->readUint16LE(); + /* uint16 screenHeight = */ stream->readUint16LE(); + stream->readUint32LE(); // unknown + stream->readUint32LE(); // unknown + /* uint32 fontMapOffset = */ stream->readUint32LE(); + + loadEXERIFX(stream, rifxOffset); +} + +void DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) { + if (stream->readUint32LE() != MKTAG('P', 'J', '0', '0')) + error("Invalid projector tag found in v7 EXE"); + + uint32 rifxOffset = stream->readUint32LE(); + stream->readUint32LE(); // unknown + stream->readUint32LE(); // unknown + stream->readUint32LE(); // unknown + stream->readUint32LE(); // unknown + stream->readUint32LE(); // some DLL offset + + loadEXERIFX(stream, rifxOffset); +} + +void DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) { + _mainArchive = new RIFXArchive(); + + if (!_mainArchive->openStream(stream, offset)) + error("Failed to load RIFX from EXE"); +} + +void DirectorEngine::loadMac() { + if (getVersion() < 4) { + // The data is part of the resource fork of the executable + _mainArchive = new MacArchive(); + + if (!_mainArchive->openFile(getEXEName())) + error("Failed to open Mac binary '%s'", getEXEName().c_str()); + } else { + // The RIFX is located in the data fork of the executable + _macBinary = new Common::MacResManager(); + + if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork()) + error("Failed to open Mac binary '%s'", getEXEName().c_str()); + + Common::SeekableReadStream *dataFork = _macBinary->getDataFork(); + _mainArchive = new RIFXArchive(); + + // First we need to detect PPC vs. 68k + + uint32 tag = dataFork->readUint32BE(); + uint32 startOffset; + + if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) { + // PPC: The RIFX shares the data fork with the binary + startOffset = dataFork->readUint32BE(); + } else { + // 68k: The RIFX is the only thing in the data fork + startOffset = 0; + } + + if (!_mainArchive->openStream(dataFork, startOffset)) + error("Failed to load RIFX from Mac binary"); + } +} + +void DirectorEngine::loadSharedCastsFrom(Common::String filename) { + Archive *shardcst = createArchive(); + + debugC(1, kDebugLoading, "Loading Shared cast '%s'", filename.c_str()); + + shardcst->openFile(filename); + + _sharedDIB = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>; + _sharedSTXT = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>; + _sharedSound = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>; + _sharedBMP = new Common::HashMap<int, Common::SeekableSubReadStreamEndian *>; + + Score *castScore = new Score(this, shardcst); + + castScore->loadConfig(*shardcst->getResource(MKTAG('V','W','C','F'), 1024)); + castScore->loadCastData(*shardcst->getResource(MKTAG('V','W','C','R'), 1024)); + + _sharedCasts = &castScore->_casts; + + Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' ')); + if (dib.size() != 0) { + debugC(3, kDebugLoading, "Loading %d DIBs", dib.size()); + + for (Common::Array<uint16>::iterator iterator = dib.begin(); iterator != dib.end(); ++iterator) { + debugC(3, kDebugLoading, "Shared DIB %d", *iterator); + _sharedDIB->setVal(*iterator, shardcst->getResource(MKTAG('D','I','B',' '), *iterator)); + } + } + + Common::Array<uint16> stxt = shardcst->getResourceIDList(MKTAG('S','T','X','T')); + if (stxt.size() != 0) { + debugC(3, kDebugLoading, "Loading %d STXTs", stxt.size()); + + for (Common::Array<uint16>::iterator iterator = stxt.begin(); iterator != stxt.end(); ++iterator) { + debugC(3, kDebugLoading, "Shared STXT %d", *iterator); + _sharedSTXT->setVal(*iterator, shardcst->getResource(MKTAG('S','T','X','T'), *iterator)); + } + } + + Common::Array<uint16> bmp = shardcst->getResourceIDList(MKTAG('B','I','T','D')); + if (bmp.size() != 0) { + debugC(3, kDebugLoading, "Loading %d BITDs", bmp.size()); + for (Common::Array<uint16>::iterator iterator = bmp.begin(); iterator != bmp.end(); ++iterator) { + _sharedBMP->setVal(*iterator, shardcst->getResource(MKTAG('B','I','T','D'), *iterator)); + } + } + + Common::Array<uint16> sound = shardcst->getResourceIDList(MKTAG('S','N','D',' ')); + if (stxt.size() != 0) { + debugC(3, kDebugLoading, "Loading %d SNDs", sound.size()); + for (Common::Array<uint16>::iterator iterator = sound.begin(); iterator != sound.end(); ++iterator) { + _sharedSound->setVal(*iterator, shardcst->getResource(MKTAG('S','N','D',' '), *iterator)); + } + } +} + +} // End of namespace Director diff --git a/engines/director/director.cpp b/engines/director/director.cpp index 9aeba7150b..40796f0b9f 100644 --- a/engines/director/director.cpp +++ b/engines/director/director.cpp @@ -23,14 +23,11 @@ #include "common/config-manager.h" #include "common/debug-channels.h" #include "common/error.h" -#include "common/macresman.h" #include "graphics/macgui/macwindowmanager.h" #include "director/director.h" -#include "director/images.h" #include "director/resource.h" -#include "director/score.h" #include "director/sound.h" #include "director/lingo/lingo.h" @@ -41,6 +38,7 @@ DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gam DebugMan.addDebugChannel(kDebugLingoExec, "lingoexec", "Lingo Execution"); DebugMan.addDebugChannel(kDebugLingoCompile, "lingocompile", "Lingo Compilation"); DebugMan.addDebugChannel(kDebugLoading, "loading", "Loading"); + DebugMan.addDebugChannel(kDebugImages, "images", "Image drawing"); if (!_mixer->isReady()) error("Sound initialization failed"); @@ -49,6 +47,14 @@ DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gam syncSoundSettings(); _sharedCasts = nullptr; + + _currentScore = nullptr; + _soundManager = nullptr; + _currentPalette = nullptr; + _currentPaletteLength = 0; + _lingo = nullptr; + + _sharedCasts = nullptr; _sharedSound = nullptr; _sharedBMP = nullptr; _sharedSTXT = nullptr; @@ -72,22 +78,18 @@ DirectorEngine::~DirectorEngine() { delete _sharedBMP; delete _sharedSTXT; delete _sharedDIB; - delete _movies; - delete _mainArchive; - delete _macBinary; + delete _currentScore; + + cleanupMainArchive(); + delete _soundManager; delete _lingo; - delete _currentScore; - delete _currentPalette; } Common::Error DirectorEngine::run() { debug("Starting v%d Director game", getVersion()); - //FIXME - _sharedMMM = "SHARDCST.MMM"; - _currentPalette = nullptr; _macBinary = nullptr; @@ -111,12 +113,10 @@ Common::Error DirectorEngine::run() { //_mainArchive = new RIFFArchive(); //_mainArchive->openFile("bookshelf_example.mmm"); - if (getPlatform() == Common::kPlatformWindows) - loadEXE(); - else - loadMac(); + loadMMMNames(ConfMan.get("path")); + loadMainArchive(); - _currentScore = new Score(this); + _currentScore = new Score(this, _mainArchive); debug(0, "Score name %s", _currentScore->getMacName().c_str()); _currentScore->loadArchive(); @@ -128,6 +128,13 @@ Common::Error DirectorEngine::run() { Common::HashMap<Common::String, Score *> DirectorEngine::loadMMMNames(Common::String folder) { Common::FSNode directory(folder); Common::FSList movies; + const char *sharedMMMname; + + if (getPlatform() == Common::kPlatformWindows) + sharedMMMname = "SHARDCST.MMM"; + else + sharedMMMname = "Shared Cast*"; + Common::HashMap<Common::String, Score *> nameMap; if (!directory.getChildren(movies, Common::FSNode::kListFilesOnly)) @@ -135,14 +142,16 @@ Common::HashMap<Common::String, Score *> DirectorEngine::loadMMMNames(Common::St if (!movies.empty()) { for (Common::FSList::const_iterator i = movies.begin(); i != movies.end(); ++i) { - if (i->getName() == _sharedMMM) { - loadSharedCastsFrom(i->getPath()); + debugC(2, kDebugLoading, "File: %s", i->getName().c_str()); + if (Common::matchString(i->getName().c_str(), sharedMMMname, true)) { + loadSharedCastsFrom(i->getName()); continue; } - RIFFArchive *arc = new RIFFArchive(); - arc->openFile(i->getPath()); - Score *sc = new Score(this); + Archive *arc = createArchive(); + + arc->openFile(i->getName()); + Score *sc = new Score(this, arc); nameMap[sc->getMacName()] = sc; } } @@ -150,144 +159,6 @@ Common::HashMap<Common::String, Score *> DirectorEngine::loadMMMNames(Common::St return nameMap; } -void DirectorEngine::loadEXE() { - Common::SeekableReadStream *exeStream = SearchMan.createReadStreamForMember(getEXEName()); - if (!exeStream) - error("Failed to open EXE '%s'", getEXEName().c_str()); - - _lingo->processEvent(kEventStart, 0); - - exeStream->seek(-4, SEEK_END); - exeStream->seek(exeStream->readUint32LE()); - - switch (getVersion()) { - case 3: - loadEXEv3(exeStream); - break; - case 4: - loadEXEv4(exeStream); - break; - case 5: - loadEXEv5(exeStream); - break; - case 7: - loadEXEv7(exeStream); - break; - default: - error("Unhandled Windows EXE version %d", getVersion()); - } -} - -void DirectorEngine::loadEXEv3(Common::SeekableReadStream *stream) { - uint16 entryCount = stream->readUint16LE(); - if (entryCount != 1) - error("Unhandled multiple entry v3 EXE"); - - stream->skip(5); // unknown - - stream->readUint32LE(); // Main MMM size - Common::String mmmFileName = readPascalString(*stream); - Common::String directoryName = readPascalString(*stream); - - debug("Main MMM: '%s'", mmmFileName.c_str()); - debug("Directory Name: '%s'", directoryName.c_str()); - - _mainArchive = new RIFFArchive(); - - if (!_mainArchive->openFile(mmmFileName)) - error("Could not open '%s'", mmmFileName.c_str()); - - delete stream; -} - -void DirectorEngine::loadEXEv4(Common::SeekableReadStream *stream) { - if (stream->readUint32BE() != MKTAG('P', 'J', '9', '3')) - error("Invalid projector tag found in v4 EXE"); - - uint32 rifxOffset = stream->readUint32LE(); - /* uint32 fontMapOffset = */ stream->readUint32LE(); - /* uint32 resourceForkOffset1 = */ stream->readUint32LE(); - /* uint32 resourceForkOffset2 = */ stream->readUint32LE(); - stream->readUint32LE(); // graphics DLL offset - stream->readUint32LE(); // sound DLL offset - /* uint32 rifxOffsetAlt = */ stream->readUint32LE(); // equivalent to rifxOffset - - loadEXERIFX(stream, rifxOffset); -} - -void DirectorEngine::loadEXEv5(Common::SeekableReadStream *stream) { - if (stream->readUint32LE() != MKTAG('P', 'J', '9', '5')) - error("Invalid projector tag found in v5 EXE"); - - uint32 rifxOffset = stream->readUint32LE(); - stream->readUint32LE(); // unknown - stream->readUint32LE(); // unknown - stream->readUint32LE(); // unknown - /* uint16 screenWidth = */ stream->readUint16LE(); - /* uint16 screenHeight = */ stream->readUint16LE(); - stream->readUint32LE(); // unknown - stream->readUint32LE(); // unknown - /* uint32 fontMapOffset = */ stream->readUint32LE(); - - loadEXERIFX(stream, rifxOffset); -} - -void DirectorEngine::loadEXEv7(Common::SeekableReadStream *stream) { - if (stream->readUint32LE() != MKTAG('P', 'J', '0', '0')) - error("Invalid projector tag found in v7 EXE"); - - uint32 rifxOffset = stream->readUint32LE(); - stream->readUint32LE(); // unknown - stream->readUint32LE(); // unknown - stream->readUint32LE(); // unknown - stream->readUint32LE(); // unknown - stream->readUint32LE(); // some DLL offset - - loadEXERIFX(stream, rifxOffset); -} - -void DirectorEngine::loadEXERIFX(Common::SeekableReadStream *stream, uint32 offset) { - _mainArchive = new RIFXArchive(); - - if (!_mainArchive->openStream(stream, offset)) - error("Failed to load RIFX from EXE"); -} - -void DirectorEngine::loadMac() { - if (getVersion() < 4) { - // The data is part of the resource fork of the executable - _mainArchive = new MacArchive(); - - if (!_mainArchive->openFile(getEXEName())) - error("Failed to open Mac binary '%s'", getEXEName().c_str()); - } else { - // The RIFX is located in the data fork of the executable - _macBinary = new Common::MacResManager(); - - if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork()) - error("Failed to open Mac binary '%s'", getEXEName().c_str()); - - Common::SeekableReadStream *dataFork = _macBinary->getDataFork(); - _mainArchive = new RIFXArchive(); - - // First we need to detect PPC vs. 68k - - uint32 tag = dataFork->readUint32BE(); - uint32 startOffset; - - if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) { - // PPC: The RIFX shares the data fork with the binary - startOffset = dataFork->readUint32BE(); - } else { - // 68k: The RIFX is the only thing in the data fork - startOffset = 0; - } - - if (!_mainArchive->openStream(dataFork, startOffset)) - error("Failed to load RIFX from Mac binary"); - } -} - Common::String DirectorEngine::readPascalString(Common::SeekableReadStream &stream) { byte length = stream.readByte(); Common::String x; @@ -303,60 +174,4 @@ void DirectorEngine::setPalette(byte *palette, uint16 count) { _currentPaletteLength = count; } -void DirectorEngine::loadSharedCastsFrom(Common::String filename) { - Archive *shardcst; - - if (getVersion() < 4) { - shardcst = new RIFFArchive(); - } else { - shardcst = new RIFXArchive(); - } - - shardcst->openFile(filename); - - Score *castScore = new Score(this); - Common::SeekableSubReadStreamEndian *castStream = shardcst->getResource(MKTAG('V','W','C','R'), 1024); - - castScore->loadCastData(*castStream); - *_sharedCasts = castScore->_casts; - - Common::Array<uint16> dib = shardcst->getResourceIDList(MKTAG('D','I','B',' ')); - - if (dib.size() != 0) { - Common::Array<uint16>::iterator iterator; - for (iterator = dib.begin(); iterator != dib.end(); ++iterator) { - debug(3, "Shared DIB %d", *iterator); - _sharedDIB->setVal(*iterator, shardcst->getResource(MKTAG('D','I','B',' '), *iterator)); - } - } - - Common::Array<uint16> stxt = shardcst->getResourceIDList(MKTAG('S','T','X','T')); - - if (stxt.size() != 0) { - Common::Array<uint16>::iterator iterator; - for (iterator = stxt.begin(); iterator != stxt.end(); ++iterator) { - debug(3, "Shared STXT %d", *iterator); - _sharedSTXT->setVal(*iterator, shardcst->getResource(MKTAG('S','T','X','T'), *iterator)); - } - } - - Common::Array<uint16> bmp = shardcst->getResourceIDList(MKTAG('B','I','T','D')); - - if (bmp.size() != 0) { - Common::Array<uint16>::iterator iterator; - for (iterator = bmp.begin(); iterator != bmp.end(); ++iterator) { - _sharedBMP->setVal(*iterator, shardcst->getResource(MKTAG('B','I','T','D'), *iterator)); - } - } - - Common::Array<uint16> sound = shardcst->getResourceIDList(MKTAG('S','N','D',' ')); - - if (stxt.size() != 0) { - Common::Array<uint16>::iterator iterator; - for (iterator = sound.begin(); iterator != sound.end(); ++iterator) { - _sharedSound->setVal(*iterator, shardcst->getResource(MKTAG('S','N','D',' '), *iterator)); - } - } -} - } // End of namespace Director diff --git a/engines/director/director.h b/engines/director/director.h index 23519f135e..4cb8640d5b 100644 --- a/engines/director/director.h +++ b/engines/director/director.h @@ -54,7 +54,8 @@ struct Cast; enum { kDebugLingoExec = 1 << 0, kDebugLingoCompile = 1 << 1, - kDebugLoading = 1 << 2 + kDebugLoading = 1 << 2, + kDebugImages = 1 << 3 }; @@ -79,6 +80,11 @@ public: const byte *getPalette() const { return _currentPalette; } uint16 getPaletteColorCount() const { return _currentPaletteLength; } void loadSharedCastsFrom(Common::String filename); + + void loadMainArchive(); + Archive *createArchive(); + void cleanupMainArchive(); + Common::HashMap<int, Common::SeekableSubReadStreamEndian *> *getSharedDIB() const { return _sharedDIB; } Common::HashMap<int, Common::SeekableSubReadStreamEndian *> *getSharedBMP() const { return _sharedBMP; } Common::HashMap<int, Common::SeekableSubReadStreamEndian *> *getSharedSTXT() const { return _sharedSTXT; } @@ -107,7 +113,6 @@ private: Common::String readPascalString(Common::SeekableReadStream &stream); - Common::String _sharedMMM; Common::HashMap<int, Cast *> *_sharedCasts; Common::HashMap<int, Common::SeekableSubReadStreamEndian *> *_sharedDIB; Common::HashMap<int, Common::SeekableSubReadStreamEndian *> *_sharedSTXT; diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp index 018cb7983c..3d5d8b6a4b 100644 --- a/engines/director/frame.cpp +++ b/engines/director/frame.cpp @@ -51,6 +51,8 @@ Frame::Frame(DirectorEngine *vm) { _skipFrameFlag = 0; _blend = 0; + _palette = NULL; + _sprites.resize(CHANNEL_COUNT); for (uint16 i = 0; i < _sprites.size(); i++) { @@ -75,6 +77,8 @@ Frame::Frame(const Frame &frame) { _blend = frame._blend; _palette = new PaletteInfo(); + debugC(1, kDebugLoading, "Frame. action: %d transType: %d transDuration: %d", _actionId, _transType, _transDuration); + _sprites.resize(CHANNEL_COUNT); for (uint16 i = 0; i < CHANNEL_COUNT; i++) { @@ -435,7 +439,7 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) { continue; } - Image::ImageDecoder *img = getImageFrom(_sprites[i]->_castId, _sprites[i]->_width, _sprites[i]->_height); + Image::ImageDecoder *img = getImageFrom(_sprites[i]->_castId); if (!img) { warning("Image with id %d not found", _sprites[i]->_castId); @@ -467,6 +471,10 @@ void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) { case kInkTypeCopy: surface.blitFrom(*img->getSurface(), Common::Point(x, y)); break; + case kInkTypeTransparent: + //FIXME: is it always white (last entry in pallette)? + surface.transBlitFrom(*img->getSurface(), Common::Point(x, y), _vm->getPaletteColorCount() - 1); + break; case kInkTypeBackgndTrans: drawBackgndTransSprite(surface, *img->getSurface(), drawRect); break; @@ -516,25 +524,7 @@ void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) { } } -static const int corrections[] = { - 1026, 27, 27, // Macro - 1027, 164, 170, // House - 1028, 154, 154, // Macromind Director - 1029, 158, 158, // Upper inscription - 1030, 54, 54, // lift - 1031, 116, 116, // Lower inscription - 1032, 113, 113, // Lower inscription 2 - 1039, 50, 50, - 1041, 110, 110, // descr - 1042, 120, 121, // descr 2 - 1065, 27, 27, // car - 1109, 104, 112, // taxi - 1110, 90, 96, // taxi - 1111, 74, 80, // taxi - 0, 0, 0 -}; - -Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId, int w, int h) { +Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId) { uint16 imgId = spriteId + 1024; Image::ImageDecoder *img = NULL; @@ -551,30 +541,27 @@ Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId, int w, int h) { } if (_vm->_currentScore->getArchive()->hasResource(MKTAG('B', 'I', 'T', 'D'), imgId)) { + Common::SeekableReadStream *pic = _vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId); + if (_vm->getVersion() < 4) { - bool c = false; - for (int i = 0; corrections[i]; i += 3) - if (corrections[i] == imgId) { - w = corrections[i + 2]; - c = true; - break; - } + BitmapCast *bc = static_cast<BitmapCast *>(_vm->_currentScore->_casts[spriteId]); + int w = bc->initialRect.width(), h = bc->initialRect.height(); - if (!c) - warning("%d, %d, %d,", imgId, w, w); + debugC(2, kDebugImages, "id: %d, w: %d, h: %d, flags: %x, some: %x, unk1: %d, unk2: %d", + imgId, w, h, bc->flags, bc->someFlaggyThing, bc->unk1, bc->unk2); img = new BITDDecoder(w, h); } else { img = new Image::BitmapDecoder(); } if (debugChannelSet(8, kDebugLoading)) { - Common::SeekableReadStream *s = _vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId); + Common::SeekableReadStream *s = pic; byte buf[1024]; int n = s->read(buf, 1024); Common::hexdump(buf, n); } - img->loadStream(*_vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId)); + img->loadStream(*pic); return img; } @@ -725,7 +712,7 @@ void Frame::drawReverseSprite(Graphics::ManagedSurface &target, const Graphics:: } void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { - //Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent + // Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent Graphics::Surface tmp; tmp.copyFrom(sprite); @@ -747,31 +734,38 @@ void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Su } if (whiteColor == -1) { - warning("No white color for Matte image"); - whiteColor = *(byte *)tmp.getBasePtr(0, 0); - } + debugC(1, kDebugImages, "No white color for Matte image"); - Graphics::FloodFill ff(&tmp, whiteColor, 0, true); + for (int yy = 0; yy < tmp.h; yy++) { + const byte *src = (const byte *)tmp.getBasePtr(0, yy); + byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy); - for (int yy = 0; yy < tmp.h; yy++) { - ff.addSeed(0, yy); - ff.addSeed(tmp.w - 1, yy); - } + for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++) + *dst = *src; + } + } else { + Graphics::FloodFill ff(&tmp, whiteColor, 0, true); - for (int xx = 0; xx < tmp.w; xx++) { - ff.addSeed(xx, 0); - ff.addSeed(xx, tmp.h - 1); - } - ff.fillMask(); + for (int yy = 0; yy < tmp.h; yy++) { + ff.addSeed(0, yy); + ff.addSeed(tmp.w - 1, yy); + } - for (int yy = 0; yy < tmp.h; yy++) { - const byte *src = (const byte *)tmp.getBasePtr(0, yy); - const byte *mask = (const byte *)ff.getMask()->getBasePtr(0, yy); - byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy); + for (int xx = 0; xx < tmp.w; xx++) { + ff.addSeed(xx, 0); + ff.addSeed(xx, tmp.h - 1); + } + ff.fillMask(); - for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++, mask++) - if (*mask == 0) - *dst = *src; + for (int yy = 0; yy < tmp.h; yy++) { + const byte *src = (const byte *)tmp.getBasePtr(0, yy); + const byte *mask = (const byte *)ff.getMask()->getBasePtr(0, yy); + byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy); + + for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++, mask++) + if (*mask == 0) + *dst = *src; + } } tmp.free(); diff --git a/engines/director/frame.h b/engines/director/frame.h index c06157c2cc..8c6f82f493 100644 --- a/engines/director/frame.h +++ b/engines/director/frame.h @@ -118,7 +118,7 @@ private: void readPaletteInfo(Common::SeekableSubReadStreamEndian &stream); void readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); void readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); - Image::ImageDecoder *getImageFrom(uint16 spriteID, int w, int h); + Image::ImageDecoder *getImageFrom(uint16 spriteID); void drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); void drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); void drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); diff --git a/engines/director/images.cpp b/engines/director/images.cpp index db429af7e9..cd8223ae8e 100644 --- a/engines/director/images.cpp +++ b/engines/director/images.cpp @@ -21,8 +21,10 @@ */ #include "common/substream.h" +#include "common/debug.h" #include "common/textconsole.h" +#include "director/director.h" #include "director/images.h" namespace Director { @@ -103,12 +105,16 @@ bool DIBDecoder::loadStream(Common::SeekableReadStream &stream) { ****************************/ BITDDecoder::BITDDecoder(int w, int h) { - int oldw = w; - //w += 8 - (w + 7) % 8; - - //warning("W: %d -> %d, %d", oldw, w, h); _surface = new Graphics::Surface(); - _surface->create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + + // We make the surface pitch a multiple of 16. + int pitch = w; + if (w % 16) + pitch += 16 - (w % 16); + + // HACK: Create a padded surface by adjusting w after create() + _surface->create(pitch, h, Graphics::PixelFormat::createFormatCLUT8()); + _surface->w = w; _palette = new byte[256 * 3]; @@ -137,6 +143,21 @@ void BITDDecoder::loadPalette(Common::SeekableReadStream &stream) { bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) { int x = 0, y = 0; + // If the stream has exactly the required number of bits for this image, + // we assume it is uncompressed. + if (stream.size() * 8 == _surface->pitch * _surface->h) { + debugC(3, kDebugImages, "Skipping compression"); + for (y = 0; y < _surface->h; y++) { + for (x = 0; x < _surface->pitch; ) { + byte color = stream.readByte(); + for (int c = 0; c < 8; c++) + *((byte *)_surface->getBasePtr(x++, y)) = (color & (1 << (7 - c))) ? 0 : 0xff; + } + } + + return true; + } + while (y < _surface->h) { int n = stream.readSByte(); int count; @@ -167,7 +188,7 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) { for (int c = 0; c < 8; c++) { *((byte *)_surface->getBasePtr(x, y)) = (color & (1 << (7 - c))) ? 0 : 0xff; x++; - if (x == _surface->w) { + if (x == _surface->pitch) { y++; x = 0; break; diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp index 2189f1f7aa..e22044c1e9 100644 --- a/engines/director/lingo/lingo-funcs.cpp +++ b/engines/director/lingo/lingo-funcs.cpp @@ -20,29 +20,6 @@ * */ -// Heavily inspired by hoc -// Copyright (C) AT&T 1995 -// All Rights Reserved -// -// Permission to use, copy, modify, and distribute this software and -// its documentation for any purpose and without fee is hereby -// granted, provided that the above copyright notice appear in all -// copies and that both that the copyright notice and this -// permission notice and warranty disclaimer appear in supporting -// documentation, and that the name of AT&T or any of its entities -// not be used in advertising or publicity pertaining to -// distribution of the software without specific, written prior -// permission. -// -// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -// THIS SOFTWARE. - #include "director/lingo/lingo.h" #include "common/file.h" #include "audio/decoders/wave.h" diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index 529738043c..17e8ea44fe 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -108,6 +108,8 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) { _exitRepeat = false; + _localvars = NULL; + warning("Lingo Inited"); } @@ -248,11 +250,31 @@ void Lingo::executeScript(ScriptType type, uint16 id) { cleanLocalVars(); } +ScriptType Lingo::event2script(LEvent ev) { + if (_vm->getVersion() < 4) { + switch (ev) { + //case kEventStartMovie: // We are precompiling it now + // return kMovieScript; + case kEventEnterFrame: + return kFrameScript; + default: + return kNoneScript; + } + } + + return kNoneScript; +} + void Lingo::processEvent(LEvent event, int entityId) { if (!_eventHandlerTypes.contains(event)) error("processEvent: Unknown event %d for entity %d", event, entityId); - debug(2, "STUB: processEvent(%s) for %d", _eventHandlerTypes[event], entityId); + ScriptType st = event2script(event); + + if (st != kNoneScript) + executeScript(st, entityId + 1); + else + debugC(8, kDebugLingoExec, "STUB: processEvent(%s) for %d", _eventHandlerTypes[event], entityId); } int Lingo::alignTypes(Datum &d1, Datum &d2) { diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index a921f49e4b..4dd00417b8 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -176,6 +176,8 @@ public: void printStack(const char *s); Common::String decodeInstruction(int pc, int *newPC = NULL); + ScriptType event2script(LEvent ev); + void processEvent(LEvent event, int entityId); void initBuiltIns(); diff --git a/engines/director/module.mk b/engines/director/module.mk index c37e9d9b9b..1ea361590a 100644 --- a/engines/director/module.mk +++ b/engines/director/module.mk @@ -1,6 +1,7 @@ MODULE := engines/director MODULE_OBJS = \ + archive.o \ detection.o \ director.o \ frame.o \ diff --git a/engines/director/score.cpp b/engines/director/score.cpp index 9b4f57245d..6d6d02274c 100644 --- a/engines/director/score.cpp +++ b/engines/director/score.cpp @@ -87,16 +87,26 @@ static byte defaultPalette[768] = { 204, 51, 255, 204, 102, 255, 204, 153, 255, 204, 204, 255, 204, 255, 255, 255, 0, 255, 255, 51, 255, 255, 102, 255, 255, 153, 255, 255, 204, 255, 255, 255 }; -Score::Score(DirectorEngine *vm) { +Score::Score(DirectorEngine *vm, Archive *archive) { _vm = vm; _surface = new Graphics::ManagedSurface; _trailSurface = new Graphics::ManagedSurface; - _movieArchive = _vm->getMainArchive(); + _movieArchive = archive; _lingo = _vm->getLingo(); _soundManager = _vm->getSoundManager(); _lingo->processEvent(kEventPrepareMovie, 0); _movieScriptCount = 0; _labels = NULL; + _font = NULL; + + _versionMinor = _versionMajor = 0; + _currentFrameRate = 20; + _castArrayStart = _castArrayEnd = 0; + _currentFrame = 0; + _nextFrameTime = 0; + _flags = 0; + _stopPlay = false; + _stageColor = 0; if (_movieArchive->hasResource(MKTAG('M','C','N','M'), 0)) { _macName = _movieArchive->getName(MKTAG('M','C','N','M'), 0).c_str(); @@ -159,11 +169,7 @@ void Score::loadArchive() { Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T')); if (stxt.size() > 0) { - Common::Array<uint16>::iterator iterator; - - for (iterator = stxt.begin(); iterator != stxt.end(); ++iterator) { - loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *iterator)); - } + loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *stxt.begin())); } } @@ -181,8 +187,6 @@ Score::~Score() { _movieArchive->close(); delete _font; - delete _movieArchive; - delete _labels; } @@ -268,6 +272,8 @@ void Score::readVersion(uint32 rid) { } void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream) { + debugC(1, kDebugLoading, "Score::loadCastData(). start: %d, end: %d", _castArrayStart, _castArrayEnd); + for (uint16 id = _castArrayStart; id <= _castArrayEnd; id++) { byte size = stream.readByte(); if (size == 0) @@ -440,6 +446,8 @@ void Score::dumpScript(const char *script, ScriptType type, uint16 id) { char buf[256]; switch (type) { + case kNoneScript: + error("Incorrect dumpScript() call"); case kFrameScript: typeName = "frame"; break; @@ -642,16 +650,17 @@ void Score::loadFontMap(Common::SeekableSubReadStreamEndian &stream) { } BitmapCast::BitmapCast(Common::SeekableSubReadStreamEndian &stream) { - /*byte flags = */ stream.readByte(); - uint16 someFlaggyThing = stream.readUint16(); + flags = stream.readByte(); + someFlaggyThing = stream.readUint16(); initialRect = Score::readRect(stream); boundingRect = Score::readRect(stream); regY = stream.readUint16(); regX = stream.readUint16(); + unk1 = unk2 = 0; if (someFlaggyThing & 0x8000) { - /*uint16 unk1 =*/ stream.readUint16(); - /*uint16 unk2 =*/ stream.readUint16(); + unk1 = stream.readUint16(); + unk2 = stream.readUint16(); } modified = 0; } @@ -664,8 +673,9 @@ TextCast::TextCast(Common::SeekableSubReadStreamEndian &stream) { textType = static_cast<TextType>(stream.readByte()); textAlign = static_cast<TextAlignType>(stream.readUint16()); stream.skip(6); //palinfo - //for now, just supposition - fontId = stream.readUint32(); + + int t = stream.readUint32(); + assert(t == 0); // So far we saw only 0 here initialRect = Score::readRect(stream); textShadow = static_cast<SizeType>(stream.readByte()); @@ -676,8 +686,11 @@ TextCast::TextCast(Common::SeekableSubReadStreamEndian &stream) { textFlags.push_back(kTextFlagAutoTab); if (flags & 0x4) textFlags.push_back(kTextFlagDoNotWrap); - //again supposition - fontSize = stream.readUint16(); + + //TODO: FIXME: guesswork + fontId = stream.readByte(); + fontSize = stream.readByte(); + modified = 0; } @@ -724,11 +737,9 @@ void Score::startLoop() { _frames[_currentFrame]->prepareFrame(this); while (!_stopPlay && _currentFrame < _frames.size() - 2) { + debugC(1, kDebugImages, "Current frame: %d", _currentFrame); update(); processEvents(); - - g_system->updateScreen(); - g_system->delayMillis(10); } } @@ -740,8 +751,8 @@ void Score::update() { _surface->copyFrom(*_trailSurface); //Enter and exit from previous frame (Director 4) - _lingo->processEvent(kEventEnterFrame, _currentFrame); - _lingo->processEvent(kEventExitFrame, _currentFrame); + _lingo->processEvent(kEventEnterFrame, _frames[_currentFrame]->_actionId); + _lingo->processEvent(kEventExitFrame, _frames[_currentFrame]->_actionId); //TODO Director 6 - another order @@ -785,13 +796,11 @@ void Score::update() { //Wait for sound channel 1 while (_soundManager->isChannelActive(1)) { processEvents(); - g_system->delayMillis(10); } } else if (tempo == 134) { //Wait for sound channel 2 while (_soundManager->isChannelActive(2)) { processEvents(); - g_system->delayMillis(10); } } } @@ -804,22 +813,29 @@ void Score::processEvents() { Common::Event event; - while (g_system->getEventManager()->pollEvent(event)) { - if (event.type == Common::EVENT_QUIT) - _stopPlay = true; + int endTime = g_system->getMillis() + 200; - if (event.type == Common::EVENT_LBUTTONDOWN) { - Common::Point pos = g_system->getEventManager()->getMousePos(); + while (g_system->getMillis() < endTime) { + while (g_system->getEventManager()->pollEvent(event)) { + if (event.type == Common::EVENT_QUIT) + _stopPlay = true; - //TODO there is dont send frame id - _lingo->processEvent(kEventMouseDown, _frames[_currentFrame]->getSpriteIDFromPos(pos)); - } + if (event.type == Common::EVENT_LBUTTONDOWN) { + Common::Point pos = g_system->getEventManager()->getMousePos(); - if (event.type == Common::EVENT_LBUTTONUP) { - Common::Point pos = g_system->getEventManager()->getMousePos(); + //TODO there is dont send frame id + _lingo->processEvent(kEventMouseDown, _frames[_currentFrame]->getSpriteIDFromPos(pos)); + } - _lingo->processEvent(kEventMouseUp, _frames[_currentFrame]->getSpriteIDFromPos(pos)); + if (event.type == Common::EVENT_LBUTTONUP) { + Common::Point pos = g_system->getEventManager()->getMousePos(); + + _lingo->processEvent(kEventMouseUp, _frames[_currentFrame]->getSpriteIDFromPos(pos)); + } } + + g_system->updateScreen(); + g_system->delayMillis(10); } } diff --git a/engines/director/score.h b/engines/director/score.h index dc6a62b971..a9ac1f97de 100644 --- a/engines/director/score.h +++ b/engines/director/score.h @@ -58,6 +58,7 @@ enum ScriptType { kMovieScript = 0, kSpriteScript = 1, kFrameScript = 2, + kNoneScript = -1, kMaxScriptType = 2 }; @@ -74,6 +75,8 @@ struct BitmapCast : Cast { uint16 regX; uint16 regY; uint8 flags; + uint16 someFlaggyThing; + uint16 unk1, unk2; }; enum ShapeType { @@ -167,7 +170,7 @@ struct Label { class Score { public: - Score(DirectorEngine *vm); + Score(DirectorEngine *vm, Archive *); ~Score(); static Common::Rect readRect(Common::SeekableSubReadStreamEndian &stream); @@ -180,6 +183,7 @@ public: void startLoop(); void processEvents(); Archive *getArchive() const { return _movieArchive; }; + void loadConfig(Common::SeekableSubReadStreamEndian &stream); void loadCastData(Common::SeekableSubReadStreamEndian &stream); void setCurrentFrame(uint16 frameId) { _currentFrame = frameId; } Common::String getMacName() const { return _macName; } @@ -187,7 +191,6 @@ public: private: void update(); void readVersion(uint32 rid); - void loadConfig(Common::SeekableSubReadStreamEndian &stream); void loadPalette(Common::SeekableSubReadStreamEndian &stream); void loadFrames(Common::SeekableSubReadStreamEndian &stream); void loadLabels(Common::SeekableSubReadStreamEndian &stream); diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp index 7fd5b3d055..77d53ae1da 100644 --- a/engines/director/sprite.cpp +++ b/engines/director/sprite.cpp @@ -51,6 +51,10 @@ Sprite::Sprite() { _volume = 0; _stretch = 0; _type = kInactiveSprite; + + _cast = nullptr; + _blend = 0; + _lineSize = 1; } Sprite::Sprite(const Sprite &sprite) { @@ -76,6 +80,13 @@ Sprite::Sprite(const Sprite &sprite) { _volume = sprite._volume; _stretch = sprite._stretch; _type = sprite._type; + + _cast = sprite._cast; + _constraint = sprite._constraint; + _moveable = sprite._moveable; + _blend = sprite._blend; + _startTime = sprite._startTime; + _lineSize = sprite._lineSize; } Sprite::~Sprite() { diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp index faef1672ca..4f70553033 100644 --- a/engines/fullpipe/behavior.cpp +++ b/engines/fullpipe/behavior.cpp @@ -49,6 +49,8 @@ void BehaviorManager::clear() { } void BehaviorManager::initBehavior(Scene *sc, GameVar *var) { + debugC(2, kDebugBehavior, "BehaviorManager::initBehavior(%d, %s)", sc->_sceneId, transCyrillic((byte *)var->_varName)); + clear(); _scene = sc; @@ -58,7 +60,10 @@ void BehaviorManager::initBehavior(Scene *sc, GameVar *var) { if (!behvar) return; + debugC(3, kDebugBehavior, "BehaviorManager::initBehavior. have Variable"); + for (GameVar *subvar = behvar->_subVars; subvar; subvar = subvar->_nextVarObj) { + debugC(3, kDebugBehavior, "BehaviorManager::initBehavior. subVar %s", transCyrillic((byte *)subvar->_varName)); if (!strcmp(subvar->_varName, "AMBIENT")) { behinfo = new BehaviorInfo; behinfo->initAmbientBehavior(subvar, sc); @@ -66,8 +71,8 @@ void BehaviorManager::initBehavior(Scene *sc, GameVar *var) { _behaviors.push_back(behinfo); } else { StaticANIObject *ani = sc->getStaticANIObject1ByName(subvar->_varName, -1); - if (ani) - for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) + if (ani) { + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) { if (((StaticANIObject *)sc->_staticANIObjectList1[i])->_id == ani->_id) { behinfo = new BehaviorInfo; behinfo->initObjectBehavior(subvar, sc, ani); @@ -75,6 +80,8 @@ void BehaviorManager::initBehavior(Scene *sc, GameVar *var) { _behaviors.push_back(behinfo); } + } + } } } } @@ -83,7 +90,7 @@ void BehaviorManager::updateBehaviors() { if (!_isActive) return; - debugC(4, kDebugBehavior, "BehaviorManager::updateBehaviors()"); + debugC(6, kDebugBehavior, "BehaviorManager::updateBehaviors()"); for (uint i = 0; i < _behaviors.size(); i++) { BehaviorInfo *beh = _behaviors[i]; @@ -122,7 +129,7 @@ void BehaviorManager::updateBehaviors() { } void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorAnim *entry) { - debugC(4, kDebugBehavior, "BehaviorManager::updateBehavior() %d", entry->_movesCount); + debugC(7, kDebugBehavior, "BehaviorManager::updateBehavior() moves: %d", entry->_movesCount); for (int i = 0; i < entry->_movesCount; i++) { BehaviorMove *bhi = entry->_behaviorMoves[i]; if (!(bhi->_flags & 1)) { @@ -144,7 +151,7 @@ void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorAnim *e } void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorAnim *bhe) { - debugC(4, kDebugBehavior, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName)); + debugC(6, kDebugBehavior, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName)); MessageQueue *mq = 0; @@ -224,7 +231,7 @@ BehaviorMove *BehaviorManager::getBehaviorMoveByMessageQueueDataId(StaticANIObje } void BehaviorInfo::clear() { - _ani = 0; + _ani = NULL; _staticsId = 0; _counter = 0; _counterMax = 0; @@ -260,7 +267,8 @@ void BehaviorInfo::initAmbientBehavior(GameVar *var, Scene *sc) { } void BehaviorInfo::initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *ani) { - debugC(4, kDebugBehavior, "BehaviorInfo::initObjectBehavior(%s)", transCyrillic((byte *)var->_varName)); + Common::String s((char *)transCyrillic((byte *)var->_varName)); + debugC(4, kDebugBehavior, "BehaviorInfo::initObjectBehavior(%s, %d, %s)", s.c_str(), sc->_sceneId, transCyrillic((byte *)ani->_objectName)); clear(); diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp index 22f2050d16..54a77938c9 100644 --- a/engines/fullpipe/fullpipe.cpp +++ b/engines/fullpipe/fullpipe.cpp @@ -55,6 +55,8 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) DebugMan.addDebugChannel(kDebugBehavior, "behavior", "Behavior"); DebugMan.addDebugChannel(kDebugMemory, "memory", "Memory management"); DebugMan.addDebugChannel(kDebugEvents, "events", "Event handling"); + DebugMan.addDebugChannel(kDebugInventory, "inventory", "Inventory"); + DebugMan.addDebugChannel(kDebugSceneLogic, "scenelogic", "Scene Logic"); // Setup mixer if (!_mixer->isReady()) { @@ -404,6 +406,7 @@ void FullpipeEngine::updateEvents() { _lastInputTicks = _updateTicks; ex->handle(); } + _mouseScreenPos = event.mouse; break; case Common::EVENT_LBUTTONDOWN: if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { @@ -416,6 +419,7 @@ void FullpipeEngine::updateEvents() { _lastInputTicks = _updateTicks; ex->handle(); } + _mouseScreenPos = event.mouse; break; case Common::EVENT_LBUTTONUP: if (!_inputArFlag && (_updateTicks - _lastButtonUpTicks) >= 2) { @@ -424,6 +428,7 @@ void FullpipeEngine::updateEvents() { _lastButtonUpTicks = _updateTicks; ex->handle(); } + _mouseScreenPos = event.mouse; break; default: break; diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h index 2012d7a344..09c9559199 100644 --- a/engines/fullpipe/fullpipe.h +++ b/engines/fullpipe/fullpipe.h @@ -55,7 +55,9 @@ enum { kDebugAnimation = 1 << 3, kDebugMemory = 1 << 4, kDebugEvents = 1 << 5, - kDebugBehavior = 1 << 6 + kDebugBehavior = 1 << 6, + kDebugInventory = 1 << 7, + kDebugSceneLogic = 1 << 8 }; class BehaviorManager; diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp index 174f66a3c8..eba5d442d5 100644 --- a/engines/fullpipe/gfx.cpp +++ b/engines/fullpipe/gfx.cpp @@ -290,8 +290,8 @@ bool GameObject::load(MfcArchive &file) { _id = file.readUint16LE(); _objectName = file.readPascalString(); - _ox = file.readUint32LE(); - _oy = file.readUint32LE(); + _ox = file.readSint32LE(); + _oy = file.readSint32LE(); _priority = file.readUint16LE(); if (g_fp->_gameProjectVersion >= 11) { @@ -353,7 +353,6 @@ bool GameObject::getPicAniInfo(PicAniInfo *info) { info->ox = _ox; info->oy = _oy; info->priority = _priority; - warning("Yep %d", _id); return true; } @@ -495,8 +494,8 @@ bool Picture::load(MfcArchive &file) { debugC(5, kDebugLoading, "Picture::load()"); MemoryObject::load(file); - _x = file.readUint32LE(); - _y = file.readUint32LE(); + _x = file.readSint32LE(); + _y = file.readSint32LE(); _field_44 = file.readUint16LE(); assert(g_fp->_gameProjectVersion >= 2); @@ -786,8 +785,8 @@ Bitmap::~Bitmap() { void Bitmap::load(Common::ReadStream *s) { debugC(5, kDebugLoading, "Bitmap::load()"); - _x = s->readUint32LE(); - _y = s->readUint32LE(); + _x = s->readSint32LE(); + _y = s->readSint32LE(); _width = s->readUint32LE(); _height = s->readUint32LE(); s->readUint32LE(); // pixels @@ -806,7 +805,7 @@ bool Bitmap::isPixelHitAtPos(int x, int y) { if (!_surface) return false; - return ((*((int32 *)_surface->getBasePtr(x - _x, y - _y)) & 0xff000000) != 0); + return ((*((int32 *)_surface->getBasePtr(x - _x, y - _y)) & 0xff) != 0); } void Bitmap::decode(int32 *palette) { @@ -1139,13 +1138,14 @@ Bitmap *Bitmap::flipVertical() { } void Bitmap::drawShaded(int type, int x, int y, byte *palette, int alpha) { - warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y); + if (alpha != 255) + warning("STUB: Bitmap::drawShaded(%d, %d, %d, %d)", type, x, y, alpha); putDib(x, y, (int32 *)palette, alpha); } void Bitmap::drawRotated(int x, int y, int angle, byte *palette, int alpha) { - warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle); + warning("STUB: Bitmap::drawRotated(%d, %d, %d, %d)", x, y, angle, alpha); putDib(x, y, (int32 *)palette, alpha); } diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp index f0abd0d02c..dc40750fe6 100644 --- a/engines/fullpipe/interaction.cpp +++ b/engines/fullpipe/interaction.cpp @@ -450,8 +450,8 @@ bool Interaction::load(MfcArchive &file) { _objectId3 = file.readUint16LE(); _objectState2 = file.readUint32LE(); _objectState1 = file.readUint32LE(); - _xOffs = file.readUint32LE(); - _yOffs = file.readUint32LE(); + _xOffs = file.readSint32LE(); + _yOffs = file.readSint32LE(); _sceneId = file.readUint32LE(); _flags = file.readUint32LE(); _actionName = file.readPascalString(); diff --git a/engines/fullpipe/inventory.cpp b/engines/fullpipe/inventory.cpp index aa229d55d7..f1dafeba7d 100644 --- a/engines/fullpipe/inventory.cpp +++ b/engines/fullpipe/inventory.cpp @@ -35,7 +35,7 @@ Inventory::~Inventory() { } bool Inventory::load(MfcArchive &file) { - debugC(5, kDebugLoading, "Inventory::load()"); + debugC(5, kDebugLoading | kDebugInventory, "Inventory::load()"); _sceneId = file.readUint16LE(); int numInvs = file.readUint32LE(); @@ -119,12 +119,36 @@ void Inventory2::addItem2(StaticANIObject *obj) { } void Inventory2::removeItem(int itemId, int count) { - warning("STUB: Inventory2::removeItem(%d, %d)", itemId, count); + debugC(2, kDebugInventory, "Inventory2::removeItem(%d, %d)", itemId, count); + + while (count) { + int i; + for (i = _inventoryItems.size() - 1; i >= 0; i--) { + if (_inventoryItems[i]->itemId == itemId) { + if (_selectedId == itemId) + unselectItem(false); + + if (_inventoryItems[i]->count > count) { + _inventoryItems[i]->count -= count; + } else { + count -= _inventoryItems[i]->count; + _inventoryItems.remove_at(i); + } + + if (getCountItemsWithId(itemId) < 0) + getInventoryPoolItemFieldCById(itemId); + + break; + } + } + } } void Inventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) { int idx = getInventoryItemIndexById(itemId); + debugC(2, kDebugInventory, "removeItem2(*, %d, %d, %d, %d)", itemId, x, y, priority); + if (idx >= 0) { if (_inventoryItems[idx]->count) { removeItem(itemId, 1); @@ -187,11 +211,15 @@ int Inventory2::getItemFlags(int itemId) { } void Inventory2::rebuildItemRects() { + debugC(2, kDebugInventory, "rebuildItemRects()"); + _scene = g_fp->accessScene(_sceneId); if (!_scene) return; + _inventoryIcons.clear(); + _picture = _scene->getBigPicture(0, 0); _picture->setAlpha(50); diff --git a/engines/fullpipe/lift.cpp b/engines/fullpipe/lift.cpp index d066c89d4a..93bfbaaa24 100644 --- a/engines/fullpipe/lift.cpp +++ b/engines/fullpipe/lift.cpp @@ -392,7 +392,8 @@ void FullpipeEngine::lift_clickButton() { lift_walkAndGo(); } -void FullpipeEngine::lift_goAnimation() { if (_lastLiftButton) { +void FullpipeEngine::lift_goAnimation() { + if (_lastLiftButton) { int parentId = _currentScene->_sceneId; int buttonId = lift_getButtonIdN(_lastLiftButton->_statics->_staticsId); @@ -428,6 +429,8 @@ void FullpipeEngine::lift_goAnimation() { if (_lastLiftButton) { delete mq; _aniMan->_flags |= 1; + + return; } } } diff --git a/engines/fullpipe/messages.cpp b/engines/fullpipe/messages.cpp index 9085e92832..981797cea2 100644 --- a/engines/fullpipe/messages.cpp +++ b/engines/fullpipe/messages.cpp @@ -61,8 +61,8 @@ bool ExCommand::load(MfcArchive &file) { _parentId = file.readUint16LE(); _messageKind = file.readUint32LE(); - _x = file.readUint32LE(); - _y = file.readUint32LE(); + _x = file.readSint32LE(); + _y = file.readSint32LE(); _field_14 = file.readUint32LE(); _sceneClickX = file.readUint32LE(); _sceneClickY = file.readUint32LE(); diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp index 096323781f..382cdfd688 100644 --- a/engines/fullpipe/modal.cpp +++ b/engines/fullpipe/modal.cpp @@ -309,7 +309,7 @@ bool ModalMap::init(int counterdiff) { _rect2.right = _rect2.left + 800; _rect2.bottom = _rect2.top + 600; - g_fp->_sceneRect =_rect2; + g_fp->_sceneRect = _rect2; _mapScene->updateScrolling2(); @@ -346,17 +346,17 @@ bool ModalMap::handleMessage(ExCommand *cmd) { _mouseX = g_fp->_mouseScreenPos.x; _mouseY = g_fp->_mouseScreenPos.x; - _field_3C = _rect2.top; _field_38 = _rect2.left; + _field_3C = _rect2.top; - break; + return false; case 30: _flag = 0; - break; + return false; case 36: - if (cmd->_keyCode != 9 && cmd->_keyCode != 27 ) + if (cmd->_keyCode != 9 && cmd->_keyCode != 27) return false; break; @@ -431,20 +431,20 @@ PictureObject *ModalMap::getScenePicture() { switch (g_fp->_currentScene->_sceneId) { case SC_1: - picId = PIC_MAP_S01; - break; + picId = PIC_MAP_S01; + break; case SC_2: - picId = PIC_MAP_S02; - break; + picId = PIC_MAP_S02; + break; case SC_3: - picId = PIC_MAP_S03; - break; + picId = PIC_MAP_S03; + break; case SC_4: - picId = PIC_MAP_S04; - break; + picId = PIC_MAP_S04; + break; case SC_5: - picId = PIC_MAP_S05; - break; + picId = PIC_MAP_S05; + break; case SC_6: picId = PIC_MAP_S06; break; @@ -489,7 +489,7 @@ PictureObject *ModalMap::getScenePicture() { picId = PIC_MAP_S20; break; case SC_21: - picId = PIC_MAP_S21; + picId = PIC_MAP_S21; break; case SC_22: picId = PIC_MAP_S22; diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp index d3b29b324a..81d92ccac8 100644 --- a/engines/fullpipe/motion.cpp +++ b/engines/fullpipe/motion.cpp @@ -372,16 +372,16 @@ bool MctlLadder::initMovement(StaticANIObject *ani, MctlLadderMovement *movement if (!v) return false; - v = v->getSubVarByName("Test_Ladder"); + GameVar *l = v->getSubVarByName("Test_Ladder"); - if (!v) + if (!l) return false; movement->staticIdsSize = 6; movement->movVars = new MctlLadderMovementVars; movement->staticIds = new int[movement->staticIdsSize]; - v = v->getSubVarByName("Up"); + v = l->getSubVarByName("Up"); if (!v) return false; @@ -393,7 +393,7 @@ bool MctlLadder::initMovement(StaticANIObject *ani, MctlLadderMovement *movement movement->staticIds[0] = ani->getMovementById(movement->movVars->varUpStart)->_staticsObj1->_staticsId; movement->staticIds[2] = ani->getMovementById(movement->movVars->varUpGo)->_staticsObj1->_staticsId; - v = v->getSubVarByName("Down"); + v = l->getSubVarByName("Down"); if (!v) return false; @@ -1332,9 +1332,9 @@ double MovGraph::putToLink(Common::Point *point, MovGraphLink *link, int fuzzyMa int n2x = link->_graphDst->_x; int n2y = link->_graphDst->_y; double dist1x = (double)(point->x - n1x); - double dist1y = (double)(point->y - n1y); + double dist1y = (double)(n1y - point->y); double dist2x = (double)(n2x - n1x); - double dist2y = (double)(n2y - n1y); + double dist2y = (double)(n1y - n2y); double dist1 = sqrt(dist1x * dist1x + dist1y * dist1y); double dist2 = (dist2y * dist1y + dist2x * dist1x) / link->_length / dist1; double distm = dist2 * dist1; @@ -1355,8 +1355,8 @@ double MovGraph::putToLink(Common::Point *point, MovGraphLink *link, int fuzzyMa return -1.0; } } else { - point->x = (int)(n1x + (dist2x * distm / link->_length)); - point->y = (int)(n1y + (dist2y * distm / link->_length)); + point->x = n1x + (int)((double)(n2x - n1x) * distm / link->_length); + point->y = n1y + (int)((double)(n2y - n1y) * distm / link->_length); } return res; @@ -2476,7 +2476,7 @@ int MctlGraph::getLinkDir(Common::Array<MovGraphLink *> *linkList, int idx, Comm } if (abs(node3->_x - node2->_x) <= abs(node3->_y - node2->_y)) - return (node3->_y < node2->_x) + 2; + return (node3->_y < node2->_y) + 2; else return node3->_x >= node2->_x; } @@ -2918,9 +2918,9 @@ bool MovGraphNode::load(MfcArchive &file) { debugC(5, kDebugLoading, "MovGraphNode::load()"); _field_14 = file.readUint32LE(); - _x = file.readUint32LE(); - _y = file.readUint32LE(); - _z = file.readUint32LE(); + _x = file.readSint32LE(); + _y = file.readSint32LE(); + _z = file.readSint32LE(); return true; } @@ -2937,12 +2937,12 @@ ReactParallel::ReactParallel() { bool ReactParallel::load(MfcArchive &file) { debugC(5, kDebugLoading, "ReactParallel::load()"); - _x1 = file.readUint32LE(); - _y1 = file.readUint32LE(); - _x2 = file.readUint32LE(); - _y2 = file.readUint32LE(); - _dx = file.readUint32LE(); - _dy = file.readUint32LE(); + _x1 = file.readSint32LE(); + _y1 = file.readSint32LE(); + _x2 = file.readSint32LE(); + _y2 = file.readSint32LE(); + _dx = file.readSint32LE(); + _dy = file.readSint32LE(); createRegion(); @@ -2995,8 +2995,8 @@ ReactPolygonal::~ReactPolygonal() { bool ReactPolygonal::load(MfcArchive &file) { debugC(5, kDebugLoading, "ReactPolygonal::load()"); - _centerX = file.readUint32LE(); - _centerY = file.readUint32LE(); + _centerX = file.readSint32LE(); + _centerY = file.readSint32LE(); _pointCount = file.readUint32LE(); if (_pointCount > 0) { diff --git a/engines/fullpipe/objects.h b/engines/fullpipe/objects.h index 1849bcb96e..f9a641d562 100644 --- a/engines/fullpipe/objects.h +++ b/engines/fullpipe/objects.h @@ -61,6 +61,8 @@ struct PicAniInfo { int32 someDynamicPhaseIndex; bool load(MfcArchive &file); + + PicAniInfo() { memset(this, 0, sizeof(PicAniInfo)); } }; union VarValue { diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp index b47988d768..70f5f1aa81 100644 --- a/engines/fullpipe/scene.cpp +++ b/engines/fullpipe/scene.cpp @@ -601,7 +601,7 @@ StaticANIObject *Scene::getStaticANIObjectAtPos(int x, int y) { if ((p->_field_8 & 0x100) && (p->_flags & 4) && p->getPixelAtPos(x, y, &pixel) && - (!res || res->_priority >= p->_priority)) + (!res || res->_priority > p->_priority)) res = p; } diff --git a/engines/fullpipe/scenes/scene03.cpp b/engines/fullpipe/scenes/scene03.cpp index e6c9fa3bbd..e374c87971 100644 --- a/engines/fullpipe/scenes/scene03.cpp +++ b/engines/fullpipe/scenes/scene03.cpp @@ -48,6 +48,8 @@ void FullpipeEngine::setSwallowedEggsState() { } void scene03_initScene(Scene *sc) { + debugC(1, kDebugSceneLogic, "scene03_initScene()"); + g_vars->scene03_eggeater = sc->getStaticANIObject1ById(ANI_EGGEATER, -1); g_vars->scene03_domino = sc->getStaticANIObject1ById(ANI_DOMINO_3, -1); @@ -60,6 +62,9 @@ void scene03_initScene(Scene *sc) { g_fp->lift_setButton(sO_Level2, ST_LBN_2N); g_fp->lift_init(sc, QU_SC3_ENTERLIFT, QU_SC3_EXITLIFT); + + debugC(2, kDebugSceneLogic, "scene03: egg1: %d egg2: %d egg3: %d", g_vars->swallowedEgg1->_value.intValue, + g_vars->swallowedEgg2->_value.intValue, g_vars->swallowedEgg3->_value.intValue); } void scene03_setEaterState() { @@ -90,10 +95,13 @@ void sceneHandler03_eaterFat() { void sceneHandler03_swallowEgg(int item) { if (!g_vars->swallowedEgg1->_value.intValue) { g_vars->swallowedEgg1->_value.intValue = item; + debugC(2, kDebugSceneLogic, "scene03: setting egg1: %d", g_vars->swallowedEgg1->_value.intValue); } else if (!g_vars->swallowedEgg2->_value.intValue) { g_vars->swallowedEgg2->_value.intValue = item; + debugC(2, kDebugSceneLogic, "scene03: setting egg2: %d", g_vars->swallowedEgg2->_value.intValue); } else if (!g_vars->swallowedEgg3->_value.intValue) { g_vars->swallowedEgg3->_value.intValue = item; + debugC(2, kDebugSceneLogic, "scene03: setting egg3: %d", g_vars->swallowedEgg3->_value.intValue); g_fp->setObjectState(sO_EggGulperGaveCoin, g_fp->getObjectEnumState(sO_EggGulperGaveCoin, sO_Yes)); diff --git a/engines/fullpipe/scenes/scene04.cpp b/engines/fullpipe/scenes/scene04.cpp index d901d74289..b6239c219f 100644 --- a/engines/fullpipe/scenes/scene04.cpp +++ b/engines/fullpipe/scenes/scene04.cpp @@ -60,6 +60,10 @@ void scene04_speakerCallback(int *phase) { } } +void scene04_springCallback(int *phase) { + // do nothing +} + void scene04_initScene(Scene *sc) { g_vars->scene04_dudeOnLadder = false; g_vars->scene04_bottle = sc->getPictureObjectById(PIC_SC4_BOTTLE, 0); @@ -127,7 +131,7 @@ void scene04_initScene(Scene *sc) { StaticANIObject *spring = sc->getStaticANIObject1ById(ANI_SPRING, -1); if (spring) - spring->_callback2 = 0; + spring->_callback2 = scene04_springCallback; g_vars->scene04_bottleObjList.clear(); g_vars->scene04_bottleObjList.push_back(sc->getPictureObjectById(PIC_SC4_BOTTLE, 0)); @@ -949,7 +953,8 @@ void sceneHandler04_springWobble() { if (g_vars->scene04_bottleWeight < newdelta) g_vars->scene04_springOffset--; - if ((oldDynIndex <= g_vars->scene04_bottleWeight && newdelta > g_vars->scene04_bottleWeight) || newdelta <= g_vars->scene04_bottleWeight) { + if ((oldDynIndex <= g_vars->scene04_bottleWeight && newdelta > g_vars->scene04_bottleWeight) + || (oldDynIndex > g_vars->scene04_bottleWeight && newdelta <= g_vars->scene04_bottleWeight)) { g_vars->scene04_springDelay++; if (g_vars->scene04_springOffset && g_vars->scene04_springDelay > 1) { diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp index c95f6c67f3..02053aa94e 100644 --- a/engines/fullpipe/stateloader.cpp +++ b/engines/fullpipe/stateloader.cpp @@ -350,8 +350,8 @@ bool PicAniInfo::load(MfcArchive &file) { field_8 = file.readUint32LE(); sceneId = file.readUint16LE(); field_E = file.readUint16LE(); - ox = file.readUint32LE(); - oy = file.readUint32LE(); + ox = file.readSint32LE(); + oy = file.readSint32LE(); priority = file.readUint32LE(); staticsId = file.readUint16LE(); movementId = file.readUint16LE(); diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp index 22be04b393..1f25bfb46e 100644 --- a/engines/fullpipe/statics.cpp +++ b/engines/fullpipe/statics.cpp @@ -108,20 +108,22 @@ bool StepArray::gotoNextPoint() { void StepArray::insertPoints(Common::Point **points, int pointsCount) { if (_currPointIndex + pointsCount >= _pointsCount) { - _points = (Common::Point **)realloc(_points, sizeof(Common::Point *) * (_currPointIndex + pointsCount)); + _points = (Common::Point **)realloc(_points, sizeof(Common::Point *) * (_pointsCount + pointsCount)); if (!_points) { error("Out of memory at StepArray::insertPoints()"); } + + for(int i = 0; i < pointsCount; i++) + _points[_pointsCount + i] = new Common::Point; + + _pointsCount += pointsCount; } _maxPointIndex = _currPointIndex + pointsCount; - for (int i = 0; i < pointsCount; i++) { - _points[_currPointIndex + i] = new Common::Point; - + for (int i = 0; i < pointsCount; i++) *_points[_currPointIndex + i] = *points[i]; - } } StaticANIObject::StaticANIObject() { @@ -831,7 +833,7 @@ void StaticANIObject::update(int counterdiff) { } } - if (dyn->_initialCountdown != dyn->_countdown || dyn->_field_68 == 0) { + if (dyn->_initialCountdown == dyn->_countdown && dyn->_field_68 != 0) { newex = new ExCommand(_id, 17, dyn->_field_68, 0, 0, 0, 1, 0, 0, 0); newex->_excFlags = 2; newex->_keyCode = _okeyCode; @@ -952,7 +954,7 @@ Common::Point *StaticANIObject::calcNextStep(Common::Point *pRes) { } void StaticANIObject::stopAnim_maybe() { - debugC(6, kDebugAnimation, "StaticANIObject::stopAnim_maybe()"); + debugC(2, kDebugAnimation, "StaticANIObject::stopAnim_maybe()"); if (!(_flags & 1)) return; @@ -967,7 +969,10 @@ void StaticANIObject::stopAnim_maybe() { setOXY(_movement->_ox, _movement->_oy); if (_flags & 0x40) { - if (!_movement->_currMovement && !_movement->_currDynamicPhaseIndex) { + if (!_movement->_currMovement) { + if (_movement->_currDynamicPhaseIndex) + goto L11; +L8: _statics = _movement->_staticsObj1; _movement->getCurrDynamicPhaseXY(point); _ox -= point.x; @@ -985,13 +990,14 @@ void StaticANIObject::stopAnim_maybe() { _ox += point.x; _oy += point.y; } - } else { - _statics = _movement->_staticsObj2; + goto L12; } - } else { - _statics = _movement->_staticsObj2; + if (!_movement->_currDynamicPhaseIndex) + goto L8; } - +L11: + _statics = _movement->_staticsObj2; +L12: _statics->getSomeXY(point); _statics->_x = _ox - point.x; @@ -1697,8 +1703,8 @@ bool Movement::load(MfcArchive &file, StaticANIObject *ani) { _staticsObj1 = ani->addReverseStatics(s); } - _mx = file.readUint32LE(); - _my = file.readUint32LE(); + _mx = file.readSint32LE(); + _my = file.readSint32LE(); staticsid = file.readUint16LE(); @@ -1709,8 +1715,8 @@ bool Movement::load(MfcArchive &file, StaticANIObject *ani) { _staticsObj2 = ani->addReverseStatics(s); } - _m2x = file.readUint32LE(); - _m2y = file.readUint32LE(); + _m2x = file.readSint32LE(); + _m2y = file.readSint32LE(); if (_staticsObj2) { _dynamicPhases.push_back(_staticsObj2); @@ -2148,11 +2154,17 @@ void Movement::gotoFirstFrame() { void Movement::gotoLastFrame() { if (_currMovement) { - while ((uint)_currDynamicPhaseIndex != _currMovement->_dynamicPhases.size() - 1) - gotoNextFrame(0, 0); + if ((uint)_currDynamicPhaseIndex != _currMovement->_dynamicPhases.size() - 1) { + do { + gotoNextFrame(0, 0); + } while ((uint)_currDynamicPhaseIndex != _currMovement->_dynamicPhases.size() - 1); + } } else { - while ((uint)_currDynamicPhaseIndex != _dynamicPhases.size() - 1) - gotoNextFrame(0, 0); + if ((uint)_currDynamicPhaseIndex != _dynamicPhases.size() - 1) { + do { + gotoNextFrame(0, 0); + } while ((uint)_currDynamicPhaseIndex != _dynamicPhases.size() - 1); + } } } @@ -2261,17 +2273,17 @@ bool DynamicPhase::load(MfcArchive &file) { _field_7C = file.readUint16LE(); _rect = new Common::Rect(); - _rect->left = file.readUint32LE(); - _rect->top = file.readUint32LE(); - _rect->right = file.readUint32LE(); - _rect->bottom = file.readUint32LE(); + _rect->left = file.readSint32LE(); + _rect->top = file.readSint32LE(); + _rect->right = file.readSint32LE(); + _rect->bottom = file.readSint32LE(); - assert (g_fp->_gameProjectVersion >= 1); + assert(g_fp->_gameProjectVersion >= 1); - _someX = file.readUint32LE(); - _someY = file.readUint32LE(); + _someX = file.readSint32LE(); + _someY = file.readSint32LE(); - assert (g_fp->_gameProjectVersion >= 12); + assert(g_fp->_gameProjectVersion >= 12); _dynFlags = file.readUint32LE(); diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp index a8e00468b5..148f779d1e 100644 --- a/engines/fullpipe/utils.cpp +++ b/engines/fullpipe/utils.cpp @@ -84,7 +84,7 @@ bool DWordArray::load(MfcArchive &file) { resize(count); for (int i = 0; i < count; i++) { - int32 t = file.readUint32LE(); + int32 t = file.readSint32LE(); push_back(t); } diff --git a/engines/kyra/animator_tim.cpp b/engines/kyra/animator_tim.cpp index 1d65ba7b1a..b1cfc6a6a8 100644 --- a/engines/kyra/animator_tim.cpp +++ b/engines/kyra/animator_tim.cpp @@ -202,6 +202,9 @@ void TimAnimator::playPart(int animIndex, int firstFrame, int lastFrame, int del return; Animation *anim = &_animations[animIndex]; + // WORKAROUND for some bugged scripts that will try to play invalid animations + if (!anim->wsa) + return; int step = (lastFrame >= firstFrame) ? 1 : -1; for (int i = firstFrame; i != (lastFrame + step); i += step) { diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp index 156f6f51f7..8cecd8c82c 100644 --- a/engines/sci/engine/file.cpp +++ b/engines/sci/engine/file.cpp @@ -200,7 +200,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u #ifdef ENABLE_SCI32 if (mode != _K_FILE_MODE_OPEN_OR_FAIL && ( - (g_sci->getGameId() == GID_PHANTASMAGORIA && filename == "phantsg.dir") || + (g_sci->getGameId() == GID_PHANTASMAGORIA && (filename == "phantsg.dir" || filename == "chase.dat")) || (g_sci->getGameId() == GID_PQSWAT && filename == "swat.dat"))) { debugC(kDebugLevelFile, " -> file_open opening %s for rewriting", wrappedName.c_str()); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index b6c35dca73..6e141e7f3b 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -183,8 +183,8 @@ static const SciKernelMapSubEntry kDoSound_subops[] = { }; #ifdef ENABLE_SCI32 -// NOTE: In SSCI, some 'unused' kDoAudio subops are actually -// called indirectly by kDoSound: +// NOTE: In SSCI, some 'unused' kDoAudio subops are actually called indirectly +// by kDoSound: // // kDoSoundGetAudioCapability -> kDoAudioGetCapability // kDoSoundPlay -> kDoAudioPlay, kDoAudioStop @@ -194,23 +194,26 @@ static const SciKernelMapSubEntry kDoSound_subops[] = { // kDoSoundSetLoop -> kDoAudioSetLoop // kDoSoundUpdateCues -> kDoAudioPosition // -// In ScummVM, logic inside these kernel functions has been -// moved to methods of Audio32, and direct calls to Audio32 -// are made from kDoSound instead. +// In ScummVM, logic inside these kernel functions has been moved to methods of +// Audio32, and direct calls to Audio32 are made from kDoSound instead. // -// Some kDoAudio methods are esoteric and appear to be used -// only by one or two games: +// Some kDoAudio methods are esoteric and appear to be used only by one or two +// games: // -// kDoAudioMixing: Phantasmagoria (other games call this -// function, but only to disable the feature) -// kDoAudioHasSignal: SQ6 TalkRandCycle -// kDoAudioPan: Rama RegionSFX::pan method +// - kDoAudioMixing: Phantasmagoria (other games call this function, but only +// to disable the feature) +// - kDoAudioHasSignal: SQ6 TalkRandCycle +// - kDoAudioPan: Rama RegionSFX::pan method +// - kDoAudioCritical: Phantasmagoria, chapter 3, nursery (room 14200), during +// the "ghost lullaby" event. It is used to make the +// lullaby sound exclusive, but it really doesn't make any +// major difference. Returning 0 means "non-critical", i.e. +// normal audio behavior. // -// Finally, there is a split in SCI2.1mid audio code. -// QFG4CD & SQ6 do not have opcodes 18 and 19, but they -// exist in GK2, KQ7 2.00b, Phantasmagoria 1, PQ:SWAT, and -// Torin. (It is unknown if they exist in MUMG Deluxe or -// Shivers 1; they are not used in either of these games.) +// Finally, there is a split in SCI2.1mid audio code. QFG4CD & SQ6 do not have +// opcodes 18 and 19, but they exist in GK2, KQ7 2.00b, Phantasmagoria 1, +// PQ:SWAT, and Torin. It is unknown if they exist in MUMG Deluxe or Shivers 1; +// they are not used in either of these games. // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kDoAudio_subops[] = { @@ -235,7 +238,7 @@ static const SciKernelMapSubEntry kDoAudio_subops[] = { { SIG_SINCE_SCI21MID, 15, MAP_CALL(DoAudioFade), "(iiii)(i)(i)", NULL }, { SIG_SINCE_SCI21MID, 16, MAP_DUMMY(DoAudioFade36), "iiiii(iii)(i)", NULL }, { SIG_SINCE_SCI21MID, 17, MAP_CALL(DoAudioHasSignal), "", NULL }, - { SIG_SINCE_SCI21MID, 18, MAP_EMPTY(DoAudioCritical), "", NULL }, + { SIG_SINCE_SCI21MID, 18, MAP_EMPTY(DoAudioCritical), "(i)", NULL }, { SIG_SINCE_SCI21MID, 19, MAP_CALL(DoAudioSetLoop), "iii(o)", NULL }, { SIG_SCI3, 20, MAP_DUMMY(DoAudioPan), "", NULL }, { SIG_SCI3, 21, MAP_DUMMY(DoAudioPanOff), "", NULL }, @@ -377,7 +380,7 @@ static const SciKernelMapSubEntry kText_subops[] = { // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kBitmap_subops[] = { { SIG_SINCE_SCI21, 0, MAP_CALL(BitmapCreate), "iiii(i)(i)(i)", NULL }, - { SIG_SINCE_SCI21, 1, MAP_CALL(BitmapDestroy), "r", NULL }, + { SIG_SINCE_SCI21, 1, MAP_CALL(BitmapDestroy), "[r!]", NULL }, { SIG_SINCE_SCI21, 2, MAP_CALL(BitmapDrawLine), "riiiii(i)(i)", NULL }, { SIG_SINCE_SCI21, 3, MAP_CALL(BitmapDrawView), "riii(i)(i)(0)(i)(i)", NULL }, { SIG_SINCE_SCI21, 4, MAP_CALL(BitmapDrawText), "rriiiiiiiiiii", NULL }, @@ -502,7 +505,7 @@ static const SciKernelMapSubEntry kString_subops[] = { { SIG_SCI32, 0, MAP_CALL(StringNew), "i(i)", NULL }, { SIG_SCI32, 1, MAP_CALL(StringSize), "[or]", NULL }, { SIG_SCI32, 2, MAP_CALL(StringAt), "[or]i", NULL }, - { SIG_SCI32, 3, MAP_CALL(StringPutAt), "[or]i(i*)", NULL }, + { SIG_SCI32, 3, MAP_CALL(StringPutAt), "[or]i(i*)", kStringPutAt_workarounds }, // StringFree accepts invalid references { SIG_SCI32, 4, MAP_CALL(StringFree), "[or0!]", NULL }, { SIG_SCI32, 5, MAP_CALL(StringFill), "[or]ii", NULL }, @@ -812,7 +815,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, { MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, - { "DisposeTextBitmap", kBitmapDestroy, SIG_SCI2, SIGFOR_ALL, "r", NULL, NULL }, + { "DisposeTextBitmap", kBitmapDestroy, SIG_SCI2, SIGFOR_ALL, "[r!]", NULL, NULL }, { MAP_CALL(FrameOut), SIG_EVERYWHERE, "(i)", NULL, NULL }, { MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL }, { MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL }, diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index e5b0aaf47a..e8b9d0461d 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -632,6 +632,15 @@ reg_t kFileIORename(EngineState *s, int argc, reg_t *argv) { Common::String oldName = s->_segMan->getString(argv[0]); Common::String newName = s->_segMan->getString(argv[1]); + // We don't fully implement all cases that could occur here, and + // assume the file to be renamed is a wrapped filename. + // Known usage: In Phant1 and KQ7 while deleting savegames. + // The scripts rewrite the dir file as a temporary file, and then + // rename it to the actual dir file. + + oldName = g_sci->wrapFilename(oldName); + newName = g_sci->wrapFilename(newName); + // SCI1.1 returns 0 on success and a DOS error code on fail. SCI32 // returns -1 on fail. We just return -1 for all versions. if (g_sci->getSaveFileManager()->renameSavefile(oldName, newName)) diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index f3eec59eaf..a33fcf3167 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -647,7 +647,16 @@ reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) { } reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) { - s->_segMan->freeBitmap(argv[0]); + const reg_t &addr = argv[0]; + const SegmentObj *const segment = s->_segMan->getSegmentObj(addr.getSegment()); + + if (segment != nullptr && + segment->getType() == SEG_TYPE_BITMAP && + segment->isValidOffset(addr.getOffset())) { + + s->_segMan->freeBitmap(addr); + } + return s->r_acc; } @@ -907,7 +916,7 @@ reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv) { */ reg_t kPaletteSetGamma(EngineState *s, int argc, reg_t *argv) { const uint8 gamma = argv[0].toUint16(); - assert(gamma >= 0 && gamma <= 6); + assert(gamma <= 6); warning("TODO: kPaletteSetGamma(%d)", gamma); diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index eeddda8390..be2d7660cb 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -427,6 +427,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) { if (getSciVersion() >= SCI_VERSION_2) { g_sci->_gfxPalette32->saveLoadWithSerializer(s); g_sci->_gfxRemap32->saveLoadWithSerializer(s); + g_sci->_gfxCursor32->saveLoadWithSerializer(s); } else #endif g_sci->_gfxPalette16->saveLoadWithSerializer(s); @@ -892,11 +893,15 @@ void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) { } void GfxCursor32::saveLoadWithSerializer(Common::Serializer &s) { - if (s.getVersion() < 37) { + if (s.getVersion() < 38) { return; } - s.syncAsSint32LE(_hideCount); + int32 hideCount; + if (s.isSaving()) { + hideCount = _hideCount; + } + s.syncAsSint32LE(hideCount); s.syncAsSint16LE(_restrictedArea.left); s.syncAsSint16LE(_restrictedArea.top); s.syncAsSint16LE(_restrictedArea.right); @@ -908,8 +913,10 @@ void GfxCursor32::saveLoadWithSerializer(Common::Serializer &s) { if (s.isLoading()) { hide(); setView(_cursorInfo.resourceId, _cursorInfo.loopNo, _cursorInfo.celNo); - if (!_hideCount) { + if (!hideCount) { show(); + } else { + _hideCount = hideCount; } } } diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index 51dbbedd87..6616081a20 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -37,7 +37,8 @@ struct EngineState; * * Version - new/changed feature * ============================= - * 37 - Segment entry data changed to pointers, SCI32 cursor + * 38 - SCI32 cursor + * 37 - Segment entry data changed to pointers * 36 - SCI32 bitmap segment * 35 - SCI32 remap * 34 - SCI32 palettes, and store play time in ticks @@ -62,7 +63,7 @@ struct EngineState; */ enum { - CURRENT_SAVEGAME_VERSION = 37, + CURRENT_SAVEGAME_VERSION = 38, MINIMUM_SAVEGAME_VERSION = 14 }; diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index e6eed0b4b7..d45c689985 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -746,12 +746,115 @@ static const uint16 gk1PatchInterrogationBug[] = { PATCH_END }; -// script, description, signature patch +// On day 10 nearly at the end of the game, Gabriel Knight dresses up and right after that +// someone will be at the door. Gabriel turns around to see what's going on. +// +// In ScummVM Gabriel turning around plays endlessly. This is caused by the loop of Gabriel +// being kept at 1, but view + cel were changed accordingly. The view used - which is view 859 - +// does not have a loop 1. kNumCels is called on that, BUT kNumCels in SSCI is broken in that +// regard. It checks for loop > count and not loop >= count and will return basically random data +// in case loop == count. +// +// In SSCI this simply worked by accident. kNumCels returned 0x53 in this case, but later script code +// fixed that up somehow, so it worked out in the end. +// +// The setup for this is done in SDJEnters::changeState(0). The cycler will never reach the goal +// because the goal will be cel -1, so it loops endlessly. +// +// We fix this by adding a setLoop(0). +// +// Applies to at least: English PC-CD, German PC-CD +// Responsible method: sDJEnters::changeState +static const uint16 gk1SignatureDay10GabrielDressUp[] = { + 0x87, 0x01, // lap param[1] + 0x65, 0x14, // aTop state + 0x36, // push + 0x3c, // dup + 0x35, 0x00, // ldi 0 + 0x1a, // eq? + 0x30, SIG_UINT16(0x006f), // bnt [next state 1] + SIG_ADDTOOFFSET(+84), + 0x39, 0x0e, // pushi 0Eh (view) + 0x78, // push1 + SIG_MAGICDWORD, + 0x38, SIG_UINT16(0x035B), // pushi 035Bh (859d) + 0x38, SIG_UINT16(0x0141), // pushi 0141h (setCel) + 0x78, // push1 + 0x76, // push0 + 0x38, SIG_UINT16(0x00E9), // pushi 00E9h (setCycle) + 0x7a, // push2 + 0x51, 0x18, // class End + 0x36, // push + 0x7c, // pushSelf + 0x81, 0x00, // lag global[0] + 0x4a, 0x14, 0x00, // send 14h + // GKEgo::view(859) + // GKEgo::setCel(0) + // GKEgo::setCycle(End, sDJEnters) + 0x32, SIG_UINT16(0x0233), // jmp [ret] + // next state + 0x3c, // dup + 0x35, 0x01, // ldi 01 + 0x1a, // eq? + 0x31, 0x07, // bnt [next state 2] + 0x35, 0x02, // ldi 02 + 0x65, 0x1a, // aTop cycles + 0x32, SIG_UINT16(0x0226), // jmp [ret] + // next state + 0x3c, // dup + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, 0x2a, // bnt [next state 3] + 0x78, // push1 + SIG_ADDTOOFFSET(+34), + // part of state 2 code, delays for 1 cycle + 0x35, 0x01, // ldi 1 + 0x65, 0x1a, // aTop cycles + SIG_END +}; + +static const uint16 gk1PatchDay10GabrielDressUp[] = { + PATCH_ADDTOOFFSET(+9), + 0x30, SIG_UINT16(0x0073), // bnt [next state 1] - offset adjusted + SIG_ADDTOOFFSET(+84 + 11), + // added by us: setting loop to 0 (5 bytes needed) + 0x38, SIG_UINT16(0x00FB), // pushi 00FBh (setLoop) + 0x78, // push1 + 0x76, // push0 + // original code, but offset changed + 0x38, SIG_UINT16(0x00E9), // pushi 00E9h (setCycle) + 0x7a, // push2 + 0x51, 0x18, // class End + 0x36, // push + 0x7c, // pushSelf + 0x81, 0x00, // lag global[0] + 0x4a, 0x1a, 0x00, // send 1Ah - adjusted + // GKEgo::view(859) + // GKEgo::setCel(0) + // GKEgo::setLoop(0) <-- new, by us + // GKEgo::setCycle(End, sDJEnters) + // end of original code + 0x3a, // toss + 0x48, // ret (saves 1 byte) + // state 1 code + 0x3c, // dup + 0x34, SIG_UINT16(0x0001), // ldi 0001 (waste 1 byte) + 0x1a, // eq? + 0x31, 2, // bnt [next state 2] + 0x33, 41, // jmp to state 2 delay code + SIG_ADDTOOFFSET(+41), + // wait 2 cycles instead of only 1 + 0x35, 0x02, // ldi 2 + PATCH_END +}; + +// script, description, signature patch static const SciScriptPatcherEntry gk1Signatures[] = { - { true, 51, "interrogation bug", 1, gk1SignatureInterrogationBug, gk1PatchInterrogationBug }, - { true, 212, "day 5 phone freeze", 1, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, - { true, 230, "day 6 police beignet timer issue", 1, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, - { true, 230, "day 6 police sleep timer issue", 1, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, + { true, 51, "interrogation bug", 1, gk1SignatureInterrogationBug, gk1PatchInterrogationBug }, + { true, 212, "day 5 phone freeze", 1, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, + { true, 230, "day 6 police beignet timer issue", 1, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, + { true, 230, "day 6 police sleep timer issue", 1, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, + { true, 808, "day 10 gabriel dress up infinite turning", 1, gk1SignatureDay10GabrielDressUp, gk1PatchDay10GabrielDressUp }, SCI_SIGNATUREENTRY_TERMINATOR }; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 8e0a90079c..7aaea0902a 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -767,6 +767,11 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = { }; // gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround +const SciWorkaroundEntry kStringPutAt_workarounds[] = { + { GID_PHANTASMAGORIA,902, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // When starting a new game from after chapter 1, the game tries to save ego's object in a string +}; + +// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround const SciWorkaroundEntry kScrollWindowAdd_workarounds[] = { { GID_PHANTASMAGORIA, 45, 64907, 0, "ScrollableWindow", "addString", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // ScrollWindow interface passes the last two parameters twice }; diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h index f2b2e55ef6..2cccd05475 100644 --- a/engines/sci/engine/workarounds.h +++ b/engines/sci/engine/workarounds.h @@ -100,6 +100,7 @@ extern const SciWorkaroundEntry kStrAt_workarounds[]; extern const SciWorkaroundEntry kStrCpy_workarounds[]; extern const SciWorkaroundEntry kStrLen_workarounds[]; extern const SciWorkaroundEntry kUnLoad_workarounds[]; +extern const SciWorkaroundEntry kStringPutAt_workarounds[]; extern const SciWorkaroundEntry kScrollWindowAdd_workarounds[]; extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin); diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp index d053fa2eef..d67a4dc03c 100644 --- a/engines/sci/graphics/celobj32.cpp +++ b/engines/sci/graphics/celobj32.cpp @@ -872,7 +872,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int _scaledWidth = READ_SCI11ENDIAN_UINT16(data + 14); _scaledHeight = READ_SCI11ENDIAN_UINT16(data + 16); - if (_scaledWidth == 0 || _scaledHeight == 0) { + if (_scaledWidth == 0 && _scaledHeight == 0) { byte sizeFlag = data[5]; if (sizeFlag == 0) { _scaledWidth = kLowResX; @@ -894,7 +894,7 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int // NOTE: This is the actual check, in the actual location, // from SCI engine. if (loopNo < 0) { - error("Loop is less than 0!"); + error("Loop is less than 0"); } const uint16 viewHeaderSize = READ_SCI11ENDIAN_UINT16(data); @@ -916,8 +916,17 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int _info.celNo = celCount - 1; } - if (_info.celNo < 0) { - error("Cel is less than 0!"); + // A celNo can be negative and still valid. At least PQ4CD uses this strange + // arrangement to load its high-resolution main menu resource. In PQ4CD, the + // low-resolution menu is at view 23, loop 9, cel 0, and the high-resolution + // menu is at view 2300, loop 0, cel 0. View 2300 is specially crafted to + // have 2 loops, with the second loop having 0 cels. When in high-resolution + // mode, the game scripts only change the view resource ID from 23 to 2300, + // leaving loop 9 and cel 0 the same. The code in CelObjView constructor + // auto-corrects loop 9 to loop 1, and then auto-corrects the cel number + // from 0 to -1, which effectively causes loop 0, cel 0 to be read. + if (_info.celNo < 0 && _info.loopNo == 0) { + error("Cel is less than 0 on loop 0"); } _hunkPaletteOffset = READ_SCI11ENDIAN_UINT32(data + 8); diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index f81d50946b..11572581ff 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -211,12 +211,12 @@ void GfxText32::drawChar(const char charIndex) { SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap); byte *pixels = bitmap.getPixels(); - _font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height); - _drawPosition.x += _font->getCharWidth(charIndex); + _font->drawToBuffer((unsigned char)charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height); + _drawPosition.x += _font->getCharWidth((unsigned char)charIndex); } uint16 GfxText32::getCharWidth(const char charIndex, const bool doScaling) const { - uint16 width = _font->getCharWidth(charIndex); + uint16 width = _font->getCharWidth((unsigned char)charIndex); if (doScaling) { width = scaleUpWidth(width); } diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 900dabe05a..86c0cffe15 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -923,14 +923,19 @@ Common::String SciEngine::getFilePrefix() const { } Common::String SciEngine::wrapFilename(const Common::String &name) const { - return getFilePrefix() + "-" + name; + Common::String prefix = getFilePrefix() + "-"; + if (name.hasPrefix(prefix.c_str())) + return name; + else + return prefix + name; } Common::String SciEngine::unwrapFilename(const Common::String &name) const { Common::String prefix = getFilePrefix() + "-"; if (name.hasPrefix(prefix.c_str())) return Common::String(name.c_str() + prefix.size()); - return name; + else + return name; } const char *SciEngine::getGameObjectName() { diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index f3354f9e44..1757088ea4 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -533,7 +533,6 @@ void RobotDecoder::initRecordAndCuePositions() { void RobotDecoder::open(const GuiResourceId robotId, const reg_t plane, const int16 priority, const int16 x, const int16 y, const int16 scale) { if (_status != kRobotStatusUninitialized) { - warning("Last robot was not closed"); close(); } diff --git a/engines/titanic/carry/bridge_piece.cpp b/engines/titanic/carry/bridge_piece.cpp index fc845feff0..6a22df3243 100644 --- a/engines/titanic/carry/bridge_piece.cpp +++ b/engines/titanic/carry/bridge_piece.cpp @@ -55,14 +55,14 @@ bool CBridgePiece::UseWithOtherMsg(CUseWithOtherMsg *msg) { CShipSetting *shipSetting = static_cast<CShipSetting *>(msg->_other); if (!shipSetting) { return CCarry::UseWithOtherMsg(msg); - } else if (shipSetting->_string4 == "NULL") { + } else if (shipSetting->_itemName != "NULL") { petAddToInventory(); return true; } else { setVisible(false); playSound("z#54.wav", 100, 0, 0); setPosition(shipSetting->_pos1); - shipSetting->_string4 = getName(); + shipSetting->_itemName = getName(); petMoveToHiddenRoom(); CAddHeadPieceMsg headpieceMsg(shipSetting->getName() == _string6 ? diff --git a/engines/titanic/carry/carry.h b/engines/titanic/carry/carry.h index fb5519e290..06e446a1b5 100644 --- a/engines/titanic/carry/carry.h +++ b/engines/titanic/carry/carry.h @@ -44,7 +44,6 @@ class CCarry : public CGameObject { bool EnterViewMsg(CEnterViewMsg *msg); bool PassOnDragStartMsg(CPassOnDragStartMsg *msg); protected: - CString _string1; int _fieldDC; CString _string3; CString _string4; @@ -59,6 +58,7 @@ protected: bool _enterFrameSet; int _visibleFrame; public: + CString _string1; int _fieldE0; Point _origPos; CString _fullViewName; diff --git a/engines/titanic/carry/glass.h b/engines/titanic/carry/glass.h index 85443840a1..608d45cb66 100644 --- a/engines/titanic/carry/glass.h +++ b/engines/titanic/carry/glass.h @@ -35,7 +35,7 @@ class CGlass : public CCarry { bool MouseDragEndMsg(CMouseDragEndMsg *msg); bool TurnOn(CTurnOn *msg); bool TurnOff(CTurnOff *msg); -private: +public: CString _string6; public: CLASSDEF; diff --git a/engines/titanic/carry/maitred_left_arm.cpp b/engines/titanic/carry/maitred_left_arm.cpp index b31c2a6f6d..0962f232bd 100644 --- a/engines/titanic/carry/maitred_left_arm.cpp +++ b/engines/titanic/carry/maitred_left_arm.cpp @@ -21,19 +21,48 @@ */ #include "titanic/carry/maitred_left_arm.h" +#include "titanic/npcs/true_talk_npc.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMaitreDLeftArm, CArm) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + void CMaitreDLeftArm::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_field174, indent); + file->writeNumberLine(_flag, indent); CArm::save(file, indent); } void CMaitreDLeftArm::load(SimpleFile *file) { file->readNumber(); - _field174 = file->readNumber(); + _flag = file->readNumber(); CArm::load(file); } +bool CMaitreDLeftArm::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (!_flag) { + CTrueTalkNPC *maitreD = dynamic_cast<CTrueTalkNPC *>(findRoomObject("MaitreD")); + startTalking(maitreD, 126); + startTalking(maitreD, 127); + } + + return true; +} + +bool CMaitreDLeftArm::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (checkPoint(msg->_mousePos) && !_flag) { + CVisibleMsg visibleMsg; + visibleMsg.execute("MD left arm background image"); + _flag = true; + + CArmPickedUpFromTableMsg takenMsg; + takenMsg.execute("Restaurant Table Pan Handler", nullptr, MSGFLAG_SCAN); + } + + return CArm::MouseDragStartMsg(msg); +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/maitred_left_arm.h b/engines/titanic/carry/maitred_left_arm.h index 8f5090b073..0e1732df46 100644 --- a/engines/titanic/carry/maitred_left_arm.h +++ b/engines/titanic/carry/maitred_left_arm.h @@ -28,11 +28,14 @@ namespace Titanic { class CMaitreDLeftArm : public CArm { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); private: - int _field174; + bool _flag; public: CLASSDEF; - CMaitreDLeftArm() : CArm(), _field174(0) {} + CMaitreDLeftArm() : CArm(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/carry/maitred_right_arm.cpp b/engines/titanic/carry/maitred_right_arm.cpp index 7030e83c9d..5cec6be9bd 100644 --- a/engines/titanic/carry/maitred_right_arm.cpp +++ b/engines/titanic/carry/maitred_right_arm.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMaitreDRightArm, CArm) + ON_MESSAGE(DropZoneLostObjectMsg) +END_MESSAGE_MAP() + void CMaitreDRightArm::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CArm::save(file, indent); @@ -34,4 +38,12 @@ void CMaitreDRightArm::load(SimpleFile *file) { CArm::load(file); } +bool CMaitreDRightArm::DropZoneLostObjectMsg(CDropZoneLostObjectMsg *msg) { + CActMsg actMsg("LoseArm"); + actMsg.execute("MaitreDBody"); + actMsg.execute("MaitreD Arm Holder"); + _fieldE0 = 1; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/maitred_right_arm.h b/engines/titanic/carry/maitred_right_arm.h index ce07ed7af4..4a53d45f69 100644 --- a/engines/titanic/carry/maitred_right_arm.h +++ b/engines/titanic/carry/maitred_right_arm.h @@ -28,6 +28,8 @@ namespace Titanic { class CMaitreDRightArm : public CArm { + DECLARE_MESSAGE_MAP; + bool DropZoneLostObjectMsg(CDropZoneLostObjectMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/carry/mouth.cpp b/engines/titanic/carry/mouth.cpp index 8c3791fa9c..e48929a391 100644 --- a/engines/titanic/carry/mouth.cpp +++ b/engines/titanic/carry/mouth.cpp @@ -21,9 +21,16 @@ */ #include "titanic/carry/mouth.h" +#include "titanic/game/head_slot.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMouth, CHeadPiece) + ON_MESSAGE(UseWithOtherMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(PETGainedObjectMsg) +END_MESSAGE_MAP() + CMouth::CMouth() : CHeadPiece() { } @@ -37,4 +44,37 @@ void CMouth::load(SimpleFile *file) { CHeadPiece::load(file); } +bool CMouth::UseWithOtherMsg(CUseWithOtherMsg *msg) { + CHeadSlot *slot = dynamic_cast<CHeadSlot *>(msg->_other); + if (!slot) + return CHeadPiece::UseWithOtherMsg(msg); + + _flag = true; + setVisible(false); + setPosition(Point(0, 0)); + petMoveToHiddenRoom(); + + CAddHeadPieceMsg addMsg(getName()); + if (addMsg._value != "NULL") + addMsg.execute("MouthSlot"); + + return true; +} + +bool CMouth::MovieEndMsg(CMovieEndMsg *msg) { + return true; +} + +bool CMouth::PETGainedObjectMsg(CPETGainedObjectMsg *msg) { + _visibleFrame = 2; + loadFrame(2); + setVisible(true); + if (!_field13C) { + stateInc38(); + _field13C = true; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/mouth.h b/engines/titanic/carry/mouth.h index e394330494..f5f0f53b45 100644 --- a/engines/titanic/carry/mouth.h +++ b/engines/titanic/carry/mouth.h @@ -28,6 +28,10 @@ namespace Titanic { class CMouth : public CHeadPiece { + DECLARE_MESSAGE_MAP; + bool UseWithOtherMsg(CUseWithOtherMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool PETGainedObjectMsg(CPETGainedObjectMsg *msg); public: CLASSDEF; CMouth(); diff --git a/engines/titanic/carry/napkin.cpp b/engines/titanic/carry/napkin.cpp index ace5a389a0..d25e8b5975 100644 --- a/engines/titanic/carry/napkin.cpp +++ b/engines/titanic/carry/napkin.cpp @@ -57,5 +57,4 @@ bool CNapkin::UseWithOtherMsg(CUseWithOtherMsg *msg) { return CCarry::UseWithOtherMsg(msg); } - } // End of namespace Titanic diff --git a/engines/titanic/carry/nose.cpp b/engines/titanic/carry/nose.cpp index 4f3afe24ac..a08d02a88c 100644 --- a/engines/titanic/carry/nose.cpp +++ b/engines/titanic/carry/nose.cpp @@ -21,9 +21,15 @@ */ #include "titanic/carry/nose.h" +#include "titanic/game/head_slot.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CNose, CHeadPiece) + ON_MESSAGE(ChangeSeasonMsg) + ON_MESSAGE(UseWithOtherMsg) +END_MESSAGE_MAP() + CNose::CNose() : CHeadPiece() { } @@ -37,4 +43,23 @@ void CNose::load(SimpleFile *file) { CHeadPiece::load(file); } +bool CNose::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + // WORKAROUND: Redundant code in original skipped + return true; +} + +bool CNose::UseWithOtherMsg(CUseWithOtherMsg *msg) { + CHeadSlot *slot = dynamic_cast<CHeadSlot *>(msg->_other); + if (!slot) + return CCarry::UseWithOtherMsg(msg); + + petMoveToHiddenRoom(); + _flag = false; + CAddHeadPieceMsg addMsg(getName()); + if (addMsg._value != "NULL") + addMsg.execute("NoseSlot"); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/nose.h b/engines/titanic/carry/nose.h index b688da231a..6e5be30df2 100644 --- a/engines/titanic/carry/nose.h +++ b/engines/titanic/carry/nose.h @@ -28,6 +28,9 @@ namespace Titanic { class CNose : public CHeadPiece { + DECLARE_MESSAGE_MAP; + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); + bool UseWithOtherMsg(CUseWithOtherMsg *msg); public: CLASSDEF; CNose(); diff --git a/engines/titanic/carry/perch.cpp b/engines/titanic/carry/perch.cpp index 281b3fce53..4f0e76bdb0 100644 --- a/engines/titanic/carry/perch.cpp +++ b/engines/titanic/carry/perch.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPerch, CCentralCore) + ON_MESSAGE(UseWithOtherMsg) +END_MESSAGE_MAP() + void CPerch::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CCentralCore::save(file, indent); @@ -34,4 +38,13 @@ void CPerch::load(SimpleFile *file) { CCentralCore::load(file); } +bool CPerch::UseWithOtherMsg(CUseWithOtherMsg *msg) { + if (msg->_other->isEquals("SpeechCentre")) { + CShowTextMsg textMsg("This does not reach."); + textMsg.execute("PET"); + } + + return CCentralCore::UseWithOtherMsg(msg); +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/perch.h b/engines/titanic/carry/perch.h index d23868d909..8941c8ea4d 100644 --- a/engines/titanic/carry/perch.h +++ b/engines/titanic/carry/perch.h @@ -28,6 +28,8 @@ namespace Titanic { class CPerch : public CCentralCore { + DECLARE_MESSAGE_MAP; + bool UseWithOtherMsg(CUseWithOtherMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/carry/phonograph_cylinder.cpp b/engines/titanic/carry/phonograph_cylinder.cpp index 0684c56611..41df050d2b 100644 --- a/engines/titanic/carry/phonograph_cylinder.cpp +++ b/engines/titanic/carry/phonograph_cylinder.cpp @@ -22,6 +22,7 @@ #include "titanic/carry/phonograph_cylinder.h" #include "titanic/game/phonograph.h" +#include "titanic/sound/music_room.h" namespace Titanic { @@ -162,10 +163,33 @@ bool CPhonographCylinder::RecordOntoCylinderMsg(CRecordOntoCylinderMsg *msg) { } bool CPhonographCylinder::SetMusicControlsMsg(CSetMusicControlsMsg *msg) { - if (_itemName.left(7) == "STMusic") { - //todo - warning("TODO"); - } + if (!_itemName.hasPrefix("STMusic")) + return true; + + CMusicRoom *musicRoom = getMusicRoom(); + musicRoom->setItem5(BELLS, _bellsMuteControl); + musicRoom->setItem2(BELLS, _bellsPitchControl); + musicRoom->setItem1(BELLS, _bellsSpeedControl); + musicRoom->setItem4(BELLS, _bellsInversionControl); + musicRoom->setItem3(BELLS, _bellsDirectionControl); + + musicRoom->setItem5(SNAKE, _snakeMuteControl); + musicRoom->setItem2(SNAKE, _snakePitchControl); + musicRoom->setItem1(SNAKE, _snakeSpeedControl); + musicRoom->setItem4(SNAKE, _snakeInversionControl); + musicRoom->setItem3(SNAKE, _snakeDirectionControl); + + musicRoom->setItem5(PIANO, _pianoMuteControl); + musicRoom->setItem2(PIANO, _pianoPitchControl); + musicRoom->setItem1(PIANO, _pianoSpeedControl); + musicRoom->setItem4(PIANO, _pianoInversionControl); + musicRoom->setItem3(PIANO, _pianoDirectionControl); + + musicRoom->setItem5(BASS, _bassMuteControl); + musicRoom->setItem2(BASS, _bassPitchControl); + musicRoom->setItem1(BASS, _bassSpeedControl); + musicRoom->setItem4(BASS, _bassInversionControl); + musicRoom->setItem3(BASS, _bassDirectionControl); return true; } diff --git a/engines/titanic/carry/photograph.cpp b/engines/titanic/carry/photograph.cpp index 7f32a0623d..039efd0252 100644 --- a/engines/titanic/carry/photograph.cpp +++ b/engines/titanic/carry/photograph.cpp @@ -21,6 +21,7 @@ */ #include "titanic/carry/photograph.h" +#include "titanic/core/dont_save_file_item.h" #include "titanic/core/room_item.h" namespace Titanic { @@ -59,8 +60,12 @@ bool CPhotograph::MouseDragEndMsg(CMouseDragEndMsg *msg) { _v1 = 0; CGameObject *target = msg->_dropTarget; - if (target && target->getName() != "NavigationComputer") { - warning("TODO: CPhotograph::MouseDragEndMsg"); + if (target && target->isEquals("NavigationComputer")) { + moveUnder(getDontSave()); + makeDirty(); + playSound("a#46.wav"); + starFn1(14); + showMouse(); return true; } else { return CCarry::MouseDragEndMsg(msg); @@ -78,7 +83,7 @@ bool CPhotograph::MouseDragStartMsg(CMouseDragStartMsg *msg) { } bool CPhotograph::PETGainedObjectMsg(CPETGainedObjectMsg *msg) { - if (getRoom()->getName() == "Home") { + if (getRoom()->isEquals("Home")) { CActMsg actMsg("PlayerPutsPhotoInPET"); actMsg.execute("Doorbot"); } diff --git a/engines/titanic/carry/plug_in.cpp b/engines/titanic/carry/plug_in.cpp index c82a4cc422..883458c9b1 100644 --- a/engines/titanic/carry/plug_in.cpp +++ b/engines/titanic/carry/plug_in.cpp @@ -47,19 +47,13 @@ bool CPlugIn::UseWithOtherMsg(CUseWithOtherMsg *msg) { if (otherName == "PET") { return CCarry::UseWithOtherMsg(msg); - } else if (otherName == "DatasideTransporter") { - CString name = getName(); - if (name == "DatasideTransporter") { - // TODO - if (name != "SendYourself") { - // TODO - } - } else { - // TODO - } - } else { + } else if (isEquals("DatasideTransporter")) { CShowTextMsg textMsg("This item is incorrectly calibrated."); textMsg.execute("PET"); + } else if (isEquals("DatasideTransporter")) { + error("TODO: Set msg->_other->fieldC4 = 2"); + } else if (isEquals("SendYourself")) { + error("TODO: Set msg->_other->fieldC8 = 1"); } return true; diff --git a/engines/titanic/carry/speech_centre.cpp b/engines/titanic/carry/speech_centre.cpp index b8076aee76..29ced484a5 100644 --- a/engines/titanic/carry/speech_centre.cpp +++ b/engines/titanic/carry/speech_centre.cpp @@ -24,10 +24,17 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSpeechCentre, CBrain) + ON_MESSAGE(PuzzleSolvedMsg) + ON_MESSAGE(ChangeSeasonMsg) + ON_MESSAGE(SpeechFallsFromTreeMsg) + ON_MESSAGE(FrameMsg) +END_MESSAGE_MAP() + void CSpeechCentre::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_field13C, indent); - file->writeQuotedLine(_string1, indent); + file->writeQuotedLine(_season, indent); file->writeNumberLine(_field14C, indent); CBrain::save(file, indent); @@ -36,10 +43,41 @@ void CSpeechCentre::save(SimpleFile *file, int indent) { void CSpeechCentre::load(SimpleFile *file) { file->readNumber(); _field13C = file->readNumber(); - _string1 = file->readString(); + _season = file->readString(); _field14C = file->readNumber(); CBrain::load(file); } +bool CSpeechCentre::PuzzleSolvedMsg(CPuzzleSolvedMsg *msg) { + if (_field13C == 1 && _season == "Autumn") + _fieldE0 = true; + return true; +} + +bool CSpeechCentre::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + _season = msg->_season; + return true; +} + +bool CSpeechCentre::SpeechFallsFromTreeMsg(CSpeechFallsFromTreeMsg *msg) { + setVisible(true); + dragMove(msg->_pos); + _field14C = true; + return true; +} + +bool CSpeechCentre::FrameMsg(CFrameMsg *msg) { + if (_field14C) { + if (_bounds.top > 200) + _field14C = false; + + makeDirty(); + _bounds.top += 3; + makeDirty(); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/speech_centre.h b/engines/titanic/carry/speech_centre.h index 50f47e9c8a..806e22247b 100644 --- a/engines/titanic/carry/speech_centre.h +++ b/engines/titanic/carry/speech_centre.h @@ -28,13 +28,18 @@ namespace Titanic { class CSpeechCentre : public CBrain { + DECLARE_MESSAGE_MAP; + bool PuzzleSolvedMsg(CPuzzleSolvedMsg *msg); + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); + bool SpeechFallsFromTreeMsg(CSpeechFallsFromTreeMsg *msg); + bool FrameMsg(CFrameMsg *msg); private: int _field13C; - CString _string1; + CString _season; int _field14C; public: CLASSDEF; - CSpeechCentre() : CBrain(), _string1("Summer"), + CSpeechCentre() : CBrain(), _season("Summer"), _field13C(1), _field14C(0) {} /** diff --git a/engines/titanic/carry/vision_centre.cpp b/engines/titanic/carry/vision_centre.cpp index 8c8bab15f8..fd30089fc5 100644 --- a/engines/titanic/carry/vision_centre.cpp +++ b/engines/titanic/carry/vision_centre.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CVisionCentre, CBrain) + ON_MESSAGE(PuzzleSolvedMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + void CVisionCentre::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBrain::save(file, indent); @@ -34,4 +40,27 @@ void CVisionCentre::load(SimpleFile *file) { CBrain::load(file); } +bool CVisionCentre::PuzzleSolvedMsg(CPuzzleSolvedMsg *msg) { + _fieldE0 = true; + return true; +} + +bool CVisionCentre::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_fieldE0) { + return CBrain::MouseButtonDownMsg(msg); + } else { + petDisplayMessage(1, "It would be nice if you could take that but you can't."); + return true; + } +} + +bool CVisionCentre::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (_fieldE0) { + return CBrain::MouseDragStartMsg(msg); + } else { + petDisplayMessage(1, "It would be nice if you could take that but you can't."); + return true; + } +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/vision_centre.h b/engines/titanic/carry/vision_centre.h index 6cf8e2c653..14055a5f5f 100644 --- a/engines/titanic/carry/vision_centre.h +++ b/engines/titanic/carry/vision_centre.h @@ -28,6 +28,10 @@ namespace Titanic { class CVisionCentre : public CBrain { + DECLARE_MESSAGE_MAP; + bool PuzzleSolvedMsg(CPuzzleSolvedMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/core/drop_target.h b/engines/titanic/core/drop_target.h index 8c497b6bc2..e07b640c9f 100644 --- a/engines/titanic/core/drop_target.h +++ b/engines/titanic/core/drop_target.h @@ -34,7 +34,7 @@ class CDropTarget : public CGameObject { bool EnterViewMsg(CEnterViewMsg *msg); bool VisibleMsg(CVisibleMsg *msg); bool DropZoneLostObjectMsg(CDropZoneLostObjectMsg *msg); -private: +protected: Point _pos1; int _itemFrame; CString _itemMatchName; diff --git a/engines/titanic/core/game_object.cpp b/engines/titanic/core/game_object.cpp index 3126aac228..2c7b7db998 100644 --- a/engines/titanic/core/game_object.cpp +++ b/engines/titanic/core/game_object.cpp @@ -1025,12 +1025,12 @@ void CGameObject::moveToView(const CString &name) { addUnder(view); } -void CGameObject::stateInc14() { - getGameManager()->_gameState.inc14(); +void CGameObject::stateChangeSeason() { + getGameManager()->_gameState.changeSeason(); } -int CGameObject::stateGet14() const { - return getGameManager()->_gameState._field14; +Season CGameObject::stateGetSeason() const { + return getGameManager()->_gameState._seasonNum; } void CGameObject::stateSet24() { @@ -1066,7 +1066,7 @@ void CGameObject::setMovieFrameRate(double rate) { _surface->setMovieFrameRate(rate); } -void CGameObject::setTextBorder(const CString &str, int border, int borderRight) { +void CGameObject::setText(const CString &str, int border, int borderRight) { if (!_text) _text = new CPetText(); _textBorder = border; @@ -1160,8 +1160,8 @@ void CGameObject::mouseUnlockE4() { CScreenManager::_screenManagerPtr->_mouseCursor->unlockE4(); } -void CGameObject::mouseSaveState(int v1, int v2, int v3) { - CScreenManager::_screenManagerPtr->_mouseCursor->saveState(v1, v2, v3); +void CGameObject::mouseSetPosition(const Point &pt, double rate) { + CScreenManager::_screenManagerPtr->_mouseCursor->setPosition(pt, rate); } void CGameObject::lockInputHandler() { diff --git a/engines/titanic/core/game_object.h b/engines/titanic/core/game_object.h index cafd96e38e..182d165e89 100644 --- a/engines/titanic/core/game_object.h +++ b/engines/titanic/core/game_object.h @@ -33,6 +33,7 @@ #include "titanic/core/named_item.h" #include "titanic/pet_control/pet_section.h" #include "titanic/pet_control/pet_text.h" +#include "titanic/game_state.h" namespace Titanic { @@ -165,7 +166,10 @@ protected: void mouseLockE4(); void mouseUnlockE4(); - void mouseSaveState(int v1, int v2, int v3); + /** + * Sets the mouse to a new position + */ + void mouseSetPosition(const Point &pt, double rate); /** * Lock the input handler @@ -349,7 +353,7 @@ protected: /** * Play an arbitrary clip */ - void playClip(const CString &name, uint flags); + void playClip(const CString &name, uint flags = 0); /** * Play a clip @@ -364,7 +368,7 @@ protected: /** * Play a clip randomly from a passed list of names */ - void playRandomClip(const char *const *names, uint flags); + void playRandomClip(const char *const *names, uint flags = 0); /** * Return the current view/node/room as a single string @@ -491,9 +495,9 @@ protected: void setMovieFrameRate(double rate); /** - * Set up the text borders for the object + * Set up the text and borders for the object */ - void setTextBorder(const CString &str, int border = 0, int borderRight = 0); + void setText(const CString &str, int border = 0, int borderRight = 0); /** * Sets whether the text will use borders @@ -941,8 +945,17 @@ public: /*--- CGameState Methods ---*/ void setState1C(bool flag); - void stateInc14(); - int stateGet14() const; + + /** + * Change to the next season + */ + void stateChangeSeason(); + + /** + * Returns the currently active season + */ + Season stateGetSeason() const; + void stateSet24(); int stateGet24() const; void stateInc38(); diff --git a/engines/titanic/core/multi_drop_target.cpp b/engines/titanic/core/multi_drop_target.cpp index f2998199b1..b95696577f 100644 --- a/engines/titanic/core/multi_drop_target.cpp +++ b/engines/titanic/core/multi_drop_target.cpp @@ -21,9 +21,14 @@ */ #include "titanic/core/multi_drop_target.h" +#include "titanic/support/string_parser.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMultiDropTarget, CDropTarget) + ON_MESSAGE(DropObjectMsg) +END_MESSAGE_MAP() + void CMultiDropTarget::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeQuotedLine(_string5, indent); @@ -40,4 +45,20 @@ void CMultiDropTarget::load(SimpleFile *file) { CDropTarget::load(file); } +bool CMultiDropTarget::DropObjectMsg(CDropObjectMsg *msg) { + CStringParser parser1(_string5); + CStringParser parser2(_string6); + CString seperatorChars = ","; + + while (parser2.parse(_itemMatchName, seperatorChars)) { + _dropFrame = parser1.readInt(); + CDropTarget::DropObjectMsg(msg); + + parser1.skipSeperators(seperatorChars); + parser2.skipSeperators(seperatorChars); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/core/multi_drop_target.h b/engines/titanic/core/multi_drop_target.h index c004b9bece..ab552f96e1 100644 --- a/engines/titanic/core/multi_drop_target.h +++ b/engines/titanic/core/multi_drop_target.h @@ -28,6 +28,8 @@ namespace Titanic { class CMultiDropTarget : public CDropTarget { + DECLARE_MESSAGE_MAP; + bool DropObjectMsg(CDropObjectMsg *msg); public: CString _string5; CString _string6; diff --git a/engines/titanic/core/saveable_object.cpp b/engines/titanic/core/saveable_object.cpp index 5fc2d7e738..db3249c107 100644 --- a/engines/titanic/core/saveable_object.cpp +++ b/engines/titanic/core/saveable_object.cpp @@ -165,6 +165,8 @@ #include "titanic/game/music_room_stop_phonograph_button.h" #include "titanic/game/music_system_lock.h" #include "titanic/game/nav_helmet.h" +#include "titanic/game/nav_helmet_on.h" +#include "titanic/game/nav_helmet_off.h" #include "titanic/game/navigation_computer.h" #include "titanic/game/no_nut_bowl.h" #include "titanic/game/nose_holder.h" @@ -250,7 +252,7 @@ #include "titanic/game/pickup/pick_up_vis_centre.h" #include "titanic/game/placeholder/bar_shelf_vis_centre.h" #include "titanic/game/placeholder/lemon_on_bar.h" -#include "titanic/game/placeholder/place_holder_item.h" +#include "titanic/game/placeholder/place_holder.h" #include "titanic/game/placeholder/tv_on_bar.h" #include "titanic/game/sgt/armchair.h" #include "titanic/game/sgt/basin.h" @@ -284,7 +286,6 @@ #include "titanic/gfx/chev_right_off.h" #include "titanic/gfx/chev_right_on.h" #include "titanic/gfx/chev_send_rec_switch.h" -#include "titanic/gfx/chev_switch.h" #include "titanic/gfx/edit_control.h" #include "titanic/gfx/elevator_button.h" #include "titanic/gfx/get_from_succ.h" @@ -575,6 +576,8 @@ DEFFN(CMusicRoomPhonograph); DEFFN(CMusicRoomStopPhonographButton); DEFFN(CMusicSystemLock); DEFFN(CNavHelmet); +DEFFN(CNavHelmetOn); +DEFFN(CNavHelmetOff); DEFFN(CNavigationComputer); DEFFN(CNoNutBowl); DEFFN(CNoseHolder); @@ -665,7 +668,7 @@ DEFFN(CPickUpSpeechCentre); DEFFN(CPickUpVisCentre); DEFFN(CBarShelfVisCentre); DEFFN(CLemonOnBar); -DEFFN(CPlaceHolderItem); +DEFFN(CPlaceHolder); DEFFN(CTVOnBar); DEFFN(CArmchair); DEFFN(CBasin); @@ -701,7 +704,6 @@ DEFFN(CChevLeftOn); DEFFN(CChevRightOff); DEFFN(CChevRightOn); DEFFN(CChevSendRecSwitch); -DEFFN(CChevSwitch); DEFFN(CEditControl); DEFFN(CElevatorButton); DEFFN(CGetFromSucc); @@ -1162,6 +1164,8 @@ void CSaveableObject::initClassList() { ADDFN(CMusicRoomStopPhonographButton, CEjectPhonographButton); ADDFN(CMusicSystemLock, CDropTarget); ADDFN(CNavHelmet, CGameObject); + ADDFN(CNavHelmetOn, CGameObject); + ADDFN(CNavHelmetOff, CGameObject); ADDFN(CNavigationComputer, CGameObject); ADDFN(CNoNutBowl, CBackground); ADDFN(CNoseHolder, CDropTarget); @@ -1245,10 +1249,10 @@ void CSaveableObject::initClassList() { ADDFN(CPickUpLemon, CPickUp); ADDFN(CPickUpSpeechCentre, CPickUp); ADDFN(CPickUpVisCentre, CPickUp); - ADDFN(CBarShelfVisCentre, CPlaceHolderItem); - ADDFN(CLemonOnBar, CPlaceHolderItem); - ADDFN(CPlaceHolderItem, CGameObject); - ADDFN(CTVOnBar, CPlaceHolderItem); + ADDFN(CBarShelfVisCentre, CPlaceHolder); + ADDFN(CLemonOnBar, CPlaceHolder); + ADDFN(CPlaceHolder, CGameObject); + ADDFN(CTVOnBar, CPlaceHolder); ADDFN(CArmchair, CSGTStateRoom); ADDFN(CBasin, CSGTStateRoom); ADDFN(CBedfoot, CSGTStateRoom); @@ -1283,7 +1287,6 @@ void CSaveableObject::initClassList() { ADDFN(CChevRightOff, CToggleSwitch); ADDFN(CChevRightOn, CToggleSwitch); ADDFN(CChevSendRecSwitch, CToggleSwitch); - ADDFN(CChevSwitch, CToggleSwitch); ADDFN(CEditControl, CGameObject); ADDFN(CElevatorButton, CSTButton); ADDFN(CGetFromSucc, CToggleSwitch); diff --git a/engines/titanic/core/tree_item.cpp b/engines/titanic/core/tree_item.cpp index 870ee38016..86c34cab8b 100644 --- a/engines/titanic/core/tree_item.cpp +++ b/engines/titanic/core/tree_item.cpp @@ -34,7 +34,7 @@ #include "titanic/core/room_item.h" #include "titanic/pet_control/pet_control.h" #include "titanic/game_manager.h" -#include "titanic/game/placeholder/place_holder_item.h" +#include "titanic/game/placeholder/place_holder.h" namespace Titanic { @@ -96,7 +96,7 @@ bool CTreeItem::isLinkItem() const { } bool CTreeItem::isPlaceHolderItem() const { - return isInstanceOf(CPlaceHolderItem::_type); + return isInstanceOf(CPlaceHolder::_type); } bool CTreeItem::isNamedItem() const { diff --git a/engines/titanic/core/turn_on_play_sound.cpp b/engines/titanic/core/turn_on_play_sound.cpp index 2f9dba24a6..ab50b33134 100644 --- a/engines/titanic/core/turn_on_play_sound.cpp +++ b/engines/titanic/core/turn_on_play_sound.cpp @@ -24,26 +24,37 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CTurnOnPlaySound, CTurnOnObject) + ON_MESSAGE(MouseButtonUpMsg) +END_MESSAGE_MAP() + CTurnOnPlaySound::CTurnOnPlaySound() : CTurnOnObject(), - _string3("NULL"), _fieldF8(80), _fieldFC(0) { + _soundName("NULL"), _soundVolume(80), _soundVal3(0) { } void CTurnOnPlaySound::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string3, indent); - file->writeNumberLine(_fieldF8, indent); - file->writeNumberLine(_fieldFC, indent); + file->writeQuotedLine(_soundName, indent); + file->writeNumberLine(_soundVolume, indent); + file->writeNumberLine(_soundVal3, indent); CTurnOnObject::save(file, indent); } void CTurnOnPlaySound::load(SimpleFile *file) { file->readNumber(); - _string3 = file->readString(); - _fieldF8 = file->readNumber(); - _fieldFC = file->readNumber(); + _soundName = file->readString(); + _soundVolume = file->readNumber(); + _soundVal3 = file->readNumber(); CTurnOnObject::load(file); } +bool CTurnOnPlaySound::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + if (_soundName != "NULL") + playSound(_soundName, _soundVolume, _soundVal3); + + return CTurnOnObject::MouseButtonUpMsg(msg); +} + } // End of namespace Titanic diff --git a/engines/titanic/core/turn_on_play_sound.h b/engines/titanic/core/turn_on_play_sound.h index 1164135071..29a25a5665 100644 --- a/engines/titanic/core/turn_on_play_sound.h +++ b/engines/titanic/core/turn_on_play_sound.h @@ -28,10 +28,12 @@ namespace Titanic { class CTurnOnPlaySound : public CTurnOnObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); private: - CString _string3; - int _fieldF8; - int _fieldFC; + CString _soundName; + int _soundVolume; + int _soundVal3; public: CLASSDEF; CTurnOnPlaySound(); diff --git a/engines/titanic/core/turn_on_turn_off.cpp b/engines/titanic/core/turn_on_turn_off.cpp index d43ddf7038..6498c226a0 100644 --- a/engines/titanic/core/turn_on_turn_off.cpp +++ b/engines/titanic/core/turn_on_turn_off.cpp @@ -24,16 +24,21 @@ namespace Titanic { -CTurnOnTurnOff::CTurnOnTurnOff() : CBackground(), _fieldE0(0), - _fieldE4(0), _fieldE8(0), _fieldEC(0), _fieldF0(0) { +BEGIN_MESSAGE_MAP(CTurnOnTurnOff, CBackground) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) +END_MESSAGE_MAP() + +CTurnOnTurnOff::CTurnOnTurnOff() : CBackground(), _startFrameOn(0), + _endFrameOn(0), _startFrameOff(0), _endFrameOff(0), _fieldF0(false) { } void CTurnOnTurnOff::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); - file->writeNumberLine(_fieldE8, indent); - file->writeNumberLine(_fieldEC, indent); + file->writeNumberLine(_startFrameOn, indent); + file->writeNumberLine(_endFrameOn, indent); + file->writeNumberLine(_startFrameOff, indent); + file->writeNumberLine(_endFrameOff, indent); file->writeNumberLine(_fieldF0, indent); CBackground::save(file, indent); @@ -41,13 +46,37 @@ void CTurnOnTurnOff::save(SimpleFile *file, int indent) { void CTurnOnTurnOff::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); - _fieldE8 = file->readNumber(); - _fieldEC = file->readNumber(); + _startFrameOn = file->readNumber(); + _endFrameOn = file->readNumber(); + _startFrameOff = file->readNumber(); + _endFrameOff = file->readNumber(); _fieldF0 = file->readNumber(); CBackground::load(file); } +bool CTurnOnTurnOff::TurnOn(CTurnOn *msg) { + if (!_fieldF0) { + if (_fieldDC) + playMovie(_startFrameOn, _endFrameOn, MOVIE_GAMESTATE); + else + playMovie(_startFrameOn, _endFrameOn, MOVIE_NOTIFY_OBJECT); + _fieldF0 = true; + } + + return true; +} + +bool CTurnOnTurnOff::TurnOff(CTurnOff *msg) { + if (!_fieldF0) { + if (_fieldDC) + playMovie(_startFrameOff, _endFrameOff, MOVIE_GAMESTATE); + else + playMovie(_startFrameOff, _endFrameOff, MOVIE_NOTIFY_OBJECT); + _fieldF0 = true; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/core/turn_on_turn_off.h b/engines/titanic/core/turn_on_turn_off.h index adca6876ff..c09f0e0d7d 100644 --- a/engines/titanic/core/turn_on_turn_off.h +++ b/engines/titanic/core/turn_on_turn_off.h @@ -28,12 +28,15 @@ namespace Titanic { class CTurnOnTurnOff : public CBackground { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); private: - int _fieldE0; - int _fieldE4; - int _fieldE8; - int _fieldEC; - int _fieldF0; + int _startFrameOn; + int _endFrameOn; + int _startFrameOff; + int _endFrameOff; + bool _fieldF0; public: CLASSDEF; CTurnOnTurnOff(); diff --git a/engines/titanic/game/arboretum_gate.cpp b/engines/titanic/game/arboretum_gate.cpp index 4c3ca03b7a..1435e3e204 100644 --- a/engines/titanic/game/arboretum_gate.cpp +++ b/engines/titanic/game/arboretum_gate.cpp @@ -21,7 +21,6 @@ */ #include "titanic/game/arboretum_gate.h" -#include "titanic/game/seasonal_adjustment.h" namespace Titanic { @@ -45,30 +44,30 @@ CArboretumGate::CArboretumGate() : CBackground() { _viewName2 = "NULL"; _seasonNum = 0; _fieldF0 = 0; - _winterOffStartFrame = 244; - _winterOffEndFrame = 304; - _springOffStartFrame = 122; - _springOffEndFrame = 182; - _summerOffStartFrame1 = 183; - _summerOffEndFrame1 = 243; - _summerOffStartFrame2 = 665; - _summerOffEndFrame2 = 724; - _autumnOffStartFrame1 = 61; - _autumnOffEndFrame1 = 121; - _autumnOffStartFrame2 = 0; - _autumnOffEndFrame2 = 60; - _winterOnStartFrame = 485; - _winterOnEndFrame = 544; - _springOnStartFrame = 425; - _springOnEndFrame = 484; - _summerOnStartFrame1 = 545; - _summerOnEndFrame1 = 604; - _summerOnStartFrame2 = 605; - _summerOnEndFrame2 = 664; - _autumnOnStartFrame1 = 305; - _autumnOnEndFrame1 = 364; - _autumnOnStartFrame2 = 365; - _autumnOnEndFrame2 = 424; + _startFrameSpringOff = 244; + _endFrameSpringOff = 304; + _startFrameSummerOff = 122; + _endFrameSummerOff = 182; + _startFrameAutumnOff1 = 183; + _endFrameAutumnOff1 = 243; + _startFrameAutumnOff2 = 665; + _endFrameAutumnOff2 = 724; + _startFrameWinterOff1 = 61; + _endFrameWinterOff1 = 121; + _startFrameWinterOff2 = 0; + _endFrameWinterOff2 = 60; + _startFrameSpringOn = 485; + _endFrameSpringOn = 544; + _startFrameSummerOn = 425; + _endFrameSummerOn = 484; + _startFrameAutumnOn1 = 545; + _endFrameAutumnOn1 = 604; + _startFrameAutumnOn2 = 605; + _endFrameAutumnOn2 = 664; + _startFrameWinterOn1 = 305; + _endFrameWinterOn1 = 364; + _startFrameWinterOn2 = 365; + _endFrameWinterOn2 = 424; } void CArboretumGate::save(SimpleFile *file, int indent) { @@ -79,30 +78,30 @@ void CArboretumGate::save(SimpleFile *file, int indent) { file->writeNumberLine(_v3, indent); file->writeQuotedLine(_viewName1, indent); file->writeNumberLine(_fieldF0, indent); - file->writeNumberLine(_winterOffStartFrame, indent); - file->writeNumberLine(_winterOffEndFrame, indent); - file->writeNumberLine(_springOffStartFrame, indent); - file->writeNumberLine(_springOffEndFrame, indent); - file->writeNumberLine(_summerOffStartFrame1, indent); - file->writeNumberLine(_summerOffEndFrame1, indent); - file->writeNumberLine(_summerOffStartFrame2, indent); - file->writeNumberLine(_summerOffEndFrame2, indent); - file->writeNumberLine(_autumnOffStartFrame1, indent); - file->writeNumberLine(_autumnOffEndFrame1, indent); - file->writeNumberLine(_autumnOffStartFrame2, indent); - file->writeNumberLine(_autumnOffEndFrame2, indent); - file->writeNumberLine(_winterOnStartFrame, indent); - file->writeNumberLine(_winterOnEndFrame, indent); - file->writeNumberLine(_springOnStartFrame, indent); - file->writeNumberLine(_springOnEndFrame, indent); - file->writeNumberLine(_summerOnStartFrame1, indent); - file->writeNumberLine(_summerOnEndFrame1, indent); - file->writeNumberLine(_summerOnStartFrame2, indent); - file->writeNumberLine(_summerOnEndFrame2, indent); - file->writeNumberLine(_autumnOnStartFrame1, indent); - file->writeNumberLine(_autumnOnEndFrame1, indent); - file->writeNumberLine(_autumnOnStartFrame2, indent); - file->writeNumberLine(_autumnOnEndFrame2, indent); + file->writeNumberLine(_startFrameSpringOff, indent); + file->writeNumberLine(_endFrameSpringOff, indent); + file->writeNumberLine(_startFrameSummerOff, indent); + file->writeNumberLine(_endFrameSummerOff, indent); + file->writeNumberLine(_startFrameAutumnOff1, indent); + file->writeNumberLine(_endFrameAutumnOff1, indent); + file->writeNumberLine(_startFrameAutumnOff2, indent); + file->writeNumberLine(_endFrameAutumnOff2, indent); + file->writeNumberLine(_startFrameWinterOff1, indent); + file->writeNumberLine(_endFrameWinterOff1, indent); + file->writeNumberLine(_startFrameWinterOff2, indent); + file->writeNumberLine(_endFrameWinterOff2, indent); + file->writeNumberLine(_startFrameSpringOn, indent); + file->writeNumberLine(_endFrameSpringOn, indent); + file->writeNumberLine(_startFrameSummerOn, indent); + file->writeNumberLine(_endFrameSummerOn, indent); + file->writeNumberLine(_startFrameAutumnOn1, indent); + file->writeNumberLine(_endFrameAutumnOn1, indent); + file->writeNumberLine(_startFrameAutumnOn2, indent); + file->writeNumberLine(_endFrameAutumnOn2, indent); + file->writeNumberLine(_startFrameWinterOn1, indent); + file->writeNumberLine(_endFrameWinterOn1, indent); + file->writeNumberLine(_startFrameWinterOn2, indent); + file->writeNumberLine(_endFrameWinterOn2, indent); file->writeQuotedLine(_viewName2, indent); CBackground::save(file, indent); @@ -116,30 +115,30 @@ void CArboretumGate::load(SimpleFile *file) { _v3 = file->readNumber(); _viewName1 = file->readString(); _fieldF0 = file->readNumber(); - _winterOffStartFrame = file->readNumber(); - _winterOffEndFrame = file->readNumber(); - _springOffStartFrame = file->readNumber(); - _springOffEndFrame = file->readNumber(); - _summerOffStartFrame1 = file->readNumber(); - _summerOffEndFrame1 = file->readNumber(); - _summerOffStartFrame2 = file->readNumber(); - _summerOffEndFrame2 = file->readNumber(); - _autumnOffStartFrame1 = file->readNumber(); - _autumnOffEndFrame1 = file->readNumber(); - _autumnOffStartFrame2 = file->readNumber(); - _autumnOffEndFrame2 = file->readNumber(); - _winterOnStartFrame = file->readNumber(); - _winterOnEndFrame = file->readNumber(); - _springOnStartFrame = file->readNumber(); - _springOnEndFrame = file->readNumber(); - _summerOnStartFrame1 = file->readNumber(); - _summerOnEndFrame1 = file->readNumber(); - _summerOnStartFrame2 = file->readNumber(); - _summerOnEndFrame2 = file->readNumber(); - _autumnOnStartFrame1 = file->readNumber(); - _autumnOnEndFrame1 = file->readNumber(); - _autumnOnStartFrame2 = file->readNumber(); - _autumnOnEndFrame2 = file->readNumber(); + _startFrameSpringOff = file->readNumber(); + _endFrameSpringOff = file->readNumber(); + _startFrameSummerOff = file->readNumber(); + _endFrameSummerOff = file->readNumber(); + _startFrameAutumnOff1 = file->readNumber(); + _endFrameAutumnOff1 = file->readNumber(); + _startFrameAutumnOff2 = file->readNumber(); + _endFrameAutumnOff2 = file->readNumber(); + _startFrameWinterOff1 = file->readNumber(); + _endFrameWinterOff1 = file->readNumber(); + _startFrameWinterOff2 = file->readNumber(); + _endFrameWinterOff2 = file->readNumber(); + _startFrameSpringOn = file->readNumber(); + _endFrameSpringOn = file->readNumber(); + _startFrameSummerOn = file->readNumber(); + _endFrameSummerOn = file->readNumber(); + _startFrameAutumnOn1 = file->readNumber(); + _endFrameAutumnOn1 = file->readNumber(); + _startFrameAutumnOn2 = file->readNumber(); + _endFrameAutumnOn2 = file->readNumber(); + _startFrameWinterOn1 = file->readNumber(); + _endFrameWinterOn1 = file->readNumber(); + _startFrameWinterOn2 = file->readNumber(); + _endFrameWinterOn2 = file->readNumber(); _viewName2 = file->readString(); CBackground::load(file); @@ -213,28 +212,28 @@ bool CArboretumGate::LeaveViewMsg(CLeaveViewMsg *msg) { bool CArboretumGate::TurnOff(CTurnOff *msg) { if (!_v3) { switch (_seasonNum) { - case SPRING: - playMovie(_springOffStartFrame, _springOffEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + case SEASON_SUMMER: + playMovie(_startFrameSummerOff, _endFrameSummerOff, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); break; - case SUMMER: + case SEASON_AUTUMN: if (_v1) { - playMovie(_summerOffStartFrame2, _summerOffEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameAutumnOff2, _endFrameAutumnOff2, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } else { - playMovie(_summerOffStartFrame1, _summerOffEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameAutumnOff1, _endFrameAutumnOff1, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } break; - case AUTUMN: + case SEASON_WINTER: if (_v1) { - playMovie(_autumnOffStartFrame2, _autumnOffEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameWinterOff2, _endFrameWinterOff2, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } else { - playMovie(_autumnOffStartFrame1, _autumnOffEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameWinterOff1, _endFrameWinterOff1, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } break; - case WINTER: - playMovie(_winterOffStartFrame, _winterOffEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + case SEASON_SPRING: + playMovie(_startFrameSpringOff, _endFrameSpringOff, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); break; default: @@ -256,28 +255,28 @@ bool CArboretumGate::TurnOn(CTurnOn *msg) { setVisible(true); switch (_seasonNum) { - case SPRING: - playMovie(_springOnStartFrame, _springOnEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + case SEASON_SUMMER: + playMovie(_startFrameSummerOn, _endFrameSummerOn, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); break; - case SUMMER: + case SEASON_AUTUMN: if (_v1) { - playMovie(_summerOnStartFrame2, _summerOnEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameAutumnOn2, _endFrameAutumnOn2, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } else { - playMovie(_summerOnStartFrame1, _summerOnEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameAutumnOn1, _endFrameAutumnOn1, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } break; - case AUTUMN: + case SEASON_WINTER: if (_v1) { - playMovie(_autumnOnStartFrame2, _autumnOnEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameWinterOn2, _endFrameWinterOn2, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } else { - playMovie(_autumnOnStartFrame1, _autumnOnEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(_startFrameWinterOn1, _endFrameWinterOn1, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); } break; - case WINTER: - playMovie(_winterOnStartFrame, _winterOnEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + case SEASON_SPRING: + playMovie(_startFrameSpringOn, _endFrameSpringOn, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); break; default: @@ -302,20 +301,20 @@ bool CArboretumGate::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { bool CArboretumGate::EnterViewMsg(CEnterViewMsg *msg) { if (!_v3) { switch (_seasonNum) { - case SPRING: - _initialFrame = _springOffStartFrame; + case SEASON_SUMMER: + _initialFrame = _startFrameSummerOff; break; - case SUMMER: - _initialFrame = _v1 ? _summerOffStartFrame2 : _summerOffStartFrame1; + case SEASON_AUTUMN: + _initialFrame = _v1 ? _startFrameAutumnOff2 : _startFrameAutumnOff1; break; - case AUTUMN: - _initialFrame = _v1 ? _autumnOffStartFrame1 : _autumnOffStartFrame2; + case SEASON_WINTER: + _initialFrame = _v1 ? _startFrameWinterOff1 : _startFrameWinterOff2; break; - case WINTER: - _initialFrame = _winterOffStartFrame; + case SEASON_SPRING: + _initialFrame = _startFrameSpringOff; break; default: diff --git a/engines/titanic/game/arboretum_gate.h b/engines/titanic/game/arboretum_gate.h index 62c9200a64..b1c06cf773 100644 --- a/engines/titanic/game/arboretum_gate.h +++ b/engines/titanic/game/arboretum_gate.h @@ -47,30 +47,30 @@ private: int _seasonNum; CString _viewName1; int _fieldF0; - int _winterOffStartFrame; - int _winterOffEndFrame; - int _springOffStartFrame; - int _springOffEndFrame; - int _summerOffStartFrame2; - int _summerOffEndFrame2; - int _summerOffStartFrame1; - int _summerOffEndFrame1; - int _autumnOffStartFrame2; - int _autumnOffEndFrame2; - int _autumnOffStartFrame1; - int _autumnOffEndFrame1; - int _winterOnStartFrame; - int _winterOnEndFrame; - int _springOnStartFrame; - int _springOnEndFrame; - int _summerOnStartFrame1; - int _summerOnEndFrame1; - int _summerOnStartFrame2; - int _summerOnEndFrame2; - int _autumnOnStartFrame1; - int _autumnOnEndFrame1; - int _autumnOnStartFrame2; - int _autumnOnEndFrame2; + int _startFrameSpringOff; + int _endFrameSpringOff; + int _startFrameSummerOff; + int _endFrameSummerOff; + int _startFrameAutumnOff2; + int _endFrameAutumnOff2; + int _startFrameAutumnOff1; + int _endFrameAutumnOff1; + int _startFrameWinterOff2; + int _endFrameWinterOff2; + int _startFrameWinterOff1; + int _endFrameWinterOff1; + int _startFrameSpringOn; + int _endFrameSpringOn; + int _startFrameSummerOn; + int _endFrameSummerOn; + int _startFrameAutumnOn1; + int _endFrameAutumnOn1; + int _startFrameAutumnOn2; + int _endFrameAutumnOn2; + int _startFrameWinterOn1; + int _endFrameWinterOn1; + int _startFrameWinterOn2; + int _endFrameWinterOn2; CString _viewName2; public: CLASSDEF; diff --git a/engines/titanic/game/code_wheel.cpp b/engines/titanic/game/code_wheel.cpp index d8ce48e390..94ee25435a 100644 --- a/engines/titanic/game/code_wheel.cpp +++ b/engines/titanic/game/code_wheel.cpp @@ -24,13 +24,20 @@ namespace Titanic { -CodeWheel::CodeWheel() : CBomb(), _field108(0), _field10C(4), _field110(0) { +BEGIN_MESSAGE_MAP(CodeWheel, CBomb) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + +CodeWheel::CodeWheel() : CBomb(), _field108(0), _state(4), _field110(0) { } void CodeWheel::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_field108, indent); - file->writeNumberLine(_field10C, indent); + file->writeNumberLine(_state, indent); file->writeNumberLine(_field110, indent); CBomb::save(file, indent); @@ -39,10 +46,63 @@ void CodeWheel::save(SimpleFile *file, int indent) { void CodeWheel::load(SimpleFile *file) { file->readNumber(); _field108 = file->readNumber(); - _field10C = file->readNumber(); + _state = file->readNumber(); _field110 = file->readNumber(); CBomb::load(file); } +bool CodeWheel::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + static const int START_FRAMES[15] = { + 0, 5, 10, 15, 19, 24, 28, 33, 38, 42, 47, 52, 57, 61, 66 + }; + static const int END_FRAMES[15] = { + 5, 10, 15, 19, 24, 28, 33, 38, 42, 47, 52, 57, 61, 66, 70 + }; + + int yp = _bounds.top + _bounds.height() / 2; + if (msg->_mousePos.y > yp) { + if (_state == _field108) + _field110 = true; + + _state = (_state + 1) % 15; + playMovie(START_FRAMES[_state], END_FRAMES[_state], + MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + } else { + if (_state == _field108) + _field110 = true; + + playMovie(START_FRAMES[14 - _state] + 68, END_FRAMES[14 - _state] + 68, + MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + + _state = (_state <= 0) ? 14 : _state - 1; + } + + playSound("z#59.wav"); + return true; +} + +bool CodeWheel::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(24); + _state = 4; + return true; +} + +bool CodeWheel::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + return true; +} + +bool CodeWheel::MovieEndMsg(CMovieEndMsg *msg) { + sleep(200); + CStatusChangeMsg changeMsg; + changeMsg._newStatus = 0; + if (_field110) + changeMsg._newStatus = -1; + if (_field108 == _state) + changeMsg._newStatus = 1; + changeMsg.execute("Bomb"); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/code_wheel.h b/engines/titanic/game/code_wheel.h index 63af97c6fb..e38a45b631 100644 --- a/engines/titanic/game/code_wheel.h +++ b/engines/titanic/game/code_wheel.h @@ -28,9 +28,14 @@ namespace Titanic { class CodeWheel : public CBomb { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); private: int _field108; - int _field10C; + int _state; int _field110; public: CLASSDEF; diff --git a/engines/titanic/game/head_smash_lever.cpp b/engines/titanic/game/head_smash_lever.cpp index d5c2eaf8c4..dabed26478 100644 --- a/engines/titanic/game/head_smash_lever.cpp +++ b/engines/titanic/game/head_smash_lever.cpp @@ -32,13 +32,13 @@ BEGIN_MESSAGE_MAP(CHeadSmashLever, CBackground) END_MESSAGE_MAP() CHeadSmashLever::CHeadSmashLever() : CBackground(), - _enabled(false), _fieldE4(false), _ticksCount(0) {} + _enabled(false), _fieldE4(false), _ticks(0) {} void CHeadSmashLever::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_enabled, indent); file->writeNumberLine(_fieldE4, indent); - file->writeNumberLine(_ticksCount, indent); + file->writeNumberLine(_ticks, indent); CBackground::save(file, indent); } @@ -47,7 +47,7 @@ void CHeadSmashLever::load(SimpleFile *file) { file->readNumber(); _enabled = file->readNumber(); _fieldE4 = file->readNumber(); - _ticksCount = file->readNumber(); + _ticks = file->readNumber(); CBackground::load(file); } @@ -58,7 +58,7 @@ bool CHeadSmashLever::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { playSound("z#54.wav"); int soundHandle = playSound("z#45.wav"); queueSound("z#49.wav", soundHandle); - _ticksCount = getTicksCount(); + _ticks = getTicksCount(); _fieldE4 = true; } else { playMovie(0); @@ -78,7 +78,7 @@ bool CHeadSmashLever::ActMsg(CActMsg *msg) { } bool CHeadSmashLever::FrameMsg(CFrameMsg *msg) { - if (_fieldE4 && msg->_ticks > (_ticksCount + 750)) { + if (_fieldE4 && msg->_ticks > (_ticks + 750)) { CActMsg actMsg1("CreatorsChamber.Node 1.S"); actMsg1.execute("MoveToCreators"); CActMsg actMsg2("PlayToEnd"); @@ -93,7 +93,7 @@ bool CHeadSmashLever::FrameMsg(CFrameMsg *msg) { bool CHeadSmashLever::LoadSuccessMsg(CLoadSuccessMsg *msg) { if (_fieldE4) - _ticksCount = getTicksCount(); + _ticks = getTicksCount(); return true; } diff --git a/engines/titanic/game/head_smash_lever.h b/engines/titanic/game/head_smash_lever.h index e2426b68da..19de07922a 100644 --- a/engines/titanic/game/head_smash_lever.h +++ b/engines/titanic/game/head_smash_lever.h @@ -36,7 +36,7 @@ class CHeadSmashLever : public CBackground { public: bool _enabled; bool _fieldE4; - int _ticksCount; + uint _ticks; public: CLASSDEF; CHeadSmashLever(); diff --git a/engines/titanic/game/long_stick_dispenser.cpp b/engines/titanic/game/long_stick_dispenser.cpp index cb562ec3ca..08a29f2e4b 100644 --- a/engines/titanic/game/long_stick_dispenser.cpp +++ b/engines/titanic/game/long_stick_dispenser.cpp @@ -21,9 +21,21 @@ */ #include "titanic/game/long_stick_dispenser.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CLongStickDispenser, CGameObject) + ON_MESSAGE(PuzzleSolvedMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(VisibleMsg) + ON_MESSAGE(EnterRoomMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + void CLongStickDispenser::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldBC, indent); @@ -42,10 +54,97 @@ void CLongStickDispenser::load(SimpleFile *file) { CGameObject::load(file); } +bool CLongStickDispenser::PuzzleSolvedMsg(CPuzzleSolvedMsg *msg) { + if (!_fieldBC && !_fieldC4 && !_fieldC0) { + CStatusChangeMsg statusMsg; + statusMsg.execute("ShatterGlass"); + _fieldC0 = 1; + loadFrame(19); + } else if (_fieldC0) { + playSound("z#63.wav"); + petDisplayMessage(1, "'This glass is totally and utterly unbreakable."); + } + + return true; +} + +bool CLongStickDispenser::MovieEndMsg(CMovieEndMsg *msg) { + CPuzzleSolvedMsg puzzleMsg; + puzzleMsg.execute("LongStick"); + _fieldC0 = 1; + return true; +} + +bool CLongStickDispenser::VisibleMsg(CVisibleMsg *msg) { + setVisible(msg->_visible); + return true; +} + bool CLongStickDispenser::EnterRoomMsg(CEnterRoomMsg *msg) { _fieldC0 = 0; _fieldC4 = 1; return true; } +bool CLongStickDispenser::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (!_fieldC0) { + playSound("z#62.wav"); + + switch (_fieldBC) { + case 0: + petDisplayMessage(1, "For emergency long stick, smash glass."); + break; + case 1: + petDisplayMessage(1, "This dispenser has suddenly been fitted with unbreakable glass " + "to prevent unseemly hoarding of sticks."); + break; + default: + break; + } + } + + return true; +} + +bool CLongStickDispenser::LeaveViewMsg(CLeaveViewMsg *msg) { + if (_fieldC0 == 1) { + if (_fieldC4) { + playMovie(19, 38, MOVIE_GAMESTATE); + } else { + playMovie(0, 18, MOVIE_GAMESTATE); + _fieldBC = 1; + } + + _fieldC4 = 1; + _fieldC0 = 0; + } + + return true; +} + +bool CLongStickDispenser::EnterViewMsg(CEnterViewMsg *msg) { + setVisible(true); + loadFrame(38); + _cursorId = CURSOR_HAND; + return true; +} + +bool CLongStickDispenser::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (!checkStartDragging(msg)) { + return false; + } else if (_fieldC0 == 1 && _fieldC4 == 1) { + CVisibleMsg visibleMsg(true); + visibleMsg.execute("LongStick"); + CPassOnDragStartMsg dragMsg(msg->_mousePos, 1); + dragMsg.execute("LongStick"); + + msg->_dragItem = getRoot()->findByName("LongStick"); + loadFrame(0); + _fieldC4 = 0; + _cursorId = CURSOR_ARROW; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/long_stick_dispenser.h b/engines/titanic/game/long_stick_dispenser.h index 2a1b86fb84..be05ef9c65 100644 --- a/engines/titanic/game/long_stick_dispenser.h +++ b/engines/titanic/game/long_stick_dispenser.h @@ -29,7 +29,15 @@ namespace Titanic { class CLongStickDispenser : public CGameObject { + DECLARE_MESSAGE_MAP; + bool PuzzleSolvedMsg(CPuzzleSolvedMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool VisibleMsg(CVisibleMsg *msg); bool EnterRoomMsg(CEnterRoomMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); private: int _fieldBC; int _fieldC0; diff --git a/engines/titanic/game/maitred/maitred_arm_holder.cpp b/engines/titanic/game/maitred/maitred_arm_holder.cpp index 4d35277a33..75d95640d2 100644 --- a/engines/titanic/game/maitred/maitred_arm_holder.cpp +++ b/engines/titanic/game/maitred/maitred_arm_holder.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMaitreDArmHolder, CDropTarget) + ON_MESSAGE(MaitreDArmHolder) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + void CMaitreDArmHolder::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CDropTarget::save(file, indent); @@ -34,4 +39,18 @@ void CMaitreDArmHolder::load(SimpleFile *file) { CDropTarget::load(file); } +bool CMaitreDArmHolder::MaitreDArmHolder(CMaitreDArmHolder *msg) { + _fieldF4 = 0; + return true; +} + +bool CMaitreDArmHolder::ActMsg(CActMsg *msg) { + if (msg->_action == "LoseArm") { + _bounds = Rect(); + setVisible(false); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/maitred/maitred_arm_holder.h b/engines/titanic/game/maitred/maitred_arm_holder.h index 3392d60e43..22f961f236 100644 --- a/engines/titanic/game/maitred/maitred_arm_holder.h +++ b/engines/titanic/game/maitred/maitred_arm_holder.h @@ -28,6 +28,9 @@ namespace Titanic { class CMaitreDArmHolder : public CDropTarget { + DECLARE_MESSAGE_MAP; + bool MaitreDArmHolder(CMaitreDArmHolder *msg); + bool ActMsg(CActMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/maitred/maitred_body.cpp b/engines/titanic/game/maitred/maitred_body.cpp index 6b495e5a1c..4cb12aac8f 100644 --- a/engines/titanic/game/maitred/maitred_body.cpp +++ b/engines/titanic/game/maitred/maitred_body.cpp @@ -20,20 +20,56 @@ * */ -#include "titanic/game/maitred/maitred_legs.h" +#include "titanic/game/maitred/maitred_body.h" namespace Titanic { -void CMaitreDLegs::save(SimpleFile *file, int indent) { +BEGIN_MESSAGE_MAP(CMaitreDBody, CMaitreDProdReceptor) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(AnimateMaitreDMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + +void CMaitreDBody::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldC8, indent); + file->writeNumberLine(_armed, indent); CMaitreDProdReceptor::save(file, indent); } -void CMaitreDLegs::load(SimpleFile *file) { +void CMaitreDBody::load(SimpleFile *file) { file->readNumber(); - _fieldC8 = file->readNumber(); + _armed = file->readNumber(); CMaitreDProdReceptor::load(file); } +bool CMaitreDBody::EnterViewMsg(CEnterViewMsg *msg) { + return true; +} + +bool CMaitreDBody::AnimateMaitreDMsg(CAnimateMaitreDMsg *msg) { + static const char *const ARMED_CLIPS[5] = { + "Talking 1", "Talking 2", "Talking 3", "Talking 4", nullptr + }; + static const char *const UNARMED_CLIPS[5] = { + "Armless Talking 1", "Armless Talking 2", "Armless Talking 3", + "Armless Talking 4", nullptr + }; + + if (!hasActiveMovie()) { + playRandomClip(_armed ? ARMED_CLIPS : UNARMED_CLIPS); + } + + return true; +} + +bool CMaitreDBody::ActMsg(CActMsg *msg) { + if (msg->_action == "LoseArm") { + _armed = false; + loadFrame(262); + playSound("c#75.wav"); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/maitred/maitred_body.h b/engines/titanic/game/maitred/maitred_body.h index 7016c15c71..1798958e84 100644 --- a/engines/titanic/game/maitred/maitred_body.h +++ b/engines/titanic/game/maitred/maitred_body.h @@ -28,11 +28,15 @@ namespace Titanic { class CMaitreDBody : public CMaitreDProdReceptor { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool AnimateMaitreDMsg(CAnimateMaitreDMsg *msg); + bool ActMsg(CActMsg *msg); private: - int _fieldC8; + bool _armed; public: CLASSDEF; - CMaitreDBody() : CMaitreDProdReceptor(), _fieldC8(1) {} + CMaitreDBody() : CMaitreDProdReceptor(), _armed(true) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/maitred/maitred_legs.cpp b/engines/titanic/game/maitred/maitred_legs.cpp index 5071805101..8c0b0db5ea 100644 --- a/engines/titanic/game/maitred/maitred_legs.cpp +++ b/engines/titanic/game/maitred/maitred_legs.cpp @@ -20,20 +20,76 @@ * */ -#include "titanic/game/maitred/maitred_body.h" +#include "titanic/game/maitred/maitred_legs.h" namespace Titanic { -void CMaitreDBody::save(SimpleFile *file, int indent) { +BEGIN_MESSAGE_MAP(CMaitreDLegs, CMaitreDProdReceptor) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(AnimateMaitreDMsg) +END_MESSAGE_MAP() + +void CMaitreDLegs::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldC8, indent); + file->writeNumberLine(_flag, indent); CMaitreDProdReceptor::save(file, indent); } -void CMaitreDBody::load(SimpleFile *file) { +void CMaitreDLegs::load(SimpleFile *file) { file->readNumber(); - _fieldC8 = file->readNumber(); + _flag = file->readNumber(); CMaitreDProdReceptor::load(file); } +bool CMaitreDLegs::EnterViewMsg(CEnterViewMsg *msg) { + _flag = true; + loadFrame(0); + return true; +} + +bool CMaitreDLegs::AnimateMaitreDMsg(CAnimateMaitreDMsg *msg) { + static const char *const WIGGLE_CLIPS[4] = { + "Hip Wiggle", "Knee Bend", "Wire Wiggle", nullptr + }; + static const char *const FIGHTING_CLIPS[4] = { + "Fighting 1", "Fighting 2", "Leg Fidget", nullptr + }; + static const char *const ARCING_SOUNDS[9] = { + "MaitreD Arcing 1.wav", "MaitreD Arcing 2.wav", + "MaitreD Arcing 3.wav", "MaitreD Arcing 4.wav", + "MaitreD Arcing 5.wav", "MaitreD Arcing 6.wav", + "MaitreD Arcing 7.wav", "MaitreD Arcing 8.wav", + "MaitreD Arcing 9.wav" + }; + + switch (msg->_value) { + case 0: + if (_flag) { + playRandomClip(FIGHTING_CLIPS); + + if (getRandomNumber(2) != 0) + playSound(ARCING_SOUNDS[getRandomNumber(9)], + 40 + getRandomNumber(30)); + } else { + playClip("Walk Right"); + _flag = true; + } + break; + + case 1: + if (_flag) { + playClip("Walk Left"); + _flag = false; + } else { + playRandomClip(WIGGLE_CLIPS); + } + break; + + default: + break; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/maitred/maitred_legs.h b/engines/titanic/game/maitred/maitred_legs.h index 24ba01e712..b8a32eef4c 100644 --- a/engines/titanic/game/maitred/maitred_legs.h +++ b/engines/titanic/game/maitred/maitred_legs.h @@ -28,11 +28,14 @@ namespace Titanic { class CMaitreDLegs : public CMaitreDProdReceptor { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool AnimateMaitreDMsg(CAnimateMaitreDMsg *msg); private: - int _fieldC8; + bool _flag; public: CLASSDEF; - CMaitreDLegs() : CMaitreDProdReceptor(), _fieldC8(1) {} + CMaitreDLegs() : CMaitreDProdReceptor(), _flag(true) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/maitred/maitred_prod_receptor.cpp b/engines/titanic/game/maitred/maitred_prod_receptor.cpp index 4823f143b0..66533a542f 100644 --- a/engines/titanic/game/maitred/maitred_prod_receptor.cpp +++ b/engines/titanic/game/maitred/maitred_prod_receptor.cpp @@ -21,13 +21,21 @@ */ #include "titanic/game/maitred/maitred_prod_receptor.h" +#include "titanic/npcs/maitre_d.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMaitreDProdReceptor, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseMoveMsg) + ON_MESSAGE(ProdMaitreDMsg) + ON_MESSAGE(DisableMaitreDProdReceptor) +END_MESSAGE_MAP() + void CMaitreDProdReceptor::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldBC, indent); - file->writeNumberLine(_fieldC0, indent); + file->writeNumberLine(_counter, indent); file->writeNumberLine(_fieldC4, indent); CGameObject::save(file, indent); @@ -36,10 +44,79 @@ void CMaitreDProdReceptor::save(SimpleFile *file, int indent) { void CMaitreDProdReceptor::load(SimpleFile *file) { file->readNumber(); _fieldBC = file->readNumber(); - _fieldC0 = file->readNumber(); + _counter = file->readNumber(); _fieldC4 = file->readNumber(); CGameObject::load(file); } +bool CMaitreDProdReceptor::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_fieldBC == 2 && static_cast<CGameObject *>(getParent())->hasActiveMovie()) { + return false; + } else { + CProdMaitreDMsg prodMsg(126); + prodMsg.execute(this); + return true; + } +} + +bool CMaitreDProdReceptor::MouseMoveMsg(CMouseMoveMsg *msg) { + if (_fieldBC == 2 && static_cast<CGameObject *>(getParent())->hasActiveMovie()) + return false; + else if (++_counter < 20) + return true; + + _counter = 0; + CProdMaitreDMsg prodMsg(126); + + if (isEquals("Stick")) + prodMsg._value = 121; + else if (isEquals("Hammer")) + prodMsg._value = 122; + else if (isEquals("Lemon")) + prodMsg._value = 123; + else if (isEquals("Chicken")) + prodMsg._value = 124; + else if (isEquals("Perch")) + prodMsg._value = 125; + + CMaitreD *maitreD = static_cast<CMaitreD *>(findRoomObject("MaitreD")); + if (maitreD->_field100 <= 0) + prodMsg.execute(this); + + return true; +} + +bool CMaitreDProdReceptor::ProdMaitreDMsg(CProdMaitreDMsg *msg) { + if (_fieldC4) { + CMaitreD *maitreD = static_cast<CMaitreD *>(findRoomObject("MaitreD")); + if (maitreD->_field100 <= 0) { + CViewItem *view = findView(); + startTalking(maitreD, msg->_value, view); + + switch (_fieldBC) { + case 1: + startTalking(maitreD, 128, view); + break; + case 2: + startTalking(maitreD, 129, view); + break; + case 3: + startTalking(maitreD, 127, view); + break; + default: + startTalking(maitreD, 130, view); + break; + } + } + } + + return true; +} + +bool CMaitreDProdReceptor::DisableMaitreDProdReceptor(CDisableMaitreDProdReceptor *msg) { + _fieldC4 = 0; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/maitred/maitred_prod_receptor.h b/engines/titanic/game/maitred/maitred_prod_receptor.h index f3a547b8ef..0b00ce0014 100644 --- a/engines/titanic/game/maitred/maitred_prod_receptor.h +++ b/engines/titanic/game/maitred/maitred_prod_receptor.h @@ -28,14 +28,19 @@ namespace Titanic { class CMaitreDProdReceptor : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseMoveMsg(CMouseMoveMsg *msg); + bool ProdMaitreDMsg(CProdMaitreDMsg *msg); + bool DisableMaitreDProdReceptor(CDisableMaitreDProdReceptor *msg); protected: int _fieldBC; - int _fieldC0; + int _counter; int _fieldC4; public: CLASSDEF; CMaitreDProdReceptor() : CGameObject(), - _fieldBC(0), _fieldC0(0), _fieldC4(1) {} + _fieldBC(0), _counter(0), _fieldC4(1) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/missiveomat.cpp b/engines/titanic/game/missiveomat.cpp index 931b146801..6f47131716 100644 --- a/engines/titanic/game/missiveomat.cpp +++ b/engines/titanic/game/missiveomat.cpp @@ -21,35 +21,310 @@ */ #include "titanic/game/missiveomat.h" +#include "titanic/core/room_item.h" +#include "titanic/titanic.h" namespace Titanic { -CMissiveOMat::CMissiveOMat() : CGameObject(), _fieldBC(1), - _fieldC0(0), _fieldC4(0), _fieldE0(-1) { +BEGIN_MESSAGE_MAP(CMissiveOMat, CGameObject) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(KeyCharMsg) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(MissiveOMatActionMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + +CMissiveOMat::CMissiveOMat() : CGameObject(), _mode(1), + _totalMessages(0), _messageNum(0), _personIndex(-1) { + // Load data for the messages, their from and to names + loadArray(_welcomeMessages, "TEXT/MISSIVEOMAT/WELCOME", 3); + loadArray(_messages, "TEXT/MISSIVEOMAT/MESSAGES", 58); + loadArray(_from, "TEXT/MISSIVEOMAT/FROM", 58); + loadArray(_to, "TEXT/MISSIVEOMAT/TO", 58); +} + +void CMissiveOMat::loadArray(CString *arr, const CString &resName, int count) { + Common::SeekableReadStream *s = g_vm->_filesManager->getResource(resName); + for (int idx = 0; idx < count; ++idx) + arr[idx] = readStringFromStream(s); + delete s; } void CMissiveOMat::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); - file->writeNumberLine(_fieldC0, indent); - file->writeNumberLine(_fieldC4, indent); + file->writeNumberLine(_mode, indent); + file->writeNumberLine(_totalMessages, indent); + file->writeNumberLine(_messageNum, indent); file->writeQuotedLine(_string1, indent); file->writeQuotedLine(_string2, indent); - file->writeNumberLine(_fieldE0, indent); + file->writeNumberLine(_personIndex, indent); CGameObject::save(file, indent); } void CMissiveOMat::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); - _fieldC0 = file->readNumber(); - _fieldC4 = file->readNumber(); + _mode = file->readNumber(); + _totalMessages = file->readNumber(); + _messageNum = file->readNumber(); _string1 = file->readString(); _string2 = file->readString(); - _fieldE0 = file->readNumber(); + _personIndex = file->readNumber(); CGameObject::load(file); } +bool CMissiveOMat::EnterViewMsg(CEnterViewMsg *msg) { + CMissiveOMatActionMsg actionMsg(9); + actionMsg.execute(this); + return true; +} + +bool CMissiveOMat::KeyCharMsg(CKeyCharMsg *msg) { + CTreeItem *loginControl = findRoom()->findByName("MissiveOMat Login Control"); + CTreeItem *welcome = findRoom()->findByName("MissiveOMat Welcome"); + CTreeItem *scrollUp = findRoom()->findByName("MissiveOMat ScrollUp Button"); + CEditControlMsg editMsg; + + switch (_mode) { + case 1: { + playSound("z#228.wav"); + editMsg._mode = 6; + editMsg._param = msg->_key; + editMsg.execute(loginControl); + + if (editMsg._param == 1000) { + editMsg._mode = 3; + editMsg.execute(loginControl); + + _string1 = editMsg._text; + if (!_string1.empty()) { + loadFrame(2); + _mode = 2; + + editMsg._mode = 1; + editMsg.execute(loginControl); + editMsg._mode = 10; + editMsg._param = 24; + editMsg.execute(loginControl); + } + } + break; + } + + case 2: { + playSound("z#228.wav"); + editMsg._mode = 6; + editMsg._param = msg->_key; + editMsg.execute(loginControl); + + _string2 = editMsg._text; + if (_string1 == "Droot Scraliontis") { + _string1 = "Scraliontis"; + } else if (_string1 == "Antar Brobostigon") { + _string1 = "Brobostigon"; + } else if (_string1 == "colin") { + _string1 = "Leovinus"; + } + + bool flag = false; + if (_string1 == "Leovinus") { + if (_string2 == "Other") { + flag = true; + _personIndex = 0; + } + } else if (_string1 == "Scraliontis") { + if (_string2 == "This") { + flag = true; + _personIndex = 1; + } + } else if (_string1 == "Brobostigon") { + if (_string2 == "That") { + flag = true; + _personIndex = 2; + } + } + + if (flag) { + _mode = 4; + loadFrame(4); + editMsg._mode = 1; + editMsg.execute(loginControl); + + getTextCursor()->hide(); + editMsg._mode = 13; + editMsg.execute(loginControl); + + editMsg._mode = 12; + editMsg.execute(welcome); + + editMsg._mode = 2; + editMsg._text = _welcomeMessages[_personIndex]; + editMsg.execute(welcome); + + editMsg._mode = 12; + editMsg._text = "MissiveOMat OK Button"; + editMsg.execute(welcome); + editMsg.execute(scrollUp); + } else { + _mode = 3; + loadFrame(3); + addTimer(1500); + + editMsg._mode = 1; + editMsg.execute(loginControl); + + getTextCursor()->hide(); + } + break; + } + + default: + break; + } + + return true; +} + +bool CMissiveOMat::TimerMsg(CTimerMsg *msg) { + if (_mode == 3) { + CTreeItem *loginControl = findRoom()->findByName("MissiveOMat Login Control"); + CEditControlMsg editMsg; + editMsg._mode = 10; + editMsg._param = 8; + editMsg.execute(loginControl); + } + + return true; +} + +bool CMissiveOMat::MissiveOMatActionMsg(CMissiveOMatActionMsg *msg) { + CTreeItem *welcome = findByName("MissiveOMat Welcome"); + + switch (msg->_action) { + case MESSAGE_SHOW: { + CTreeItem *btnOk = findRoom()->findByName("MissiveOMat OK Button"); + CTreeItem *btnNext = findRoom()->findByName("MissiveOMat Next Button"); + CTreeItem *btnPrev = findRoom()->findByName("MissiveOMat Prev Button"); + CTreeItem *btnLogout = findRoom()->findByName("MissiveOMat Logout Button"); + + _mode = MESSAGE_5; + CVisibleMsg visibleMsg; + visibleMsg._visible = false; + visibleMsg.execute(btnOk); + visibleMsg._visible = true; + visibleMsg.execute(btnNext); + visibleMsg.execute(btnPrev); + visibleMsg.execute(btnLogout); + + _messageNum = 0; + _totalMessages = 0; + CString *strP = &_messages[_personIndex * 19]; + for (_totalMessages = 0; !strP->empty(); ++strP, ++_totalMessages) + ; + + CMissiveOMatActionMsg actionMsg; + actionMsg._action = REDRAW_MESSAGE; + actionMsg.execute(this); + break; + } + + case NEXT_MESSAGE: + if (_messageNum < (_totalMessages - 1)) { + ++_messageNum; + CMissiveOMatActionMsg actionMsg; + actionMsg._action = REDRAW_MESSAGE; + actionMsg.execute(this); + } + break; + + case PRIOR_MESSAGE: + if (_messageNum > 0) { + --_messageNum; + CMissiveOMatActionMsg actionMsg; + actionMsg._action = REDRAW_MESSAGE; + actionMsg.execute(this); + } + break; + + case MESSAGE_5: { + CMissiveOMatActionMsg actionMsg; + actionMsg._action = MESSAGE_9; + actionMsg.execute(this); + break; + } + + case MESSAGE_DOWN: + if (welcome) + scrollTextDown(); + break; + + case MESSAGE_UP: + if (welcome) + scrollTextUp(); + break; + + case REDRAW_MESSAGE: + if (welcome) { + CString str = CString::format( + "Missive %d of %d.\nFrom: %s\nTo: %s\n\n%s\n", + _messageNum + 1, _totalMessages, _from[_messageNum].c_str(), + _to[_messageNum].c_str(), _messages[_messageNum].c_str()); + + setText(str); + } + break; + + case MESSAGE_9: { + loadFrame(1); + _mode = MESSAGE_NONE; + _personIndex = -1; + + static const char *const WIDGETS[7] = { + "MissiveOMat Login Control", "MissiveOMat OK Button", + "MissiveOMat Next Button", "MissiveOMat Prev Button", + "MissiveOMat Logout Button", "MissiveOMat ScrollDown Button", + "MissiveOMat ScrollUp Button" + }; + CEditControlMsg editMsg; + + for (int idx = 0; idx < 7; ++idx) { + editMsg._mode = 0; + editMsg._param = 12; + editMsg.execute(WIDGETS[idx]); + editMsg._mode = 1; + editMsg.execute(WIDGETS[idx]); + editMsg._mode = 13; + editMsg.execute(WIDGETS[idx]); + } + + editMsg._mode = 12; + editMsg.execute("MissiveOMat Login Control"); + editMsg._mode = 10; + editMsg._param = 8; + editMsg.execute("MissiveOMat Login Control"); + editMsg._mode = 8; + editMsg.execute("MissiveOMat Login Control"); + + _string1.clear(); + _string2.clear(); + break; + } + + default: + break; + } + + return true; +} + +bool CMissiveOMat::LeaveViewMsg(CLeaveViewMsg *msg) { + CEditControlMsg editMsg; + editMsg._mode = 9; + editMsg.execute("MissiveOMat Login Control"); + petShowCursor(); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/missiveomat.h b/engines/titanic/game/missiveomat.h index 7fde8cf25d..9810fcc403 100644 --- a/engines/titanic/game/missiveomat.h +++ b/engines/titanic/game/missiveomat.h @@ -27,14 +27,33 @@ namespace Titanic { +enum MissiveOMatAction { + MESSAGE_NONE = 1, MESSAGE_SHOW = 2, NEXT_MESSAGE = 3, PRIOR_MESSAGE = 4, + MESSAGE_5 = 5, MESSAGE_DOWN = 6, MESSAGE_UP = 7, REDRAW_MESSAGE = 8, + MESSAGE_9 = 9 +}; + class CMissiveOMat : public CGameObject { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool KeyCharMsg(CKeyCharMsg *msg); + bool TimerMsg(CTimerMsg *msg); + bool MissiveOMatActionMsg(CMissiveOMatActionMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); +private: + CString _welcomeMessages[3]; + CString _messages[58]; + CString _from[58]; + CString _to[58]; +private: + void loadArray(CString *arr, const CString &resName, int count); public: - int _fieldBC; - int _fieldC0; - int _fieldC4; + int _mode; + int _totalMessages; + int _messageNum; CString _string1; CString _string2; - int _fieldE0; + int _personIndex; public: CLASSDEF; CMissiveOMat(); diff --git a/engines/titanic/game/missiveomat_button.cpp b/engines/titanic/game/missiveomat_button.cpp index d5ae75dbc2..b7ad7f8f6f 100644 --- a/engines/titanic/game/missiveomat_button.cpp +++ b/engines/titanic/game/missiveomat_button.cpp @@ -21,21 +21,47 @@ */ #include "titanic/game/missiveomat_button.h" +#include "titanic/core/room_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMissiveOMatButton, CEditControl) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(VisibleMsg) + ON_MESSAGE(MouseDoubleClickMsg) +END_MESSAGE_MAP() + void CMissiveOMatButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldFC, indent); + file->writeNumberLine(_buttonId, indent); CEditControl::save(file, indent); } void CMissiveOMatButton::load(SimpleFile *file) { file->readNumber(); - _fieldFC = file->readNumber(); + _buttonId = file->readNumber(); CEditControl::load(file); } +bool CMissiveOMatButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CMissiveOMatActionMsg actionMsg; + actionMsg._action = _buttonId; + actionMsg.execute(findRoom()->findByName("MissiveOMat")); + return true; +} + +bool CMissiveOMatButton::VisibleMsg(CVisibleMsg *msg) { + setVisible(msg->_visible); + return true; +} + +bool CMissiveOMatButton::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) { + CMissiveOMatActionMsg actionMsg; + actionMsg._action = _buttonId; + actionMsg.execute(findRoom()->findByName("MissiveOMat")); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/missiveomat_button.h b/engines/titanic/game/missiveomat_button.h index d36f5bd958..6dbfd4cd56 100644 --- a/engines/titanic/game/missiveomat_button.h +++ b/engines/titanic/game/missiveomat_button.h @@ -28,11 +28,15 @@ namespace Titanic { class CMissiveOMatButton : public CEditControl { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool VisibleMsg(CVisibleMsg *msg); + bool MouseDoubleClickMsg(CMouseDoubleClickMsg *msg); public: - int _fieldFC; + int _buttonId; public: CLASSDEF; - CMissiveOMatButton() : CEditControl(), _fieldFC(2) {} + CMissiveOMatButton() : CEditControl(), _buttonId(2) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/movie_tester.cpp b/engines/titanic/game/movie_tester.cpp index 1b266d9c7e..bbd66a9bce 100644 --- a/engines/titanic/game/movie_tester.cpp +++ b/engines/titanic/game/movie_tester.cpp @@ -24,18 +24,36 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMovieTester, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CMovieTester::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value1, indent); - file->writeNumberLine(_value2, indent); + file->writeNumberLine(_movieNumFrames, indent); + file->writeNumberLine(_movieFrameNum, indent); CGameObject::save(file, indent); } void CMovieTester::load(SimpleFile *file) { file->readNumber(); - _value1 = file->readNumber(); - _value2 = file->readNumber(); + _movieNumFrames = file->readNumber(); + _movieFrameNum = file->readNumber(); CGameObject::load(file); } +bool CMovieTester::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (msg->_buttons == MB_RIGHT) { + if (--_movieFrameNum < 0) { + _movieFrameNum = _movieNumFrames - 1; + } + } else { + if (++_movieFrameNum >= _movieNumFrames) + _movieFrameNum = 0; + } + + loadFrame(_movieFrameNum); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/movie_tester.h b/engines/titanic/game/movie_tester.h index de2ef2cc5e..17a7d489d8 100644 --- a/engines/titanic/game/movie_tester.h +++ b/engines/titanic/game/movie_tester.h @@ -28,11 +28,13 @@ namespace Titanic { class CMovieTester : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: - int _value1, _value2; + int _movieNumFrames, _movieFrameNum; public: CLASSDEF; - CMovieTester() : CGameObject(), _value1(0), _value2(0) {} + CMovieTester() : CGameObject(), _movieNumFrames(0), _movieFrameNum(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/music_console_button.cpp b/engines/titanic/game/music_console_button.cpp index 1bc78ffe23..9cf385e3a7 100644 --- a/engines/titanic/game/music_console_button.cpp +++ b/engines/titanic/game/music_console_button.cpp @@ -21,9 +21,18 @@ */ #include "titanic/game/music_console_button.h" +#include "titanic/core/room_item.h" +#include "titanic/sound/music_handler.h" +#include "titanic/titanic.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMusicConsoleButton, CMusicPlayer) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(SetMusicControlsMsg) +END_MESSAGE_MAP() + void CMusicConsoleButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CMusicPlayer::save(file, indent); @@ -34,4 +43,91 @@ void CMusicConsoleButton::load(SimpleFile *file) { CMusicPlayer::load(file); } +bool CMusicConsoleButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_isActive) { + CStopMusicMsg stopMsg(this); + stopMsg.execute(this); + stopMovie(); + loadFrame(0); + } else { + CStartMusicMsg startMsg(this); + startMsg.execute(this); + playMovie(MOVIE_REPEAT); + + CMusicHasStartedMsg startedMsg; + startedMsg.execute("Music Room Phonograph"); + + if (CMusicRoom::_musicHandler->checkSound(1) + && CMusicRoom::_musicHandler->checkSound(2) + && CMusicRoom::_musicHandler->checkSound(3)) { + CCorrectMusicPlayedMsg correctMsg; + correctMsg.execute(findRoom()); + } + } + + return true; +} + +bool CMusicConsoleButton::LeaveViewMsg(CLeaveViewMsg *msg) { + if (_isActive) { + CStopMusicMsg stopMsg(this); + stopMsg.execute(this); + stopMovie(); + loadFrame(0); + } + + return true; +} + +bool CMusicConsoleButton::SetMusicControlsMsg(CSetMusicControlsMsg *msg) { + CMusicRoom *musicRoom = getMusicRoom(); + CQueryMusicControlSettingMsg queryMsg; + + queryMsg.execute("Bells Mute Control"); + musicRoom->setItem5(BELLS, queryMsg._value == 1 ? 1 : 0); + queryMsg.execute("Bells Pitch Control"); + musicRoom->setItem2(BELLS, queryMsg._value); + queryMsg.execute("Bells Speed Control"); + musicRoom->setItem1(BELLS, queryMsg._value); + queryMsg.execute("Bells Inversion Control"); + musicRoom->setItem4(BELLS, queryMsg._value == 0 ? 1 : 0); + queryMsg.execute("Bells Direction Control"); + musicRoom->setItem3(BELLS, queryMsg._value == 0 ? 1 : 0); + + queryMsg.execute("Snake Mute Control"); + musicRoom->setItem5(SNAKE, queryMsg._value == 1 ? 1 : 0); + queryMsg.execute("Snake Pitch Control"); + musicRoom->setItem2(SNAKE, queryMsg._value); + queryMsg.execute("Snake Speed Control"); + musicRoom->setItem1(SNAKE, queryMsg._value); + queryMsg.execute("Snake Inversion Control"); + musicRoom->setItem4(SNAKE, queryMsg._value == 0 ? 1 : 0); + queryMsg.execute("Snake Direction Control"); + musicRoom->setItem3(SNAKE, queryMsg._value == 0 ? 1 : 0); + + queryMsg.execute("Piano Mute Control"); + musicRoom->setItem5(PIANO, queryMsg._value == 1 ? 1 : 0); + queryMsg.execute("Piano Pitch Control"); + musicRoom->setItem2(PIANO, queryMsg._value); + queryMsg.execute("Piano Speed Control"); + musicRoom->setItem1(PIANO, queryMsg._value); + queryMsg.execute("Piano Inversion Control"); + musicRoom->setItem4(PIANO, queryMsg._value == 0 ? 1 : 0); + queryMsg.execute("Piano Direction Control"); + musicRoom->setItem3(PIANO, queryMsg._value == 0 ? 1 : 0); + + queryMsg.execute("Bass Mute Control"); + musicRoom->setItem5(BASS, queryMsg._value == 1 ? 1 : 0); + queryMsg.execute("Bass Pitch Control"); + musicRoom->setItem2(BASS, queryMsg._value); + queryMsg.execute("Bass Speed Control"); + musicRoom->setItem1(BASS, queryMsg._value); + queryMsg.execute("Bass Inversion Control"); + musicRoom->setItem4(BASS, queryMsg._value == 0 ? 1 : 0); + queryMsg.execute("Bass Direction Control"); + musicRoom->setItem3(BASS, queryMsg._value == 0 ? 1 : 0); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/music_console_button.h b/engines/titanic/game/music_console_button.h index 8e05b698d7..80ce719c96 100644 --- a/engines/titanic/game/music_console_button.h +++ b/engines/titanic/game/music_console_button.h @@ -28,6 +28,10 @@ namespace Titanic { class CMusicConsoleButton : public CMusicPlayer { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool SetMusicControlsMsg(CSetMusicControlsMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/music_room_stop_phonograph_button.cpp b/engines/titanic/game/music_room_stop_phonograph_button.cpp index 44342fc2d6..dee2c0883e 100644 --- a/engines/titanic/game/music_room_stop_phonograph_button.cpp +++ b/engines/titanic/game/music_room_stop_phonograph_button.cpp @@ -24,16 +24,52 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMusicRoomStopPhonographButton, CEjectPhonographButton) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(FrameMsg) +END_MESSAGE_MAP() + void CMusicRoomStopPhonographButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_field100, indent); + file->writeNumberLine(_ticks, indent); CEjectPhonographButton::save(file, indent); } void CMusicRoomStopPhonographButton::load(SimpleFile *file) { file->readNumber(); - _field100 = file->readNumber(); + _ticks = file->readNumber(); CEjectPhonographButton::load(file); } +bool CMusicRoomStopPhonographButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (!_ejected) { + loadFrame(1); + playSound(_soundName); + _readyFlag = true; + + CPhonographStopMsg stopMsg; + stopMsg.execute(getParent(), nullptr, MSGFLAG_SCAN); + if (stopMsg._value2) { + _ticks = getTicksCount(); + } else { + CEjectCylinderMsg ejectMsg; + ejectMsg.execute(getParent(), nullptr, MSGFLAG_SCAN); + _ejected = true; + } + } + + return true; +} + +bool CMusicRoomStopPhonographButton::FrameMsg(CFrameMsg *msg) { + if (_readyFlag && _ticks && msg->_ticks >= (_ticks + 100)) { + loadFrame(0); + playSound(_readySoundName); + _ticks = 0; + _readyFlag = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/music_room_stop_phonograph_button.h b/engines/titanic/game/music_room_stop_phonograph_button.h index 7260e5aaab..dd9e8b4bc0 100644 --- a/engines/titanic/game/music_room_stop_phonograph_button.h +++ b/engines/titanic/game/music_room_stop_phonograph_button.h @@ -28,11 +28,14 @@ namespace Titanic { class CMusicRoomStopPhonographButton : public CEjectPhonographButton { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool FrameMsg(CFrameMsg *msg); private: - int _field100; + uint _ticks; public: CLASSDEF; - CMusicRoomStopPhonographButton() : CEjectPhonographButton(), _field100(0) {} + CMusicRoomStopPhonographButton() : CEjectPhonographButton(), _ticks(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/music_system_lock.cpp b/engines/titanic/game/music_system_lock.cpp index f1e062b3ee..074864e7c3 100644 --- a/engines/titanic/game/music_system_lock.cpp +++ b/engines/titanic/game/music_system_lock.cpp @@ -21,9 +21,16 @@ */ #include "titanic/game/music_system_lock.h" +#include "titanic/core/room_item.h" +#include "titanic/carry/carry.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMusicSystemLock, CDropTarget) + ON_MESSAGE(DropObjectMsg) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CMusicSystemLock::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_value, indent); @@ -36,4 +43,25 @@ void CMusicSystemLock::load(SimpleFile *file) { CDropTarget::load(file); } +bool CMusicSystemLock::DropObjectMsg(CDropObjectMsg *msg) { + CTreeItem *key = msg->_item->findByName("Music System Key"); + if (key) { + setVisible(true); + playMovie(MOVIE_NOTIFY_OBJECT); + } + + return true; +} + +bool CMusicSystemLock::MovieEndMsg(CMovieEndMsg *msg) { + CTreeItem *phonograph = findRoom()->findByName("Restaurant Phonograph"); + CQueryPhonographState queryMsg; + queryMsg.execute(phonograph); + CLockPhonographMsg lockMsg(queryMsg._value); + lockMsg.execute(phonograph, nullptr, MSGFLAG_SCAN); + + setVisible(false); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/music_system_lock.h b/engines/titanic/game/music_system_lock.h index ff826f5c77..0947915caa 100644 --- a/engines/titanic/game/music_system_lock.h +++ b/engines/titanic/game/music_system_lock.h @@ -28,6 +28,9 @@ namespace Titanic { class CMusicSystemLock : public CDropTarget { + DECLARE_MESSAGE_MAP; + bool DropObjectMsg(CDropObjectMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); private: int _value; public: diff --git a/engines/titanic/game/nav_helmet.cpp b/engines/titanic/game/nav_helmet.cpp index 770eb7375e..08ff073c26 100644 --- a/engines/titanic/game/nav_helmet.cpp +++ b/engines/titanic/game/nav_helmet.cpp @@ -21,19 +21,114 @@ */ #include "titanic/game/nav_helmet.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CNavHelmet, CGameObject) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(PETHelmetOnOffMsg) + ON_MESSAGE(PETPhotoOnOffMsg) + ON_MESSAGE(PETStarFieldLockMsg) + ON_MESSAGE(PETSetStarDestinationMsg) +END_MESSAGE_MAP() + void CNavHelmet::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_flag, indent); CGameObject::save(file, indent); } void CNavHelmet::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _flag = file->readNumber(); CGameObject::load(file); } +bool CNavHelmet::MovieEndMsg(CMovieEndMsg *msg) { + if (_flag) { + setVisible(false); + + CPetControl *pet = getPetControl(); + if (pet) { + pet->setArea(PET_STARFIELD); + petDisplayMessage(1, "Now would be an excellent opportunity to adjust your viewing apparatus."); + pet->incAreaLocks(); + } + + starFn1(0); + starFn1(12); + } + + return true; +} + +bool CNavHelmet::EnterViewMsg(CEnterViewMsg *msg) { + petSetRemoteTarget(); + return true; +} + +bool CNavHelmet::LeaveViewMsg(CLeaveViewMsg *msg) { + petClear(); + return true; +} + +bool CNavHelmet::PETHelmetOnOffMsg(CPETHelmetOnOffMsg *msg) { + CPetControl *pet = getPetControl(); + + if (_flag) { + _flag = false; + setVisible(true); + starFn1(1); + playMovie(61, 120, MOVIE_NOTIFY_OBJECT); + playSound("a#47.wav"); + playSound("a#48.wav"); + + if (pet) { + pet->decAreaLocks(); + pet->setArea(PET_REMOTE); + } + + dec54(); + } else { + inc54(); + _flag = true; + setVisible(true); + playMovie(0, 60, MOVIE_NOTIFY_OBJECT); + playSound("a#48.wav"); + playSound("a#47.wav"); + } + + return true; +} + +bool CNavHelmet::PETPhotoOnOffMsg(CPETPhotoOnOffMsg *msg) { + if (_flag) + starFn1(9); + + return true; +} + +bool CNavHelmet::PETStarFieldLockMsg(CPETStarFieldLockMsg *msg) { + if (_flag) { + if (msg->_value) { + playSound("a#6.wav"); + starFn1(17); + } else { + playSound("a#5.wav"); + starFn1(18); + } + } + + return true; +} + +bool CNavHelmet::PETSetStarDestinationMsg(CPETSetStarDestinationMsg *msg) { + CActMsg actMsg("SetDestin"); + actMsg.execute("CaptainsWheel"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/nav_helmet.h b/engines/titanic/game/nav_helmet.h index 74caa52534..c408d05c97 100644 --- a/engines/titanic/game/nav_helmet.h +++ b/engines/titanic/game/nav_helmet.h @@ -24,15 +24,24 @@ #define TITANIC_NAV_HELMET_H #include "titanic/core/game_object.h" +#include "titanic/messages/pet_messages.h" namespace Titanic { class CNavHelmet : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MovieEndMsg(CMovieEndMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool PETHelmetOnOffMsg(CPETHelmetOnOffMsg *msg); + bool PETPhotoOnOffMsg(CPETPhotoOnOffMsg *msg); + bool PETStarFieldLockMsg(CPETStarFieldLockMsg *msg); + bool PETSetStarDestinationMsg(CPETSetStarDestinationMsg *msg); private: - int _value; + bool _flag; public: CLASSDEF; - CNavHelmet() : CGameObject(), _value(0) {} + CNavHelmet() : CGameObject(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/nav_helmet_off.cpp b/engines/titanic/game/nav_helmet_off.cpp new file mode 100644 index 0000000000..289e9e3f55 --- /dev/null +++ b/engines/titanic/game/nav_helmet_off.cpp @@ -0,0 +1,49 @@ +/* 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 "titanic/game/nav_helmet_off.h" +#include "titanic/pet_control/pet_control.h" +#include "titanic/messages/pet_messages.h" + +namespace Titanic { + +BEGIN_MESSAGE_MAP(CNavHelmetOff, CNavHelmet) + ON_MESSAGE(MouseButtonUpMsg) +END_MESSAGE_MAP() + +void CNavHelmetOff::save(SimpleFile *file, int indent) { + file->writeNumberLine(1, indent); + file->writeQuotedLine(_target, indent); +} + +void CNavHelmetOff::load(SimpleFile *file) { + file->readNumber(); + _target = file->readString(); +} + +bool CNavHelmetOff::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + CDoffNavHelmet doffMsg; + doffMsg.execute(_target); + return true; +} + +} // End of namespace Titanic diff --git a/engines/titanic/gfx/chev_switch.h b/engines/titanic/game/nav_helmet_off.h index 01da53c854..c9529fe8e9 100644 --- a/engines/titanic/gfx/chev_switch.h +++ b/engines/titanic/game/nav_helmet_off.h @@ -20,23 +20,22 @@ * */ -#ifndef TITANIC_CHEV_SWITCH_H -#define TITANIC_CHEV_SWITCH_H +#ifndef TITANIC_NAV_HELMET_OFF_H +#define TITANIC_NAV_HELMET_OFF_H -#include "titanic/gfx/toggle_switch.h" +#include "titanic/game/nav_helmet.h" +#include "titanic/messages/pet_messages.h" namespace Titanic { -class CChevSwitch : public CToggleSwitch { +class CNavHelmetOff : public CNavHelmet { DECLARE_MESSAGE_MAP; bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); - bool SetChevButtonImageMsg(CSetChevButtonImageMsg *msg); - bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); -public: - int _value; +private: + CString _target; public: CLASSDEF; - CChevSwitch(); + CNavHelmetOff() : CNavHelmet(), _target("NULL") {} /** * Save the data for the class to file @@ -51,4 +50,4 @@ public: } // End of namespace Titanic -#endif /* TITANIC_CHEV_SWITCH_H */ +#endif /* TITANIC_NAV_HELMET_OFF_H */ diff --git a/engines/titanic/game/nav_helmet_on.cpp b/engines/titanic/game/nav_helmet_on.cpp new file mode 100644 index 0000000000..59ceebc4ad --- /dev/null +++ b/engines/titanic/game/nav_helmet_on.cpp @@ -0,0 +1,49 @@ +/* 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 "titanic/game/nav_helmet_on.h" +#include "titanic/pet_control/pet_control.h" +#include "titanic/messages/pet_messages.h" + +namespace Titanic { + +BEGIN_MESSAGE_MAP(CNavHelmetOn, CNavHelmet) + ON_MESSAGE(MouseButtonUpMsg) +END_MESSAGE_MAP() + +void CNavHelmetOn::save(SimpleFile *file, int indent) { + file->writeNumberLine(1, indent); + file->writeQuotedLine(_target, indent); +} + +void CNavHelmetOn::load(SimpleFile *file) { + file->readNumber(); + _target = file->readString(); +} + +bool CNavHelmetOn::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + CDonNavHelmet donMsg; + donMsg.execute(_target); + return true; +} + +} // End of namespace Titanic diff --git a/engines/adl/hires0.h b/engines/titanic/game/nav_helmet_on.h index 624f248ea8..452637c48a 100644 --- a/engines/adl/hires0.h +++ b/engines/titanic/game/nav_helmet_on.h @@ -1,59 +1,53 @@ -/* 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 ADL_HIRES0_H
-#define ADL_HIRES0_H
-
-#include "adl/adl_v2.h"
-
-namespace Adl {
-
-#define IDS_HR0_DISK_IMAGE "MISSION.NIB"
-
-#define IDI_HR0_NUM_ROOMS 43
-#define IDI_HR0_NUM_MESSAGES 142
-#define IDI_HR0_NUM_VARS 40
-#define IDI_HR0_NUM_ITEM_PICS 2
-#define IDI_HR0_NUM_ITEM_OFFSETS 16
-
-// Messages used outside of scripts
-#define IDI_HR0_MSG_CANT_GO_THERE 110
-#define IDI_HR0_MSG_DONT_UNDERSTAND 112
-#define IDI_HR0_MSG_ITEM_DOESNT_MOVE 114
-#define IDI_HR0_MSG_ITEM_NOT_HERE 115
-#define IDI_HR0_MSG_THANKS_FOR_PLAYING 113
-
-class HiRes0Engine : public AdlEngine_v2 {
-public:
- HiRes0Engine(OSystem *syst, const AdlGameDescription *gd) :
- AdlEngine_v2(syst, gd) { }
- ~HiRes0Engine() { }
-
-private:
- // AdlEngine
- void init();
- void initGameState();
-};
-
-} // End of namespace Adl
-
-#endif
+/* 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 TITANIC_NAV_HELMET_ON_H +#define TITANIC_NAV_HELMET_ON_H + +#include "titanic/game/nav_helmet.h" +#include "titanic/messages/pet_messages.h" + +namespace Titanic { + +class CNavHelmetOn : public CNavHelmet { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); +private: + CString _target; +public: + CLASSDEF; + CNavHelmetOn() : CNavHelmet(), _target("NULL") {} + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_NAV_HELMET_ON_H */ diff --git a/engines/titanic/game/no_nut_bowl.cpp b/engines/titanic/game/no_nut_bowl.cpp index 47f9d7901e..8c0a95ac9a 100644 --- a/engines/titanic/game/no_nut_bowl.cpp +++ b/engines/titanic/game/no_nut_bowl.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CNoNutBowl, CBackground) + ON_MESSAGE(ActMsg) + ON_MESSAGE(ReplaceBowlAndNutsMsg) + ON_MESSAGE(NutPuzzleMsg) +END_MESSAGE_MAP() + void CNoNutBowl::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBackground::save(file, indent); @@ -34,4 +40,19 @@ void CNoNutBowl::load(SimpleFile *file) { CBackground::load(file); } +bool CNoNutBowl::ActMsg(CActMsg *msg) { + return true; +} + +bool CNoNutBowl::ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg) { + setVisible(false); + return true; +} + +bool CNoNutBowl::NutPuzzleMsg(CNutPuzzleMsg *msg) { + if (msg->_value == "NutsGone") + setVisible(true); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/no_nut_bowl.h b/engines/titanic/game/no_nut_bowl.h index 548b324869..cd8bc65179 100644 --- a/engines/titanic/game/no_nut_bowl.h +++ b/engines/titanic/game/no_nut_bowl.h @@ -28,6 +28,10 @@ namespace Titanic { class CNoNutBowl : public CBackground { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg); + bool NutPuzzleMsg(CNutPuzzleMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/nose_holder.cpp b/engines/titanic/game/nose_holder.cpp index cd9433ee9c..ac6c10dafd 100644 --- a/engines/titanic/game/nose_holder.cpp +++ b/engines/titanic/game/nose_holder.cpp @@ -24,7 +24,16 @@ namespace Titanic { -CNoseHolder::CNoseHolder() : CDropTarget(), _field118(0), _field11C(0) { +BEGIN_MESSAGE_MAP(CNoseHolder, CDropTarget) + ON_MESSAGE(ActMsg) + ON_MESSAGE(FrameMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +CNoseHolder::CNoseHolder() : CDropTarget(), _dragObject(nullptr), + _field11C(0) { } void CNoseHolder::save(SimpleFile *file, int indent) { @@ -41,4 +50,72 @@ void CNoseHolder::load(SimpleFile *file) { CDropTarget::load(file); } +bool CNoseHolder::ActMsg(CActMsg *msg) { + if (msg->_action == "Sneeze" && !_itemName.empty() && _fieldF4) { + CProximity prox; + prox._positioningMode = POSMODE_VECTOR; + playSound("z#35.wav", prox); + + if (getView() == findView()) { + setVisible(true); + playMovie(1, 13, MOVIE_NOTIFY_OBJECT); + } + } + + return true; +} + +bool CNoseHolder::FrameMsg(CFrameMsg *msg) { + if (!_dragObject) { + CGameObject *dragObj = getDraggingObject(); + if (!dragObj) + return false; + + if (!dragObj->isEquals("Feathers") || getView() != findView()) + return false; + + _dragObject = dragObj; + } + + if (_dragObject) { + if (!checkPoint(Point(_dragObject->_bounds.left, + _dragObject->_bounds.top))) { + _field11C = false; + } else if (!_field11C) { + CActMsg actMsg("Sneeze"); + actMsg.execute(this); + _field11C = true; + } + } + + return true; +} + +bool CNoseHolder::LeaveViewMsg(CLeaveViewMsg *msg) { + _field11C = false; + _dragObject = nullptr; + if (_fieldF4) { + loadFrame(_dropFrame); + setVisible(false); + } + + return true; +} + +bool CNoseHolder::MovieEndMsg(CMovieEndMsg *msg) { + if (_fieldF4) { + loadFrame(_dropFrame); + setVisible(false); + } + + return true; +} + +bool CNoseHolder::EnterViewMsg(CEnterViewMsg *msg) { + if (_fieldF4) + setVisible(false); + + return CDropTarget::EnterViewMsg(msg); +} + } // End of namespace Titanic diff --git a/engines/titanic/game/nose_holder.h b/engines/titanic/game/nose_holder.h index b8cca95869..7b3fbba625 100644 --- a/engines/titanic/game/nose_holder.h +++ b/engines/titanic/game/nose_holder.h @@ -28,8 +28,14 @@ namespace Titanic { class CNoseHolder : public CDropTarget { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool FrameMsg(CFrameMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); private: - int _field118; + CGameObject *_dragObject; int _field11C; public: CLASSDEF; diff --git a/engines/titanic/game/nut_replacer.cpp b/engines/titanic/game/nut_replacer.cpp index 9a73355c91..6b05d1d0e9 100644 --- a/engines/titanic/game/nut_replacer.cpp +++ b/engines/titanic/game/nut_replacer.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CNutReplacer, CGameObject) + ON_MESSAGE(ReplaceBowlAndNutsMsg) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CNutReplacer::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -34,4 +39,15 @@ void CNutReplacer::load(SimpleFile *file) { CGameObject::load(file); } +bool CNutReplacer::ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg) { + setVisible(true); + playMovie(MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + return true; +} + +bool CNutReplacer::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(false); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/nut_replacer.h b/engines/titanic/game/nut_replacer.h index ead9713801..e2eed4e247 100644 --- a/engines/titanic/game/nut_replacer.h +++ b/engines/titanic/game/nut_replacer.h @@ -28,6 +28,9 @@ namespace Titanic { class CNutReplacer : public CGameObject { + DECLARE_MESSAGE_MAP; + bool ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/parrot/parrot_lobby_controller.cpp b/engines/titanic/game/parrot/parrot_lobby_controller.cpp index f1e054a8dd..907e7519b8 100644 --- a/engines/titanic/game/parrot/parrot_lobby_controller.cpp +++ b/engines/titanic/game/parrot/parrot_lobby_controller.cpp @@ -21,9 +21,14 @@ */ #include "titanic/game/parrot/parrot_lobby_controller.h" +#include "titanic/core/room_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotLobbyController, CParrotLobbyObject) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + void CParrotLobbyController::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CParrotLobbyObject::save(file, indent); @@ -34,4 +39,34 @@ void CParrotLobbyController::load(SimpleFile *file) { CParrotLobbyObject::load(file); } +bool CParrotLobbyController::ActMsg(CActMsg *msg) { + if (msg->_action == "Refresh") + return false; + else if (msg->_action == "GainParrot") + _haveParrot = true; + else if (msg->_action == "LoseParrot") + _haveParrot = false; + else if (msg->_action == "GainPerch") + _havePerch = true; + else if (msg->_action == "LosePerch") + _havePerch = false; + else if (msg->_action == "GainStick") + _haveStick = true; + else if (msg->_action == "LoseStick") + _haveStick = false; + + _flags = 0; + if (_haveParrot) + _flags = 4; + if (_havePerch) + _flags |= 2; + if (_haveStick) + _flags |= 1; + + CActMsg actMsg("Refresh"); + actMsg.execute(findRoom(), CParrotLobbyObject::_type, MSGFLAG_CLASS_DEF | MSGFLAG_SCAN); + actMsg.execute("ParrotLobbyUpdater_TOW"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_lobby_controller.h b/engines/titanic/game/parrot/parrot_lobby_controller.h index d2fa4a1801..896a4e19d2 100644 --- a/engines/titanic/game/parrot/parrot_lobby_controller.h +++ b/engines/titanic/game/parrot/parrot_lobby_controller.h @@ -28,6 +28,8 @@ namespace Titanic { class CParrotLobbyController : public CParrotLobbyObject { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/parrot/parrot_lobby_link_updater.cpp b/engines/titanic/game/parrot/parrot_lobby_link_updater.cpp index 25d5ec724b..47311c31f5 100644 --- a/engines/titanic/game/parrot/parrot_lobby_link_updater.cpp +++ b/engines/titanic/game/parrot/parrot_lobby_link_updater.cpp @@ -21,9 +21,46 @@ */ #include "titanic/game/parrot/parrot_lobby_link_updater.h" +#include "titanic/titanic.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotLobbyLinkUpdater, CParrotLobbyObject) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + +/*------------------------------------------------------------------------*/ + +LinkUpdatorEntry::LinkUpdatorEntry() { + Common::fill(&_vals[0], &_vals[8], 0); +} + +void LinkUpdatorEntry::load(Common::SeekableReadStream *s) { + _linkStr = readStringFromStream(s); + for (int idx = 0; idx < 8; ++idx) + _vals[idx] = s->readByte(); +} + +/*------------------------------------------------------------------------*/ + +void LinkUpdatorEntries::load(Common::SeekableReadStream *s, int count) { + resize(count); + for (int idx = 0; idx < count; ++idx) + (*this)[idx].load(s); +} + +/*------------------------------------------------------------------------*/ + +CParrotLobbyLinkUpdater::CParrotLobbyLinkUpdater() : CParrotLobbyObject(), _fieldBC(1) { + Common::SeekableReadStream *s = g_vm->_filesManager->getResource("DATA/PARROT_LOBBY_LINK_UPDATOR"); + _entries[0].load(s, 7); + _entries[1].load(s, 5); + _entries[2].load(s, 6); + _entries[3].load(s, 9); + _entries[4].load(s, 1); + delete s; +} + void CParrotLobbyLinkUpdater::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CParrotLobbyObject::save(file, indent); @@ -34,4 +71,45 @@ void CParrotLobbyLinkUpdater::load(SimpleFile *file) { CParrotLobbyObject::load(file); } +bool CParrotLobbyLinkUpdater::ActMsg(CActMsg *msg) { + if (msg->_action != "Refresh") + return false; + + CNodeItem *node = findNode(); + LinkUpdatorEntries *entriesP; + if (isEquals("ParrotLobbyUpdater_TOW")) { + entriesP = &_entries[4]; + } else { + if (node->_nodeNumber > 3) + return true; + entriesP = &_entries[node->_nodeNumber]; + } + int count = entriesP->size(); + + for (CTreeItem *item = node->getFirstChild(); item; item = item->scan(node)) { + CLinkItem *link = dynamic_cast<CLinkItem *>(item); + if (!link || count == 0) + continue; + + CString linkName = link->getName(); + char c = linkName.lastChar(); + if (c >= 'a' && c <= 'd') + linkName.deleteLastChar(); + + for (uint idx = 0; idx < entriesP->size(); ++idx) { + const LinkUpdatorEntry &entry = (*entriesP)[idx]; + if (entry._linkStr == linkName) { + int val = entry._vals[CParrotLobbyObject::_flags]; + if (val) + linkName += (char)(0x60 + val); + + link->_name = linkName; + break; + } + } + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_lobby_link_updater.h b/engines/titanic/game/parrot/parrot_lobby_link_updater.h index 0470a62dee..93db931a53 100644 --- a/engines/titanic/game/parrot/parrot_lobby_link_updater.h +++ b/engines/titanic/game/parrot/parrot_lobby_link_updater.h @@ -23,16 +23,34 @@ #ifndef TITANIC_PARROT_LOBBY_LINK_UPDATER_H #define TITANIC_PARROT_LOBBY_LINK_UPDATER_H +#include "common/stream.h" #include "titanic/game/parrot/parrot_lobby_object.h" namespace Titanic { +struct LinkUpdatorEntry { + CString _linkStr; + int _vals[8]; + + LinkUpdatorEntry(); + void load(Common::SeekableReadStream *s); +}; + +class LinkUpdatorEntries : public Common::Array<LinkUpdatorEntry> { +public: + void load(Common::SeekableReadStream *s, int count); +}; + class CParrotLobbyLinkUpdater : public CParrotLobbyObject { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); +private: + LinkUpdatorEntries _entries[5]; public: int _fieldBC; public: CLASSDEF; - CParrotLobbyLinkUpdater() : CParrotLobbyObject(), _fieldBC(1) {} + CParrotLobbyLinkUpdater(); /** * Save the data for the class to file diff --git a/engines/titanic/game/parrot/parrot_lobby_object.cpp b/engines/titanic/game/parrot/parrot_lobby_object.cpp index a78ab2b6d9..06222fd063 100644 --- a/engines/titanic/game/parrot/parrot_lobby_object.cpp +++ b/engines/titanic/game/parrot/parrot_lobby_object.cpp @@ -26,34 +26,34 @@ namespace Titanic { EMPTY_MESSAGE_MAP(CParrotLobbyObject, CGameObject); -int CParrotLobbyObject::_v1; -int CParrotLobbyObject::_v2; -int CParrotLobbyObject::_v3; -int CParrotLobbyObject::_v4; +bool CParrotLobbyObject::_haveParrot; +bool CParrotLobbyObject::_havePerch; +bool CParrotLobbyObject::_haveStick; +int CParrotLobbyObject::_flags; void CParrotLobbyObject::init() { - _v1 = 1; - _v2 = 1; - _v3 = 1; - _v4 = 7; + _haveParrot = true; + _havePerch = true; + _haveStick = true; + _flags = 7; } void CParrotLobbyObject::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_v1, indent); - file->writeNumberLine(_v2, indent); - file->writeNumberLine(_v3, indent); - file->writeNumberLine(_v4, indent); + file->writeNumberLine(_haveParrot, indent); + file->writeNumberLine(_havePerch, indent); + file->writeNumberLine(_haveStick, indent); + file->writeNumberLine(_flags, indent); CGameObject::save(file, indent); } void CParrotLobbyObject::load(SimpleFile *file) { file->readNumber(); - _v1 = file->readNumber(); - _v2 = file->readNumber(); - _v3 = file->readNumber(); - _v4 = file->readNumber(); + _haveParrot = file->readNumber(); + _havePerch = file->readNumber(); + _haveStick = file->readNumber(); + _flags = file->readNumber(); CGameObject::load(file); } diff --git a/engines/titanic/game/parrot/parrot_lobby_object.h b/engines/titanic/game/parrot/parrot_lobby_object.h index 5272303888..a210331399 100644 --- a/engines/titanic/game/parrot/parrot_lobby_object.h +++ b/engines/titanic/game/parrot/parrot_lobby_object.h @@ -30,10 +30,10 @@ namespace Titanic { class CParrotLobbyObject : public CGameObject { DECLARE_MESSAGE_MAP; public: - static int _v1; - static int _v2; - static int _v3; - static int _v4; + static bool _haveParrot; + static bool _havePerch; + static bool _haveStick; + static int _flags; static void init(); public: diff --git a/engines/titanic/game/parrot/parrot_lobby_view_object.cpp b/engines/titanic/game/parrot/parrot_lobby_view_object.cpp index ae398036a8..1151325676 100644 --- a/engines/titanic/game/parrot/parrot_lobby_view_object.cpp +++ b/engines/titanic/game/parrot/parrot_lobby_view_object.cpp @@ -24,16 +24,28 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotLobbyViewObject, CParrotLobbyObject) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + void CParrotLobbyViewObject::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); + file->writeNumberLine(_flag, indent); CParrotLobbyObject::save(file, indent); } void CParrotLobbyViewObject::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); + _flag = file->readNumber(); CParrotLobbyObject::load(file); } +bool CParrotLobbyViewObject::ActMsg(CActMsg *msg) { + if (msg->_action != "Refresh") + return false; + + setVisible(_flag ? _haveParrot : _haveStick); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_lobby_view_object.h b/engines/titanic/game/parrot/parrot_lobby_view_object.h index 3179bb962d..484d70908e 100644 --- a/engines/titanic/game/parrot/parrot_lobby_view_object.h +++ b/engines/titanic/game/parrot/parrot_lobby_view_object.h @@ -28,11 +28,13 @@ namespace Titanic { class CParrotLobbyViewObject : public CParrotLobbyObject { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); public: - int _fieldBC; + bool _flag; public: CLASSDEF; - CParrotLobbyViewObject() : CParrotLobbyObject(), _fieldBC(1) {} + CParrotLobbyViewObject() : CParrotLobbyObject(), _flag(true) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/parrot/parrot_loser.cpp b/engines/titanic/game/parrot/parrot_loser.cpp index 6e23ef8314..dc854ee9bd 100644 --- a/engines/titanic/game/parrot/parrot_loser.cpp +++ b/engines/titanic/game/parrot/parrot_loser.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotLoser, CGameObject) + ON_MESSAGE(LeaveRoomMsg) +END_MESSAGE_MAP() + void CParrotLoser::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -34,4 +38,10 @@ void CParrotLoser::load(SimpleFile *file) { CGameObject::load(file); } +bool CParrotLoser::LeaveRoomMsg(CLeaveRoomMsg *msg) { + CActMsg actMsg("FreeParrot"); + actMsg.execute("CarryParrot"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_loser.h b/engines/titanic/game/parrot/parrot_loser.h index 819fd6614c..e03bfb0727 100644 --- a/engines/titanic/game/parrot/parrot_loser.h +++ b/engines/titanic/game/parrot/parrot_loser.h @@ -28,6 +28,8 @@ namespace Titanic { class CParrotLoser : public CGameObject { + DECLARE_MESSAGE_MAP; + bool LeaveRoomMsg(CLeaveRoomMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/parrot/parrot_nut_bowl_actor.cpp b/engines/titanic/game/parrot/parrot_nut_bowl_actor.cpp index c83d66cbdf..9dfc866c0e 100644 --- a/engines/titanic/game/parrot/parrot_nut_bowl_actor.cpp +++ b/engines/titanic/game/parrot/parrot_nut_bowl_actor.cpp @@ -21,27 +21,95 @@ */ #include "titanic/game/parrot/parrot_nut_bowl_actor.h" +#include "titanic/core/room_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotNutBowlActor, CGameObject) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(BowlStateChangeMsg) + ON_MESSAGE(IsEarBowlPuzzleDone) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(ReplaceBowlAndNutsMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(NutPuzzleMsg) +END_MESSAGE_MAP() + CParrotNutBowlActor::CParrotNutBowlActor() : CGameObject(), - _value1(0), _value2(0) { + _puzzleDone(0), _state(0) { } void CParrotNutBowlActor::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value1, indent); - file->writeNumberLine(_value2, indent); + file->writeNumberLine(_puzzleDone, indent); + file->writeNumberLine(_state, indent); CGameObject::save(file, indent); } void CParrotNutBowlActor::load(SimpleFile *file) { file->readNumber(); - _value1 = file->readNumber(); - _value2 = file->readNumber(); + _puzzleDone = file->readNumber(); + _state = file->readNumber(); CGameObject::load(file); } +bool CParrotNutBowlActor::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + if (!_state) { + CActMsg actMsg("Jiggle"); + actMsg.execute("BowlNutsRustler"); + } + + return true; +} + +bool CParrotNutBowlActor::BowlStateChangeMsg(CBowlStateChangeMsg *msg) { + _state = msg->_state; + if (msg->_state == 3) { + if (!_puzzleDone) { + CReplaceBowlAndNutsMsg replaceMsg; + replaceMsg.execute(findRoom(), nullptr, MSGFLAG_SCAN); + playSound("z#47.wav"); + } + + _puzzleDone = true; + } + + return true; +} + +bool CParrotNutBowlActor::CParrotNutBowlActor::IsEarBowlPuzzleDone(CIsEarBowlPuzzleDone *msg) { + msg->_value = _puzzleDone; + return true; +} + +bool CParrotNutBowlActor::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + +bool CParrotNutBowlActor::ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg) { + if (!_puzzleDone) + _state = 0; + return true; +} + +bool CParrotNutBowlActor::LeaveViewMsg(CLeaveViewMsg *msg) { + if (!_puzzleDone && _state) { + CReplaceBowlAndNutsMsg replaceMsg; + replaceMsg.execute(findRoom(), nullptr, MSGFLAG_SCAN); + } + + return true; +} + +bool CParrotNutBowlActor::NutPuzzleMsg(CNutPuzzleMsg *msg) { + if (msg->_value == "NutsGone") + _state = 1; + else if (msg->_value == "BowlUnlocked") + _state = 2; + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_nut_bowl_actor.h b/engines/titanic/game/parrot/parrot_nut_bowl_actor.h index d8395bb65a..b228c0ea9e 100644 --- a/engines/titanic/game/parrot/parrot_nut_bowl_actor.h +++ b/engines/titanic/game/parrot/parrot_nut_bowl_actor.h @@ -28,8 +28,17 @@ namespace Titanic { class CParrotNutBowlActor : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool BowlStateChangeMsg(CBowlStateChangeMsg *msg); + bool IsEarBowlPuzzleDone(CIsEarBowlPuzzleDone *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool NutPuzzleMsg(CNutPuzzleMsg *msg); public: - int _value1, _value2; + bool _puzzleDone; + int _state; public: CLASSDEF; CParrotNutBowlActor(); diff --git a/engines/titanic/game/parrot/parrot_nut_eater.cpp b/engines/titanic/game/parrot/parrot_nut_eater.cpp index 309b379ab8..751da931ac 100644 --- a/engines/titanic/game/parrot/parrot_nut_eater.cpp +++ b/engines/titanic/game/parrot/parrot_nut_eater.cpp @@ -21,9 +21,17 @@ */ #include "titanic/game/parrot/parrot_nut_eater.h" +#include "titanic/core/room_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotNutEater, CGameObject) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(ReplaceBowlAndNutsMsg) + ON_MESSAGE(NutPuzzleMsg) + ON_MESSAGE(MovieFrameMsg) +END_MESSAGE_MAP() + CParrotNutEater::CParrotNutEater() : CGameObject(), _fieldBC(0), _fieldC0(69), _fieldC4(132), _fieldC8(0), _fieldCC(68) { } @@ -42,4 +50,48 @@ void CParrotNutEater::load(SimpleFile *file) { CGameObject::load(file); } +bool CParrotNutEater::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(false); + CNutPuzzleMsg nutMsg("NutsGone"); + nutMsg.execute(getRoom(), nullptr, MSGFLAG_SCAN); + + playSound("z#47.wav"); + return true; +} + +bool CParrotNutEater::ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg) { + setVisible(false); + return true; +} + +bool CParrotNutEater::NutPuzzleMsg(CNutPuzzleMsg *msg) { + if (msg->_value == "Jiggle") { + playMovie(MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + movieEvent(68); + movieEvent(132); + playSound("z#215.wav"); + + CTrueTalkTriggerActionMsg triggerMsg; + triggerMsg._param1 = triggerMsg._param2 = 0; + triggerMsg.execute("PerchedParrot"); + } + + return true; +} + +bool CParrotNutEater::MovieFrameMsg(CMovieFrameMsg *msg) { + switch (msg->_frameNumber) { + case 68: + playSound("z#214.wav"); + break; + case 132: + playSound("z#216.wav"); + break; + default: + break; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_nut_eater.h b/engines/titanic/game/parrot/parrot_nut_eater.h index 5dcb01ca11..e09ad63947 100644 --- a/engines/titanic/game/parrot/parrot_nut_eater.h +++ b/engines/titanic/game/parrot/parrot_nut_eater.h @@ -28,6 +28,11 @@ namespace Titanic { class CParrotNutEater : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MovieEndMsg(CMovieEndMsg *msg); + bool ReplaceBowlAndNutsMsg(CReplaceBowlAndNutsMsg *msg); + bool NutPuzzleMsg(CNutPuzzleMsg *msg); + bool MovieFrameMsg(CMovieFrameMsg *msg); public: int _fieldBC; int _fieldC0; diff --git a/engines/titanic/game/parrot/parrot_perch_holder.cpp b/engines/titanic/game/parrot/parrot_perch_holder.cpp index dd8523990b..d594446219 100644 --- a/engines/titanic/game/parrot/parrot_perch_holder.cpp +++ b/engines/titanic/game/parrot/parrot_perch_holder.cpp @@ -21,9 +21,19 @@ */ #include "titanic/game/parrot/parrot_perch_holder.h" +#include "titanic/game/cage.h" +#include "titanic/core/project_item.h" +#include "titanic/npcs/parrot.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotPerchHolder, CMultiDropTarget) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(DropObjectMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + void CParrotPerchHolder::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CMultiDropTarget::save(file, indent); @@ -34,4 +44,39 @@ void CParrotPerchHolder::load(SimpleFile *file) { CMultiDropTarget::load(file); } +bool CParrotPerchHolder::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (CParrot::_v1) { + if (CCage::_open) { + petDisplayMessage("You cannot take this because the cage is locked shut."); + } else if (!CParrot::_v4) { + CTrueTalkTriggerActionMsg triggerMsg(280252, 0, 0); + triggerMsg.execute(getRoot(), CParrot::_type, + MSGFLAG_CLASS_DEF | MSGFLAG_BREAK_IF_HANDLED | MSGFLAG_SCAN); + } + } + + return true; +} + +bool CParrotPerchHolder::StatusChangeMsg(CStatusChangeMsg *msg) { + _fieldF4 = msg->_newStatus; + return true; +} + +bool CParrotPerchHolder::DropObjectMsg(CDropObjectMsg *msg) { + if (CCage::_open) + return false; + else + return CMultiDropTarget::DropObjectMsg(msg); +} + +bool CParrotPerchHolder::ActMsg(CActMsg *msg) { + if (msg->_action == "FlashCore") { + playMovie(2, 2, 0); + playMovie(1, 1, 0); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_perch_holder.h b/engines/titanic/game/parrot/parrot_perch_holder.h index ff618f09dc..c1fe243476 100644 --- a/engines/titanic/game/parrot/parrot_perch_holder.h +++ b/engines/titanic/game/parrot/parrot_perch_holder.h @@ -28,6 +28,11 @@ namespace Titanic { class CParrotPerchHolder : public CMultiDropTarget { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool DropObjectMsg(CDropObjectMsg *msg); + bool ActMsg(CActMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/parrot/parrot_trigger.cpp b/engines/titanic/game/parrot/parrot_trigger.cpp index 36e99ada33..b7287ebb6a 100644 --- a/engines/titanic/game/parrot/parrot_trigger.cpp +++ b/engines/titanic/game/parrot/parrot_trigger.cpp @@ -21,9 +21,15 @@ */ #include "titanic/game/parrot/parrot_trigger.h" +#include "titanic/npcs/parrot.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CParrotTrigger, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CParrotTrigger::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_value, indent); @@ -36,4 +42,11 @@ void CParrotTrigger::load(SimpleFile *file) { CGameObject::load(file); } +bool CParrotTrigger::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CTrueTalkTriggerActionMsg triggerMsg(_value, 0, 0); + triggerMsg.execute(getRoot(), CParrot::_type, + MSGFLAG_CLASS_DEF | MSGFLAG_BREAK_IF_HANDLED | MSGFLAG_SCAN); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/parrot/parrot_trigger.h b/engines/titanic/game/parrot/parrot_trigger.h index 28a1663fa8..6fba77b56d 100644 --- a/engines/titanic/game/parrot/parrot_trigger.h +++ b/engines/titanic/game/parrot/parrot_trigger.h @@ -28,6 +28,8 @@ namespace Titanic { class CParrotTrigger : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: int _value; public: diff --git a/engines/titanic/game/parrot/player_meets_parrot.cpp b/engines/titanic/game/parrot/player_meets_parrot.cpp index 6db9345bc0..cdb14516bf 100644 --- a/engines/titanic/game/parrot/player_meets_parrot.cpp +++ b/engines/titanic/game/parrot/player_meets_parrot.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPlayerMeetsParrot, CGameObject) + ON_MESSAGE(EnterRoomMsg) +END_MESSAGE_MAP() + void CPlayerMeetsParrot::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -35,7 +39,7 @@ void CPlayerMeetsParrot::load(SimpleFile *file) { } bool CPlayerMeetsParrot::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CPlayerMeetsParrot::handleEvent"); + stateSet24(); return true; } diff --git a/engines/titanic/game/parrot/player_meets_parrot.h b/engines/titanic/game/parrot/player_meets_parrot.h index 9cee9ee322..edae18801f 100644 --- a/engines/titanic/game/parrot/player_meets_parrot.h +++ b/engines/titanic/game/parrot/player_meets_parrot.h @@ -29,6 +29,7 @@ namespace Titanic { class CPlayerMeetsParrot : public CGameObject { + DECLARE_MESSAGE_MAP; protected: bool EnterRoomMsg(CEnterRoomMsg *msg); public: diff --git a/engines/titanic/game/pet/pet.cpp b/engines/titanic/game/pet/pet.cpp index cd4e16d38c..99c9e01eb3 100644 --- a/engines/titanic/game/pet/pet.cpp +++ b/engines/titanic/game/pet/pet.cpp @@ -21,9 +21,14 @@ */ #include "titanic/game/pet/pet.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPET, CGameObject) + ON_MESSAGE(ShowTextMsg) +END_MESSAGE_MAP() + CPET::CPET() : CGameObject(), _fieldBC(0), _fieldC0(3), _fieldC4(0), _fieldC8(0), _fieldD8(0), _fieldDC(0) { } @@ -54,4 +59,11 @@ void CPET::load(SimpleFile *file) { CGameObject::load(file); } +bool CPET::ShowTextMsg(CShowTextMsg *msg) { + CPetControl *pet = getPetControl(); + if (pet) + pet->petDisplayMessage(1, msg->_value); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet/pet.h b/engines/titanic/game/pet/pet.h index cdad649401..de31a423d0 100644 --- a/engines/titanic/game/pet/pet.h +++ b/engines/titanic/game/pet/pet.h @@ -28,6 +28,8 @@ namespace Titanic { class CPET : public CGameObject { + DECLARE_MESSAGE_MAP; + bool ShowTextMsg(CShowTextMsg *msg); public: int _fieldBC; int _fieldC0; diff --git a/engines/titanic/game/pet/pet_lift.cpp b/engines/titanic/game/pet/pet_lift.cpp index 39b0d01540..afa9dd04cd 100644 --- a/engines/titanic/game/pet/pet_lift.cpp +++ b/engines/titanic/game/pet/pet_lift.cpp @@ -21,9 +21,14 @@ */ #include "titanic/game/pet/pet_lift.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPETLift, CPETTransport) + ON_MESSAGE(TransportMsg) +END_MESSAGE_MAP() + void CPETLift::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CPETTransport::save(file, indent); @@ -34,4 +39,36 @@ void CPETLift::load(SimpleFile *file) { CPETTransport::load(file); } +bool CPETLift::TransportMsg(CTransportMsg *msg) { + CPetControl *pet = getPetControl(); + if (msg->_value1 != 1) + return false; + + int floorNum = -1; + if (msg->_roomName == "TopOfWell") { + floorNum = 1; + } else if (msg->_roomName == "BottomOfWell") { + floorNum = 39; + } else if (msg->_roomName == "PlayersRoom" && pet) { + int assignedFloor = pet->getAssignedFloorNum(); + if (assignedFloor < 1 || assignedFloor > 39) { + pet->petDisplayMessage("You have not assigned a room to go to."); + floorNum = -1; + } + } + + if (floorNum != -1) { + int elevatorNum = pet ? pet->getRoomsElevatorNum() : 0; + + if ((elevatorNum == 2 || elevatorNum == 4) && floorNum > 27) { + petDisplayMessage("Sorry, this elevator does not go below floor 27."); + } else { + CTrueTalkTriggerActionMsg triggerMsg(2, floorNum, 0); + triggerMsg.execute("Liftbot"); + } + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet/pet_lift.h b/engines/titanic/game/pet/pet_lift.h index 88b4e1c029..ce3aace1a6 100644 --- a/engines/titanic/game/pet/pet_lift.h +++ b/engines/titanic/game/pet/pet_lift.h @@ -28,6 +28,8 @@ namespace Titanic { class CPETLift : public CPETTransport { + DECLARE_MESSAGE_MAP; + bool TransportMsg(CTransportMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/pet/pet_monitor.cpp b/engines/titanic/game/pet/pet_monitor.cpp index 6a0d207a55..2716a81fa8 100644 --- a/engines/titanic/game/pet/pet_monitor.cpp +++ b/engines/titanic/game/pet/pet_monitor.cpp @@ -21,6 +21,8 @@ */ #include "titanic/game/pet/pet_monitor.h" +#include "titanic/core/room_item.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { @@ -39,7 +41,23 @@ void CPETMonitor::load(SimpleFile *file) { } bool CPETMonitor::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CPETMonitor::handleEvent"); + bool flag = true; + if (msg->_newRoom && msg->_oldRoom) { + CString oldRoomName = msg->_oldRoom->getName(); + CString newRoomName = msg->_newRoom->getName(); + + if (newRoomName == "SgtLobby" && oldRoomName == "SGTState") + flag = false; + } + + if (flag) { + CPetControl *pet = getPetControl(); + if (pet) { + pet->setRoomsRoomNum(0); + pet->resetRoomsHighlight(); + } + } + return true; } diff --git a/engines/titanic/game/pet/pet_pellerator.cpp b/engines/titanic/game/pet/pet_pellerator.cpp index a29942ca59..59516ebcde 100644 --- a/engines/titanic/game/pet/pet_pellerator.cpp +++ b/engines/titanic/game/pet/pet_pellerator.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPETPellerator, CPETTransport) + ON_MESSAGE(PETActivateMsg) +END_MESSAGE_MAP() + void CPETPellerator::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CPETTransport::save(file, indent); @@ -34,4 +38,24 @@ void CPETPellerator::load(SimpleFile *file) { CPETTransport::load(file); } +bool CPETPellerator::PETActivateMsg(CPETActivateMsg *msg) { + CStatusChangeMsg statusMsg; + + if (msg->_name == "PromenadeDeck") + statusMsg._newStatus = 0; + else if (msg->_name == "MusicRoom") + statusMsg._newStatus = 1; + else if (msg->_name == "Bar") + statusMsg._newStatus = 2; + else if (msg->_name == "TopOfWell") + statusMsg._newStatus = 4; + else if (msg->_name == "1stClassRestaurant") + statusMsg._newStatus = 5; + else if (msg->_name == "Arboretum") + statusMsg._newStatus = 6; + + statusMsg.execute("PelleratorObject"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet/pet_pellerator.h b/engines/titanic/game/pet/pet_pellerator.h index 9b90c9af28..51af6f1bcd 100644 --- a/engines/titanic/game/pet/pet_pellerator.h +++ b/engines/titanic/game/pet/pet_pellerator.h @@ -24,10 +24,13 @@ #define TITANIC_PET_PELLERATOR_H #include "titanic/game/pet/pet_transport.h" +#include "titanic/messages/pet_messages.h" namespace Titanic { class CPETPellerator : public CPETTransport { + DECLARE_MESSAGE_MAP; + bool PETActivateMsg(CPETActivateMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/pet/pet_sentinal.cpp b/engines/titanic/game/pet/pet_sentinal.cpp index 1b647d7c62..ac4cbc8418 100644 --- a/engines/titanic/game/pet/pet_sentinal.cpp +++ b/engines/titanic/game/pet/pet_sentinal.cpp @@ -21,17 +21,46 @@ */ #include "titanic/game/pet/pet_sentinal.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPETSentinal, CGameObject) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +CPETSentinal::CPETSentinal() : CGameObject(), _elevatorNum(0), + _wellEntry(0), _resetHighlight(0) { +} + void CPETSentinal::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); + file->writeNumberLine(_elevatorNum, indent); + file->writeNumberLine(_wellEntry, indent); + file->writeNumberLine(_resetHighlight, indent); CGameObject::save(file, indent); } void CPETSentinal::load(SimpleFile *file) { file->readNumber(); + _elevatorNum = file->readNumber(); + _wellEntry = file->readNumber(); + _resetHighlight = file->readNumber(); CGameObject::load(file); } +bool CPETSentinal::EnterViewMsg(CEnterViewMsg *msg) { + CPetControl *pet = getPetControl(); + if (pet) { + if (_elevatorNum != -1) + pet->setRoomsElevatorNum(_elevatorNum); + if (_wellEntry) + pet->setRoomsWellEntry(_wellEntry); + if (_resetHighlight) + pet->resetRoomsHighlight(); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet/pet_sentinal.h b/engines/titanic/game/pet/pet_sentinal.h index f7f9fef0ba..150fe4a87e 100644 --- a/engines/titanic/game/pet/pet_sentinal.h +++ b/engines/titanic/game/pet/pet_sentinal.h @@ -28,8 +28,15 @@ namespace Titanic { class CPETSentinal : public CGameObject { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); +private: + int _elevatorNum; + int _wellEntry; + bool _resetHighlight; public: CLASSDEF; + CPETSentinal(); /** * Save the data for the class to file diff --git a/engines/titanic/game/pet/pet_sounds.cpp b/engines/titanic/game/pet/pet_sounds.cpp index d612c745bb..c7f3cd3bf8 100644 --- a/engines/titanic/game/pet/pet_sounds.cpp +++ b/engines/titanic/game/pet/pet_sounds.cpp @@ -24,16 +24,40 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPETSounds, CGameObject) + ON_MESSAGE(PETPlaySoundMsg) + ON_MESSAGE(LoadSuccessMsg) +END_MESSAGE_MAP() + void CPETSounds::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_ticks, indent); CGameObject::save(file, indent); } void CPETSounds::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _ticks = file->readNumber(); CGameObject::load(file); } +bool CPETSounds::PETPlaySoundMsg(CPETPlaySoundMsg *msg) { + if (msg->_soundNum == 1) { + playSound("z#65.wav"); + } else if (msg->_soundNum == 2 && stateGet24()) { + uint ticks = getTicksCount(); + if (!_ticks || ticks > (_ticks + 12000)) { + playSound("z#36.wav"); + _ticks = ticks; + } + } + + return true; +} + +bool CPETSounds::LoadSuccessMsg(CLoadSuccessMsg *msg) { + _ticks = 0; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet/pet_sounds.h b/engines/titanic/game/pet/pet_sounds.h index 1d3acdb5f3..2262fde916 100644 --- a/engines/titanic/game/pet/pet_sounds.h +++ b/engines/titanic/game/pet/pet_sounds.h @@ -24,15 +24,19 @@ #define TITANIC_PET_SOUNDS_H #include "titanic/core/game_object.h" +#include "titanic/messages/pet_messages.h" namespace Titanic { class CPETSounds : public CGameObject { + DECLARE_MESSAGE_MAP; + bool PETPlaySoundMsg(CPETPlaySoundMsg *msg); + bool LoadSuccessMsg(CLoadSuccessMsg *msg); public: - int _value; + uint _ticks; public: CLASSDEF; - CPETSounds() : CGameObject(), _value(0) {} + CPETSounds() : CGameObject(), _ticks(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/pet/pet_transition.cpp b/engines/titanic/game/pet/pet_transition.cpp index 33cc36ca11..ec10569236 100644 --- a/engines/titanic/game/pet/pet_transition.cpp +++ b/engines/titanic/game/pet/pet_transition.cpp @@ -21,9 +21,15 @@ */ #include "titanic/game/pet/pet_transition.h" +#include "titanic/pet_control/pet_control.h" +#include "titanic/core/view_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPETTransition, CGameObject) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + void CPETTransition::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -34,4 +40,21 @@ void CPETTransition::load(SimpleFile *file) { CGameObject::load(file); } +bool CPETTransition::EnterViewMsg(CEnterViewMsg *msg) { + CPetControl *pet = getPetControl(); + + if (compareRoomNameTo("1stClassLobby") && pet) { + int elevatorNum = pet->getRoomsElevatorNum(); + CString nodeView = msg->_newView->getNodeViewName(); + + if (nodeView == "Node 1.E") { + pet->setRoomsElevatorNum((elevatorNum == 1 || elevatorNum == 2) ? 1 : 3); + } else if (nodeView == "Node 1.W") { + pet->setRoomsElevatorNum((elevatorNum == 1 || elevatorNum == 2) ? 2 : 4); + } + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet/pet_transition.h b/engines/titanic/game/pet/pet_transition.h index 4abf16d509..d0fa20ccc5 100644 --- a/engines/titanic/game/pet/pet_transition.h +++ b/engines/titanic/game/pet/pet_transition.h @@ -28,6 +28,8 @@ namespace Titanic { class CPETTransition : public CGameObject { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/pet/pet_transport.cpp b/engines/titanic/game/pet/pet_transport.cpp index 9661cace2c..a48e70ed01 100644 --- a/engines/titanic/game/pet/pet_transport.cpp +++ b/engines/titanic/game/pet/pet_transport.cpp @@ -39,7 +39,7 @@ void CPETTransport::load(SimpleFile *file) { } bool CPETTransport::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CPETTransport::handleEvent"); + petClear(); return true; } diff --git a/engines/titanic/game/pet_disabler.cpp b/engines/titanic/game/pet_disabler.cpp index 2275156503..c4946fe39f 100644 --- a/engines/titanic/game/pet_disabler.cpp +++ b/engines/titanic/game/pet_disabler.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPetDisabler, CGameObject) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + void CPetDisabler::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeQuotedLine(_value, indent); @@ -36,4 +41,14 @@ void CPetDisabler::load(SimpleFile *file) { CGameObject::load(file); } +bool CPetDisabler::EnterViewMsg(CEnterViewMsg *msg) { + petLockInput(); + return true; +} + +bool CPetDisabler::LeaveViewMsg(CLeaveViewMsg *msg) { + petUnlockInput(); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pet_disabler.h b/engines/titanic/game/pet_disabler.h index 92b4dff0a8..06e99be49e 100644 --- a/engines/titanic/game/pet_disabler.h +++ b/engines/titanic/game/pet_disabler.h @@ -28,6 +28,9 @@ namespace Titanic { class CPetDisabler : public CGameObject { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); public: CString _value; public: diff --git a/engines/titanic/game/phonograph.cpp b/engines/titanic/game/phonograph.cpp index 9740e29273..408cfa3413 100644 --- a/engines/titanic/game/phonograph.cpp +++ b/engines/titanic/game/phonograph.cpp @@ -24,9 +24,18 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPhonograph, CMusicPlayer) + ON_MESSAGE(PhonographPlayMsg) + ON_MESSAGE(PhonographStopMsg) + ON_MESSAGE(PhonographRecordMsg) + ON_MESSAGE(EnterRoomMsg) + ON_MESSAGE(LeaveRoomMsg) + ON_MESSAGE(MusicHasStartedMsg) +END_MESSAGE_MAP() + CPhonograph::CPhonograph() : CMusicPlayer(), - _fieldE0(0), _fieldE4(0), _fieldE8(0), _fieldEC(0), - _fieldF0(0), _fieldF4(0) { + _fieldE0(false), _fieldE4(0), _fieldE8(0), _fieldEC(0), + _fieldF0(0), _fieldF4(0) { } void CPhonograph::save(SimpleFile *file, int indent) { @@ -55,8 +64,113 @@ void CPhonograph::load(SimpleFile *file) { CMusicPlayer::load(file); } +bool CPhonograph::PhonographPlayMsg(CPhonographPlayMsg *msg) { + CQueryCylinderHolderMsg holderMsg; + holderMsg.execute(this); + if (!holderMsg._value2) { + _fieldE0 = false; + return true; + } + + CQueryCylinderMsg cylinderMsg; + cylinderMsg.execute(holderMsg._target); + + if (cylinderMsg._name.empty()) { + _fieldE0 = false; + } else if (cylinderMsg._name.hasPrefix("STMusic")) { + CStartMusicMsg startMsg(this); + startMsg.execute(this); + _fieldE0 = true; + msg->_value = 1; + } else { + stopGlobalSound(0, -1); + playGlobalSound(cylinderMsg._name, -2, true, true, 0); + _fieldE0 = true; + msg->_value = 1; + } + + return true; +} + +bool CPhonograph::PhonographStopMsg(CPhonographStopMsg *msg) { + CQueryCylinderHolderMsg holderMsg; + holderMsg.execute(this); + if (!holderMsg._value2) + return true; + + _fieldE0 = false; + CQueryCylinderMsg cylinderMsg; + cylinderMsg.execute(holderMsg._target); + + if (_fieldE0) { + if (!cylinderMsg._name.empty()) { + if (cylinderMsg._name.hasPrefix("STMusic")) { + CStopMusicMsg stopMsg; + stopMsg.execute(this); + } else { + stopGlobalSound(msg->_value1, -1); + } + msg->_value2 = 1; + } + + if (!msg->_value3) + _fieldE0 = false; + } else if (_fieldE4) { + _fieldE4 = false; + msg->_value2 = 1; + } + + return true; +} + +bool CPhonograph::PhonographRecordMsg(CPhonographRecordMsg *msg) { + if (!_fieldE0 && !_fieldE4 && !_fieldE8) { + CQueryCylinderHolderMsg holderMsg; + holderMsg.execute(this); + + if (holderMsg._value2) { + _fieldE4 = true; + CErasePhonographCylinderMsg eraseMsg; + eraseMsg.execute(holderMsg._target); + } else { + _fieldE4 = false; + } + } + + return true; +} + bool CPhonograph::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CPhonograph::handleEvent"); + if (_fieldE0) { + CPhonographPlayMsg playMsg; + playMsg.execute(this); + } + + return true; +} + +bool CPhonograph::LeaveRoomMsg(CLeaveRoomMsg *msg) { + if (_fieldE0) { + CPhonographStopMsg stopMsg; + stopMsg._value1 = 1; + stopMsg.execute(this); + } + + return true; +} + +bool CPhonograph::MusicHasStartedMsg(CMusicHasStartedMsg *msg) { + if (_fieldE4) { + CQueryCylinderHolderMsg holderMsg; + holderMsg.execute(this); + if (holderMsg._value2) { + CRecordOntoCylinderMsg recordMsg; + recordMsg.execute(holderMsg._target); + } else { + _fieldE4 = false; + } + } + return true; } diff --git a/engines/titanic/game/phonograph.h b/engines/titanic/game/phonograph.h index 274d4ba367..b13a5ea910 100644 --- a/engines/titanic/game/phonograph.h +++ b/engines/titanic/game/phonograph.h @@ -29,10 +29,16 @@ namespace Titanic { class CPhonograph : public CMusicPlayer { + DECLARE_MESSAGE_MAP; + bool PhonographPlayMsg(CPhonographPlayMsg *msg); + bool PhonographStopMsg(CPhonographStopMsg *msg); + bool PhonographRecordMsg(CPhonographRecordMsg *msg); bool EnterRoomMsg(CEnterRoomMsg *msg); + bool LeaveRoomMsg(CLeaveRoomMsg *msg); + bool MusicHasStartedMsg(CMusicHasStartedMsg *msg); protected: CString _string2; - int _fieldE0; + bool _fieldE0; int _fieldE4; int _fieldE8; int _fieldEC; diff --git a/engines/titanic/game/phonograph_lid.cpp b/engines/titanic/game/phonograph_lid.cpp index a0518420f7..3741749fbf 100644 --- a/engines/titanic/game/phonograph_lid.cpp +++ b/engines/titanic/game/phonograph_lid.cpp @@ -24,16 +24,63 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPhonographLid, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(LockPhonographMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + void CPhonographLid::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_open, indent); CGameObject::save(file, indent); } void CPhonographLid::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _open = file->readNumber(); CGameObject::load(file); } +bool CPhonographLid::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CQueryPhonographState stateMsg; + stateMsg.execute(getParent(), nullptr, MSGFLAG_SCAN); + if (stateMsg._value) { + if (_open) { + CGameObject *lock = dynamic_cast<CGameObject *>(findByName("Music System Lock")); + if (lock) + lock->setVisible(false); + playMovie(0, 27, 0); + } else { + playMovie(27, 55, 0); + } + + _open = !_open; + } else { + petDisplayMessage(0, "This is the restaurant music system. It appears to be locked."); + } + + return true; +} + +bool CPhonographLid::MovieEndMsg(CMovieEndMsg *msg) { + // WORKAROUND: Redundant code in original not included + return true; +} + +bool CPhonographLid::LockPhonographMsg(CLockPhonographMsg *msg) { + _cursorId = msg->_value ? CURSOR_INVALID : CURSOR_ARROW; + return true; +} + +bool CPhonographLid::LeaveViewMsg(CLeaveViewMsg *msg) { + if (_open) { + playMovie(27, 55, MOVIE_GAMESTATE); + _open = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/phonograph_lid.h b/engines/titanic/game/phonograph_lid.h index ab32be268b..4e71d70ec2 100644 --- a/engines/titanic/game/phonograph_lid.h +++ b/engines/titanic/game/phonograph_lid.h @@ -28,11 +28,16 @@ namespace Titanic { class CPhonographLid : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool LockPhonographMsg(CLockPhonographMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); private: - int _value; + bool _open; public: CLASSDEF; - CPhonographLid() : CGameObject(), _value(0) {} + CPhonographLid() : CGameObject(), _open(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/pickup/pick_up.cpp b/engines/titanic/game/pickup/pick_up.cpp index c660a36a32..64d2d1d0d2 100644 --- a/engines/titanic/game/pickup/pick_up.cpp +++ b/engines/titanic/game/pickup/pick_up.cpp @@ -24,16 +24,26 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPickUp, CGameObject) + ON_MESSAGE(StatusChangeMsg) +END_MESSAGE_MAP() + void CPickUp::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); + file->writeNumberLine(_enabled, indent); CGameObject::save(file, indent); } void CPickUp::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); + _enabled = file->readNumber(); CGameObject::load(file); } +bool CPickUp::StatusChangeMsg(CStatusChangeMsg *msg) { + _enabled = msg->_newStatus == 1; + setVisible(_enabled); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pickup/pick_up.h b/engines/titanic/game/pickup/pick_up.h index f0b6794442..f5ee06fd32 100644 --- a/engines/titanic/game/pickup/pick_up.h +++ b/engines/titanic/game/pickup/pick_up.h @@ -28,11 +28,13 @@ namespace Titanic { class CPickUp : public CGameObject { -private: - int _fieldBC; + DECLARE_MESSAGE_MAP; + bool StatusChangeMsg(CStatusChangeMsg *msg); +protected: + bool _enabled; public: CLASSDEF; - CPickUp() : CGameObject(), _fieldBC(0) {} + CPickUp() : CGameObject(), _enabled(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/pickup/pick_up_bar_glass.cpp b/engines/titanic/game/pickup/pick_up_bar_glass.cpp index 85b883281e..9da17b139e 100644 --- a/engines/titanic/game/pickup/pick_up_bar_glass.cpp +++ b/engines/titanic/game/pickup/pick_up_bar_glass.cpp @@ -21,9 +21,16 @@ */ #include "titanic/game/pickup/pick_up_bar_glass.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPickUpBarGlass, CPickUp) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(MouseDragStartMsg) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CPickUpBarGlass::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CPickUp::save(file, indent); @@ -34,4 +41,48 @@ void CPickUpBarGlass::load(SimpleFile *file) { CPickUp::load(file); } +bool CPickUpBarGlass::StatusChangeMsg(CStatusChangeMsg *msg) { + switch (msg->_newStatus) { + case 0: + setVisible(false); + _enabled = false; + break; + case 1: + setVisible(true); + _enabled = true; + break; + case 2: + setVisible(true); + _enabled = false; + break; + default: + break; + } + + return true; +} + +bool CPickUpBarGlass::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (checkStartDragging(msg) && _enabled) { + CTurnOn onMsg; + onMsg.execute("BeerGlass"); + CVisibleMsg visibleMsg; + visibleMsg.execute("BeerGlass"); + CPassOnDragStartMsg passMsg(msg->_mousePos, 1, 3); + passMsg.execute("BeerGlass"); + + msg->_dragItem = getRoot()->findByName("BeerGlass"); + + CActMsg actMsg("PlayerTakesGlass"); + actMsg.execute("Barbot"); + return true; + } else { + return false; + } +} + +bool CPickUpBarGlass::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pickup/pick_up_bar_glass.h b/engines/titanic/game/pickup/pick_up_bar_glass.h index b5ef6f5a47..d273d96170 100644 --- a/engines/titanic/game/pickup/pick_up_bar_glass.h +++ b/engines/titanic/game/pickup/pick_up_bar_glass.h @@ -28,6 +28,10 @@ namespace Titanic { class CPickUpBarGlass : public CPickUp { + DECLARE_MESSAGE_MAP; + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/pickup/pick_up_hose.cpp b/engines/titanic/game/pickup/pick_up_hose.cpp index 7375ddaa63..d07088cefd 100644 --- a/engines/titanic/game/pickup/pick_up_hose.cpp +++ b/engines/titanic/game/pickup/pick_up_hose.cpp @@ -21,14 +21,24 @@ */ #include "titanic/game/pickup/pick_up_hose.h" +#include "titanic/core/project_item.h" +#include "titanic/core/room_item.h" +#include "titanic/core/view_item.h" namespace Titanic { -int CPickUpHose::_v1; +BEGIN_MESSAGE_MAP(CPickUpHose, CPickUp) + ON_MESSAGE(MouseDragStartMsg) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + +bool CPickUpHose::_v1; void CPickUpHose::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string1, indent); + file->writeQuotedLine(_target, indent); file->writeNumberLine(_v1, indent); CPickUp::save(file, indent); @@ -36,10 +46,61 @@ void CPickUpHose::save(SimpleFile *file, int indent) { void CPickUpHose::load(SimpleFile *file) { file->readNumber(); - _string1 = file->readString(); + _target = file->readString(); _v1 = file->readNumber(); CPickUp::load(file); } +bool CPickUpHose::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (!checkStartDragging(msg)) + return true; + if (_v1 || !_enabled) + return false; + + CViewItem *view = getView(); + if (view) { + _v1 = true; + CRoomItem *room = locateRoom("Arboretum"); + CTreeItem *hose = room ? room->findByName("Hose") : nullptr; + + if (!hose) { + room = locateRoom("FrozenArboretum"); + if (room) + hose = room->findByName("Hose"); + } + + if (hose) { + CVisibleMsg visibleMsg; + visibleMsg.execute(this); + moveUnder(view); + + CPassOnDragStartMsg passMsg(msg->_mousePos, 1); + passMsg.execute("Hose"); + + msg->_dragItem = getRoot()->findByName("Hose"); + _cursorId = CURSOR_IGNORE; + + CActMsg actMsg("PlayerGetsHose"); + actMsg.execute(_target); + } + } + + return true; +} + +bool CPickUpHose::StatusChangeMsg(CStatusChangeMsg *msg) { + _cursorId = msg->_newStatus == 1 ? CURSOR_HAND : CURSOR_IGNORE; + return true; +} + +bool CPickUpHose::EnterViewMsg(CEnterViewMsg *msg) { + _cursorId = CURSOR_IGNORE; + return true; +} + +bool CPickUpHose::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return _enabled; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pickup/pick_up_hose.h b/engines/titanic/game/pickup/pick_up_hose.h index 80ccedc845..2ad7c2a583 100644 --- a/engines/titanic/game/pickup/pick_up_hose.h +++ b/engines/titanic/game/pickup/pick_up_hose.h @@ -28,10 +28,15 @@ namespace Titanic { class CPickUpHose : public CPickUp { + DECLARE_MESSAGE_MAP; + bool MouseDragStartMsg(CMouseDragStartMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); private: - static int _v1; + static bool _v1; - CString _string1; + CString _target; public: CLASSDEF; diff --git a/engines/titanic/game/pickup/pick_up_lemon.cpp b/engines/titanic/game/pickup/pick_up_lemon.cpp index 772114f76c..5109c36304 100644 --- a/engines/titanic/game/pickup/pick_up_lemon.cpp +++ b/engines/titanic/game/pickup/pick_up_lemon.cpp @@ -21,9 +21,15 @@ */ #include "titanic/game/pickup/pick_up_lemon.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPickUpLemon, CPickUp) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + void CPickUpLemon::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CPickUp::save(file, indent); @@ -34,4 +40,23 @@ void CPickUpLemon::load(SimpleFile *file) { CPickUp::load(file); } +bool CPickUpLemon::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + +bool CPickUpLemon::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (!checkStartDragging(msg)) + return true; + if (!_enabled) + return false; + + CVisibleMsg visibleMsg; + visibleMsg.execute("Lemon"); + CPassOnDragStartMsg passMsg(msg->_mousePos, 1); + passMsg.execute("Lemon"); + + msg->_dragItem = getRoot()->findByName("Lemon"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pickup/pick_up_lemon.h b/engines/titanic/game/pickup/pick_up_lemon.h index 0312c71012..c196acdeaf 100644 --- a/engines/titanic/game/pickup/pick_up_lemon.h +++ b/engines/titanic/game/pickup/pick_up_lemon.h @@ -28,6 +28,9 @@ namespace Titanic { class CPickUpLemon : public CPickUp { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/pickup/pick_up_speech_centre.cpp b/engines/titanic/game/pickup/pick_up_speech_centre.cpp index 0b9a8d2c48..5e99c0a3b7 100644 --- a/engines/titanic/game/pickup/pick_up_speech_centre.cpp +++ b/engines/titanic/game/pickup/pick_up_speech_centre.cpp @@ -21,9 +21,16 @@ */ #include "titanic/game/pickup/pick_up_speech_centre.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPickUpSpeechCentre, CPickUp) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + void CPickUpSpeechCentre::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CPickUp::save(file, indent); @@ -34,4 +41,33 @@ void CPickUpSpeechCentre::load(SimpleFile *file) { CPickUp::load(file); } +bool CPickUpSpeechCentre::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + +bool CPickUpSpeechCentre::StatusChangeMsg(CStatusChangeMsg *msg) { + _enabled = msg->_newStatus == 1; + return true; +} + +bool CPickUpSpeechCentre::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (checkStartDragging(msg)) { + if (_enabled) { + CVisibleMsg visibleMsg; + visibleMsg.execute("SpeechCentre"); + CPassOnDragStartMsg passMsg(msg->_mousePos, 1); + passMsg.execute("SpeechCentre"); + + msg->_dragItem = getRoot()->findByName("SpeechCentre"); + + CActMsg actMsg("PlayerGetsSpeechCentre"); + actMsg.execute("SeasonalAdjust"); + } else { + petDisplayMessage("You can't pick this up on account of it being stuck to the branch."); + } + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pickup/pick_up_speech_centre.h b/engines/titanic/game/pickup/pick_up_speech_centre.h index 29dce04fb3..81ee0b5d77 100644 --- a/engines/titanic/game/pickup/pick_up_speech_centre.h +++ b/engines/titanic/game/pickup/pick_up_speech_centre.h @@ -28,6 +28,10 @@ namespace Titanic { class CPickUpSpeechCentre : public CPickUp { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/pickup/pick_up_vis_centre.cpp b/engines/titanic/game/pickup/pick_up_vis_centre.cpp index 796e46778c..baf1763d09 100644 --- a/engines/titanic/game/pickup/pick_up_vis_centre.cpp +++ b/engines/titanic/game/pickup/pick_up_vis_centre.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPickUpVisCentre, CPickUp) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + void CPickUpVisCentre::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CPickUp::save(file, indent); @@ -34,4 +39,22 @@ void CPickUpVisCentre::load(SimpleFile *file) { CPickUp::load(file); } + +bool CPickUpVisCentre::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + +bool CPickUpVisCentre::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (!checkStartDragging(msg) || !_enabled) + return false; + + setVisible(false); + CVisibleMsg visibleMsg; + visibleMsg.execute("VisionCentre"); + msg->execute("VisionCentre"); + CActMsg actMsg("PlayerTakesVisCentre"); + actMsg.execute("Barbot"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/pickup/pick_up_vis_centre.h b/engines/titanic/game/pickup/pick_up_vis_centre.h index 4f808f73c5..a5f59211d3 100644 --- a/engines/titanic/game/pickup/pick_up_vis_centre.h +++ b/engines/titanic/game/pickup/pick_up_vis_centre.h @@ -28,6 +28,9 @@ namespace Titanic { class CPickUpVisCentre : public CPickUp { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/placeholder/bar_shelf_vis_centre.cpp b/engines/titanic/game/placeholder/bar_shelf_vis_centre.cpp index fc5d680f0c..6e5037f237 100644 --- a/engines/titanic/game/placeholder/bar_shelf_vis_centre.cpp +++ b/engines/titanic/game/placeholder/bar_shelf_vis_centre.cpp @@ -24,7 +24,7 @@ namespace Titanic { -BEGIN_MESSAGE_MAP(CBarShelfVisCentre, CPlaceHolderItem) +BEGIN_MESSAGE_MAP(CBarShelfVisCentre, CPlaceHolder) ON_MESSAGE(MouseButtonDownMsg) ON_MESSAGE(TimerMsg) ON_MESSAGE(EnterViewMsg) @@ -33,13 +33,13 @@ END_MESSAGE_MAP() void CBarShelfVisCentre::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_flag, indent); - CPlaceHolderItem::save(file, indent); + CPlaceHolder::save(file, indent); } void CBarShelfVisCentre::load(SimpleFile *file) { file->readNumber(); _flag = file->readNumber(); - CPlaceHolderItem::load(file); + CPlaceHolder::load(file); } bool CBarShelfVisCentre::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { diff --git a/engines/titanic/game/placeholder/bar_shelf_vis_centre.h b/engines/titanic/game/placeholder/bar_shelf_vis_centre.h index 672655d368..8ad3dcb8d1 100644 --- a/engines/titanic/game/placeholder/bar_shelf_vis_centre.h +++ b/engines/titanic/game/placeholder/bar_shelf_vis_centre.h @@ -23,11 +23,11 @@ #ifndef TITANIC_BAR_SHELF_VIS_CENTRE_H #define TITANIC_BAR_SHELF_VIS_CENTRE_H -#include "titanic/game/placeholder/place_holder_item.h" +#include "titanic/game/placeholder/place_holder.h" namespace Titanic { -class CBarShelfVisCentre : public CPlaceHolderItem { +class CBarShelfVisCentre : public CPlaceHolder { DECLARE_MESSAGE_MAP; bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); bool TimerMsg(CTimerMsg *msg); @@ -36,7 +36,7 @@ private: bool _flag; public: CLASSDEF; - CBarShelfVisCentre() : CPlaceHolderItem(), _flag(false) {} + CBarShelfVisCentre() : CPlaceHolder(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/placeholder/lemon_on_bar.cpp b/engines/titanic/game/placeholder/lemon_on_bar.cpp index 917c751e67..e9cf6a309a 100644 --- a/engines/titanic/game/placeholder/lemon_on_bar.cpp +++ b/engines/titanic/game/placeholder/lemon_on_bar.cpp @@ -24,20 +24,20 @@ namespace Titanic { -BEGIN_MESSAGE_MAP(CLemonOnBar, CPlaceHolderItem) +BEGIN_MESSAGE_MAP(CLemonOnBar, CPlaceHolder) ON_MESSAGE(VisibleMsg) END_MESSAGE_MAP() void CLemonOnBar::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writePoint(_lemonPos, indent); - CPlaceHolderItem::save(file, indent); + CPlaceHolder::save(file, indent); } void CLemonOnBar::load(SimpleFile *file) { file->readNumber(); _lemonPos = file->readPoint(); - CPlaceHolderItem::load(file); + CPlaceHolder::load(file); } bool CLemonOnBar::VisibleMsg(CVisibleMsg *msg) { diff --git a/engines/titanic/game/placeholder/lemon_on_bar.h b/engines/titanic/game/placeholder/lemon_on_bar.h index af5d5e67c8..c6512ced67 100644 --- a/engines/titanic/game/placeholder/lemon_on_bar.h +++ b/engines/titanic/game/placeholder/lemon_on_bar.h @@ -23,11 +23,11 @@ #ifndef TITANIC_LEMON_ON_BAR_H #define TITANIC_LEMON_ON_BAR_H -#include "titanic/game/placeholder/place_holder_item.h" +#include "titanic/game/placeholder/place_holder.h" namespace Titanic { -class CLemonOnBar : public CPlaceHolderItem { +class CLemonOnBar : public CPlaceHolder { DECLARE_MESSAGE_MAP; bool VisibleMsg(CVisibleMsg *msg); private: diff --git a/engines/titanic/game/placeholder/place_holder_item.cpp b/engines/titanic/game/placeholder/place_holder.cpp index 365e8cbe50..ae42cabc29 100644 --- a/engines/titanic/game/placeholder/place_holder_item.cpp +++ b/engines/titanic/game/placeholder/place_holder.cpp @@ -20,18 +20,27 @@ * */ -#include "titanic/game/placeholder/place_holder_item.h" +#include "titanic/game/placeholder/place_holder.h" namespace Titanic { -void CPlaceHolderItem::save(SimpleFile *file, int indent) { +BEGIN_MESSAGE_MAP(CPlaceHolder, CGameObject) + ON_MESSAGE(VisibleMsg) +END_MESSAGE_MAP() + +void CPlaceHolder::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); } -void CPlaceHolderItem::load(SimpleFile *file) { +void CPlaceHolder::load(SimpleFile *file) { file->readNumber(); CGameObject::load(file); } +bool CPlaceHolder::VisibleMsg(CVisibleMsg *msg) { + setVisible(msg->_visible); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/placeholder/place_holder_item.h b/engines/titanic/game/placeholder/place_holder.h index de04a64bf7..b1aa041710 100644 --- a/engines/titanic/game/placeholder/place_holder_item.h +++ b/engines/titanic/game/placeholder/place_holder.h @@ -27,7 +27,9 @@ namespace Titanic { -class CPlaceHolderItem : public CGameObject { +class CPlaceHolder : public CGameObject { + DECLARE_MESSAGE_MAP; + bool VisibleMsg(CVisibleMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/placeholder/tv_on_bar.cpp b/engines/titanic/game/placeholder/tv_on_bar.cpp index efbbe50461..710b5a346e 100644 --- a/engines/titanic/game/placeholder/tv_on_bar.cpp +++ b/engines/titanic/game/placeholder/tv_on_bar.cpp @@ -24,16 +24,30 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CTVOnBar, CPlaceHolder) + ON_MESSAGE(VisibleMsg) +END_MESSAGE_MAP() + void CTVOnBar::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writePoint(_pos1, indent); - CPlaceHolderItem::save(file, indent); + file->writePoint(_tvPos, indent); + CPlaceHolder::save(file, indent); } void CTVOnBar::load(SimpleFile *file) { file->readNumber(); - _pos1 = file->readPoint(); - CPlaceHolderItem::load(file); + _tvPos = file->readPoint(); + CPlaceHolder::load(file); +} + +bool CTVOnBar::VisibleMsg(CVisibleMsg *msg) { + setVisible(msg->_visible); + if (msg->_visible) + setPosition(_tvPos); + else + setPosition(Point(0, 0)); + + return true; } } // End of namespace Titanic diff --git a/engines/titanic/game/placeholder/tv_on_bar.h b/engines/titanic/game/placeholder/tv_on_bar.h index d41d972e73..0157bc8764 100644 --- a/engines/titanic/game/placeholder/tv_on_bar.h +++ b/engines/titanic/game/placeholder/tv_on_bar.h @@ -23,13 +23,15 @@ #ifndef TITANIC_TV_ON_BAR_H #define TITANIC_TV_ON_BAR_H -#include "titanic/game/placeholder/place_holder_item.h" +#include "titanic/game/placeholder/place_holder.h" namespace Titanic { -class CTVOnBar : public CPlaceHolderItem { +class CTVOnBar : public CPlaceHolder { + DECLARE_MESSAGE_MAP; + bool VisibleMsg(CVisibleMsg *msg); private: - Point _pos1; + Point _tvPos; public: CLASSDEF; diff --git a/engines/titanic/game/play_music_button.cpp b/engines/titanic/game/play_music_button.cpp index 8066739f10..93416911b8 100644 --- a/engines/titanic/game/play_music_button.cpp +++ b/engines/titanic/game/play_music_button.cpp @@ -21,23 +21,58 @@ */ #include "titanic/game/play_music_button.h" +#include "titanic/sound/music_room.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CPlayMusicButton, CBackground) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(FrameMsg) +END_MESSAGE_MAP() + void CPlayMusicButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); + file->writeNumberLine(_flag, indent); + file->writeNumberLine(_ticks, indent); CBackground::save(file, indent); } void CPlayMusicButton::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); + _flag = file->readNumber(); + _ticks = file->readNumber(); CBackground::load(file); } +bool CPlayMusicButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CMusicRoom *musicRoom = getMusicRoom(); + if (_flag) { + musicRoom->stopMusic(); + stopMovie(); + loadFrame(0); + _flag = false; + } else { + musicRoom->startMusic(100); + playMovie(MOVIE_REPEAT); + _ticks = getTicksCount(); + _flag = true; + } + + return true; +} + +bool CPlayMusicButton::FrameMsg(CFrameMsg *msg) { + if (_flag && !CMusicRoom::_musicHandler->isBusy()) { + CMusicRoom *musicRoom = getMusicRoom(); + musicRoom->stopMusic(); + stopMovie(); + loadFrame(0); + _flag = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/play_music_button.h b/engines/titanic/game/play_music_button.h index 4e3474181c..824b372bf9 100644 --- a/engines/titanic/game/play_music_button.h +++ b/engines/titanic/game/play_music_button.h @@ -28,12 +28,15 @@ namespace Titanic { class CPlayMusicButton : public CBackground { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool FrameMsg(CFrameMsg *msg); public: - int _fieldE0; - int _fieldE4; + bool _flag; + uint _ticks; public: CLASSDEF; - CPlayMusicButton() : CBackground(), _fieldE0(0), _fieldE4(0) {} + CPlayMusicButton() : CBackground(), _flag(false), _ticks(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/play_on_act.cpp b/engines/titanic/game/play_on_act.cpp index e1ef1201c6..9c368c335d 100644 --- a/engines/titanic/game/play_on_act.cpp +++ b/engines/titanic/game/play_on_act.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CPlayOnAct, CBackground) + ON_MESSAGE(ActMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + void CPlayOnAct::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBackground::save(file, indent); @@ -34,4 +39,20 @@ void CPlayOnAct::load(SimpleFile *file) { CBackground::load(file); } +bool CPlayOnAct::ActMsg(CActMsg *msg) { + if (msg->_action == "PlayMovie") { + setVisible(true); + playMovie(0); + } else if (msg->_action == "PlayToEnd") { + setVisible(true); + playMovie(MOVIE_GAMESTATE); + } + + return true; +} + +bool CPlayOnAct::LeaveViewMsg(CLeaveViewMsg *msg) { + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/play_on_act.h b/engines/titanic/game/play_on_act.h index 197e647943..72615f2fc4 100644 --- a/engines/titanic/game/play_on_act.h +++ b/engines/titanic/game/play_on_act.h @@ -28,6 +28,9 @@ namespace Titanic { class CPlayOnAct : public CBackground { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/port_hole.cpp b/engines/titanic/game/port_hole.cpp index f3c447f443..25807b1b1d 100644 --- a/engines/titanic/game/port_hole.cpp +++ b/engines/titanic/game/port_hole.cpp @@ -24,26 +24,72 @@ namespace Titanic { -CPortHole::CPortHole() : CGameObject(), _fieldBC(0), - _string1("b#47.wav"), _string2("b#46.wav") { +BEGIN_MESSAGE_MAP(CPortHole, CGameObject) + ON_MESSAGE(ActMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +CPortHole::CPortHole() : CGameObject(), _open(false), + _closeSoundName("b#47.wav"), _openSoundName("b#46.wav") { } void CPortHole::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); - file->writeQuotedLine(_string1, indent); - file->writeQuotedLine(_string2, indent); + file->writeNumberLine(_open, indent); + file->writeQuotedLine(_closeSoundName, indent); + file->writeQuotedLine(_openSoundName, indent); CGameObject::save(file, indent); } void CPortHole::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); - _string1 = file->readString(); - _string2 = file->readString(); + _open = file->readNumber(); + _closeSoundName = file->readString(); + _openSoundName = file->readString(); CGameObject::load(file); } +bool CPortHole::ActMsg(CActMsg *msg) { + if (msg->_action == "TogglePortHole") { + if (_open) { + playMovie(14, 26, MOVIE_NOTIFY_OBJECT); + playSound(_closeSoundName); + _open = false; + } else { + setVisible(true); + playMovie(1, 13, 0); + playSound(_openSoundName); + _open = true; + } + } + + return true; +} + +bool CPortHole::MovieEndMsg(CMovieEndMsg *msg) { + _open = false; + setVisible(false); + return true; +} + +bool CPortHole::LeaveViewMsg(CLeaveViewMsg *msg) { + if (_open) { + playSound(_closeSoundName); + playMovie(14, 26, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _open = false; + } + + return true; +} + +bool CPortHole::EnterViewMsg(CEnterViewMsg *msg) { + setVisible(false); + _open = false; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/port_hole.h b/engines/titanic/game/port_hole.h index 7bba18d12a..9f1997a517 100644 --- a/engines/titanic/game/port_hole.h +++ b/engines/titanic/game/port_hole.h @@ -28,9 +28,14 @@ namespace Titanic { class CPortHole : public CGameObject { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); private: - int _fieldBC; - CString _string1, _string2; + bool _open; + CString _closeSoundName, _openSoundName; public: CLASSDEF; CPortHole(); diff --git a/engines/titanic/game/record_phonograph_button.cpp b/engines/titanic/game/record_phonograph_button.cpp index f022957dbb..1ffaec4228 100644 --- a/engines/titanic/game/record_phonograph_button.cpp +++ b/engines/titanic/game/record_phonograph_button.cpp @@ -24,16 +24,44 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CRecordPhonographButton, CBackground) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(PhonographStopMsg) +END_MESSAGE_MAP() + void CRecordPhonographButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_active, indent); CBackground::save(file, indent); } void CRecordPhonographButton::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _active = file->readNumber(); CBackground::load(file); } +bool CRecordPhonographButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CPhonographRecordMsg recordMsg; + recordMsg.execute(getParent()); + + if (recordMsg._value) { + playSound("z#58.wav"); + loadFrame(1); + _active = true; + } + + return true; +} + +bool CRecordPhonographButton::PhonographStopMsg(CPhonographStopMsg *msg) { + if (_active) { + playSound("z#57.wav"); + loadFrame(0); + _active = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/record_phonograph_button.h b/engines/titanic/game/record_phonograph_button.h index 3383c01e31..985a4c4576 100644 --- a/engines/titanic/game/record_phonograph_button.h +++ b/engines/titanic/game/record_phonograph_button.h @@ -28,11 +28,14 @@ namespace Titanic { class CRecordPhonographButton : public CBackground { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool PhonographStopMsg(CPhonographStopMsg *msg); public: - int _value; + bool _active; public: CLASSDEF; - CRecordPhonographButton() : CBackground(), _value(0) {} + CRecordPhonographButton() : CBackground(), _active(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/replacement_ear.cpp b/engines/titanic/game/replacement_ear.cpp index 1f9960365d..e8bd384207 100644 --- a/engines/titanic/game/replacement_ear.cpp +++ b/engines/titanic/game/replacement_ear.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CReplacementEar, CBackground) + ON_MESSAGE(VisibleMsg) +END_MESSAGE_MAP() + void CReplacementEar::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBackground::save(file, indent); @@ -34,4 +38,11 @@ void CReplacementEar::load(SimpleFile *file) { CBackground::load(file); } +bool CReplacementEar::VisibleMsg(CVisibleMsg *msg) { + setVisible(true); + playMovie(MOVIE_GAMESTATE); + playSound("z#64.wav"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/replacement_ear.h b/engines/titanic/game/replacement_ear.h index 0d282b7fb4..7775a9631a 100644 --- a/engines/titanic/game/replacement_ear.h +++ b/engines/titanic/game/replacement_ear.h @@ -28,6 +28,8 @@ namespace Titanic { class CReplacementEar : public CBackground { + DECLARE_MESSAGE_MAP; + bool VisibleMsg(CVisibleMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/reserved_table.cpp b/engines/titanic/game/reserved_table.cpp index a600190709..734d53af45 100644 --- a/engines/titanic/game/reserved_table.cpp +++ b/engines/titanic/game/reserved_table.cpp @@ -21,22 +21,55 @@ */ #include "titanic/game/reserved_table.h" +#include "titanic/core/room_item.h" +#include "titanic/core/view_item.h" +#include "titanic/npcs/maitre_d.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CReservedTable, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(PlayerTriesRestaurantTableMsg) +END_MESSAGE_MAP() + void CReservedTable::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value1, indent); - file->writeNumberLine(_value2, indent); + file->writeNumberLine(_flag, indent); + file->writeNumberLine(_tableId, indent); CGameObject::save(file, indent); } void CReservedTable::load(SimpleFile *file) { file->readNumber(); - _value1 = file->readNumber(); - _value2 = file->readNumber(); + _flag = file->readNumber(); + _tableId = file->readNumber(); CGameObject::load(file); } +bool CReservedTable::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (!_flag) { + CPlayerTriesRestaurantTableMsg tryMsg(_tableId, 0); + tryMsg.execute(findRoom(), CReservedTable::_type, MSGFLAG_CLASS_DEF | MSGFLAG_SCAN); + } + + return true; +} + +bool CReservedTable::PlayerTriesRestaurantTableMsg(CPlayerTriesRestaurantTableMsg *msg) { + if (msg->_tableId == _tableId) { + if (!msg->_result) { + CMaitreD *maitreD = dynamic_cast<CMaitreD *>(findRoomObject("MaitreD")); + startTalking(maitreD, 118, maitreD->findView()); + msg->_result = true; + } + + _cursorId = CURSOR_INVALID; + _flag = true; + return true; + } else { + return false; + } +} + } // End of namespace Titanic diff --git a/engines/titanic/game/reserved_table.h b/engines/titanic/game/reserved_table.h index a3532c7d14..bc037ae3d9 100644 --- a/engines/titanic/game/reserved_table.h +++ b/engines/titanic/game/reserved_table.h @@ -28,11 +28,15 @@ namespace Titanic { class CReservedTable : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool PlayerTriesRestaurantTableMsg(CPlayerTriesRestaurantTableMsg *msg); public: - int _value1, _value2; + bool _flag; + int _tableId; public: CLASSDEF; - CReservedTable() : CGameObject(), _value1(0), _value2(0) {} + CReservedTable() : CGameObject(), _flag(false), _tableId(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/restaurant_cylinder_holder.cpp b/engines/titanic/game/restaurant_cylinder_holder.cpp index d70009f151..8726d1a925 100644 --- a/engines/titanic/game/restaurant_cylinder_holder.cpp +++ b/engines/titanic/game/restaurant_cylinder_holder.cpp @@ -24,20 +24,29 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CRestaurantCylinderHolder, CDropTarget) + ON_MESSAGE(EjectCylinderMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(QueryCylinderHolderMsg) + ON_MESSAGE(QueryCylinderNameMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + CRestaurantCylinderHolder::CRestaurantCylinderHolder() : CDropTarget(), _field118(0), _field11C(0), _field12C(0), _field130(0), - _string6("z#61.wav"), _field140(1) { + _ejectSoundName("z#61.wav"), _defaultCursorId(CURSOR_ARROW) { } void CRestaurantCylinderHolder::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_field118, indent); file->writeNumberLine(_field11C, indent); - file->writeQuotedLine(_string5, indent); + file->writeQuotedLine(_target, indent); file->writeNumberLine(_field12C, indent); file->writeNumberLine(_field130, indent); - file->writeQuotedLine(_string6, indent); - file->writeNumberLine(_field140, indent); + file->writeQuotedLine(_ejectSoundName, indent); + file->writeNumberLine(_defaultCursorId, indent); CDropTarget::save(file, indent); } @@ -46,13 +55,98 @@ void CRestaurantCylinderHolder::load(SimpleFile *file) { file->readNumber(); _field118 = file->readNumber(); _field11C = file->readNumber(); - _string5 = file->readString(); + _target = file->readString(); _field12C = file->readNumber(); _field130 = file->readNumber(); - _string6 = file->readString(); - _field140 = file->readNumber(); + _ejectSoundName = file->readString(); + _defaultCursorId = (CursorId)file->readNumber(); CDropTarget::load(file); } +bool CRestaurantCylinderHolder::EjectCylinderMsg(CEjectCylinderMsg *msg) { + _field11C = true; + bool hasCylinder = findByName("Phonograph Cylinder") != nullptr; + + if (_field118) { + playClip(hasCylinder ? "CloseHolder_Full" : "CloseHolder_Empty", + MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _fieldF4 = 1; + } else { + playClip(hasCylinder ? "OpenHolder_Full" : "OpenHolder_Empty", + MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + } + + playSound(_ejectSoundName, 50); + return true; +} + +bool CRestaurantCylinderHolder::EnterViewMsg(CEnterViewMsg *msg) { + if (_field118) { + CTreeItem *cylinder = findByName("Phonograph Cylinder", true); + if (cylinder) { + loadFrame(_dropFrame); + _cursorId = _dropCursorId; + } else { + loadFrame(_dragFrame); + _cursorId = _dragCursorId; + } + } else { + loadFrame(_field130); + _cursorId = _defaultCursorId; + } + + return true; +} + +bool CRestaurantCylinderHolder::MovieEndMsg(CMovieEndMsg *msg) { + _field11C = false; + if (_field118) { + _field118 = false; + _cursorId = _defaultCursorId; + + CPhonographReadyToPlayMsg readyMsg; + readyMsg.execute(_target); + } else { + _field118 = true; + _fieldF4 = false; + _cursorId = findByName("Phonograph Cylinder") ? _dropCursorId : _dragCursorId; + } + + CCylinderHolderReadyMsg holderMsg; + holderMsg.execute(_target); + return true; +} + +bool CRestaurantCylinderHolder::QueryCylinderHolderMsg(CQueryCylinderHolderMsg *msg) { + CNamedItem *cylinder = findByName("Phonograph Cylinder", true); + + msg->_value1 = _field118; + if (cylinder) { + msg->_value2 = 1; + msg->_target = cylinder; + } + + return true; +} + +bool CRestaurantCylinderHolder::QueryCylinderNameMsg(CQueryCylinderNameMsg *msg) { + CNamedItem *cylinder = findByName("Phonograph Cylinder", true); + + if (cylinder) { + CQueryCylinderMsg queryMsg; + queryMsg.execute(cylinder); + msg->_name = queryMsg._name; + } + + return true; +} + +bool CRestaurantCylinderHolder::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (_field118) + return CDropTarget::MouseDragStartMsg(msg); + else + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/restaurant_cylinder_holder.h b/engines/titanic/game/restaurant_cylinder_holder.h index 3aa979b0a5..cd0b0783bd 100644 --- a/engines/titanic/game/restaurant_cylinder_holder.h +++ b/engines/titanic/game/restaurant_cylinder_holder.h @@ -28,14 +28,21 @@ namespace Titanic { class CRestaurantCylinderHolder : public CDropTarget { + DECLARE_MESSAGE_MAP; + bool EjectCylinderMsg(CEjectCylinderMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool QueryCylinderHolderMsg(CQueryCylinderHolderMsg *msg); + bool QueryCylinderNameMsg(CQueryCylinderNameMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); private: int _field118; int _field11C; - CString _string5; + CString _target; int _field12C; int _field130; - CString _string6; - int _field140; + CString _ejectSoundName; + CursorId _defaultCursorId; public: CLASSDEF; CRestaurantCylinderHolder(); diff --git a/engines/titanic/game/restaurant_phonograph.cpp b/engines/titanic/game/restaurant_phonograph.cpp index 83a4ac3e71..881079e020 100644 --- a/engines/titanic/game/restaurant_phonograph.cpp +++ b/engines/titanic/game/restaurant_phonograph.cpp @@ -21,9 +21,20 @@ */ #include "titanic/game/restaurant_phonograph.h" +#include "titanic/core/room_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CRestaurantPhonograph, CPhonograph) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(PhonographPlayMsg) + ON_MESSAGE(PhonographStopMsg) + ON_MESSAGE(PhonographReadyToPlayMsg) + ON_MESSAGE(EjectCylinderMsg) + ON_MESSAGE(QueryPhonographState) + ON_MESSAGE(LockPhonographMsg) +END_MESSAGE_MAP() + CRestaurantPhonograph::CRestaurantPhonograph() : CPhonograph(), _fieldF8(1), _field114(0) {} @@ -48,4 +59,89 @@ void CRestaurantPhonograph::load(SimpleFile *file) { CPhonograph::load(file); } +bool CRestaurantPhonograph::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (!_fieldF8 && !_fieldE0) { + CQueryCylinderHolderMsg holderMsg; + holderMsg.execute(this); + + if (!holderMsg._value1) { + CPhonographPlayMsg playMsg; + playMsg.execute(this); + } else if (holderMsg._value2) { + CEjectCylinderMsg ejectMsg; + ejectMsg.execute(this); + + _fieldE8 = true; + if (_field114) { + loadFrame(_fieldEC); + playSound(_ejectSoundName); + } + } + } + + return true; +} + +bool CRestaurantPhonograph::PhonographPlayMsg(CPhonographPlayMsg *msg) { + if (_fieldE0) { + if (findView() == getView() && (!_fieldE8 || !_field114)) { + loadFrame(_fieldEC); + playSound(_ejectSoundName); + } + + CQueryCylinderNameMsg nameMsg; + nameMsg.execute(this); + CRestaurantMusicChanged musicMsg(nameMsg._name); + musicMsg.execute(findRoom()); + } else { + loadFrame(_fieldF0); + } + + return true; +} + +bool CRestaurantPhonograph::PhonographStopMsg(CPhonographStopMsg *msg) { + bool flag = _fieldE0; + CPhonograph::PhonographStopMsg(msg); + + if (_fieldE0) { + loadFrame(_fieldF0); + if (flag) + playSound(_string3); + } else { + loadFrame(_fieldEC); + } + + return true; +} + +bool CRestaurantPhonograph::PhonographReadyToPlayMsg(CPhonographReadyToPlayMsg *msg) { + if (_fieldE8) { + CPhonographPlayMsg playMsg; + playMsg.execute(this); + _fieldE8 = false; + } + + return true; +} + +bool CRestaurantPhonograph::EjectCylinderMsg(CEjectCylinderMsg *msg) { + if (_fieldE0) { + CPhonographStopMsg stopMsg; + stopMsg.execute(this); + } + + return true; +} + +bool CRestaurantPhonograph::QueryPhonographState(CQueryPhonographState *msg) { + msg->_value = _fieldF8; + return true; +} + +bool CRestaurantPhonograph::LockPhonographMsg(CLockPhonographMsg *msg) { + _fieldF8 = msg->_value; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/restaurant_phonograph.h b/engines/titanic/game/restaurant_phonograph.h index 710a2edd73..9661df0dfb 100644 --- a/engines/titanic/game/restaurant_phonograph.h +++ b/engines/titanic/game/restaurant_phonograph.h @@ -28,9 +28,17 @@ namespace Titanic { class CRestaurantPhonograph : public CPhonograph { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool PhonographPlayMsg(CPhonographPlayMsg *msg); + bool PhonographStopMsg(CPhonographStopMsg *msg); + bool PhonographReadyToPlayMsg(CPhonographReadyToPlayMsg *msg); + bool EjectCylinderMsg(CEjectCylinderMsg *msg); + bool QueryPhonographState(CQueryPhonographState *msg); + bool LockPhonographMsg(CLockPhonographMsg *msg); private: int _fieldF8; - CString _string2; + CString _ejectSoundName; CString _string3; int _field114; public: diff --git a/engines/titanic/game/sauce_dispensor.cpp b/engines/titanic/game/sauce_dispensor.cpp index 8dc818d917..29f0be7ee4 100644 --- a/engines/titanic/game/sauce_dispensor.cpp +++ b/engines/titanic/game/sauce_dispensor.cpp @@ -21,9 +21,20 @@ */ #include "titanic/game/sauce_dispensor.h" +#include "titanic/carry/chicken.h" +#include "titanic/carry/glass.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CSauceDispensor, CBackground) + ON_MESSAGE(Use) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(ActMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(StatusChangeMsg) +END_MESSAGE_MAP() + CSauceDispensor::CSauceDispensor() : CBackground(), _fieldEC(0), _fieldF0(0), _field104(0), _field108(0) { } @@ -54,4 +65,105 @@ void CSauceDispensor::load(SimpleFile *file) { CBackground::load(file); } +bool CSauceDispensor::Use(CUse *msg) { + CVisibleMsg visibleMsg(true); + + if (msg->_item->isEquals("Chicken")) { + CChicken *chicken = static_cast<CChicken *>(msg->_item); + _field104 = true; + if (_fieldF0) { + playSound("b#15.wav", 50); + + if (chicken->_string6 != "None") { + petDisplayMessage(1, "This foodstuff is already sufficiently garnished."); + msg->execute("Chicken"); + } else { + setVisible(true); + if (chicken->_field12C) { + playMovie(_pos1.x, _pos1.y, MOVIE_NOTIFY_OBJECT); + } else { + CActMsg actMsg(_string3); + actMsg.execute("Chicken"); + playMovie(_pos2.x, _pos2.y, MOVIE_NOTIFY_OBJECT); + } + } + + if (_fieldF0) + return true; + } + + CMovieEndMsg endMsg(0, 0); + endMsg.execute(this); + playSound("z#120.wav"); + + petDisplayMessage(1, "Sadly, this dispenser is currently empty."); + } else if (msg->_item->isEquals("BeerGlass")) { + CGlass *glass = static_cast<CGlass *>(msg->_item); + _field108 = true; + + if (_field104 || _fieldF0) { + petAddToInventory(); + } else if (glass->_string6 != "None") { + visibleMsg.execute("BeerGlass"); + } else if (_fieldEC) { + glass->setPosition(Point( + _bounds.left + (_bounds.width() / 2) - (glass->_bounds.width() / 2), + 300)); + setVisible(true); + + CActMsg actMsg(_string3); + actMsg.execute("BeerGlass"); + } + } + + return true; +} + +bool CSauceDispensor::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(false); + _fieldEC = false; + + CActMsg actMsg("GoToPET"); + if (_field104) + actMsg.execute("Chicken"); + if (_field108) + actMsg.execute("BeerGlass"); + + _field104 = false; + _field108 = false; + return true; +} + +bool CSauceDispensor::ActMsg(CActMsg *msg) { + if (msg->_action == "StarlingsDead") + _fieldF0 = true; + + return true; +} + +bool CSauceDispensor::LeaveViewMsg(CLeaveViewMsg *msg) { + setVisible(false); + loadFrame(0); + + if (_field108) { + CGameObject *glass = findRoomObject("Beerglass"); + if (glass) + glass->petAddToInventory(); + } + + _field104 = false; + _field108 = false; + return true; +} + +bool CSauceDispensor::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + petDisplayMessage(1, "Please place food source beneath dispenser for sauce delivery."); + return true; +} + +bool CSauceDispensor::StatusChangeMsg(CStatusChangeMsg *msg) { + petDisplayMessage(1, "Please place food source beneath dispenser for sauce delivery."); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sauce_dispensor.h b/engines/titanic/game/sauce_dispensor.h index aa177050d5..f8021f368b 100644 --- a/engines/titanic/game/sauce_dispensor.h +++ b/engines/titanic/game/sauce_dispensor.h @@ -28,6 +28,13 @@ namespace Titanic { class CSauceDispensor : public CBackground { + DECLARE_MESSAGE_MAP; + bool Use(CUse *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool ActMsg(CActMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); public: CString _string3; int _fieldEC; diff --git a/engines/titanic/game/search_point.cpp b/engines/titanic/game/search_point.cpp index f60a3132b7..bbe923267a 100644 --- a/engines/titanic/game/search_point.cpp +++ b/engines/titanic/game/search_point.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSearchPoint, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CSearchPoint::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_value, indent); @@ -36,4 +40,21 @@ void CSearchPoint::load(SimpleFile *file) { CGameObject::load(file); } +bool CSearchPoint::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_value > 0) { + CGameObject *child = dynamic_cast<CGameObject *>(getFirstChild()); + if (child) { + child->petAddToInventory(); + CVisibleMsg visibleMsg(true); + visibleMsg.execute(child->getName()); + playSound("z#47.wav"); + } + + if (--_value == 0) + _cursorId = CURSOR_ARROW; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/search_point.h b/engines/titanic/game/search_point.h index 3c5639b104..421f272804 100644 --- a/engines/titanic/game/search_point.h +++ b/engines/titanic/game/search_point.h @@ -28,6 +28,8 @@ namespace Titanic { class CSearchPoint : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: int _value; public: diff --git a/engines/titanic/game/season_background.cpp b/engines/titanic/game/season_background.cpp index 1c63f3d892..20ad6aca1d 100644 --- a/engines/titanic/game/season_background.cpp +++ b/engines/titanic/game/season_background.cpp @@ -24,28 +24,113 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSeasonBackground, CBackground) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(ChangeSeasonMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + CSeasonBackground::CSeasonBackground() : CBackground(), - _fieldE0(0), _fieldE4(0), _fieldE8(46), _fieldEC(0) { + _seasonNum(SEASON_SUMMER), _flag(false), _defaultFrame(46), _unused(0) { } void CSeasonBackground::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); - file->writeNumberLine(_fieldE8, indent); - file->writeNumberLine(_fieldEC, indent); + file->writeNumberLine(_seasonNum, indent); + file->writeNumberLine(_flag, indent); + file->writeNumberLine(_defaultFrame, indent); + file->writeNumberLine(_unused, indent); CBackground::save(file, indent); } void CSeasonBackground::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); - _fieldE8 = file->readNumber(); - _fieldEC = file->readNumber(); + _seasonNum = (Season)file->readNumber(); + _flag = file->readNumber(); + _defaultFrame = file->readNumber(); + _unused = file->readNumber(); CBackground::load(file); } +bool CSeasonBackground::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(_defaultFrame); + return true; +} + +bool CSeasonBackground::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + _seasonNum = (Season)(((int)_seasonNum + 1) % 4); + + switch (_seasonNum) { + case SEASON_SUMMER: + playMovie(0, 45, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 45; + break; + + case SEASON_AUTUMN: + if (_flag) { + playMovie(232, 278, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 278; + } else { + playMovie(45, 91, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 91; + } + break; + + case SEASON_WINTER: + if (_flag) { + playMovie(278, 326, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 326; + } else { + CStatusChangeMsg changeMsg; + changeMsg._newStatus = 0; + changeMsg.execute("PickUpSpeechCentre"); + playMovie(91, 139, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 139; + } + break; + + case SEASON_SPRING: + if (_flag) { + playMovie(326, 417, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 417; + } else { + playMovie(139, 228, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + _defaultFrame = 228; + } + break; + + default: + break; + } + + return true; +} + +bool CSeasonBackground::MovieEndMsg(CMovieEndMsg *msg) { + if (msg->_endFrame == _defaultFrame) { + CTurnOn onMsg; + onMsg.execute("SeasonalAdjust"); + } + + if (msg->_endFrame == 91 && !_flag) { + CStatusChangeMsg changeMsg; + changeMsg.execute("PickUpSpeechCentre"); + } + + return true; +} + +bool CSeasonBackground::ActMsg(CActMsg *msg) { + if (msg->_action == "PlayerGetsSpeechCentre") { + loadFrame(278); + _defaultFrame = 278; + _flag = true; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/season_background.h b/engines/titanic/game/season_background.h index f0fd2cdc63..d30fd7aedc 100644 --- a/engines/titanic/game/season_background.h +++ b/engines/titanic/game/season_background.h @@ -28,11 +28,16 @@ namespace Titanic { class CSeasonBackground : public CBackground { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool ActMsg(CActMsg *msg); public: - int _fieldE0; - int _fieldE4; - int _fieldE8; - int _fieldEC; + Season _seasonNum; + bool _flag; + int _defaultFrame; + int _unused; public: CLASSDEF; CSeasonBackground(); diff --git a/engines/titanic/game/season_barrel.cpp b/engines/titanic/game/season_barrel.cpp index 9594396885..e08cdf323b 100644 --- a/engines/titanic/game/season_barrel.cpp +++ b/engines/titanic/game/season_barrel.cpp @@ -24,19 +24,38 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSeasonBarrel, CBackground) + ON_MESSAGE(ChangeSeasonMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + void CSeasonBarrel::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); + file->writeNumberLine(_unused, indent); + file->writeNumberLine(_startFrame, indent); CBackground::save(file, indent); } void CSeasonBarrel::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); + _unused = file->readNumber(); + _startFrame = file->readNumber(); CBackground::load(file); } +bool CSeasonBarrel::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + if (_startFrame >= 28) + _startFrame = 0; + + playMovie(_startFrame, _startFrame + 7, 0); + _startFrame += 7; + return true; +} + +bool CSeasonBarrel::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(_startFrame); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/season_barrel.h b/engines/titanic/game/season_barrel.h index f77864599d..6296b6f7b1 100644 --- a/engines/titanic/game/season_barrel.h +++ b/engines/titanic/game/season_barrel.h @@ -28,12 +28,15 @@ namespace Titanic { class CSeasonBarrel : public CBackground { + DECLARE_MESSAGE_MAP; + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); public: - int _fieldE0; - int _fieldE4; + int _unused; + int _startFrame; public: CLASSDEF; - CSeasonBarrel() : CBackground(), _fieldE0(0), _fieldE4(7) {} + CSeasonBarrel() : CBackground(), _unused(0), _startFrame(7) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/seasonal_adjustment.cpp b/engines/titanic/game/seasonal_adjustment.cpp index 33a0ae89c5..1f1cb88afb 100644 --- a/engines/titanic/game/seasonal_adjustment.cpp +++ b/engines/titanic/game/seasonal_adjustment.cpp @@ -21,9 +21,20 @@ */ #include "titanic/game/seasonal_adjustment.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CSeasonalAdjustment, CBackground) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + void CSeasonalAdjustment::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldE0, indent); @@ -40,4 +51,86 @@ void CSeasonalAdjustment::load(SimpleFile *file) { CBackground::load(file); } +bool CSeasonalAdjustment::StatusChangeMsg(CStatusChangeMsg *msg) { + CChangeSeasonMsg changeMsg; + switch (stateGetSeason()) { + case SEASON_SUMMER: + changeMsg._season = "Summer"; + break; + case SEASON_AUTUMN: + changeMsg._season = "Autumn"; + break; + case SEASON_WINTER: + changeMsg._season = "Winter"; + break; + case SEASON_SPRING: + changeMsg._season = "Spring"; + break; + default: + break; + } + + changeMsg.execute(getRoot(), nullptr, MSGFLAG_SCAN); + return true; +} + +bool CSeasonalAdjustment::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + +bool CSeasonalAdjustment::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + playSound("z#42.wav"); + if (!_fieldE4) { + petDisplayMessage(1, "The Seasonal Adjustment switch is not operational at the present time."); + } else if (!_fieldE0) { + playMovie(0, 6, MOVIE_NOTIFY_OBJECT); + playMovie(6, 18, 0); + } + + return true; +} + +bool CSeasonalAdjustment::MovieEndMsg(CMovieEndMsg *msg) { + if (msg->_endFrame == 6) { + stateChangeSeason(); + CStatusChangeMsg changeMsg; + changeMsg.execute(this); + CTurnOff offMsg; + offMsg.execute(this); + offMsg.execute("LeftPanExit"); + offMsg.execute("RightPanExit"); + } + + return true; +} + +bool CSeasonalAdjustment::TurnOn(CTurnOn *msg) { + if (_fieldE0) { + _fieldE0 = false; + CTurnOn onMsg; + onMsg.execute("LeftPanExit"); + onMsg.execute("RightPanExit"); + } + + return true; +} + +bool CSeasonalAdjustment::TurnOff(CTurnOff *msg) { + _fieldE0 = true; + return true; +} + +bool CSeasonalAdjustment::ActMsg(CActMsg *msg) { + if (msg->_action == "PlayerGetsSpeechCentre") { + msg->execute("SeasonBackground"); + msg->execute("ArbGate"); + } else if (msg->_action == "EnableObject") { + _fieldE4 = true; + } else if (msg->_action == "DisableObject") { + _fieldE4 = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/seasonal_adjustment.h b/engines/titanic/game/seasonal_adjustment.h index f96c13619d..4b7ef3d4f6 100644 --- a/engines/titanic/game/seasonal_adjustment.h +++ b/engines/titanic/game/seasonal_adjustment.h @@ -27,15 +27,16 @@ namespace Titanic { -enum Season { - SPRING = 0, - SUMMER = 1, - AUTUMN = 2, - WINTER = 3 -}; - class CSeasonalAdjustment : public CBackground { -public: + DECLARE_MESSAGE_MAP; + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool ActMsg(CActMsg *msg); +private: int _fieldE0; int _fieldE4; public: diff --git a/engines/titanic/game/service_elevator_window.cpp b/engines/titanic/game/service_elevator_window.cpp index 95b2735b37..b0cc53abb4 100644 --- a/engines/titanic/game/service_elevator_window.cpp +++ b/engines/titanic/game/service_elevator_window.cpp @@ -21,9 +21,19 @@ */ #include "titanic/game/service_elevator_window.h" +#include "titanic/core/room_item.h" +#include "titanic/npcs/doorbot.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CServiceElevatorWindow, CBackground) + ON_MESSAGE(ServiceElevatorFloorChangeMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +static const int FACTORS[4] = { 0, 20, 100, 0 }; + CServiceElevatorWindow::CServiceElevatorWindow() : CBackground(), _fieldE0(0), _fieldE4(0), _fieldE8(0), _fieldEC(0) { } @@ -48,4 +58,57 @@ void CServiceElevatorWindow::load(SimpleFile *file) { CBackground::load(file); } +bool CServiceElevatorWindow::ServiceElevatorFloorChangeMsg(CServiceElevatorFloorChangeMsg *msg) { + if (getView() == findView()) { + CDoorbot *doorbot = dynamic_cast<CDoorbot *>(findRoom()->findByName("Doorbot")); + int val = (_fieldE8 && doorbot) ? 65 : 15; + CMovieClip *clip = _movieClips.findByName("Going Up"); + + if (!clip) + return true; + + int count = _endFrame - _startFrame; + setMovieFrameRate(1.0 * count / val); + + int startFrame = clip->_startFrame + count * FACTORS[msg->_value1] / 100; + int endFrame = clip->_startFrame + count * FACTORS[msg->_value2] / 100; + + if (_fieldE4) { + playMovie(startFrame, endFrame, MOVIE_NOTIFY_OBJECT); + } else { + playMovie(startFrame, endFrame, 0); + if (_fieldEC) + playClip("Into Space"); + } + } + + _fieldE0 = msg->_value2; + return true; +} + +bool CServiceElevatorWindow::MovieEndMsg(CMovieEndMsg *msg) { + CServiceElevatorMsg elevMsg(5); + elevMsg.execute(findRoom()->findByName("Service Elevator Entity")); + return true; +} + +bool CServiceElevatorWindow::EnterViewMsg(CEnterViewMsg *msg) { + if (_fieldEC) { + playClip("Fade Up"); + playMovie(1, 2, 0); + } else { + CMovieClip *clip = _movieClips.findByName("Going Up"); + + if (clip) { + int frameNum = clip->_startFrame + (clip->_endFrame - clip->_startFrame) + * FACTORS[_fieldE0] / 100; + loadFrame(frameNum); + } else { + loadFrame(0); + } + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/service_elevator_window.h b/engines/titanic/game/service_elevator_window.h index 4233b8405a..88e1663aba 100644 --- a/engines/titanic/game/service_elevator_window.h +++ b/engines/titanic/game/service_elevator_window.h @@ -28,6 +28,10 @@ namespace Titanic { class CServiceElevatorWindow : public CBackground { + DECLARE_MESSAGE_MAP; + bool ServiceElevatorFloorChangeMsg(CServiceElevatorFloorChangeMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); public: int _fieldE0; int _fieldE4; diff --git a/engines/titanic/game/sgt/bedhead.cpp b/engines/titanic/game/sgt/bedhead.cpp index 6f427ab625..216d22ee71 100644 --- a/engines/titanic/game/sgt/bedhead.cpp +++ b/engines/titanic/game/sgt/bedhead.cpp @@ -21,6 +21,7 @@ */ #include "titanic/game/sgt/bedhead.h" +#include "titanic/titanic.h" namespace Titanic { @@ -29,6 +30,52 @@ BEGIN_MESSAGE_MAP(CBedhead, CSGTStateRoom) ON_MESSAGE(TurnOff) END_MESSAGE_MAP() +void BedheadEntry::load(Common::SeekableReadStream *s) { + _name1 = readStringFromStream(s); + _name2 = readStringFromStream(s); + _name3 = readStringFromStream(s); + _name4 = readStringFromStream(s); + _startFrame = s->readUint32LE(); + _endFrame = s->readUint32LE(); +} + +/*------------------------------------------------------------------------*/ + +void BedheadEntries::load(Common::SeekableReadStream *s, int count) { + resize(count); + for (int idx = 0; idx < count; ++idx) + (*this)[idx].load(s); +} + +/*------------------------------------------------------------------------*/ + +void TurnOnEntries::load(Common::SeekableReadStream *s) { + _closed.load(s, 4); + _restingTV.load(s, 2); + _restingUV.load(s, 2); + _closedWrong.load(s, 2); +} + +/*------------------------------------------------------------------------*/ + +void TurnOffEntries::load(Common::SeekableReadStream *s) { + _open.load(s, 3); + _restingUTV.load(s, 1); + _restingV.load(s, 1); + _restingG.load(s, 3); + _openWrong.load(s, 1); + _restingDWrong.load(s, 1); +} + +/*------------------------------------------------------------------------*/ + +CBedhead::CBedhead() : CSGTStateRoom() { + Common::SeekableReadStream *s = g_vm->_filesManager->getResource("DATA/BEDHEAD"); + _on.load(s); + _off.load(s); + delete s; +} + void CBedhead::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -40,12 +87,83 @@ void CBedhead::load(SimpleFile *file) { } bool CBedhead::TurnOn(CTurnOn *msg) { - // TODO + if (_statics->_v2 == "Closed" || _statics->_v2 == "RestingUnderTV") + return true; + + const BedheadEntries *data = nullptr; + if (_statics->_v1 == "Closed") + data = &_on._closed; + else if (_statics->_v1 == "RestingTV") + data = &_on._restingTV; + else if (_statics->_v1 == "RestingUV") + data = &_on._restingUV; + else if (_statics->_v1 == "ClosedWrong") + data = &_on._closedWrong; + else + return true; + + for (uint idx = 0; idx < data->size(); ++idx) { + const BedheadEntry &entry = (*data)[idx]; + if ((entry._name1 == _statics->_v4 || entry._name1 == "Any") + && (entry._name2 == _statics->_v3 || entry._name2 == "Any") + && (entry._name3 == _statics->_v5 || entry._name3 == "Any")) { + CVisibleMsg visibleMsg(false); + visibleMsg.execute("Bedfoot"); + setVisible(true); + + _statics->_v1 = entry._name4; + playMovie(entry._startFrame, entry._endFrame, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + playSound("b#6.wav"); + _fieldE0 = false; + } + } + + if (_statics->_v1 == "Open") { + playMovie(71, 78, 0); + playSound("196_436 bed inflate 2.wav"); + } + return true; } bool CBedhead::TurnOff(CTurnOff *msg) { - // TODO + if (_statics->_v1 == "Open") { + playMovie(78, 85, 0); + playSound("191_436_bed inflate deflate.wav"); + } + + BedheadEntries *data = nullptr; + if (_statics->_v1 == "Open") + data = &_off._open; + else if (_statics->_v1 == "RestingUTV") + data = &_off._restingUTV; + else if (_statics->_v1 == "RestingV") + data = &_off._restingV; + else if (_statics->_v1 == "RestingG") + data = &_off._restingG; + else if (_statics->_v1 == "OpenWrong") + data = &_off._openWrong; + else if (_statics->_v1 == "RestingDWrong") + data = &_off._restingDWrong; + else + return true; + + for (uint idx = 0; idx < data->size(); ++idx) { + const BedheadEntry &entry = (*data)[idx]; + if ((entry._name1 == _statics->_v4 || entry._name1 == "Any") + && (entry._name2 == _statics->_v3 || entry._name2 == "Any") + && (entry._name3 == _statics->_v5 || entry._name3 == "Any")) { + CVisibleMsg visibleMsg(false); + visibleMsg.execute("Bedfoot"); + setVisible(true); + + _statics->_v1 = entry._name4; + playMovie(entry._startFrame, entry._endFrame, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + playSound("193_436_bed fold up 1.wav"); + _fieldE0 = false; + } + } + return true; } diff --git a/engines/titanic/game/sgt/bedhead.h b/engines/titanic/game/sgt/bedhead.h index 665dec021c..7784cb8caf 100644 --- a/engines/titanic/game/sgt/bedhead.h +++ b/engines/titanic/game/sgt/bedhead.h @@ -23,16 +23,56 @@ #ifndef TITANIC_BEDHEAD_H #define TITANIC_BEDHEAD_H +#include "common/array.h" #include "titanic/game/sgt/sgt_state_room.h" namespace Titanic { +struct BedheadEntry { + CString _name1; + CString _name2; + CString _name3; + CString _name4; + int _startFrame; + int _endFrame; + + void load(Common::SeekableReadStream *s); +}; +class BedheadEntries : public Common::Array<BedheadEntry> { +public: + void load(Common::SeekableReadStream *s, int count); +}; + +struct TurnOnEntries { + BedheadEntries _closed; + BedheadEntries _restingTV; + BedheadEntries _restingUV; + BedheadEntries _closedWrong; + + void load(Common::SeekableReadStream *s); +}; + +struct TurnOffEntries { + BedheadEntries _open; + BedheadEntries _restingUTV; + BedheadEntries _restingV; + BedheadEntries _restingG; + BedheadEntries _openWrong; + BedheadEntries _restingDWrong; + + void load(Common::SeekableReadStream *s); +}; + class CBedhead : public CSGTStateRoom { DECLARE_MESSAGE_MAP; bool TurnOn(CTurnOn *msg); bool TurnOff(CTurnOff *msg); +private: + TurnOnEntries _on; + TurnOffEntries _off; public: CLASSDEF; + CBedhead(); /** * Save the data for the class to file diff --git a/engines/titanic/game/sgt/sgt_doors.cpp b/engines/titanic/game/sgt/sgt_doors.cpp index 516b0f1351..71eae9800c 100644 --- a/engines/titanic/game/sgt/sgt_doors.cpp +++ b/engines/titanic/game/sgt/sgt_doors.cpp @@ -21,13 +21,21 @@ */ #include "titanic/game/sgt/sgt_doors.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CSGTDoors, CGameObject) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(LeaveRoomMsg) +END_MESSAGE_MAP() + void CSGTDoors::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_value1, indent); - file->writeNumberLine(_value2, indent); + file->writeNumberLine(_open, indent); CGameObject::save(file, indent); } @@ -35,9 +43,58 @@ void CSGTDoors::save(SimpleFile *file, int indent) { void CSGTDoors::load(SimpleFile *file) { file->readNumber(); _value1 = file->readNumber(); - _value2 = file->readNumber(); + _open = file->readNumber(); CGameObject::load(file); } +bool CSGTDoors::EnterViewMsg(CEnterViewMsg *msg) { + setVisible(true); + _open = true; + CPetControl *pet = getPetControl(); + + if (pet) { + int roomNum = pet->getRoomsRoomNum(); + static const int START_FRAMES[7] = { 0, 26, 30, 34, 38, 42, 46 }; + static const int END_FRAMES[7] = { 12, 29, 33, 37, 41, 45, 49 }; + + if (pet->getRooms1CC() == 1) + playMovie(START_FRAMES[roomNum], END_FRAMES[roomNum], + MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + else + playMovie(0, 12, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + } + + return true; +} + +bool CSGTDoors::LeaveViewMsg(CLeaveViewMsg *msg) { + return true; +} + +bool CSGTDoors::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(!_open); + return true; +} + +bool CSGTDoors::LeaveRoomMsg(CLeaveRoomMsg *msg) { + setVisible(true); + _open = false; + CPetControl *pet = getPetControl(); + + if (pet) { + int roomNum = pet->getRoomsRoomNum(); + static const int START_FRAMES[7] = { 12, 69, 65, 61, 57, 53, 49 }; + static const int END_FRAMES[7] = { 25, 72, 68, 64, 60, 56, 52 }; + + if (pet->getRooms1CC() == 1) + playMovie(START_FRAMES[roomNum], END_FRAMES[roomNum], + MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + else + playMovie(12, 25, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/sgt_doors.h b/engines/titanic/game/sgt/sgt_doors.h index 4b4f4a3153..b19c5860af 100644 --- a/engines/titanic/game/sgt/sgt_doors.h +++ b/engines/titanic/game/sgt/sgt_doors.h @@ -28,11 +28,17 @@ namespace Titanic { class CSGTDoors : public CGameObject { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool LeaveRoomMsg(CLeaveRoomMsg *msg); public: - int _value1, _value2; + int _value1; + bool _open; public: CLASSDEF; - CSGTDoors() : CGameObject(), _value1(0), _value2(0) {} + CSGTDoors() : CGameObject(), _value1(0), _open(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/sgt/sgt_nav.cpp b/engines/titanic/game/sgt/sgt_nav.cpp index f98e486fd0..c004f947d2 100644 --- a/engines/titanic/game/sgt/sgt_nav.cpp +++ b/engines/titanic/game/sgt/sgt_nav.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(SGTNav, CSGTStateRoom) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseMoveMsg) +END_MESSAGE_MAP() + void SGTNav::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -34,4 +39,43 @@ void SGTNav::load(SimpleFile *file) { CSGTStateRoom::load(file); } +bool SGTNav::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CTurnOn onMsg; + CTurnOff offMsg; + + if (_statics->_v6 == "Open" && _statics->_v1 == "Open") { + if (_statics->_v3 == "Open") + offMsg.execute("Vase"); + if (_statics->_v4 == "Closed") + onMsg.execute("SGTTV"); + if (_statics->_v7 == "Open") + offMsg.execute("Drawer"); + if (_statics->_v8 == "Open") + offMsg.execute("Armchair"); + if (_statics->_v9 == "Open") + offMsg.execute("Deskchair"); + if (_statics->_v12 == "Open") + offMsg.execute("Toilet"); + + changeView("SGTState.Node 2.E"); + } else if (_statics->_v1 == "Open") { + petDisplayMessage(1, "This is your stateroom. It is for sleeping. If you desire " + "entertainment or relaxation, please visit your local leisure lounge."); + } else if (_statics->_v6 == "Closed") { + petDisplayMessage(1, "The bed will not currently support your weight." + " We are working on this problem but are unlikely to be able to fix it."); + } + + return true; +} + +bool SGTNav::MouseMoveMsg(CMouseMoveMsg *msg) { + if (_statics->_v6 == "Open" && _statics->_v1 == "Open") + _cursorId = CURSOR_MOVE_FORWARD; + else + _cursorId = CURSOR_ARROW; + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/sgt_nav.h b/engines/titanic/game/sgt/sgt_nav.h index 40fdc4eff1..78f6417229 100644 --- a/engines/titanic/game/sgt/sgt_nav.h +++ b/engines/titanic/game/sgt/sgt_nav.h @@ -28,6 +28,9 @@ namespace Titanic { class SGTNav : public CSGTStateRoom { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseMoveMsg(CMouseMoveMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/sgt/sgt_navigation.cpp b/engines/titanic/game/sgt/sgt_navigation.cpp index 7bb64f934d..031226226f 100644 --- a/engines/titanic/game/sgt/sgt_navigation.cpp +++ b/engines/titanic/game/sgt/sgt_navigation.cpp @@ -21,9 +21,16 @@ */ #include "titanic/game/sgt/sgt_navigation.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CSGTNavigation, CGameObject) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + CSGTNavigationStatics *CSGTNavigation::_statics; void CSGTNavigation::init() { @@ -36,7 +43,7 @@ void CSGTNavigation::deinit() { void CSGTNavigation::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_statics->_changeViewFlag, indent); + file->writeNumberLine(_statics->_changeViewNum, indent); file->writeQuotedLine(_statics->_destView, indent); file->writeQuotedLine(_statics->_destRoom, indent); @@ -45,11 +52,79 @@ void CSGTNavigation::save(SimpleFile *file, int indent) { void CSGTNavigation::load(SimpleFile *file) { file->readNumber(); - _statics->_changeViewFlag = file->readNumber(); + _statics->_changeViewNum = file->readNumber(); _statics->_destView = file->readString(); _statics->_destRoom = file->readString(); CGameObject::load(file); } +bool CSGTNavigation::StatusChangeMsg(CStatusChangeMsg *msg) { + CPetControl *pet = getPetControl(); + + if (isEquals("SGTLL")) { + static const int FRAMES[7] = { 0, 149, 112, 74, 0, 36, 74 }; + _statics->_changeViewNum = msg->_newStatus; + if (pet->getRooms1CC() != _statics->_changeViewNum) { + changeView("SGTLittleLift.Node 1.N"); + } + + int startVal = pet->getRooms1CC(); + if (startVal > _statics->_changeViewNum) + playMovie(FRAMES[startVal], FRAMES[_statics->_changeViewNum], MOVIE_GAMESTATE); + else + playMovie(FRAMES[startVal + 3], FRAMES[_statics->_changeViewNum + 3], MOVIE_GAMESTATE); + + _cursorId = _statics->_changeViewNum != 1 ? CURSOR_MOVE_FORWARD : CURSOR_INVALID; + + pet->setRooms1CC(_statics->_changeViewNum); + pet->resetRoomsHighlight(); + } + + return true; +} + +bool CSGTNavigation::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (compareRoomNameTo("SgtLobby")) { + _statics->_destView = getRoomNodeName(); + _statics->_destRoom = "SgtLobby"; + changeView("SGTState.Node 1.S"); + } else if (compareRoomNameTo("SGTLittleLift")) { + if (_statics->_changeViewNum != 1) { + _statics->_destRoom = "SGTLittleLift"; + changeView("SGTState.Node 1.S"); + } + } else if (compareRoomNameTo("SGTState")) { + if (_statics->_destRoom == "SgtLobby") { + if (compareViewNameTo("SGTState.Node 2.N")) { + changeView("SGTState.Node 1.N"); + _statics->_destView += ".S"; + } else { + _statics->_destView += ".N"; + } + + changeView(_statics->_destView); + } else if (_statics->_destRoom == "SGTLittleLift") { + if (compareViewNameTo("SGTState.Node 1.S")) { + changeView("SGTLittleLift.Node 1.N"); + } else { + changeView("SGTState.Node 1.N"); + changeView("SGTLittleLift.Node 1.S"); + } + } + } + + return true; +} + +bool CSGTNavigation::EnterViewMsg(CEnterViewMsg *msg) { + if (isEquals("SGTLL")) { + static const int FRAMES[3] = { 0, 36, 74 }; + CPetControl *pet = getPetControl(); + loadFrame(FRAMES[pet->getRooms1CC() - 1]); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/sgt_navigation.h b/engines/titanic/game/sgt/sgt_navigation.h index ed58d918e9..69ecd1267a 100644 --- a/engines/titanic/game/sgt/sgt_navigation.h +++ b/engines/titanic/game/sgt/sgt_navigation.h @@ -28,12 +28,16 @@ namespace Titanic { struct CSGTNavigationStatics { - bool _changeViewFlag; + int _changeViewNum; CString _destView; CString _destRoom; }; class CSGTNavigation : public CGameObject { + DECLARE_MESSAGE_MAP; + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); protected: static CSGTNavigationStatics *_statics; public: diff --git a/engines/titanic/game/sgt/sgt_restaurant_doors.cpp b/engines/titanic/game/sgt/sgt_restaurant_doors.cpp index 74a71e75b2..5c36ceb0ff 100644 --- a/engines/titanic/game/sgt/sgt_restaurant_doors.cpp +++ b/engines/titanic/game/sgt/sgt_restaurant_doors.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSGTRestaurantDoors, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CSGTRestaurantDoors::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldBC, indent); @@ -36,4 +40,10 @@ void CSGTRestaurantDoors::load(SimpleFile *file) { CGameObject::load(file); } +bool CSGTRestaurantDoors::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CTurnOff offMsg; + offMsg.execute("ChickenDispenser"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/sgt_restaurant_doors.h b/engines/titanic/game/sgt/sgt_restaurant_doors.h index 2a10d8f059..bcaaa71014 100644 --- a/engines/titanic/game/sgt/sgt_restaurant_doors.h +++ b/engines/titanic/game/sgt/sgt_restaurant_doors.h @@ -28,6 +28,8 @@ namespace Titanic { class CSGTRestaurantDoors : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); private: int _fieldBC; public: diff --git a/engines/titanic/game/sgt/sgt_state_control.cpp b/engines/titanic/game/sgt/sgt_state_control.cpp index 07c1f5efc0..9617f2f127 100644 --- a/engines/titanic/game/sgt/sgt_state_control.cpp +++ b/engines/titanic/game/sgt/sgt_state_control.cpp @@ -24,16 +24,59 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSGTStateControl, CBackground) + ON_MESSAGE(PETUpMsg) + ON_MESSAGE(PETDownMsg) + ON_MESSAGE(PETActivateMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + void CSGTStateControl::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); + file->writeNumberLine(_state, indent); CBackground::save(file, indent); } void CSGTStateControl::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); + _state = file->readNumber(); CBackground::load(file); } +bool CSGTStateControl::PETUpMsg(CPETUpMsg *msg) { + // WORKAROUND: Redundant code in original not included + return true; +} + +bool CSGTStateControl::PETDownMsg(CPETDownMsg *msg) { + // WORKAROUND: Redundant code in original not included + return true; +} + +bool CSGTStateControl::PETActivateMsg(CPETActivateMsg *msg) { + if (msg->_name == "SGTSelector") { + static const char *const TARGETS[] = { + "Vase", "Bedfoot", "Toilet", "Drawer", "SGTTV", "Armchair", "BedHead", + "WashStand", "Desk", "DeskChair", "Basin", "ChestOfDrawers" + }; + _state = msg->_numValue; + CActMsg actMsg; + actMsg.execute(TARGETS[_state]); + } + + return true; +} + +bool CSGTStateControl::EnterViewMsg(CEnterViewMsg *msg) { + _state = 1; + petSetRemoteTarget(); + return true; +} + +bool CSGTStateControl::LeaveViewMsg(CLeaveViewMsg *msg) { + petClear(); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/sgt_state_control.h b/engines/titanic/game/sgt/sgt_state_control.h index 49fd5113cd..6f96359761 100644 --- a/engines/titanic/game/sgt/sgt_state_control.h +++ b/engines/titanic/game/sgt/sgt_state_control.h @@ -24,15 +24,22 @@ #define TITANIC_SGT_STATE_CONTROL_H #include "titanic/core/background.h" +#include "titanic/messages/pet_messages.h" namespace Titanic { class CSGTStateControl : public CBackground { + DECLARE_MESSAGE_MAP; + bool PETUpMsg(CPETUpMsg *msg); + bool PETDownMsg(CPETDownMsg *msg); + bool PETActivateMsg(CPETActivateMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); private: - int _fieldE0; + int _state; public: CLASSDEF; - CSGTStateControl() : CBackground(), _fieldE0(1) {} + CSGTStateControl() : CBackground(), _state(1) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/sgt/sgt_tv.cpp b/engines/titanic/game/sgt/sgt_tv.cpp index ae4c59e2f9..08ed381b2b 100644 --- a/engines/titanic/game/sgt/sgt_tv.cpp +++ b/engines/titanic/game/sgt/sgt_tv.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSGTTV, CSGTStateRoom) + ON_MESSAGE(TurnOff) + ON_MESSAGE(TurnOn) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CSGTTV::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -34,4 +40,35 @@ void CSGTTV::load(SimpleFile *file) { CSGTStateRoom::load(file); } +bool CSGTTV::TurnOff(CTurnOff *msg) { + if (CSGTStateRoom::_statics->_v4 == "Open") { + CSGTStateRoom::_statics->_v4 = "Closed"; + _fieldE0 = true; + _startFrame = 6; + _endFrame = 12; + playMovie(6, 12, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + } + + return true; +} + +bool CSGTTV::TurnOn(CTurnOn *msg) { + if (CSGTStateRoom::_statics->_v4 == "Closed" && + CSGTStateRoom::_statics->_v2 == "Closed") { + CSGTStateRoom::_statics->_v4 = "Open"; + setVisible(true); + _fieldE0 = false; + _startFrame = 1; + _endFrame = 6; + playMovie(1, 6, MOVIE_GAMESTATE); + } + + return true; +} + +bool CSGTTV::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(false); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/sgt_tv.h b/engines/titanic/game/sgt/sgt_tv.h index 90fed90efe..e5de38e84b 100644 --- a/engines/titanic/game/sgt/sgt_tv.h +++ b/engines/titanic/game/sgt/sgt_tv.h @@ -28,6 +28,10 @@ namespace Titanic { class CSGTTV : public CSGTStateRoom { + DECLARE_MESSAGE_MAP; + bool TurnOff(CTurnOff *msg); + bool TurnOn(CTurnOn *msg); + bool MovieEndMsg(CMovieEndMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/sgt/toilet.cpp b/engines/titanic/game/sgt/toilet.cpp index 799abd6c76..b8e87b645a 100644 --- a/engines/titanic/game/sgt/toilet.cpp +++ b/engines/titanic/game/sgt/toilet.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CToilet, CSGTStateRoom) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CToilet::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -34,4 +40,42 @@ void CToilet::load(SimpleFile *file) { CSGTStateRoom::load(file); } +bool CToilet::TurnOn(CTurnOn *msg) { + if (CSGTStateRoom::_statics->_v12 == "Closed" + && CSGTStateRoom::_statics->_v10 == "Open" + && CSGTStateRoom::_statics->_v8 == "Closed") { + setVisible(true); + CSGTStateRoom::_statics->_v12 = "Open"; + + _fieldE0 = false; + _startFrame = 0; + _endFrame = 11; + playMovie(0, 11, MOVIE_GAMESTATE); + playSound("b#1.wav"); + } + + return true; +} + +bool CToilet::TurnOff(CTurnOff *msg) { + if (CSGTStateRoom::_statics->_v12 == "Open") { + CSGTStateRoom::_statics->_v12 = "Closed"; + + _fieldE0 = true; + _startFrame = 11; + _endFrame = 18; + playMovie(11, 18, MOVIE_GAMESTATE); + playSound("b#1.wav"); + } + + return true; +} + +bool CToilet::MovieEndMsg(CMovieEndMsg *msg) { + if (CSGTStateRoom::_statics->_v12 == "Closed") + setVisible(false); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/toilet.h b/engines/titanic/game/sgt/toilet.h index d87531ad7a..a4bc318fb2 100644 --- a/engines/titanic/game/sgt/toilet.h +++ b/engines/titanic/game/sgt/toilet.h @@ -28,6 +28,10 @@ namespace Titanic { class CToilet : public CSGTStateRoom { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool MovieEndMsg(CMovieEndMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/sgt/vase.cpp b/engines/titanic/game/sgt/vase.cpp index 3e04b5db9e..2d37818340 100644 --- a/engines/titanic/game/sgt/vase.cpp +++ b/engines/titanic/game/sgt/vase.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CVase, CSGTStateRoom) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CVase::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -34,4 +40,38 @@ void CVase::load(SimpleFile *file) { CSGTStateRoom::load(file); } +bool CVase::TurnOn(CTurnOn *msg) { + if (CSGTStateRoom::_statics->_v3 == "Closed") { + CSGTStateRoom::_statics->_v3 = "Open"; + setVisible(true); + _fieldE0 = false; + _startFrame = 1; + _endFrame = 12; + playMovie(1, 12, MOVIE_GAMESTATE); + } + + return true; +} + +bool CVase::TurnOff(CTurnOff *msg) { + if (CSGTStateRoom::_statics->_v3 == "Open" + && CSGTStateRoom::_statics->_v1 != "RestingV" + && CSGTStateRoom::_statics->_v1 != "RestingUV") { + CSGTStateRoom::_statics->_v3 = "Closed"; + _fieldE0 = true; + _startFrame = 12; + _endFrame = 25; + playMovie(12, 25, MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + } + + return true; +} + +bool CVase::MovieEndMsg(CMovieEndMsg *msg) { + if (CSGTStateRoom::_statics->_v3 == "Closed") + setVisible(false); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/vase.h b/engines/titanic/game/sgt/vase.h index 8aa35acdf5..e07d9efb80 100644 --- a/engines/titanic/game/sgt/vase.h +++ b/engines/titanic/game/sgt/vase.h @@ -28,6 +28,10 @@ namespace Titanic { class CVase : public CSGTStateRoom { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool MovieEndMsg(CMovieEndMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/sgt/washstand.cpp b/engines/titanic/game/sgt/washstand.cpp index 8127a59a59..afdc74414d 100644 --- a/engines/titanic/game/sgt/washstand.cpp +++ b/engines/titanic/game/sgt/washstand.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CWashstand, CSGTStateRoom) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CWashstand::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -34,4 +40,36 @@ void CWashstand::load(SimpleFile *file) { CSGTStateRoom::load(file); } +bool CWashstand::TurnOn(CTurnOn *msg) { + if (_statics->_v10 == "Closed" && _statics->_v2 == "NotOnWashstand") { + setVisible(true); + _statics->_v10 = "Open"; + _fieldE0 = false; + _startFrame = 0; + _endFrame = 14; + playMovie(0, 14, MOVIE_GAMESTATE); + playSound("b#14.wav"); + } + + return true; +} + +bool CWashstand::TurnOff(CTurnOff *msg) { + if (_statics->_v10 == "Open" && _statics->_v11 == "Closed" + && _statics->_v12 == "Closed" && _statics->_v2 == "Open") { + _statics->_v10 = "Closed"; + _fieldE0 = true; + _startFrame = 14; + _endFrame = 28; + playMovie(14, 28, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + playSound("b#14.wav"); + } + + return true; +} + +bool CWashstand::MovieEndMsg(CMovieEndMsg *msg) { + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/washstand.h b/engines/titanic/game/sgt/washstand.h index f140b17f49..1b72cfa1c4 100644 --- a/engines/titanic/game/sgt/washstand.h +++ b/engines/titanic/game/sgt/washstand.h @@ -28,6 +28,10 @@ namespace Titanic { class CWashstand : public CSGTStateRoom { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool MovieEndMsg(CMovieEndMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/ship_setting.cpp b/engines/titanic/game/ship_setting.cpp index 462f396501..93800e899b 100644 --- a/engines/titanic/game/ship_setting.cpp +++ b/engines/titanic/game/ship_setting.cpp @@ -21,35 +21,109 @@ */ #include "titanic/game/ship_setting.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CShipSetting, CBackground) + ON_MESSAGE(AddHeadPieceMsg) + ON_MESSAGE(SetFrameMsg) + ON_MESSAGE(EnterRoomMsg) + ON_MESSAGE(MouseDragStartMsg) +END_MESSAGE_MAP() + CShipSetting::CShipSetting() : CBackground(), - _string4("NULL"), _string5("NULL") { + _itemName("NULL"), _frameTarget("NULL") { } void CShipSetting::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string3, indent); + file->writeQuotedLine(_target, indent); file->writePoint(_pos1, indent); - file->writeQuotedLine(_string4, indent); - file->writeQuotedLine(_string5, indent); + file->writeQuotedLine(_itemName, indent); + file->writeQuotedLine(_frameTarget, indent); CBackground::save(file, indent); } void CShipSetting::load(SimpleFile *file) { file->readNumber(); - _string3 = file->readString(); + _target = file->readString(); _pos1 = file->readPoint(); - _string4 = file->readString(); - _string5 = file->readString(); + _itemName = file->readString(); + _frameTarget = file->readString(); CBackground::load(file); } +bool CShipSetting::AddHeadPieceMsg(CAddHeadPieceMsg *msg) { + _cursorId = CURSOR_HAND; + + if (msg->_value == "Enable") { + CTurnOn onMsg; + onMsg.execute(_target); + + if (isEquals("ChickenSetting")) { + CActMsg actMsg("DecreaseQuantity"); + actMsg.execute("ChickenDispenser"); + } + } else { + CTurnOff offMsg; + offMsg.execute(_target); + } + + return true; +} + +bool CShipSetting::SetFrameMsg(CSetFrameMsg *msg) { + msg->execute(_frameTarget); + return true; +} + bool CShipSetting::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CShipSetting::handleEvent"); + CSetFrameMsg frameMsg; + + if (_itemName == "ChickenBridge") + frameMsg._frameNumber = 1; + else if (_itemName == "FanBridge") + frameMsg._frameNumber = 2; + else if (_itemName == "SeasonBridge") + frameMsg._frameNumber = 3; + else if (_itemName == "BeamBridge") + frameMsg._frameNumber = 4; + + frameMsg.execute(this); + return true; +} + +bool CShipSetting::MouseDragStartMsg(CMouseDragStartMsg *msg) { + if (!checkStartDragging(msg)) + return false; + if (_itemName == "NULL") + return true; + + CTurnOff offMsg; + offMsg.execute(_target); + + if (isEquals("ChickenSetting") || _itemName == "ChickenBridge") { + CActMsg actMsg("IncreaseQuantity"); + actMsg.execute("ChickenDispenser"); + } + + if (_itemName != "NULL") { + CPassOnDragStartMsg passMsg(msg->_mousePos, 1); + passMsg.execute(_itemName); + + msg->_dragItem = getRoot()->findByName(_itemName); + + CVisibleMsg visibleMsg(true); + visibleMsg.execute(_itemName); + } + + CSetFrameMsg frameMsg(0); + frameMsg.execute(_frameTarget); + _itemName = "NULL"; + _cursorId = CURSOR_ARROW; return true; } diff --git a/engines/titanic/game/ship_setting.h b/engines/titanic/game/ship_setting.h index 4fcc10a424..198d97d250 100644 --- a/engines/titanic/game/ship_setting.h +++ b/engines/titanic/game/ship_setting.h @@ -29,12 +29,16 @@ namespace Titanic { class CShipSetting : public CBackground { + DECLARE_MESSAGE_MAP; + bool AddHeadPieceMsg(CAddHeadPieceMsg *msg); + bool SetFrameMsg(CSetFrameMsg *msg); bool EnterRoomMsg(CEnterRoomMsg *msg); + bool MouseDragStartMsg(CMouseDragStartMsg *msg); public: - CString _string3; + CString _target; Point _pos1; - CString _string4; - CString _string5; + CString _itemName; + CString _frameTarget; public: CLASSDEF; CShipSetting(); diff --git a/engines/titanic/game/ship_setting_button.cpp b/engines/titanic/game/ship_setting_button.cpp index 7dc2cabac0..d485e06668 100644 --- a/engines/titanic/game/ship_setting_button.cpp +++ b/engines/titanic/game/ship_setting_button.cpp @@ -24,25 +24,69 @@ namespace Titanic { -CShipSettingButton::CShipSettingButton() : CGameObject(), _fieldC8(0), _fieldCC(0) { +BEGIN_MESSAGE_MAP(CShipSettingButton, CGameObject) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +CShipSettingButton::CShipSettingButton() : CGameObject(), _pressed(false), _enabled(false) { } void CShipSettingButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string1, indent); - file->writeNumberLine(_fieldC8, indent); - file->writeNumberLine(_fieldCC, indent); + file->writeQuotedLine(_target, indent); + file->writeNumberLine(_pressed, indent); + file->writeNumberLine(_enabled, indent); CGameObject::save(file, indent); } void CShipSettingButton::load(SimpleFile *file) { file->readNumber(); - _string1 = file->readString(); - _fieldC8 = file->readNumber(); - _fieldCC = file->readNumber(); + _target = file->readString(); + _pressed = file->readNumber(); + _enabled = file->readNumber(); CGameObject::load(file); } +bool CShipSettingButton::TurnOn(CTurnOn *msg) { + _pressed = true; + return true; +} + +bool CShipSettingButton::TurnOff(CTurnOff *msg) { + _pressed = false; + return true; +} + +bool CShipSettingButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_pressed) { + if (_enabled) + playMovie(8, 16, 0); + else + playMovie(0, 8, 0); + + _enabled = !_enabled; + CActMsg actMsg(_enabled ? "EnableObject" : "DisableObject"); + actMsg.execute(_target); + } else { + if (_enabled) { + playMovie(8, 16, 0); + playMovie(0, 8, 0); + } else { + playMovie(0, 16, 0); + } + } + + return true; +} + +bool CShipSettingButton::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(_enabled ? 8 : 16); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/ship_setting_button.h b/engines/titanic/game/ship_setting_button.h index e152e8e2c3..e5457fa532 100644 --- a/engines/titanic/game/ship_setting_button.h +++ b/engines/titanic/game/ship_setting_button.h @@ -28,10 +28,15 @@ namespace Titanic { class CShipSettingButton : public CGameObject { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); private: - CString _string1; - int _fieldC8; - int _fieldCC; + CString _target; + bool _pressed; + bool _enabled; public: CLASSDEF; CShipSettingButton(); diff --git a/engines/titanic/game/show_cell_points.cpp b/engines/titanic/game/show_cell_points.cpp index 7d54401a02..985cb93734 100644 --- a/engines/titanic/game/show_cell_points.cpp +++ b/engines/titanic/game/show_cell_points.cpp @@ -21,21 +21,50 @@ */ #include "titanic/game/show_cell_points.h" +#include "titanic/pet_control/pet_control.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CShowCellpoints, CGameObject) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + void CShowCellpoints::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_strValue, indent); - file->writeNumberLine(_numValue, indent); + file->writeQuotedLine(_npcName, indent); + file->writeNumberLine(_flag, indent); CGameObject::save(file, indent); } void CShowCellpoints::load(SimpleFile *file) { file->readNumber(); - _strValue = file->readString(); - _numValue = file->readNumber(); + _npcName = file->readString(); + _flag = file->readNumber(); CGameObject::load(file); } +bool CShowCellpoints::EnterViewMsg(CEnterViewMsg *msg) { + CPetControl *pet = getPetControl(); + if (pet) { + petSetArea(PET_CONVERSATION); + pet->setActiveNPC(_npcName); + pet->incAreaLocks(); + _flag = true; + } + + return true; +} + +bool CShowCellpoints::LeaveViewMsg(CLeaveViewMsg *msg) { + CPetControl *pet = getPetControl(); + if (pet && _flag) { + pet->resetDials0(); + pet->decAreaLocks(); + _flag = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/show_cell_points.h b/engines/titanic/game/show_cell_points.h index 9de2e06dca..205547d7c2 100644 --- a/engines/titanic/game/show_cell_points.h +++ b/engines/titanic/game/show_cell_points.h @@ -28,12 +28,15 @@ namespace Titanic { class CShowCellpoints : public CGameObject { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); public: - CString _strValue; - int _numValue; + CString _npcName; + bool _flag; public: CLASSDEF; - CShowCellpoints() : CGameObject(), _numValue(0) {} + CShowCellpoints() : CGameObject(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/speech_dispensor.cpp b/engines/titanic/game/speech_dispensor.cpp index f9cc019672..20ff3c69e0 100644 --- a/engines/titanic/game/speech_dispensor.cpp +++ b/engines/titanic/game/speech_dispensor.cpp @@ -24,15 +24,26 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSpeechDispensor, CBackground) + ON_MESSAGE(FrameMsg) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(ChangeSeasonMsg) +END_MESSAGE_MAP() + +CSpeechDispensor::CSpeechDispensor() : CBackground(), _dragItem(nullptr), + _fieldE0(0), _state(0), _fieldEC(0), _fieldF8(0), _seasonNum(SEASON_SUMMER) { +} + void CSpeechDispensor::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); + file->writeNumberLine(_state, indent); file->writeNumberLine(_fieldEC, indent); - file->writeNumberLine(_fieldF0, indent); - file->writeNumberLine(_fieldF4, indent); + file->writeNumberLine(_itemPos.x, indent); + file->writeNumberLine(_itemPos.y, indent); file->writeNumberLine(_fieldF8, indent); - file->writeNumberLine(_fieldFC, indent); + file->writeNumberLine(_seasonNum, indent); CBackground::save(file, indent); } @@ -40,14 +51,93 @@ void CSpeechDispensor::save(SimpleFile *file, int indent) { void CSpeechDispensor::load(SimpleFile *file) { file->readNumber(); _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); + _state = file->readNumber(); _fieldEC = file->readNumber(); - _fieldF0 = file->readNumber(); - _fieldF4 = file->readNumber(); + _itemPos.x = file->readNumber(); + _itemPos.y = file->readNumber(); _fieldF8 = file->readNumber(); - _fieldFC = file->readNumber(); + _seasonNum = (Season)file->readNumber(); CBackground::load(file); } +bool CSpeechDispensor::FrameMsg(CFrameMsg *msg) { + if (_fieldEC || _seasonNum == SEASON_SUMMER || _seasonNum == SEASON_SPRING) + return true; + + CGameObject *dragObject = getDraggingObject(); + if (!_dragItem && dragObject && getView() == findView()) { + if (dragObject->isEquals("Perch")) { + petDisplayMessage(1, "This stick is too short to reach the branches."); + return true; + } + + if (dragObject->isEquals("LongStick")) + _dragItem = dragObject; + } + + if (_dragItem) { + Point pt(_itemPos.x + _dragItem->_bounds.left, + _itemPos.y + _dragItem->_bounds.top); + if (!checkPoint(pt, true)) + return true; + + switch (_state) { + case 0: + playSound("z#93.wav"); + if (_seasonNum == SEASON_WINTER) { + petDisplayMessage(1, "You cannot get this, it is frozen to the branch."); + _fieldE0 = false; + _state = 1; + } else { + if (++_fieldE0 >= 5) { + CActMsg actMsg("PlayerGetsSpeechCentre"); + actMsg.execute("SeasonalAdjust"); + CSpeechFallsFromTreeMsg fallMsg(pt); + fallMsg.execute("SpeechCentre"); + + _fieldEC = true; + _fieldE0 = false; + } + + _state = 1; + } + break; + + case 2: + _state = 0; + ++_fieldE0; + break; + + default: + break; + } + } + + return true; +} + +bool CSpeechDispensor::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + if (!_fieldEC) { + playSound("z#93.wav"); + if (_fieldF8) { + petDisplayMessage(1, "Sadly, this is out of your reach."); + } else { + petDisplayMessage(1, "You can't pick this up on account of it being stuck to the branch."); + } + } + + return true; +} + +bool CSpeechDispensor::StatusChangeMsg(CStatusChangeMsg *msg) { + _fieldF8 = msg->_newStatus == 1; + return true; +} + +bool CSpeechDispensor::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + _seasonNum = (Season)(((int)_seasonNum + 1) % 4); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/speech_dispensor.h b/engines/titanic/game/speech_dispensor.h index 3b877e8d99..038cc024cc 100644 --- a/engines/titanic/game/speech_dispensor.h +++ b/engines/titanic/game/speech_dispensor.h @@ -28,17 +28,22 @@ namespace Titanic { class CSpeechDispensor : public CBackground { + DECLARE_MESSAGE_MAP; + bool FrameMsg(CFrameMsg *msg); + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); private: int _fieldE0; - int _fieldE4; - int _fieldE8; + int _state; + CGameObject *_dragItem; int _fieldEC; - int _fieldF0; - int _fieldF4; + Point _itemPos; int _fieldF8; - int _fieldFC; + Season _seasonNum; public: CLASSDEF; + CSpeechDispensor(); /** * Save the data for the class to file diff --git a/engines/titanic/game/starling_puret.cpp b/engines/titanic/game/starling_puret.cpp index 359ad774df..2f1909d963 100644 --- a/engines/titanic/game/starling_puret.cpp +++ b/engines/titanic/game/starling_puret.cpp @@ -24,16 +24,56 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CStarlingPuret, CGameObject) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CStarlingPuret::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_flag, indent); CGameObject::save(file, indent); } void CStarlingPuret::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _flag = file->readNumber(); CGameObject::load(file); } +bool CStarlingPuret::StatusChangeMsg(CStatusChangeMsg *msg) { + _flag = msg->_newStatus == 1; + if (_flag) { + CStatusChangeMsg changeMsg; + changeMsg._newStatus = 1; + changeMsg.execute("StarlingLoop01"); + } + + return true; +} + +bool CStarlingPuret::EnterViewMsg(CEnterViewMsg *msg) { + if (_flag) { + CStatusChangeMsg changeMsg; + changeMsg._newStatus = 1; + changeMsg.execute("PromDeckStarlings"); + + playMovie(MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + CSignalObject signalMsg; + signalMsg._numValue = 4; + signalMsg.execute("PromDeckStarlings"); + _flag = false; + } + + return true; +} + +bool CStarlingPuret::MovieEndMsg(CMovieEndMsg *msg) { + CActMsg actMsg("StarlingsDead"); + actMsg.execute("FanController"); + actMsg.execute("BirdSauceDisp"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/starling_puret.h b/engines/titanic/game/starling_puret.h index fcd3319958..62a6173093 100644 --- a/engines/titanic/game/starling_puret.h +++ b/engines/titanic/game/starling_puret.h @@ -28,11 +28,15 @@ namespace Titanic { class CStarlingPuret : public CGameObject { + DECLARE_MESSAGE_MAP; + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); private: - int _value; + bool _flag; public: CLASSDEF; - CStarlingPuret() : CGameObject(), _value(0) {} + CStarlingPuret() : CGameObject(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/stop_phonograph_button.cpp b/engines/titanic/game/stop_phonograph_button.cpp index d18f4713ac..75e0ca9337 100644 --- a/engines/titanic/game/stop_phonograph_button.cpp +++ b/engines/titanic/game/stop_phonograph_button.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CStopPhonographButton, CBackground) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CStopPhonographButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBackground::save(file, indent); @@ -34,4 +38,19 @@ void CStopPhonographButton::load(SimpleFile *file) { CBackground::load(file); } +bool CStopPhonographButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CQueryPhonographState queryMsg; + queryMsg.execute(getParent()); + + if (!queryMsg._value) { + playMovie(0, 1, 0); + playMovie(1, 0, 0); + + CPhonographStopMsg stopMsg; + stopMsg.execute(getParent()); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/stop_phonograph_button.h b/engines/titanic/game/stop_phonograph_button.h index b469375e20..d416c4f8fe 100644 --- a/engines/titanic/game/stop_phonograph_button.h +++ b/engines/titanic/game/stop_phonograph_button.h @@ -28,6 +28,8 @@ namespace Titanic { class CStopPhonographButton : public CBackground { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/sub_glass.cpp b/engines/titanic/game/sub_glass.cpp index f1349f06ea..041f49097d 100644 --- a/engines/titanic/game/sub_glass.cpp +++ b/engines/titanic/game/sub_glass.cpp @@ -24,17 +24,25 @@ namespace Titanic { -CSUBGlass::CSUBGlass() : _fieldBC(0), _fieldC0(0), _fieldC4(1), _fieldC8(0) { +BEGIN_MESSAGE_MAP(CSUBGlass, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(SignalObject) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + +CSUBGlass::CSUBGlass() : _fieldBC(0), _startFrame(0), _endFrame(1), _signalStartFrame(0) { } void CSUBGlass::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldBC, indent); - file->writeNumberLine(_fieldC0, indent); - file->writeNumberLine(_fieldC4, indent); - file->writeNumberLine(_fieldC8, indent); - file->writeNumberLine(_fieldCC, indent); - file->writeQuotedLine(_string, indent); + file->writeNumberLine(_startFrame, indent); + file->writeNumberLine(_endFrame, indent); + file->writeNumberLine(_signalStartFrame, indent); + file->writeNumberLine(_signalEndFrame, indent); + file->writeQuotedLine(_target, indent); CGameObject::save(file, indent); } @@ -42,13 +50,58 @@ void CSUBGlass::save(SimpleFile *file, int indent) { void CSUBGlass::load(SimpleFile *file) { file->readNumber(); _fieldBC = file->readNumber(); - _fieldC0 = file->readNumber(); - _fieldC4 = file->readNumber(); - _fieldC8 = file->readNumber(); - _fieldCC = file->readNumber(); - _string = file->readString(); + _startFrame = file->readNumber(); + _endFrame = file->readNumber(); + _signalStartFrame = file->readNumber(); + _signalEndFrame = file->readNumber(); + _target = file->readString(); CGameObject::load(file); } +bool CSUBGlass::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + return true; +} + +bool CSUBGlass::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + if (!_fieldBC && _startFrame >= 0) { + _fieldBC = true; + playMovie(_startFrame, _endFrame, MOVIE_NOTIFY_OBJECT); + playSound("z#30.wav"); + } + + return true; +} + +bool CSUBGlass::MovieEndMsg(CMovieEndMsg *msg) { + if (msg->_endFrame == _endFrame) { + _fieldBC = true; + CSignalObject signalMsg(getName(), 1); + signalMsg.execute(_target); + } + + return true; +} + +bool CSUBGlass::SignalObject(CSignalObject *msg) { + if (msg->_numValue == 1) { + setVisible(true); + + if (_signalStartFrame >= 0) { + playMovie(_signalStartFrame, _signalEndFrame, MOVIE_GAMESTATE); + playSound("z#30.wav"); + _fieldBC = false; + } + } + + return true; +} + +bool CSUBGlass::LeaveViewMsg(CLeaveViewMsg *msg) { + _fieldBC = false; + setVisible(true); + loadFrame(0); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sub_glass.h b/engines/titanic/game/sub_glass.h index aab5c8400e..22d16ff4d5 100644 --- a/engines/titanic/game/sub_glass.h +++ b/engines/titanic/game/sub_glass.h @@ -28,13 +28,19 @@ namespace Titanic { class CSUBGlass : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool SignalObject(CSignalObject *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); private: int _fieldBC; - int _fieldC0; - int _fieldC4; - int _fieldC8; - int _fieldCC; - CString _string; + int _startFrame; + int _endFrame; + int _signalStartFrame; + int _signalEndFrame; + CString _target; public: CLASSDEF; CSUBGlass(); diff --git a/engines/titanic/game/sub_wrapper.cpp b/engines/titanic/game/sub_wrapper.cpp index dcc489316b..4080487d6d 100644 --- a/engines/titanic/game/sub_wrapper.cpp +++ b/engines/titanic/game/sub_wrapper.cpp @@ -24,16 +24,56 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSUBWrapper, CGameObject) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(SignalObject) +END_MESSAGE_MAP() + void CSUBWrapper::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_flag, indent); CGameObject::save(file, indent); } void CSUBWrapper::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _flag = file->readNumber(); CGameObject::load(file); } +bool CSUBWrapper::MovieEndMsg(CMovieEndMsg *msg) { + if (_flag) { + stopMovie(); + setVisible(false); + _flag = false; + } + + return true; +} + +bool CSUBWrapper::SignalObject(CSignalObject *msg) { + switch (msg->_numValue) { + case 1: + if (!_flag) { + loadFrame(0); + setVisible(true); + playMovie(MOVIE_NOTIFY_OBJECT); + _flag = true; + } + break; + + case 2: + if (!_flag) { + setVisible(true); + _flag = true; + } + break; + + default: + break; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sub_wrapper.h b/engines/titanic/game/sub_wrapper.h index 81f8fdc941..1094a2e677 100644 --- a/engines/titanic/game/sub_wrapper.h +++ b/engines/titanic/game/sub_wrapper.h @@ -28,11 +28,14 @@ namespace Titanic { class CSUBWrapper : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MovieEndMsg(CMovieEndMsg *msg); + bool SignalObject(CSignalObject *msg); public: - int _value; + bool _flag; public: CLASSDEF; - CSUBWrapper() : CGameObject(), _value(0) {} + CSUBWrapper() : CGameObject(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/sweet_bowl.cpp b/engines/titanic/game/sweet_bowl.cpp index e14f900e77..d0a2525bc4 100644 --- a/engines/titanic/game/sweet_bowl.cpp +++ b/engines/titanic/game/sweet_bowl.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSweetBowl, CGameObject) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + void CSweetBowl::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -34,4 +40,28 @@ void CSweetBowl::load(SimpleFile *file) { CGameObject::load(file); } +bool CSweetBowl::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(false); + return true; +} + +bool CSweetBowl::EnterViewMsg(CEnterViewMsg *msg) { + setVisible(false); + loadSound("b#43.wav"); + playSound("b#42.wav"); + return true; +} + +bool CSweetBowl::ActMsg(CActMsg *msg) { + if (msg->_action == "Jiggle") { + setVisible(true); + playMovie(MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + playSound(getRandomNumber(1) == 1 ? "b#42.wav" : "b#43.wav"); + } + + petDisplayMessage(isEquals("BowlNutsRustler") ? + "A bowl of pistachio nuts." : "Not a bowl of pistachio nuts."); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sweet_bowl.h b/engines/titanic/game/sweet_bowl.h index cf3d0023a4..53433c8c08 100644 --- a/engines/titanic/game/sweet_bowl.h +++ b/engines/titanic/game/sweet_bowl.h @@ -28,6 +28,10 @@ namespace Titanic { class CSweetBowl : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MovieEndMsg(CMovieEndMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool ActMsg(CActMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/third_class_canal.cpp b/engines/titanic/game/third_class_canal.cpp index 6b0a101f7b..97b559e35d 100644 --- a/engines/titanic/game/third_class_canal.cpp +++ b/engines/titanic/game/third_class_canal.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CThirdClassCanal, CBackground) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CThirdClassCanal::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBackground::save(file, indent); @@ -34,4 +38,9 @@ void CThirdClassCanal::load(SimpleFile *file) { CBackground::load(file); } +bool CThirdClassCanal::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + petDisplayMessage("This area is off limits to passengers."); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/third_class_canal.h b/engines/titanic/game/third_class_canal.h index f6fc471444..d0be8c05aa 100644 --- a/engines/titanic/game/third_class_canal.h +++ b/engines/titanic/game/third_class_canal.h @@ -28,6 +28,8 @@ namespace Titanic { class CThirdClassCanal : public CBackground { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/throw_tv_down_well.cpp b/engines/titanic/game/throw_tv_down_well.cpp index c8a9fc7c9e..9de028cbde 100644 --- a/engines/titanic/game/throw_tv_down_well.cpp +++ b/engines/titanic/game/throw_tv_down_well.cpp @@ -24,18 +24,73 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CThrowTVDownWell, CGameObject) + ON_MESSAGE(ActMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(MovieFrameMsg) +END_MESSAGE_MAP() + void CThrowTVDownWell::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_strValue, indent); - file->writeNumberLine(_numValue, indent); + file->writeQuotedLine(_viewName, indent); + file->writeNumberLine(_flag, indent); CGameObject::save(file, indent); } void CThrowTVDownWell::load(SimpleFile *file) { file->readNumber(); - _strValue = file->readString(); - _numValue = file->readNumber(); + _viewName = file->readString(); + _flag = file->readNumber(); CGameObject::load(file); } +bool CThrowTVDownWell::ActMsg(CActMsg *msg) { + if (msg->_action == "ThrowTVDownWell" && !_flag) { + CString viewName = getFullViewName(); + lockMouse(); + addTimer(1, 8000, 0); + + CActMsg actMsg("ThrownTVDownWell"); + actMsg.execute("BOWTelevisionMonitor"); + } + + return true; +} + +bool CThrowTVDownWell::EnterViewMsg(CEnterViewMsg *msg) { + playMovie(MOVIE_NOTIFY_OBJECT | MOVIE_GAMESTATE); + movieEvent(49); + return true; +} + +bool CThrowTVDownWell::MovieEndMsg(CMovieEndMsg *msg) { + sleep(2000); + changeView("ParrotLobby.Node 11.N"); + playSound("z#471.wav"); + addTimer(2, 7000, 0); + return true; +} + +bool CThrowTVDownWell::TimerMsg(CTimerMsg *msg) { + if (msg->_actionVal == 1) { + changeView("ParrotLobby.Node 10.N"); + } else if (msg->_actionVal == 2) { + playSound("z#468.wav", 50); + sleep(1500); + changeView(_viewName); + _viewName = "NULL"; + unlockMouse(); + playSound("z#47.wav"); + } + + return true; +} + +bool CThrowTVDownWell::MovieFrameMsg(CMovieFrameMsg *msg) { + playSound("z#470.wav"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/throw_tv_down_well.h b/engines/titanic/game/throw_tv_down_well.h index b6003aa3ef..c9e8fd57a9 100644 --- a/engines/titanic/game/throw_tv_down_well.h +++ b/engines/titanic/game/throw_tv_down_well.h @@ -28,12 +28,18 @@ namespace Titanic { class CThrowTVDownWell : public CGameObject { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool TimerMsg(CTimerMsg *msg); + bool MovieFrameMsg(CMovieFrameMsg *msg); public: - CString _strValue; - int _numValue; + CString _viewName; + bool _flag; public: CLASSDEF; - CThrowTVDownWell() : CGameObject(), _numValue(0) {} + CThrowTVDownWell() : CGameObject(), _flag(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/titania_still_control.cpp b/engines/titanic/game/titania_still_control.cpp index 67866ecdcb..1ce0a85b4e 100644 --- a/engines/titanic/game/titania_still_control.cpp +++ b/engines/titanic/game/titania_still_control.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CTitaniaStillControl, CGameObject) + ON_MESSAGE(SetFrameMsg) + ON_MESSAGE(VisibleMsg) +END_MESSAGE_MAP() + void CTitaniaStillControl::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -34,4 +39,15 @@ void CTitaniaStillControl::load(SimpleFile *file) { CGameObject::load(file); } +bool CTitaniaStillControl::SetFrameMsg(CSetFrameMsg *msg) { + loadFrame(msg->_frameNumber); + setVisible(true); + return true; +} + +bool CTitaniaStillControl::VisibleMsg(CVisibleMsg *msg) { + setVisible(false); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/titania_still_control.h b/engines/titanic/game/titania_still_control.h index 66c3045187..b77227a539 100644 --- a/engines/titanic/game/titania_still_control.h +++ b/engines/titanic/game/titania_still_control.h @@ -28,6 +28,9 @@ namespace Titanic { class CTitaniaStillControl : public CGameObject { + DECLARE_MESSAGE_MAP; + bool SetFrameMsg(CSetFrameMsg *msg); + bool VisibleMsg(CVisibleMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/tow_parrot_nav.cpp b/engines/titanic/game/tow_parrot_nav.cpp index 9361808870..57f1649add 100644 --- a/engines/titanic/game/tow_parrot_nav.cpp +++ b/engines/titanic/game/tow_parrot_nav.cpp @@ -21,9 +21,14 @@ */ #include "titanic/game/tow_parrot_nav.h" +#include "titanic/npcs/parrot.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CTOWParrotNav, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CTOWParrotNav::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CGameObject::save(file, indent); @@ -34,4 +39,16 @@ void CTOWParrotNav::load(SimpleFile *file) { CGameObject::load(file); } +bool CTOWParrotNav::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CActMsg actMsg("EnteringFromTOW"); + actMsg.execute("PerchedParrot"); + + CString clipString = "_EXIT,36,1,N,9,3,N"; + if (CParrot::_v4) + clipString += 'a'; + changeView("ParrotLobby.Node 3.N", clipString); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/tow_parrot_nav.h b/engines/titanic/game/tow_parrot_nav.h index 17618ff6de..252d9b631d 100644 --- a/engines/titanic/game/tow_parrot_nav.h +++ b/engines/titanic/game/tow_parrot_nav.h @@ -28,6 +28,8 @@ namespace Titanic { class CTOWParrotNav : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/transport/lift_indicator.cpp b/engines/titanic/game/transport/lift_indicator.cpp index 1336daf7aa..7471affc36 100644 --- a/engines/titanic/game/transport/lift_indicator.cpp +++ b/engines/titanic/game/transport/lift_indicator.cpp @@ -93,14 +93,14 @@ bool CLiftindicator::EnterViewMsg(CEnterViewMsg *msg) { case 1: case 2: setPosition(Point(_bounds.left, _indicatorPos.y + - multiplier * CLift::_elevator1Floor)); + (int)(multiplier * CLift::_elevator1Floor))); _startFrame = CLift::_elevator1Floor; break; case 3: case 4: setPosition(Point(_bounds.left, _indicatorPos.y + - multiplier * CLift::_elevator3Floor)); + (int)(multiplier * CLift::_elevator3Floor))); _startFrame = CLift::_elevator3Floor; break; @@ -115,14 +115,14 @@ bool CLiftindicator::EnterViewMsg(CEnterViewMsg *msg) { case 1: case 2: setPosition(Point(_bounds.left, _indicatorPos.y + - multiplier * CLift::_elevator2Floor)); + (int)(multiplier * CLift::_elevator2Floor))); _startFrame = CLift::_elevator2Floor; break; case 3: case 4: setPosition(Point(_bounds.left, _indicatorPos.y + - multiplier * CLift::_elevator4Floor)); + (int)(multiplier * CLift::_elevator4Floor))); _startFrame = CLift::_elevator4Floor; break; @@ -158,8 +158,8 @@ bool CLiftindicator::PETActivateMsg(CPETActivateMsg *msg) { && pet->getRoomsFloorNum() != CLift::_elevator4Floor) { petDisplayMessage(1, "This elevator is currently in an advanced state of non-functionality."); } else { - _start = _indicatorPos.y + _startFrame * multiplier; - _end = _indicatorPos.y + _endFrame * multiplier; + _start = _indicatorPos.y + (int)(_startFrame * multiplier); + _end = _indicatorPos.y + (int)(_endFrame * multiplier); lockMouse(); addTimer(100); diff --git a/engines/titanic/game/transport/service_elevator.cpp b/engines/titanic/game/transport/service_elevator.cpp index 1ea8d14e36..1980825cb6 100644 --- a/engines/titanic/game/transport/service_elevator.cpp +++ b/engines/titanic/game/transport/service_elevator.cpp @@ -21,15 +21,27 @@ */ #include "titanic/game/transport/service_elevator.h" +#include "titanic/core/room_item.h" +#include "titanic/npcs/doorbot.h" -namespace Titanic { +namespace Titanic { -int CServiceElevator::_v1; +BEGIN_MESSAGE_MAP(CServiceElevator, CTransport) + ON_MESSAGE(BodyInBilgeRoomMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(ServiceElevatorMsg) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(ServiceElevatorFloorRequestMsg) + ON_MESSAGE(LeaveRoomMsg) + ON_MESSAGE(OpeningCreditsMsg) +END_MESSAGE_MAP() + +bool CServiceElevator::_v1; int CServiceElevator::_v2; int CServiceElevator::_v3; CServiceElevator::CServiceElevator() : CTransport(), - _fieldF8(0), _fieldFC(0), _field100(0), _field104(0) { + _fieldF8(0), _soundHandle1(0), _timerId(0), _soundHandle2(0) { } void CServiceElevator::save(SimpleFile *file, int indent) { @@ -38,9 +50,9 @@ void CServiceElevator::save(SimpleFile *file, int indent) { file->writeNumberLine(_v2, indent); file->writeNumberLine(_v3, indent); file->writeNumberLine(_fieldF8, indent); - file->writeNumberLine(_fieldFC, indent); - file->writeNumberLine(_field100, indent); - file->writeNumberLine(_field104, indent); + file->writeNumberLine(_soundHandle1, indent); + file->writeNumberLine(_timerId, indent); + file->writeNumberLine(_soundHandle2, indent); CTransport::save(file, indent); } @@ -51,11 +63,208 @@ void CServiceElevator::load(SimpleFile *file) { _v2 = file->readNumber(); _v3 = file->readNumber(); _fieldF8 = file->readNumber(); - _fieldFC = file->readNumber(); - _field100 = file->readNumber(); - _field104 = file->readNumber(); + _soundHandle1 = file->readNumber(); + _timerId = file->readNumber(); + _soundHandle2 = file->readNumber(); CTransport::load(file); } +bool CServiceElevator::BodyInBilgeRoomMsg(CBodyInBilgeRoomMsg *msg) { + _v2 = true; + _string1 = "BilgeRoomWith.Node 2.N"; + return true; +} + +bool CServiceElevator::EnterViewMsg(CEnterViewMsg *msg) { + petShow(); + return true; +} + +bool CServiceElevator::ServiceElevatorMsg(CServiceElevatorMsg *msg) { + switch (msg->_value) { + case 1: + case 2: + case 3: { + switch (msg->_value) { + case 1: + _v3 = 0; + break; + case 2: + _v3 = 1; + break; + case 3: + _v3 = 2; + break; + } + + CServiceElevatorFloorRequestMsg requestMsg; + requestMsg.execute(this); + break; + } + + case 4: + if (!_string1.empty()) { + if (_string1 == "DeepSpace") { + disableMouse(); + _soundHandle1 = playSound("z#413.wav", 50); + _timerId = addTimer(1, 1000, 500); + } else { + changeView(_string1); + } + } + break; + + case 5: + _fieldF8 = false; + _fieldDC = _v3; + loadSound("z#423.wav"); + stopSound(_soundHandle2); + _soundHandle2 = playSound("z#423.wav", 80); + + switch (_fieldDC) { + case 0: + _string1 = "DeepSpace"; + _string2 = "a#2.wav"; + queueSound("z#416.wav", _soundHandle2, 50); + break; + + case 1: + _string1 = _v2 ? "BilgeRoomWith.Node 2.N" : "BilgeRoom.Node 1.N"; + queueSound("z#421.wav", _soundHandle2, 50); + break; + + case 2: + _string1 = _v1 ? "MoonEmbLobby.Node 1.NE" : "EmbLobby.Node 1.NE"; + queueSound("z#411.wav", _soundHandle2, 50); + break; + + default: + break; + } + + enableMouse(); + if (findRoom()->findByName("Doorbot")) + addTimer(3, 3000, 0); + break; + + default: + break; + } + + return true; +} + +bool CServiceElevator::TimerMsg(CTimerMsg *msg) { + CDoorbot *doorbot = dynamic_cast<CDoorbot *>(findRoom()->findByName("Doorbot")); + + switch (msg->_actionVal) { + case 0: + case 1: + if (!isSoundActive(_soundHandle1)) { + stopAnimTimer(_timerId); + if (msg->_actionVal == 0) { + _fieldF8 = true; + CServiceElevatorFloorChangeMsg changeMsg(_fieldDC, _v3); + changeMsg.execute(getRoom()); + _soundHandle2 = playSound("z#424.wav"); + + if (doorbot) { + CActMsg actMsg("DoorbotPlayerPressedTopButton"); + actMsg.execute(doorbot); + } + } else { + enableMouse(); + if (doorbot) { + CActMsg actMsg; + if (_v3 == 0) + actMsg._action = "DoorbotPlayerPressedBottomButton"; + else if (_v3 == 1) + actMsg._action = "DoorbotPlayerPressedMiddleButton"; + + actMsg.execute(doorbot); + } + } + } + break; + + case 3: { + CActMsg actMsg("DoorbotReachedEmbLobby"); + actMsg.execute(doorbot); + break; + } + + default: + break; + } + + return true; +} + +bool CServiceElevator::ServiceElevatorFloorRequestMsg(CServiceElevatorFloorRequestMsg *msg) { + disableMouse(); + CDoorbot *doorbot = dynamic_cast<CDoorbot *>(findRoom()->findByName("Doorbot")); + + if (doorbot && _v3 == 0) { + _soundHandle1 = playSound("z#415.wav", 50); + addTimer(1, 1000, 500); + } else if (doorbot && _v3 == 1) { + _soundHandle1 = playSound("z#417.wav", 50); + addTimer(1, 1000, 500); + } else if (_fieldDC == _v3) { + switch (_v3) { + case 0: + _soundHandle1 = playSound("z#415.wav", 50); + break; + case 1: + _soundHandle1 = playSound("z#420.wav", 50); + break; + case 2: + _soundHandle1 = playSound("z#410.wav", 50); + break; + default: + break; + } + + addTimer(1, 1000, 500); + } else { + switch (_v3) { + case 0: + _soundHandle1 = playSound("z#414.wav", 50); + break; + case 1: + _soundHandle1 = playSound(_fieldDC ? "z#419.wav" : "z#418.wav", 50); + break; + case 2: + _soundHandle1 = playSound("z#414.wav", 50); + break; + default: + break; + } + + addTimer(0, 1000, 500); + } + + return true; +} + +bool CServiceElevator::LeaveRoomMsg(CLeaveRoomMsg *msg) { + CDoorbot *doorbot = dynamic_cast<CDoorbot *>(findRoom()->findByName("Doorbot")); + + if (doorbot) { + CPutBotBackInHisBoxMsg boxMsg(0); + boxMsg.execute("Doorbot"); + doorbot->performAction(false); + enableMouse(); + } + + return true; +} + +bool CServiceElevator::OpeningCreditsMsg(COpeningCreditsMsg *msg) { + _v1 = false; + _string1 = "EmbLobby.Node 1.NE"; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/transport/service_elevator.h b/engines/titanic/game/transport/service_elevator.h index b2c135021a..5cf1f6f0d5 100644 --- a/engines/titanic/game/transport/service_elevator.h +++ b/engines/titanic/game/transport/service_elevator.h @@ -28,15 +28,23 @@ namespace Titanic { class CServiceElevator : public CTransport { + DECLARE_MESSAGE_MAP; + bool BodyInBilgeRoomMsg(CBodyInBilgeRoomMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool ServiceElevatorMsg(CServiceElevatorMsg *msg); + bool TimerMsg(CTimerMsg *msg); + bool ServiceElevatorFloorRequestMsg(CServiceElevatorFloorRequestMsg *msg); + bool LeaveRoomMsg(CLeaveRoomMsg *msg); + bool OpeningCreditsMsg(COpeningCreditsMsg *msg); private: - static int _v1; + static bool _v1; static int _v2; static int _v3; int _fieldF8; - int _fieldFC; - int _field100; - int _field104; + int _soundHandle1; + int _timerId; + int _soundHandle2; public: CLASSDEF; CServiceElevator(); diff --git a/engines/titanic/game/up_lighter.cpp b/engines/titanic/game/up_lighter.cpp index f03b8f37a0..d133a7e9df 100644 --- a/engines/titanic/game/up_lighter.cpp +++ b/engines/titanic/game/up_lighter.cpp @@ -21,9 +21,21 @@ */ #include "titanic/game/up_lighter.h" +#include "titanic/core/project_item.h" +#include "titanic/npcs/parrot.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CUpLighter, CDropTarget) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(PumpingMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(EnterRoomMsg) + ON_MESSAGE(ChangeSeasonMsg) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(LeaveRoomMsg) +END_MESSAGE_MAP() + CUpLighter::CUpLighter() : CDropTarget(), _field118(0), _field11C(0), _field120(0), _field124(0) { } @@ -48,8 +60,61 @@ void CUpLighter::load(SimpleFile *file) { CDropTarget::load(file); } +bool CUpLighter::MovieEndMsg(CMovieEndMsg *msg) { + if (_field118) { + playSound("z#47.wav"); + _field124 = true; + + CVisibleMsg visibleMsg(true); + visibleMsg.execute("NoseHolder"); + CDropZoneLostObjectMsg lostMsg(nullptr); + lostMsg.execute(this); + _clipName.clear(); + _itemMatchName = "Nothing"; + _field118 = 0; + } + + return true; +} + +bool CUpLighter::PumpingMsg(CPumpingMsg *msg) { + _field118 = msg->_value; + _clipName = (_field118 && !_field124) ? "WholeSequence" : "HoseToNose"; + return true; +} + +bool CUpLighter::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CTrueTalkTriggerActionMsg triggerMsg(280245, 0, 0); + triggerMsg.execute(getRoot(), CParrot::_type, + MSGFLAG_BREAK_IF_HANDLED | MSGFLAG_CLASS_DEF | MSGFLAG_SCAN); + return true; +} + bool CUpLighter::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CUpLighter::handleEvent"); + _field11C = true; + addTimer(5000 + getRandomNumber(15000), 0); + return true; +} + +bool CUpLighter::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + _field120 = msg->_season == "Spring"; + if (_field120) + addTimer(5000 + getRandomNumber(15000), 0); + return true; +} + +bool CUpLighter::TimerMsg(CTimerMsg *msg) { + if (_field120 && _field11C & !_field118) { + CActMsg actMsg("Sneeze"); + actMsg.execute(findRoom()->findByName("NoseHolder")); + addTimer(1000 + getRandomNumber(19000), 0); + } + + return true; +} + +bool CUpLighter::LeaveRoomMsg(CLeaveRoomMsg *msg) { + _field11C = false; return true; } diff --git a/engines/titanic/game/up_lighter.h b/engines/titanic/game/up_lighter.h index 2367e41314..e6a53cf7bd 100644 --- a/engines/titanic/game/up_lighter.h +++ b/engines/titanic/game/up_lighter.h @@ -29,7 +29,14 @@ namespace Titanic { class CUpLighter : public CDropTarget { + DECLARE_MESSAGE_MAP; + bool MovieEndMsg(CMovieEndMsg *msg); + bool PumpingMsg(CPumpingMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); bool EnterRoomMsg(CEnterRoomMsg *msg); + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); + bool TimerMsg(CTimerMsg *msg); + bool LeaveRoomMsg(CLeaveRoomMsg *msg); private: int _field118; int _field11C; diff --git a/engines/titanic/game/useless_lever.cpp b/engines/titanic/game/useless_lever.cpp index e48ad55a71..82d8983710 100644 --- a/engines/titanic/game/useless_lever.cpp +++ b/engines/titanic/game/useless_lever.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CUselessLever, CToggleButton) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + void CUselessLever::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CToggleButton::save(file, indent); @@ -34,4 +39,23 @@ void CUselessLever::load(SimpleFile *file) { CToggleButton::load(file); } +bool CUselessLever::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_fieldE0) { + playMovie(15, 30, 0); + playSound("z#56.wav"); + _fieldE0 = false; + } else { + playMovie(0, 14, 0); + playSound("z#56.wav"); + _fieldE0 = true; + } + + return true; +} + +bool CUselessLever::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(_fieldE0 ? 15 : 0); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/useless_lever.h b/engines/titanic/game/useless_lever.h index 27397de216..33ed94b2ac 100644 --- a/engines/titanic/game/useless_lever.h +++ b/engines/titanic/game/useless_lever.h @@ -28,6 +28,9 @@ namespace Titanic { class CUselessLever : public CToggleButton { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/wheel_button.cpp b/engines/titanic/game/wheel_button.cpp index 19c42a8807..730a5d9005 100644 --- a/engines/titanic/game/wheel_button.cpp +++ b/engines/titanic/game/wheel_button.cpp @@ -24,14 +24,20 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CWheelButton, CBackground) + ON_MESSAGE(SignalObject) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + CWheelButton::CWheelButton() : CBackground(), - _fieldE0(0), _fieldE4(0), _fieldE8(0) { + _fieldE0(false), _timerId(0), _fieldE8(0) { } void CWheelButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); + file->writeNumberLine(_timerId, indent); file->writeNumberLine(_fieldE8, indent); CBackground::save(file, indent); @@ -40,10 +46,43 @@ void CWheelButton::save(SimpleFile *file, int indent) { void CWheelButton::load(SimpleFile *file) { file->readNumber(); _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); + _timerId = file->readNumber(); _fieldE8 = file->readNumber(); CBackground::load(file); } +bool CWheelButton::SignalObject(CSignalObject *msg) { + bool oldFlag = _fieldE0; + _fieldE0 = msg->_numValue != 0; + + if (oldFlag != _fieldE0) { + if (_fieldE0) { + _timerId = addTimer(500, 500); + } else { + stopAnimTimer(_timerId); + _timerId = 0; + setVisible(false); + } + } + + return true; +} + +bool CWheelButton::TimerMsg(CTimerMsg *msg) { + setVisible(!_visible); + makeDirty(); + return true; +} + +bool CWheelButton::LeaveViewMsg(CLeaveViewMsg *msg) { + if (_timerId) { + stopAnimTimer(_timerId); + _timerId = 0; + setVisible(false); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/wheel_button.h b/engines/titanic/game/wheel_button.h index cb089a660f..2725e60622 100644 --- a/engines/titanic/game/wheel_button.h +++ b/engines/titanic/game/wheel_button.h @@ -28,9 +28,13 @@ namespace Titanic { class CWheelButton : public CBackground { + DECLARE_MESSAGE_MAP; + bool SignalObject(CSignalObject *msg); + bool TimerMsg(CTimerMsg *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); public: - int _fieldE0; - int _fieldE4; + bool _fieldE0; + int _timerId; int _fieldE8; public: CLASSDEF; diff --git a/engines/titanic/game/wheel_hotspot.cpp b/engines/titanic/game/wheel_hotspot.cpp index f9af594cd5..544e6f5470 100644 --- a/engines/titanic/game/wheel_hotspot.cpp +++ b/engines/titanic/game/wheel_hotspot.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CWheelHotSpot, CBackground) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(SignalObject) +END_MESSAGE_MAP() + void CWheelHotSpot::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldE0, indent); @@ -40,4 +45,39 @@ void CWheelHotSpot::load(SimpleFile *file) { CBackground::load(file); } +bool CWheelHotSpot::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_fieldE0) { + CActMsg actMsg; + + switch (_fieldE4) { + case 1: + actMsg._action = "Stop"; + actMsg.execute("CaptainsWheel"); + break; + + case 2: + actMsg._action = "Cruise"; + actMsg.execute("CaptainsWheel"); + break; + + case 3: + actMsg._action = "Go"; + actMsg.execute("CaptainsWheel"); + break; + + default: + break; + } + } else if (_fieldE4 == 3) { + petDisplayMessage("Go where?"); + } + + return true; +} + +bool CWheelHotSpot::SignalObject(CSignalObject *msg) { + _fieldE0 = msg->_numValue != 0; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/wheel_hotspot.h b/engines/titanic/game/wheel_hotspot.h index 364fe9a060..e9071a2fa4 100644 --- a/engines/titanic/game/wheel_hotspot.h +++ b/engines/titanic/game/wheel_hotspot.h @@ -28,6 +28,9 @@ namespace Titanic { class CWheelHotSpot : public CBackground { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool SignalObject(CSignalObject *msg); public: int _fieldE0; int _fieldE4; diff --git a/engines/titanic/game/wheel_spin.cpp b/engines/titanic/game/wheel_spin.cpp index daa9918e29..79f83873e1 100644 --- a/engines/titanic/game/wheel_spin.cpp +++ b/engines/titanic/game/wheel_spin.cpp @@ -24,16 +24,36 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CWheelSpin, CBackground) + ON_MESSAGE(SignalObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CWheelSpin::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value, indent); + file->writeNumberLine(_active, indent); CBackground::save(file, indent); } void CWheelSpin::load(SimpleFile *file) { file->readNumber(); - _value = file->readNumber(); + _active = file->readNumber(); CBackground::load(file); } +bool CWheelSpin::SignalObject(CSignalObject *msg) { + _active = msg->_numValue != 0; + setVisible(_active); + return true; +} + +bool CWheelSpin::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_active) { + CActMsg actMsg("Spin"); + actMsg.execute("CaptainsWheel"); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/wheel_spin.h b/engines/titanic/game/wheel_spin.h index 509db1a4bf..f7993f0188 100644 --- a/engines/titanic/game/wheel_spin.h +++ b/engines/titanic/game/wheel_spin.h @@ -28,11 +28,14 @@ namespace Titanic { class CWheelSpin : public CBackground { + DECLARE_MESSAGE_MAP; + bool SignalObject(CSignalObject *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: - int _value; + bool _active; public: CLASSDEF; - CWheelSpin() : CBackground(), _value(0) {} + CWheelSpin() : CBackground(), _active(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game_manager.cpp b/engines/titanic/game_manager.cpp index 73ec5de993..7d9dc37a10 100644 --- a/engines/titanic/game_manager.cpp +++ b/engines/titanic/game_manager.cpp @@ -164,7 +164,7 @@ void CGameManager::update() { frameMessage(getRoom()); _timers.update(g_vm->_events->getTicksCount()); _trueTalkManager.removeCompleted(); - _trueTalkManager.update2(); + CScreenManager::_screenManagerPtr->_mouseCursor->update(); CViewItem *view = getView(); diff --git a/engines/titanic/game_state.cpp b/engines/titanic/game_state.cpp index 5628161558..8814dba831 100644 --- a/engines/titanic/game_state.cpp +++ b/engines/titanic/game_state.cpp @@ -47,7 +47,7 @@ bool CGameStateMovieList::clear() { CGameState::CGameState(CGameManager *gameManager) : _gameManager(gameManager), _gameLocation(this), _passengerClass(0), _priorClass(0), _mode(GSMODE_NONE), - _field14(0), _petActive(false), _field1C(false), _quitGame(false), + _seasonNum(SEASON_SUMMER), _petActive(false), _field1C(false), _quitGame(false), _field24(0), _nodeChangeCtr(0), _nodeEnterTicks(0), _field38(0) { } @@ -55,7 +55,7 @@ void CGameState::save(SimpleFile *file) const { file->writeNumber(_petActive); file->writeNumber(_passengerClass); file->writeNumber(_priorClass); - file->writeNumber(_field14); + file->writeNumber(_seasonNum); file->writeNumber(_field24); file->writeNumber(_field38); _gameLocation.save(file); @@ -66,7 +66,7 @@ void CGameState::load(SimpleFile *file) { _petActive = file->readNumber() != 0; _passengerClass = file->readNumber(); _priorClass = file->readNumber(); - _field14 = file->readNumber(); + _seasonNum = (Season)file->readNumber(); _field24 = file->readNumber(); _field38 = file->readNumber(); _gameLocation.load(file); diff --git a/engines/titanic/game_state.h b/engines/titanic/game_state.h index 0bfa0d5b31..70d47b55c1 100644 --- a/engines/titanic/game_state.h +++ b/engines/titanic/game_state.h @@ -35,7 +35,14 @@ class CGameManager; enum GameStateMode { GSMODE_NONE = 0, GSMODE_INTERACTIVE = 1, GSMODE_CUTSCENE = 2, - GSMODE_3 = 3, GSMODE_4 = 4, GSMODE_5 = 5, GSMODE_PENDING_LOAD = 6 + GSMODE_3 = 3, GSMODE_4 = 4, GSMODE_INSERT_CD = 5, GSMODE_PENDING_LOAD = 6 +}; + +enum Season { + SEASON_SUMMER = 0, + SEASON_AUTUMN = 1, + SEASON_WINTER = 2, + SEASON_SPRING = 3 }; PTR_LIST_ITEM(CMovie); @@ -60,7 +67,7 @@ public: int _passengerClass; int _priorClass; GameStateMode _mode; - int _field14; + Season _seasonNum; bool _petActive; bool _field1C; bool _quitGame; @@ -127,7 +134,13 @@ public: */ void addMovie(CMovie *movie); - void inc14() { _field14 = (_field14 + 1) & 3; } + /** + * Change to the next season + */ + void changeSeason() { + _seasonNum = (Season)(((int)_seasonNum + 1) & 3); + } + void set24(int v) { _field24 = v; } int get24() const { return _field24; } int getNodeChangedCtr() const { return _nodeChangeCtr; } diff --git a/engines/titanic/gfx/edit_control.cpp b/engines/titanic/gfx/edit_control.cpp index 4098220c3a..3f3c4d4035 100644 --- a/engines/titanic/gfx/edit_control.cpp +++ b/engines/titanic/gfx/edit_control.cpp @@ -190,8 +190,8 @@ bool CEditControl::EditControlMsg(CEditControlMsg *msg) { case 14: { makeDirty(); - CString borderName = _fieldF4 ? CString('*', _text.size()) : _text; - setTextBorder(borderName); + CString str = _fieldF4 ? CString('*', _text.size()) : _text; + setText(str); int textWidth = getTextWidth(); if (_fieldF0 == 2) { diff --git a/engines/titanic/gfx/move_object_button.cpp b/engines/titanic/gfx/move_object_button.cpp index bdc90a673c..bcd2b2bd76 100644 --- a/engines/titanic/gfx/move_object_button.cpp +++ b/engines/titanic/gfx/move_object_button.cpp @@ -21,9 +21,14 @@ */ #include "titanic/gfx/move_object_button.h" +#include "titanic/core/project_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMoveObjectButton, CSTButton) + ON_MESSAGE(MouseButtonUpMsg) +END_MESSAGE_MAP() + CMoveObjectButton::CMoveObjectButton() : CSTButton(), _field11C(1) { } @@ -43,4 +48,14 @@ void CMoveObjectButton::load(SimpleFile *file) { CSTButton::load(file); } +bool CMoveObjectButton::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + CGameObject *obj = dynamic_cast<CGameObject *>(getRoot()->findByName(_actionTarget)); + if (obj) { + obj->petAddToInventory(); + obj->setVisible(_field11C); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/gfx/move_object_button.h b/engines/titanic/gfx/move_object_button.h index eb2fdc4ff2..46c49c36e2 100644 --- a/engines/titanic/gfx/move_object_button.h +++ b/engines/titanic/gfx/move_object_button.h @@ -28,6 +28,8 @@ namespace Titanic { class CMoveObjectButton : public CSTButton { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); private: Point _pos1; int _field11C; diff --git a/engines/titanic/gfx/music_control.cpp b/engines/titanic/gfx/music_control.cpp index 85a3d777ef..317bec209f 100644 --- a/engines/titanic/gfx/music_control.cpp +++ b/engines/titanic/gfx/music_control.cpp @@ -24,15 +24,20 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMusicControl, CBackground) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseDoubleClickMsg) +END_MESSAGE_MAP() + CMusicControl::CMusicControl() : CBackground(), - _fieldE0(0), _fieldE4(0), _fieldE8(1), _fieldEC(1) { + _controlArea(BELLS), _controlVal(0), _controlMax(1), _fieldEC(1) { } void CMusicControl::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); - file->writeNumberLine(_fieldE8, indent); + file->writeNumberLine(_controlArea, indent); + file->writeNumberLine(_controlVal, indent); + file->writeNumberLine(_controlMax, indent); file->writeNumberLine(_fieldEC, indent); CBackground::save(file, indent); @@ -40,12 +45,24 @@ void CMusicControl::save(SimpleFile *file, int indent) { void CMusicControl::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); - _fieldE8 = file->readNumber(); + _controlArea = (MusicControlArea)file->readNumber(); + _controlVal = file->readNumber(); + _controlMax = file->readNumber(); _fieldEC = file->readNumber(); CBackground::load(file); } +bool CMusicControl::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CMusicSettingChangedMsg changedMsg; + changedMsg.execute(this); + return true; +} + +bool CMusicControl::MouseDoubleClickMsg(CMouseDoubleClickMsg *msg) { + CMusicSettingChangedMsg changedMsg; + changedMsg.execute(this); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/gfx/music_control.h b/engines/titanic/gfx/music_control.h index 04085f789c..a0e73392f9 100644 --- a/engines/titanic/gfx/music_control.h +++ b/engines/titanic/gfx/music_control.h @@ -24,14 +24,18 @@ #define TITANIC_MUSIC_CONTROL_H #include "titanic/core/background.h" +#include "titanic/sound/music_room.h" namespace Titanic { class CMusicControl : public CBackground { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseDoubleClickMsg(CMouseDoubleClickMsg *msg); public: - int _fieldE0; - int _fieldE4; - int _fieldE8; + MusicControlArea _controlArea; + int _controlVal; + int _controlMax; int _fieldEC; public: CLASSDEF; diff --git a/engines/titanic/gfx/music_slider_pitch.cpp b/engines/titanic/gfx/music_slider_pitch.cpp new file mode 100644 index 0000000000..5f0432e742 --- /dev/null +++ b/engines/titanic/gfx/music_slider_pitch.cpp @@ -0,0 +1,67 @@ +/* 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 "titanic/gfx/music_slider_pitch.h" + +namespace Titanic { + +BEGIN_MESSAGE_MAP(CMusicSliderPitch, CMusicSlider) + ON_MESSAGE(MusicSettingChangedMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(QueryMusicControlSettingMsg) +END_MESSAGE_MAP() + +void CMusicSliderPitch::save(SimpleFile *file, int indent) { + file->writeNumberLine(1, indent); + CMusicSlider::save(file, indent); +} + +void CMusicSliderPitch::load(SimpleFile *file) { + file->readNumber(); + CMusicSlider::load(file); +} + +bool CMusicSliderPitch::MusicSettingChangedMsg(CMusicSettingChangedMsg *msg) { + if (_fieldEC) { + if (++_controlVal > _controlMax) + _controlVal = 0; + + loadFrame(3 - _controlVal); + playSound("z#54.wav", 50); + } else { + playSound("z#46.wav"); + } + + return true; +} + +bool CMusicSliderPitch::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(3 - _controlVal); + return true; +} + +bool CMusicSliderPitch::QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg) { + msg->_value = _controlVal - 2; + return true; +} + +} // End of namespace Titanic diff --git a/engines/titanic/gfx/music_slider_pitch.h b/engines/titanic/gfx/music_slider_pitch.h index 10c1d62c3a..c375c6db33 100644 --- a/engines/titanic/gfx/music_slider_pitch.h +++ b/engines/titanic/gfx/music_slider_pitch.h @@ -28,24 +28,22 @@ namespace Titanic { class CMusicSliderPitch : public CMusicSlider { + DECLARE_MESSAGE_MAP; + bool MusicSettingChangedMsg(CMusicSettingChangedMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg); public: CLASSDEF; /** * Save the data for the class to file */ - virtual void save(SimpleFile *file, int indent) { - file->writeNumberLine(1, indent); - CMusicSlider::save(file, indent); - } + virtual void save(SimpleFile *file, int indent); /** * Load the data for the class from file */ - virtual void load(SimpleFile *file) { - file->readNumber(); - CMusicSlider::load(file); - } + virtual void load(SimpleFile *file); }; } // End of namespace Titanic diff --git a/engines/titanic/gfx/music_slider_speed.cpp b/engines/titanic/gfx/music_slider_speed.cpp new file mode 100644 index 0000000000..93af5d82b7 --- /dev/null +++ b/engines/titanic/gfx/music_slider_speed.cpp @@ -0,0 +1,67 @@ +/* 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 "titanic/gfx/music_slider_speed.h" + +namespace Titanic { + +BEGIN_MESSAGE_MAP(CMusicSliderSpeed, CMusicSlider) + ON_MESSAGE(MusicSettingChangedMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(QueryMusicControlSettingMsg) +END_MESSAGE_MAP() + +void CMusicSliderSpeed::save(SimpleFile *file, int indent) { + file->writeNumberLine(1, indent); + CMusicSlider::save(file, indent); +} + +void CMusicSliderSpeed::load(SimpleFile *file) { + file->readNumber(); + CMusicSlider::load(file); +} + +bool CMusicSliderSpeed::MusicSettingChangedMsg(CMusicSettingChangedMsg *msg) { + if (_fieldEC) { + if (++_controlVal > _controlMax) + _controlVal = 0; + + loadFrame(3 - _controlVal); + playSound("z#54.wav", 50); + } else { + playSound("z#46.wav"); + } + + return true; +} + +bool CMusicSliderSpeed::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(3 - _controlVal); + return true; +} + +bool CMusicSliderSpeed::QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg) { + msg->_value = _controlVal - 1; + return true; +} + +} // End of namespace Titanic diff --git a/engines/titanic/gfx/music_slider_speed.h b/engines/titanic/gfx/music_slider_speed.h index 9814ca0312..2d54f4487c 100644 --- a/engines/titanic/gfx/music_slider_speed.h +++ b/engines/titanic/gfx/music_slider_speed.h @@ -27,26 +27,24 @@ namespace Titanic { - class CMusicSliderSpeed : public CMusicSlider { - public: - CLASSDEF; - - /** - * Save the data for the class to file - */ - virtual void save(SimpleFile *file, int indent) { - file->writeNumberLine(1, indent); - CMusicSlider::save(file, indent); - } - - /** - * Load the data for the class from file - */ - virtual void load(SimpleFile *file) { - file->readNumber(); - CMusicSlider::load(file); - } - }; +class CMusicSliderSpeed : public CMusicSlider { + DECLARE_MESSAGE_MAP; + bool MusicSettingChangedMsg(CMusicSettingChangedMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg); +public: + CLASSDEF; + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); +}; } // End of namespace Titanic diff --git a/engines/titanic/gfx/chev_switch.cpp b/engines/titanic/gfx/music_switch_inversion.cpp index 177f0ada76..d11df79ab4 100644 --- a/engines/titanic/gfx/chev_switch.cpp +++ b/engines/titanic/gfx/music_switch_inversion.cpp @@ -20,58 +20,47 @@ * */ -#include "titanic/gfx/chev_switch.h" +#include "titanic/gfx/music_switch_inversion.h" namespace Titanic { -BEGIN_MESSAGE_MAP(CChevSwitch, CToggleSwitch) - ON_MESSAGE(MouseButtonUpMsg) - ON_MESSAGE(SetChevButtonImageMsg) - ON_MESSAGE(MouseButtonDownMsg) +BEGIN_MESSAGE_MAP(CMusicSwitchInversion, CMusicSwitch) + ON_MESSAGE(MusicSettingChangedMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(QueryMusicControlSettingMsg) END_MESSAGE_MAP() -CChevSwitch::CChevSwitch() : CToggleSwitch(), _value(0) { -} - -void CChevSwitch::save(SimpleFile *file, int indent) { +void CMusicSwitchInversion::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - CToggleSwitch::save(file, indent); + CMusicSwitch::save(file, indent); } -void CChevSwitch::load(SimpleFile *file) { +void CMusicSwitchInversion::load(SimpleFile *file) { file->readNumber(); - CToggleSwitch::load(file); -} - -bool CChevSwitch::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { - return true; + CMusicSwitch::load(file); } -bool CChevSwitch::SetChevButtonImageMsg(CSetChevButtonImageMsg *msg) { - if (msg->_value2 && getParent()) { - error("TODO: Don't know parent type"); - } +bool CMusicSwitchInversion::MusicSettingChangedMsg(CMusicSettingChangedMsg *msg) { + if (_fieldEC) { + if (++_controlVal > _controlMax) + _controlVal = 0; - _fieldBC = msg->_value1; - if (_fieldBC) { - loadImage((_value & 1) ? "on_odd.tga" : "on_even.tga"); + loadFrame(_controlVal); + playSound("z#59.wav", 50); } else { - loadImage((_value & 1) ? "off_odd.tga" : "off_even.tga"); + playSound("z#46.wav"); } return true; } -bool CChevSwitch::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { - _fieldBC ^= 1; - if (getParent()) { - CSetChevPanelBitMsg bitMsg(_value, _fieldBC); - bitMsg.execute(getParent()); - } - - CSetChevButtonImageMsg chevMsg(_fieldBC, 0); - chevMsg.execute(this); +bool CMusicSwitchInversion::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(_controlVal); + return true; +} +bool CMusicSwitchInversion::QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg) { + msg->_value = _controlVal; return true; } diff --git a/engines/titanic/gfx/music_switch_inversion.h b/engines/titanic/gfx/music_switch_inversion.h index 8b3718cf14..869b4745ea 100644 --- a/engines/titanic/gfx/music_switch_inversion.h +++ b/engines/titanic/gfx/music_switch_inversion.h @@ -28,24 +28,22 @@ namespace Titanic { class CMusicSwitchInversion : public CMusicSwitch { + DECLARE_MESSAGE_MAP; + bool MusicSettingChangedMsg(CMusicSettingChangedMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg); public: CLASSDEF; /** * Save the data for the class to file */ - virtual void save(SimpleFile *file, int indent) { - file->writeNumberLine(1, indent); - CMusicSwitch::save(file, indent); - } + virtual void save(SimpleFile *file, int indent); /** * Load the data for the class from file */ - virtual void load(SimpleFile *file) { - file->readNumber(); - CMusicSwitch::load(file); - } + virtual void load(SimpleFile *file); }; } // End of namespace Titanic diff --git a/engines/titanic/gfx/music_switch_reverse.cpp b/engines/titanic/gfx/music_switch_reverse.cpp new file mode 100644 index 0000000000..9fe6d51d47 --- /dev/null +++ b/engines/titanic/gfx/music_switch_reverse.cpp @@ -0,0 +1,66 @@ +/* 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 "titanic/gfx/music_switch_reverse.h" + +namespace Titanic { + +BEGIN_MESSAGE_MAP(CMusicSwitchReverse, CMusicSwitch) + ON_MESSAGE(MusicSettingChangedMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(QueryMusicControlSettingMsg) +END_MESSAGE_MAP() + +void CMusicSwitchReverse::save(SimpleFile *file, int indent) { + file->writeNumberLine(1, indent); + CMusicSwitch::save(file, indent); +} + +void CMusicSwitchReverse::load(SimpleFile *file) { + file->readNumber(); + CMusicSwitch::load(file); +} +bool CMusicSwitchReverse::MusicSettingChangedMsg(CMusicSettingChangedMsg *msg) { + if (_fieldEC) { + if (++_controlVal > _controlMax) + _controlVal = 0; + + loadFrame(_controlVal); + playSound("z#59.wav", 50); + } else { + playSound("z#46.wav"); + } + + return true; +} + +bool CMusicSwitchReverse::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(_controlVal); + return true; +} + +bool CMusicSwitchReverse::QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg) { + msg->_value = _controlVal; + return true; +} + +} // End of namespace Titanic diff --git a/engines/titanic/gfx/music_switch_reverse.h b/engines/titanic/gfx/music_switch_reverse.h index 3bfcb53b00..c101f19d25 100644 --- a/engines/titanic/gfx/music_switch_reverse.h +++ b/engines/titanic/gfx/music_switch_reverse.h @@ -27,26 +27,24 @@ namespace Titanic { - class CMusicSwitchReverse : public CMusicSwitch { - public: - CLASSDEF; - - /** - * Save the data for the class to file - */ - virtual void save(SimpleFile *file, int indent) { - file->writeNumberLine(1, indent); - CMusicSwitch::save(file, indent); - } - - /** - * Load the data for the class from file - */ - virtual void load(SimpleFile *file) { - file->readNumber(); - CMusicSwitch::load(file); - } - }; +class CMusicSwitchReverse : public CMusicSwitch { + DECLARE_MESSAGE_MAP; + bool MusicSettingChangedMsg(CMusicSettingChangedMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg); +public: + CLASSDEF; + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); +}; } // End of namespace Titanic diff --git a/engines/titanic/gfx/music_voice_mute.cpp b/engines/titanic/gfx/music_voice_mute.cpp new file mode 100644 index 0000000000..ff59edc988 --- /dev/null +++ b/engines/titanic/gfx/music_voice_mute.cpp @@ -0,0 +1,59 @@ +/* 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 "titanic/gfx/music_voice_mute.h" +#include "titanic/sound/music_room.h" + +namespace Titanic { + +BEGIN_MESSAGE_MAP(CMusicVoiceMute, CMusicControl) + ON_MESSAGE(MusicSettingChangedMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(QueryMusicControlSettingMsg) +END_MESSAGE_MAP() + +bool CMusicVoiceMute::MusicSettingChangedMsg(CMusicSettingChangedMsg *msg) { + if (++_controlVal > _controlMax) + _controlVal = 0; + + CMusicRoom *musicRoom = getMusicRoom(); + musicRoom->setItem5(_controlArea, _controlVal == 1 ? 1 : 0); + loadFrame(1 - _controlVal); + playSound("z#55.wav", 50); + + return true; +} + +bool CMusicVoiceMute::EnterViewMsg(CEnterViewMsg *msg) { + loadFrame(1 - _controlVal); + CMusicRoom *musicRoom = getMusicRoom(); + musicRoom->setItem5(_controlArea, _controlVal == 1 ? 1 : 0); + + return true; +} + +bool CMusicVoiceMute::QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg) { + msg->_value = _controlVal; + return true; +} + +} // End of namespace Titanic diff --git a/engines/titanic/gfx/music_voice_mute.h b/engines/titanic/gfx/music_voice_mute.h index ca15806c09..f64b107423 100644 --- a/engines/titanic/gfx/music_voice_mute.h +++ b/engines/titanic/gfx/music_voice_mute.h @@ -28,6 +28,10 @@ namespace Titanic { class CMusicVoiceMute : public CMusicControl { + DECLARE_MESSAGE_MAP; + bool MusicSettingChangedMsg(CMusicSettingChangedMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool QueryMusicControlSettingMsg(CQueryMusicControlSettingMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/gfx/slider_button.cpp b/engines/titanic/gfx/slider_button.cpp index 0633158e97..b3dbbed08f 100644 --- a/engines/titanic/gfx/slider_button.cpp +++ b/engines/titanic/gfx/slider_button.cpp @@ -24,6 +24,14 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CSliderButton, CSTButton) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseDragMoveMsg) + ON_MESSAGE(StatusChangeMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + CSliderButton::CSliderButton() : CSTButton(), _field114(0), _field118(0), _field11C(0) { } @@ -48,4 +56,39 @@ void CSliderButton::load(SimpleFile *file) { CSTButton::load(file); } +bool CSliderButton::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + _pos1 = msg->_mousePos; + CStatusChangeMsg changeMsg; + changeMsg.execute(this); + return true; +} + +bool CSliderButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + _pos1 = msg->_mousePos; + return true; +} + +bool CSliderButton::MouseDragMoveMsg(CMouseDragMoveMsg *msg) { + _pos1 = msg->_mousePos; + if (_field118) { + CStatusChangeMsg changeMsg; + changeMsg.execute(this); + } + + return true; +} + +bool CSliderButton::StatusChangeMsg(CStatusChangeMsg *msg) { + CStatusChangeMsg changeMsg; + changeMsg._oldStatus = _currentStatus; + _currentStatus = (_pos1.y - _bounds.top) / _field11C; + changeMsg._newStatus = _currentStatus; + changeMsg.execute(_actionTarget); + return true; +} + +bool CSliderButton::EnterViewMsg(CEnterViewMsg *msg) { + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/gfx/slider_button.h b/engines/titanic/gfx/slider_button.h index 398290bb05..18ebbae3db 100644 --- a/engines/titanic/gfx/slider_button.h +++ b/engines/titanic/gfx/slider_button.h @@ -28,6 +28,12 @@ namespace Titanic { class CSliderButton : public CSTButton { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseDragMoveMsg(CMouseDragMoveMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); private: int _field114; int _field118; diff --git a/engines/titanic/gfx/status_change_button.cpp b/engines/titanic/gfx/status_change_button.cpp index 6644247ff2..e38f1ee07e 100644 --- a/engines/titanic/gfx/status_change_button.cpp +++ b/engines/titanic/gfx/status_change_button.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CStatusChangeButton, CSTButton) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + CStatusChangeButton::CStatusChangeButton() : CSTButton() { } @@ -37,4 +41,11 @@ void CStatusChangeButton::load(SimpleFile *file) { CSTButton::load(file); } +bool CStatusChangeButton::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CStatusChangeMsg changeMsg; + changeMsg._newStatus = _statusInc; + changeMsg.execute(_actionTarget); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/gfx/status_change_button.h b/engines/titanic/gfx/status_change_button.h index 9e410c66f2..9d187493a7 100644 --- a/engines/titanic/gfx/status_change_button.h +++ b/engines/titanic/gfx/status_change_button.h @@ -28,6 +28,8 @@ namespace Titanic { class CStatusChangeButton : public CSTButton { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; CStatusChangeButton(); diff --git a/engines/titanic/gfx/toggle_button.h b/engines/titanic/gfx/toggle_button.h index 5328072982..4fb7cdfaba 100644 --- a/engines/titanic/gfx/toggle_button.h +++ b/engines/titanic/gfx/toggle_button.h @@ -29,7 +29,7 @@ namespace Titanic { class CToggleButton : public CBackground { DECLARE_MESSAGE_MAP; -private: +protected: int _fieldE0; public: CLASSDEF; diff --git a/engines/titanic/gfx/toggle_switch.cpp b/engines/titanic/gfx/toggle_switch.cpp index 20cbb863ee..815f96cb5a 100644 --- a/engines/titanic/gfx/toggle_switch.cpp +++ b/engines/titanic/gfx/toggle_switch.cpp @@ -24,12 +24,18 @@ namespace Titanic { -CToggleSwitch::CToggleSwitch() : CGameObject(), _fieldBC(0) { +BEGIN_MESSAGE_MAP(CToggleSwitch, CGameObject) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(ChildDragStartMsg) + ON_MESSAGE(ChildDragMoveMsg) +END_MESSAGE_MAP() + +CToggleSwitch::CToggleSwitch() : CGameObject(), _pressed(false) { } void CToggleSwitch::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); + file->writeNumberLine(_pressed, indent); file->writePoint(_pos1, indent); CGameObject::save(file, indent); @@ -37,10 +43,30 @@ void CToggleSwitch::save(SimpleFile *file, int indent) { void CToggleSwitch::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); + _pressed = file->readNumber(); _pos1 = file->readPoint(); CGameObject::load(file); } +bool CToggleSwitch::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + _pressed = !_pressed; + if (_pressed) + fn10(0, 0, 0); + else + fn10(0xff, 0xff, 0xff); + return true; +} + +bool CToggleSwitch::ChildDragStartMsg(CChildDragStartMsg *msg) { + _pos1.x = msg->_mousePos.x - _bounds.left; + _pos1.y = msg->_mousePos.y - _bounds.top; + return true; +} + +bool CToggleSwitch::ChildDragMoveMsg(CChildDragMoveMsg *msg) { + setPosition(Point(msg->_mousePos.x - _pos1.x, msg->_mousePos.y - _pos1.y)); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/gfx/toggle_switch.h b/engines/titanic/gfx/toggle_switch.h index 8e7d057d8c..69b8c50eec 100644 --- a/engines/titanic/gfx/toggle_switch.h +++ b/engines/titanic/gfx/toggle_switch.h @@ -28,8 +28,12 @@ namespace Titanic { class CToggleSwitch : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool ChildDragStartMsg(CChildDragStartMsg *msg); + bool ChildDragMoveMsg(CChildDragMoveMsg *msg); protected: - int _fieldBC; + bool _pressed; Point _pos1; public: CLASSDEF; diff --git a/engines/titanic/main_game_window.cpp b/engines/titanic/main_game_window.cpp index 486bc417d7..690acdc25f 100644 --- a/engines/titanic/main_game_window.cpp +++ b/engines/titanic/main_game_window.cpp @@ -49,19 +49,24 @@ CMainGameWindow::CMainGameWindow(TitanicEngine *vm): _vm(vm), CMainGameWindow::~CMainGameWindow() { } -bool CMainGameWindow::Create() { - Image image; - image.load("TITANIC"); - - // TODO: Stuff - return true; -} - void CMainGameWindow::applicationStarting() { // Set the video mode CScreenManager *screenManager = CScreenManager::setCurrent(); screenManager->setMode(640, 480, 16, 0, true); +#if 0 + // Show the initial copyright & info screen for the game + if (gDebugLevel <= 0) { + Image image; + image.load("Bitmap/TITANIC"); + _vm->_screen->blitFrom(image, Point( + SCREEN_WIDTH / 2 - image.w / 2, + SCREEN_HEIGHT / 2 - image.h / 2 + )); + _vm->_events->sleep(5000); + } +#endif + // Set up the game project, and get game slot int saveSlot = getSavegameSlot(); if (saveSlot == -2) @@ -77,8 +82,6 @@ void CMainGameWindow::applicationStarting() { _inputAllowed = true; _gameManager->_gameState.setMode(GSMODE_INTERACTIVE); - // TODO: Cursor/image - // Generate starting messages for entering the view, node, and room. // Note the old fields are nullptr, since there's no previous view/node/room CViewItem *view = _gameManager->_gameState._gameLocation.getView(); @@ -157,8 +160,9 @@ void CMainGameWindow::draw() { scrManager->drawCursors(); break; - case GSMODE_5: - g_vm->_filesManager->debug(scrManager); + case GSMODE_INSERT_CD: + scrManager->drawCursors(); + _vm->_filesManager->insertCD(scrManager); break; case GSMODE_PENDING_LOAD: @@ -216,7 +220,7 @@ void CMainGameWindow::drawViewContents(CScreenManager *screenManager) { } void CMainGameWindow::mouseChanged() { - if (_gameManager->_gameState._mode != GSMODE_5) + if (_gameManager->_gameState._mode != GSMODE_INSERT_CD) _gameManager->update(); } diff --git a/engines/titanic/main_game_window.h b/engines/titanic/main_game_window.h index 82e24e250e..070f7df69b 100644 --- a/engines/titanic/main_game_window.h +++ b/engines/titanic/main_game_window.h @@ -104,11 +104,6 @@ public: virtual void keyUp(Common::KeyState keyState); /** - * Creates the window - */ - bool Create(); - - /** * Called when the application starts */ void applicationStarting(); diff --git a/engines/titanic/messages/messages.h b/engines/titanic/messages/messages.h index fa05416fdc..b70bc5e16c 100644 --- a/engines/titanic/messages/messages.h +++ b/engines/titanic/messages/messages.h @@ -189,7 +189,7 @@ MESSAGE1(CAnimateMaitreDMsg, int, value, 0); MESSAGE1(CArboretumGateMsg, int, value, 0); MESSAGE0(CArmPickedUpFromTableMsg); MESSAGE0(CBodyInBilgeRoomMsg); -MESSAGE1(CBowlStateChangeMsg, int, value, 0); +MESSAGE1(CBowlStateChangeMsg, int, state, 0); MESSAGE2(CCarryObjectArrivedMsg, CString, strValue, "", int, numValue, 0); MESSAGE2(CChangeMusicMsg, CString, filename, "", int, flags, 0); MESSAGE1(CChangeSeasonMsg, CString, season, "Summer"); @@ -245,14 +245,14 @@ MESSAGE1(CLoadSuccessMsg, int, ticks, 0); MESSAGE1(CLockPhonographMsg, int, value, 0); MESSAGE0(CMaitreDDefeatedMsg); MESSAGE0(CMaitreDHappyMsg); -MESSAGE1(CMissiveOMatActionMsg, int, value, 0); +MESSAGE1(CMissiveOMatActionMsg, int, action, 0); MESSAGE0(CMoveToStartPosMsg); MESSAGE2(CMovieEndMsg, int, startFrame, 0, int, endFrame, 0); MESSAGE2(CMovieFrameMsg, int, frameNumber, 0, int, value2, 0); MESSAGE0(CMusicHasStartedMsg); MESSAGE0(CMusicHasStoppedMsg); MESSAGE0(CMusicSettingChangedMsg); -MESSAGE2(CNPCPlayAnimationMsg, const char *const *, names, nullptr, int, value2, 0); +MESSAGE2(CNPCPlayAnimationMsg, const char *const *, names, nullptr, int, maxDuration, 0); MESSAGE1(CNPCPlayIdleAnimationMsg, const char *const *, names, 0); MESSAGE3(CNPCPlayTalkingAnimationMsg, int, value1, 0, int, value2, 0, const char *const *, names, nullptr); MESSAGE0(CNPCQueueIdleAnimMsg); @@ -267,14 +267,14 @@ MESSAGE0(CPhonographReadyToPlayMsg); MESSAGE1(CPhonographRecordMsg, int, value, 0); MESSAGE3(CPhonographStopMsg, int, value1, 0, int, value2, 0, int, value3, 0); MESSAGE2(CPlayRangeMsg, int, value1, 0, int, value2, 0); -MESSAGE2(CPlayerTriesRestaurantTableMsg, int, value1, 0, int, value2, 0); +MESSAGE2(CPlayerTriesRestaurantTableMsg, int, tableId, 0, bool, result, false); MESSAGE1(CPreSaveMsg, int, value, 0); MESSAGE1(CProdMaitreDMsg, int, value, 0); MESSAGE2(CPumpingMsg, int, value, 0, CGameObject *, object, nullptr); MESSAGE1(CPutBotBackInHisBoxMsg, int, value, 0); MESSAGE1(CPutParrotBackMsg, int, value, 0); MESSAGE0(CPuzzleSolvedMsg); -MESSAGE3(CQueryCylinderHolderMsg, int, value1, 0, int, value2, 0, int, value3, 0); +MESSAGE3(CQueryCylinderHolderMsg, int, value1, 0, int, value2, 0, CTreeItem *, target, (CTreeItem *)nullptr); MESSAGE1(CQueryCylinderMsg, CString, name, ""); MESSAGE1(CQueryCylinderNameMsg, CString, name, ""); MESSAGE3(CQueryCylinderTypeMsg, int, value1, 0, int, value2, 0, int, value3, 0); @@ -303,10 +303,10 @@ MESSAGE2(CSetVolumeMsg, int, volume, 70, int, secondsTransition, 0); MESSAGE2(CShipSettingMsg, int, value, 0, CString, name, ""); MESSAGE1(CShowTextMsg, CString, value, "NO TEXT INCLUDED!!!"); MESSAGE2(CSignalObject, CString, strValue, "", int, numValue, 0); -MESSAGE2(CSpeechFallsFromTreeMsg, int, value1, 0, int, value2, 0); +MESSAGE1(CSpeechFallsFromTreeMsg, Point, pos, Point()); MESSAGE1(CStartMusicMsg, CMusicPlayer *, musicPlayer, (CMusicPlayer *)nullptr); MESSAGE3(CStatusChangeMsg, int, oldStatus, 0, int, newStatus, 0, bool, success, false); -MESSAGE1(CStopMusicMsg, int, value, 0); +MESSAGE1(CStopMusicMsg, CMusicPlayer *, musicPlayer, (CMusicPlayer *)nullptr); MESSAGE4(CSubAcceptCCarryMsg, CString, string1, "", int, value1, 0, int, value2, 0, CCarry *, item, nullptr); MESSAGE0(CSubDeliverCCarryMsg); MESSAGE0(CSubSendCCarryMsg); diff --git a/engines/titanic/messages/pet_messages.h b/engines/titanic/messages/pet_messages.h index 48e5bab64c..60981726ed 100644 --- a/engines/titanic/messages/pet_messages.h +++ b/engines/titanic/messages/pet_messages.h @@ -35,7 +35,7 @@ MESSAGE0(CPETLostObjectMsg); MESSAGE0(CPETObjectSelectedMsg); MESSAGE1(CPETObjectStateMsg, int, value, 0); MESSAGE0(CPETPhotoOnOffMsg); -MESSAGE1(CPETPlaySoundMsg, int, value, 0); +MESSAGE1(CPETPlaySoundMsg, int, soundNum, 0); MESSAGE0(CPETReceiveMsg); MESSAGE0(CPETSetStarDestinationMsg); MESSAGE1(CPETStarFieldLockMsg, int, value, 0); diff --git a/engines/titanic/messages/service_elevator_door.cpp b/engines/titanic/messages/service_elevator_door.cpp index 748790e4aa..7011b1ad44 100644 --- a/engines/titanic/messages/service_elevator_door.cpp +++ b/engines/titanic/messages/service_elevator_door.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CServiceElevatorDoor, CDoorAutoSoundEvent) + ON_MESSAGE(PreEnterNodeMsg) +END_MESSAGE_MAP() + CServiceElevatorDoor::CServiceElevatorDoor() : CDoorAutoSoundEvent() { _string1 = "z#31.wav"; _string2 = "z#32.wav"; @@ -45,4 +49,10 @@ void CServiceElevatorDoor::load(SimpleFile *file) { CDoorAutoSoundEvent::load(file); } +bool CServiceElevatorDoor::PreEnterNodeMsg(CPreEnterNodeMsg *msg) { + if (!findRoom()->isEquals("BilgeRoomWith")) + CDoorAutoSoundEvent::PreEnterNodeMsg(msg); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/messages/service_elevator_door.h b/engines/titanic/messages/service_elevator_door.h index cc8da0917d..69ad1e15b9 100644 --- a/engines/titanic/messages/service_elevator_door.h +++ b/engines/titanic/messages/service_elevator_door.h @@ -28,6 +28,8 @@ namespace Titanic { class CServiceElevatorDoor : public CDoorAutoSoundEvent { + DECLARE_MESSAGE_MAP; + bool PreEnterNodeMsg(CPreEnterNodeMsg *msg); public: CLASSDEF; CServiceElevatorDoor(); diff --git a/engines/titanic/module.mk b/engines/titanic/module.mk index a3afc7e4a4..793427991d 100644 --- a/engines/titanic/module.mk +++ b/engines/titanic/module.mk @@ -157,6 +157,8 @@ MODULE_OBJS := \ game/music_system_lock.o \ game/musical_instrument.o \ game/nav_helmet.o \ + game/nav_helmet_off.o \ + game/nav_helmet_on.o \ game/navigation_computer.o \ game/no_nut_bowl.o \ game/nose_holder.o \ @@ -240,7 +242,7 @@ MODULE_OBJS := \ game/pickup/pick_up_speech_centre.o \ game/pickup/pick_up_vis_centre.o \ game/placeholder/bar_shelf_vis_centre.o \ - game/placeholder/place_holder_item.o \ + game/placeholder/place_holder.o \ game/placeholder/lemon_on_bar.o \ game/placeholder/tv_on_bar.o \ game/transport/gondolier.o \ @@ -275,7 +277,6 @@ MODULE_OBJS := \ gfx/chev_right_off.o \ gfx/chev_right_on.o \ gfx/chev_send_rec_switch.o \ - gfx/chev_switch.o \ gfx/edit_control.o \ gfx/elevator_button.o \ gfx/get_from_succ.o \ @@ -294,7 +295,12 @@ MODULE_OBJS := \ gfx/move_object_button.o \ gfx/music_control.o \ gfx/music_slider.o \ + gfx/music_slider_pitch.o \ + gfx/music_slider_speed.o \ gfx/music_switch.o \ + gfx/music_switch_inversion.o \ + gfx/music_switch_reverse.o \ + gfx/music_voice_mute.o \ gfx/send_to_succ.o \ gfx/sgt_selector.o \ gfx/slider_button.o \ @@ -468,6 +474,7 @@ MODULE_OBJS := \ support/screen_manager.o \ support/simple_file.o \ support/string.o \ + support/string_parser.o \ support/text_cursor.o \ support/time_event_info.o \ support/video_surface.o \ diff --git a/engines/titanic/moves/enter_exit_mini_lift.cpp b/engines/titanic/moves/enter_exit_mini_lift.cpp index e626d70a9e..3caa674ab8 100644 --- a/engines/titanic/moves/enter_exit_mini_lift.cpp +++ b/engines/titanic/moves/enter_exit_mini_lift.cpp @@ -56,7 +56,7 @@ bool CEnterExitMiniLift::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { if (pet) pet->setRoomsRoomNum(_destRoomNum); } else if (compareRoomNameTo("SGTLittleLift")) { - if (_statics->_changeViewFlag) { + if (_statics->_changeViewNum) { changeView(_statics->_destView); } } @@ -65,7 +65,7 @@ bool CEnterExitMiniLift::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { } bool CEnterExitMiniLift::EnterViewMsg(CEnterViewMsg *msg) { - _cursorId = _statics->_changeViewFlag ? CURSOR_MOVE_FORWARD : CURSOR_INVALID; + _cursorId = _statics->_changeViewNum ? CURSOR_MOVE_FORWARD : CURSOR_INVALID; return true; } diff --git a/engines/titanic/moves/exit_arboretum.cpp b/engines/titanic/moves/exit_arboretum.cpp index e0c2ab9c9d..ba162843b5 100644 --- a/engines/titanic/moves/exit_arboretum.cpp +++ b/engines/titanic/moves/exit_arboretum.cpp @@ -57,7 +57,7 @@ void CExitArboretum::load(SimpleFile *file) { bool CExitArboretum::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { if (_enabled) { CActMsg actMsg; - if (_seasonNum == AUTUMN) { + if (_seasonNum == SEASON_WINTER) { switch (_fieldCC) { case 0: actMsg._action = "ExitLFrozen"; diff --git a/engines/titanic/moves/move_player_in_parrot_room.cpp b/engines/titanic/moves/move_player_in_parrot_room.cpp index df38c63cd4..1ef2e96e92 100644 --- a/engines/titanic/moves/move_player_in_parrot_room.cpp +++ b/engines/titanic/moves/move_player_in_parrot_room.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMovePlayerInParrotRoom, CMovePlayerTo) + ON_MESSAGE(ActMsg) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + CMovePlayerInParrotRoom::CMovePlayerInParrotRoom() : CMovePlayerTo() { } @@ -37,4 +42,20 @@ void CMovePlayerInParrotRoom::load(SimpleFile *file) { CMovePlayerTo::load(file); } +bool CMovePlayerInParrotRoom::ActMsg(CActMsg *msg) { + if (msg->_action == "PanAwayFromParrot") { + unlockMouse(); + changeView(_destination); + } + + return true; +} + +bool CMovePlayerInParrotRoom::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + lockMouse(); + CPanningAwayFromParrotMsg awayMsg(this); + awayMsg.execute("PerchedParrot"); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/move_player_in_parrot_room.h b/engines/titanic/moves/move_player_in_parrot_room.h index de693fe2e2..54dc2eb992 100644 --- a/engines/titanic/moves/move_player_in_parrot_room.h +++ b/engines/titanic/moves/move_player_in_parrot_room.h @@ -28,6 +28,9 @@ namespace Titanic { class CMovePlayerInParrotRoom : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; CMovePlayerInParrotRoom(); diff --git a/engines/titanic/moves/move_player_to.cpp b/engines/titanic/moves/move_player_to.cpp index 9b6000c4f8..a91215b539 100644 --- a/engines/titanic/moves/move_player_to.cpp +++ b/engines/titanic/moves/move_player_to.cpp @@ -21,9 +21,15 @@ */ #include "titanic/moves/move_player_to.h" +#include "titanic/game_manager.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CMovePlayerTo, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + CMovePlayerTo::CMovePlayerTo() : CGameObject() { } @@ -41,4 +47,17 @@ void CMovePlayerTo::load(SimpleFile *file) { CGameObject::load(file); } +bool CMovePlayerTo::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CGameManager *gameManager = getGameManager(); + if (gameManager) + changeView(_destination); + + return true; +} + +bool CMovePlayerTo::ActMsg(CActMsg *msg) { + _destination = msg->_action; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/move_player_to.h b/engines/titanic/moves/move_player_to.h index 4bfffcb0b2..822df69422 100644 --- a/engines/titanic/moves/move_player_to.h +++ b/engines/titanic/moves/move_player_to.h @@ -28,6 +28,9 @@ namespace Titanic { class CMovePlayerTo : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool ActMsg(CActMsg *msg); protected: CString _destination; public: diff --git a/engines/titanic/moves/move_player_to_from.cpp b/engines/titanic/moves/move_player_to_from.cpp index 1a67dc8505..c57cc2cf51 100644 --- a/engines/titanic/moves/move_player_to_from.cpp +++ b/engines/titanic/moves/move_player_to_from.cpp @@ -21,10 +21,16 @@ */ #include "titanic/moves/move_player_to_from.h" +#include "titanic/core/view_item.h" +#include "titanic/core/link_item.h" namespace Titanic { -CMovePlayerToFrom::CMovePlayerToFrom() : CGameObject() { +BEGIN_MESSAGE_MAP(CMovePlayerToFrom, CMovePlayerTo) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + +CMovePlayerToFrom::CMovePlayerToFrom() : CMovePlayerTo() { } void CMovePlayerToFrom::save(SimpleFile *file, int indent) { @@ -41,4 +47,17 @@ void CMovePlayerToFrom::load(SimpleFile *file) { CGameObject::load(file); } +bool CMovePlayerToFrom::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_string2.empty()) { + changeView(_destination); + } else { + CViewItem *view = parseView(_string2); + CViewItem *destView = parseView(_destination); + CLinkItem *link = view->findLink(destView); + changeView(_destination, link->getName()); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/move_player_to_from.h b/engines/titanic/moves/move_player_to_from.h index c9eefe532f..fde4e94ab5 100644 --- a/engines/titanic/moves/move_player_to_from.h +++ b/engines/titanic/moves/move_player_to_from.h @@ -23,11 +23,13 @@ #ifndef TITANIC_MOVE_PLAYER_TO_FROM_H #define TITANIC_MOVE_PLAYER_TO_FROM_H -#include "titanic/core/game_object.h" +#include "titanic/moves/move_player_to.h" namespace Titanic { -class CMovePlayerToFrom : public CGameObject { +class CMovePlayerToFrom : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); private: CString _string2; public: diff --git a/engines/titanic/moves/multi_move.cpp b/engines/titanic/moves/multi_move.cpp index fb5570df9b..4ca4fdb8f3 100644 --- a/engines/titanic/moves/multi_move.cpp +++ b/engines/titanic/moves/multi_move.cpp @@ -24,29 +24,37 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CMultiMove, CMovePlayerTo) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + CMultiMove::CMultiMove() : CMovePlayerTo() { } void CMultiMove::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string1, indent); - file->writeQuotedLine(_string2, indent); - file->writeQuotedLine(_string3, indent); - file->writeQuotedLine(_string4, indent); - file->writeQuotedLine(_string5, indent); + for (int idx = 0; idx < 5; ++idx) + file->writeQuotedLine(_viewNames[idx], indent); CMovePlayerTo::save(file, indent); } void CMultiMove::load(SimpleFile *file) { file->readNumber(); - _string1 = file->readString(); - _string2 = file->readString(); - _string3 = file->readString(); - _string5 = file->readString(); - _string4 = file->readString(); + for (int idx = 0; idx < 5; ++idx) + _viewNames[idx] = file->readString(); CMovePlayerTo::load(file); } +bool CMultiMove::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + lockMouse(); + + for (int idx = 0; idx < 5 && _viewNames[idx] != "NULL"; ++idx) + changeView(_viewNames[idx]); + + unlockMouse(); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/multi_move.h b/engines/titanic/moves/multi_move.h index 977afc2a20..12dd246823 100644 --- a/engines/titanic/moves/multi_move.h +++ b/engines/titanic/moves/multi_move.h @@ -28,12 +28,10 @@ namespace Titanic { class CMultiMove : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); private: - CString _string1; - CString _string2; - CString _string3; - CString _string4; - CString _string5; + CString _viewNames[5]; public: CLASSDEF; CMultiMove(); diff --git a/engines/titanic/moves/pan_from_pel.cpp b/engines/titanic/moves/pan_from_pel.cpp index fccc643ec5..ca48e888c1 100644 --- a/engines/titanic/moves/pan_from_pel.cpp +++ b/engines/titanic/moves/pan_from_pel.cpp @@ -24,23 +24,33 @@ namespace Titanic { -CPanFromPel::CPanFromPel() : CMovePlayerTo(), _fieldC8(0) { +BEGIN_MESSAGE_MAP(CPanFromPel, CMovePlayerTo) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + +CPanFromPel::CPanFromPel() : CMovePlayerTo(), _closeLeft(false) { } void CPanFromPel::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldC8, indent); - file->writeQuotedLine(_string1, indent); + file->writeNumberLine(_closeLeft, indent); + file->writeQuotedLine(_target, indent); CMovePlayerTo::save(file, indent); } void CPanFromPel::load(SimpleFile *file) { file->readNumber(); - _fieldC8 = file->readNumber(); - _string1 = file->readString(); + _closeLeft = file->readNumber(); + _target = file->readString(); CMovePlayerTo::load(file); } +bool CPanFromPel::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + CActMsg actMsg(_closeLeft ? "CloseLeft" : "CloseRight"); + actMsg.execute(_target); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/pan_from_pel.h b/engines/titanic/moves/pan_from_pel.h index c81be9f338..0a01aefea3 100644 --- a/engines/titanic/moves/pan_from_pel.h +++ b/engines/titanic/moves/pan_from_pel.h @@ -28,9 +28,11 @@ namespace Titanic { class CPanFromPel : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); protected: - int _fieldC8; - CString _string1; + bool _closeLeft; + CString _target; public: CLASSDEF; CPanFromPel(); diff --git a/engines/titanic/moves/restaurant_pan_handler.cpp b/engines/titanic/moves/restaurant_pan_handler.cpp index 92f55b46cc..d93e331254 100644 --- a/engines/titanic/moves/restaurant_pan_handler.cpp +++ b/engines/titanic/moves/restaurant_pan_handler.cpp @@ -24,24 +24,40 @@ namespace Titanic { -int CRestaurantPanHandler::_v1; +BEGIN_MESSAGE_MAP(CRestaurantPanHandler, CMovePlayerTo) + ON_MESSAGE(ArmPickedUpFromTableMsg) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + +bool CRestaurantPanHandler::_armPickedUp; void CRestaurantPanHandler::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_v1, indent); - file->writeQuotedLine(_string1, indent); - file->writeQuotedLine(_string2, indent); + file->writeNumberLine(_armPickedUp, indent); + file->writeQuotedLine(_armlessDestination, indent); + file->writeQuotedLine(_armDestination, indent); CMovePlayerTo::save(file, indent); } void CRestaurantPanHandler::load(SimpleFile *file) { file->readNumber(); - _v1 = file->readNumber(); - _string1 = file->readString(); - _string2 = file->readString(); + _armPickedUp = file->readNumber(); + _armlessDestination = file->readString(); + _armDestination = file->readString(); CMovePlayerTo::load(file); } +bool CRestaurantPanHandler::ArmPickedUpFromTableMsg(CArmPickedUpFromTableMsg *msg) { + _armPickedUp = true; + return true; +} + +bool CRestaurantPanHandler::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + _destination = _armPickedUp ? _armDestination : _armlessDestination; + changeView(_destination); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/restaurant_pan_handler.h b/engines/titanic/moves/restaurant_pan_handler.h index 4925aa685b..9684fd07f5 100644 --- a/engines/titanic/moves/restaurant_pan_handler.h +++ b/engines/titanic/moves/restaurant_pan_handler.h @@ -28,11 +28,14 @@ namespace Titanic { class CRestaurantPanHandler : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool ArmPickedUpFromTableMsg(CArmPickedUpFromTableMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); protected: - static int _v1; - - CString _string1; - CString _string2; + CString _armDestination; + CString _armlessDestination; +public: + static bool _armPickedUp; public: CLASSDEF; diff --git a/engines/titanic/moves/restricted_move.cpp b/engines/titanic/moves/restricted_move.cpp index 5f18dab8ff..37cb1c46dc 100644 --- a/engines/titanic/moves/restricted_move.cpp +++ b/engines/titanic/moves/restricted_move.cpp @@ -24,21 +24,59 @@ namespace Titanic { -CRestrictedMove::CRestrictedMove() : CMovePlayerTo(), _fieldC8(0) { +BEGIN_MESSAGE_MAP(CRestrictedMove, CMovePlayerTo) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +CRestrictedMove::CRestrictedMove() : CMovePlayerTo(), _classNum(0) { } void CRestrictedMove::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldC8, indent); + file->writeNumberLine(_classNum, indent); CMovePlayerTo::save(file, indent); } void CRestrictedMove::load(SimpleFile *file) { file->readNumber(); - _fieldC8 = file->readNumber(); + _classNum = file->readNumber(); CMovePlayerTo::load(file); } +bool CRestrictedMove::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + int classNum = getPassengerClass(); + if (classNum <= _classNum) { + // Okay to change to the given destination + changeView(_destination); + } else if (classNum != 4) { + petDisplayMessage(1, "Passengers of your class are not permitted to enter this area."); + } else if (compareRoomNameTo("EmbLobby")) { + playSound("a#17.wav"); + petDisplayMessage(1, "Please check in at the reception desk."); + } else if (compareViewNameTo("Titania.Node 1.S")) { + playSound("z#226.wav"); + changeView(_destination); + } + + return true; +} + +bool CRestrictedMove::EnterViewMsg(CEnterViewMsg *msg) { + int classNum = getPassengerClass(); + bool flag = classNum > _classNum; + + if (classNum == 4) { + if (compareRoomNameTo("EmbLobby")) + flag = false; + else if (compareViewNameTo("Titania.Node 1.S")) + flag = true; + } + + _cursorId = flag ? CURSOR_MOVE_FORWARD : CURSOR_INVALID; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/restricted_move.h b/engines/titanic/moves/restricted_move.h index bdf093c353..639b024701 100644 --- a/engines/titanic/moves/restricted_move.h +++ b/engines/titanic/moves/restricted_move.h @@ -28,8 +28,11 @@ namespace Titanic { class CRestrictedMove : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); protected: - int _fieldC8; + int _classNum; public: CLASSDEF; CRestrictedMove(); diff --git a/engines/titanic/moves/scraliontis_table.cpp b/engines/titanic/moves/scraliontis_table.cpp index 77d2f9df60..8d39e2104f 100644 --- a/engines/titanic/moves/scraliontis_table.cpp +++ b/engines/titanic/moves/scraliontis_table.cpp @@ -24,15 +24,21 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CScraliontisTable, CRestaurantPanHandler) + ON_MESSAGE(MouseMoveMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MaitreDDefeatedMsg) +END_MESSAGE_MAP() + CScraliontisTable::CScraliontisTable() : CRestaurantPanHandler(), - _fieldE0(0), _fieldE4(0), _fieldE8(0), _fieldEC(0) { + _fieldE0(false), _counter(0), _ticks(0), _fieldEC(false) { } void CScraliontisTable::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldE0, indent); - file->writeNumberLine(_fieldE4, indent); - file->writeNumberLine(_fieldE8, indent); + file->writeNumberLine(_counter, indent); + file->writeNumberLine(_ticks, indent); file->writeNumberLine(_fieldEC, indent); CRestaurantPanHandler::save(file, indent); @@ -41,11 +47,42 @@ void CScraliontisTable::save(SimpleFile *file, int indent) { void CScraliontisTable::load(SimpleFile *file) { file->readNumber(); _fieldE0 = file->readNumber(); - _fieldE4 = file->readNumber(); - _fieldE8 = file->readNumber(); + _counter = file->readNumber(); + _ticks = file->readNumber(); _fieldEC = file->readNumber(); CRestaurantPanHandler::load(file); } +bool CScraliontisTable::MouseMoveMsg(CMouseMoveMsg *msg) { + if (!_fieldEC && !_fieldE0) { + if (++_counter > 20) { + CTriggerNPCEvent triggerMsg; + triggerMsg.execute("MaitreD"); + _fieldE0 = true; + } + } + + return true; +} + +bool CScraliontisTable::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (_fieldEC) { + changeView(_destination, _armPickedUp ? _armDestination : _armlessDestination); + } + else if (!_ticks || (getTicksCount() - _ticks) >= 5000) { + CTriggerNPCEvent triggerMsg(119); + triggerMsg.execute("MaitreD"); + _ticks = getTicksCount(); + } + + return true; +} + +bool CScraliontisTable::MaitreDDefeatedMsg(CMaitreDDefeatedMsg *msg) { + _cursorId = CURSOR_MOVE_FORWARD; + _fieldEC = true; + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/scraliontis_table.h b/engines/titanic/moves/scraliontis_table.h index 2ce3745654..b0d8c6b5af 100644 --- a/engines/titanic/moves/scraliontis_table.h +++ b/engines/titanic/moves/scraliontis_table.h @@ -28,11 +28,15 @@ namespace Titanic { class CScraliontisTable : public CRestaurantPanHandler { + DECLARE_MESSAGE_MAP; + bool MouseMoveMsg(CMouseMoveMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MaitreDDefeatedMsg(CMaitreDDefeatedMsg *msg); private: - int _fieldE0; - int _fieldE4; - int _fieldE8; - int _fieldEC; + bool _fieldE0; + int _counter; + uint _ticks; + bool _fieldEC; public: CLASSDEF; CScraliontisTable(); diff --git a/engines/titanic/moves/trip_down_canal.cpp b/engines/titanic/moves/trip_down_canal.cpp index c8051dda03..e9818fa96d 100644 --- a/engines/titanic/moves/trip_down_canal.cpp +++ b/engines/titanic/moves/trip_down_canal.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CTripDownCanal, CMovePlayerTo) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + CTripDownCanal::CTripDownCanal() : CMovePlayerTo() { } @@ -37,4 +41,14 @@ void CTripDownCanal::load(SimpleFile *file) { CMovePlayerTo::load(file); } +bool CTripDownCanal::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (stateGetSeason() == SEASON_WINTER) { + petDisplayMessage("Sadly, the Grand Canal transport system is closed for the winter."); + } else if (getGameManager()) { + changeView(_destination); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/moves/trip_down_canal.h b/engines/titanic/moves/trip_down_canal.h index 736caf4131..f43fb05de1 100644 --- a/engines/titanic/moves/trip_down_canal.h +++ b/engines/titanic/moves/trip_down_canal.h @@ -28,6 +28,8 @@ namespace Titanic { class CTripDownCanal : public CMovePlayerTo { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); public: CLASSDEF; CTripDownCanal(); diff --git a/engines/titanic/npcs/bellbot.cpp b/engines/titanic/npcs/bellbot.cpp index ac6881a45c..0170491270 100644 --- a/engines/titanic/npcs/bellbot.cpp +++ b/engines/titanic/npcs/bellbot.cpp @@ -135,8 +135,7 @@ bool CBellBot::MovieEndMsg(CMovieEndMsg *msg) { } bool CBellBot::Use(CUse *msg) { - error("TODO: Figure out what msg->_item points to"); - // msg->_item = "Bellbot"; + dynamic_cast<CCarry *>(msg->_item)->_string1 = "Bellbot"; return true; } diff --git a/engines/titanic/npcs/doorbot.cpp b/engines/titanic/npcs/doorbot.cpp index 4a5f3690c0..41ef2b2366 100644 --- a/engines/titanic/npcs/doorbot.cpp +++ b/engines/titanic/npcs/doorbot.cpp @@ -288,7 +288,7 @@ bool CDoorbot::TimerMsg(CTimerMsg *msg) { case 6: CMouseButtonDownMsg::generate(); - mouseSaveState(200, 430, 2500); + mouseSetPosition(Point(200, 430), 2500); _timerId = addTimer(7, 2500, 0); break; @@ -476,7 +476,7 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) case 10568: mouseLockE4(); - mouseSaveState(600, 250, 2500); + mouseSetPosition(Point(600, 250), 2500); _timerId = addTimer(6, 2500, 0); break; @@ -488,7 +488,7 @@ bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) break; case 10570: - mouseSaveState(200, 430, 2500); + mouseSetPosition(Point(200, 430), 2500); _timerId = addTimer(7, 3000, 0); break; diff --git a/engines/titanic/npcs/mobile.h b/engines/titanic/npcs/mobile.h index 68e74a5afe..2ad939afa6 100644 --- a/engines/titanic/npcs/mobile.h +++ b/engines/titanic/npcs/mobile.h @@ -29,7 +29,7 @@ namespace Titanic { class CMobile : public CCharacter { DECLARE_MESSAGE_MAP; -private: +protected: Point _pos1; int _fieldDC; public: diff --git a/engines/titanic/npcs/true_talk_npc.cpp b/engines/titanic/npcs/true_talk_npc.cpp index 5ba68aafbe..97913dffea 100644 --- a/engines/titanic/npcs/true_talk_npc.cpp +++ b/engines/titanic/npcs/true_talk_npc.cpp @@ -188,7 +188,34 @@ bool CTrueTalkNPC::TimerMsg(CTimerMsg *msg) { } bool CTrueTalkNPC::NPCPlayAnimationMsg(CNPCPlayAnimationMsg *msg) { - warning("CTrueTalkNPC::NPCPlayAnimationMsg"); +// const char *const *nameP = msg->_names; + int count; + for (count = 0; msg->_names[count]; ++count) + ; + + if (msg->_maxDuration) { + // Randomly pick a clip that's less than the allowed maximum + int tries = 10, index; + do { + index = getRandomNumber(count - 1); + } while (getClipDuration(msg->_names[index]) > msg->_maxDuration && --tries); + + if (tries) { + // Sequentially go through the clips to find any below the maximum + index = 0; + for (int idx = 0; idx < count; ++idx) { + if (getClipDuration(msg->_names[idx]) < msg->_maxDuration) { + index = idx; + break; + } + } + } + + playClip(msg->_names[index], MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + } else { + playClip(msg->_names[getRandomNumber(count - 1)]); + } + return true; } diff --git a/engines/titanic/npcs/true_talk_npc.h b/engines/titanic/npcs/true_talk_npc.h index 1eade1966d..5254eaf9b7 100644 --- a/engines/titanic/npcs/true_talk_npc.h +++ b/engines/titanic/npcs/true_talk_npc.h @@ -62,15 +62,11 @@ protected: int _fieldF4; int _fieldF8; int _speechTimerId; - int _field100; int _field104; protected: void processInput(CTextInputMsg *msg, CViewItem *view); - - /** - * Perform an action - */ - void performAction(bool startTalking, CViewItem *view = nullptr); +public: + int _field100; public: CLASSDEF; CTrueTalkNPC(); @@ -94,6 +90,11 @@ public: * Start the talker in the given view */ void startTalker(CViewItem *view); + + /** + * Perform an action + */ + void performAction(bool startTalking, CViewItem *view = nullptr); }; } // End of namespace Titanic diff --git a/engines/titanic/pet_control/pet_control.cpp b/engines/titanic/pet_control/pet_control.cpp index b32a7907a4..a0f8fab267 100644 --- a/engines/titanic/pet_control/pet_control.cpp +++ b/engines/titanic/pet_control/pet_control.cpp @@ -194,6 +194,10 @@ void CPetControl::setActiveNPC(CTrueTalkNPC *npc) { } } +void CPetControl::setActiveNPC(const CString &name) { + _conversations.setActiveNPC(name); +} + void CPetControl::refreshNPC() { _conversations.setNPC(_activeNPCName); } @@ -355,7 +359,8 @@ bool CPetControl::VirtualKeyCharMsg(CVirtualKeyCharMsg *msg) { } bool CPetControl::TimerMsg(CTimerMsg *msg) { - warning("TODO: CPetControl::CTimerMsg"); + if (_timers[msg->_actionVal]._target) + _timers[msg->_actionVal]._target->timerExpired(msg->_actionVal); return true; } @@ -660,6 +665,10 @@ void CPetControl::convResetDials(int flag) { _conversations.resetDials(_activeNPCName); } +void CPetControl::resetDials0() { + _conversations.resetDials0(); +} + int CPetControl::getMailDest(const CRoomFlags &roomFlags) const { if (!roomFlags.isSuccUBusRoomFlags()) return roomFlags.getPassengerClassNum(); diff --git a/engines/titanic/pet_control/pet_control.h b/engines/titanic/pet_control/pet_control.h index a86d110458..439a94e2d3 100644 --- a/engines/titanic/pet_control/pet_control.h +++ b/engines/titanic/pet_control/pet_control.h @@ -358,9 +358,7 @@ public: /** * Sets the active NPC */ - void setActiveNPC(const CString &name) { - _conversations.setActiveNPC(name); - } + void setActiveNPC(const CString &name); /** * Sets the actie NPC @@ -387,7 +385,7 @@ public: /** * Resets the conversation dials back to 0 position */ - void resetDials0() { _conversations.resetDials0(); } + void resetDials0(); /** * Resets the dial display in the conversation tab to reflect new values diff --git a/engines/titanic/pet_control/pet_conversations.h b/engines/titanic/pet_control/pet_conversations.h index 9e8b093d62..3333bdc523 100644 --- a/engines/titanic/pet_control/pet_conversations.h +++ b/engines/titanic/pet_control/pet_conversations.h @@ -100,16 +100,6 @@ private: void summonBot(const CString &name); /** - * Starts the NPC timer - */ - void startNPCTimer(); - - /** - * Stops the NPC timer - */ - void stopNPCTimer(); - - /** * Get the TrueTalk script associated with a given NPC */ TTnpcScript *getNPCScript(const CString &name) const; @@ -260,6 +250,16 @@ public: * Adds a line to the log */ void addLine(const CString &line); + + /** + * Starts the NPC timer + */ + void startNPCTimer(); + + /** + * Stops the NPC timer + */ + void stopNPCTimer(); }; } // End of namespace Titanic diff --git a/engines/titanic/pet_control/pet_load_save.h b/engines/titanic/pet_control/pet_load_save.h index dd1c907ef1..26ddec0ff9 100644 --- a/engines/titanic/pet_control/pet_load_save.h +++ b/engines/titanic/pet_control/pet_load_save.h @@ -38,11 +38,6 @@ private: Rect getSlotBounds(int index); /** - * Highlight one of the slots - */ - void highlightSlot(int index); - - /** * Called when savegame slot highlight changes or the view is reset */ void highlightChange(); @@ -67,6 +62,11 @@ protected: * Reset the slot names list */ void resetSlots(); + + /** + * Highlight one of the slots + */ + void highlightSlot(int index); public: /** * Setup the glyph diff --git a/engines/titanic/pet_control/pet_save.cpp b/engines/titanic/pet_control/pet_save.cpp index b5e16736bc..9305759117 100644 --- a/engines/titanic/pet_control/pet_save.cpp +++ b/engines/titanic/pet_control/pet_save.cpp @@ -22,6 +22,7 @@ #include "titanic/pet_control/pet_save.h" #include "titanic/pet_control/pet_control.h" +#include "titanic/core/project_item.h" namespace Titanic { @@ -58,15 +59,28 @@ void CPetSave::getTooltip(CPetText *text) { } void CPetSave::highlightSave(int index) { - warning("TODO: CPetSave::highlightSave"); + if (index >= 0) + _slotNames[index].showCursor(-2); } void CPetSave::unhighlightSave(int index) { - warning("TODO: CPetSave::unhighlightSave"); + if (index >= 0) + _slotNames[index].hideCursor(); } void CPetSave::execute() { - warning("TODO: CPetSave::execute"); + CPetControl *pet = getPetControl(); + if (_savegameSlotNum >= 0) { + highlightSlot(-1); + CProjectItem *project = pet ? pet->getRoot() : nullptr; + + if (project) { + project->saveGame(_savegameSlotNum, _slotNames[_savegameSlotNum].getText()); + pet->displayMessage(""); + } + } else if (pet) { + pet->displayMessage("You must select a game to save first."); + } } } // End of namespace Titanic diff --git a/engines/titanic/sound/music_room.h b/engines/titanic/sound/music_room.h index 15363ef392..5f0b271ab3 100644 --- a/engines/titanic/sound/music_room.h +++ b/engines/titanic/sound/music_room.h @@ -31,6 +31,8 @@ namespace Titanic { class CGameManager; class CSound; +enum MusicControlArea { BELLS = 0, SNAKE = 1, PIANO = 2, BASS = 3 }; + class CMusicRoom { struct Entry { uint _val1; @@ -62,11 +64,11 @@ public: */ void destroyMusicHandler(); - void setItem1(int index, int val) { _items[index]._val1 = val; } - void setItem2(int index, int val) { _items[index]._val2 = val; } - void setItem3(int index, int val) { _items[index]._val3 = val; } - void setItem4(int index, int val) { _items[index]._val4 = val; } - void setItem5(int index, int val) { _items[index]._val5 = val; } + void setItem1(MusicControlArea index, int val) { _items[index]._val1 = val; } + void setItem2(MusicControlArea index, int val) { _items[index]._val2 = val; } + void setItem3(MusicControlArea index, int val) { _items[index]._val3 = val; } + void setItem4(MusicControlArea index, int val) { _items[index]._val4 = val; } + void setItem5(MusicControlArea index, int val) { _items[index]._val5 = val; } /** * Start playing a given music number diff --git a/engines/titanic/sound/sound_manager.cpp b/engines/titanic/sound/sound_manager.cpp index 4846329784..ae806feb52 100644 --- a/engines/titanic/sound/sound_manager.cpp +++ b/engines/titanic/sound/sound_manager.cpp @@ -33,14 +33,14 @@ CSoundManager::CSoundManager() : _musicPercent(75.0), _speechPercent(75.0), _masterPercent(75.0), _parrotPercent(75.0), _handleCtr(1) { } -double CSoundManager::getModeVolume(int mode) { +uint CSoundManager::getModeVolume(int mode) { switch (mode) { case -1: - return _masterPercent; + return (uint)_masterPercent; case -2: - return _masterPercent * 30 / 100; + return (uint)(_masterPercent * 30 / 100); case -3: - return _masterPercent * 15 / 100; + return (uint)(_masterPercent * 15 / 100); default: return 0; } diff --git a/engines/titanic/sound/sound_manager.h b/engines/titanic/sound/sound_manager.h index 3dfba92e9c..d1afdb4ad4 100644 --- a/engines/titanic/sound/sound_manager.h +++ b/engines/titanic/sound/sound_manager.h @@ -214,7 +214,7 @@ public: /** * Gets the volume for a given mode? value */ - double getModeVolume(int mode); + uint getModeVolume(int mode); }; class QSoundManagerSound : public ListItem { diff --git a/engines/titanic/sound/titania_speech.cpp b/engines/titanic/sound/titania_speech.cpp index a07cc79334..d0ff423342 100644 --- a/engines/titanic/sound/titania_speech.cpp +++ b/engines/titanic/sound/titania_speech.cpp @@ -59,7 +59,7 @@ bool CTitaniaSpeech::ActMsg(CActMsg *msg) { movieSetAudioTiming(true); loadSound("a#12.wav"); sleep(1000); - playMovie(0, 187, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(0, 187, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); movieEvent(0); break; @@ -78,7 +78,7 @@ bool CTitaniaSpeech::ActMsg(CActMsg *msg) { visibleMsg._visible = false; visibleMsg.execute("TitaniaStillControl"); loadSound("a#10.wav"); - playMovie(585, 706, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(585, 706, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); playSound("a#10.wav"); break; @@ -86,7 +86,7 @@ bool CTitaniaSpeech::ActMsg(CActMsg *msg) { visibleMsg._visible = false; visibleMsg.execute("TitaniaStillControl"); loadSound("a#9.wav"); - playMovie(707, 905, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(707, 905, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); playSound("a#9.wav"); break; @@ -94,7 +94,7 @@ bool CTitaniaSpeech::ActMsg(CActMsg *msg) { visibleMsg._visible = false; visibleMsg.execute("TitaniaStillControl"); loadSound("a#8.wav"); - playMovie(906, 938, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playMovie(906, 938, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); playSound("a#8.wav"); break; diff --git a/engines/titanic/star_control/surface_fader.cpp b/engines/titanic/star_control/surface_fader.cpp index 089ad51717..0ee03673a4 100644 --- a/engines/titanic/star_control/surface_fader.cpp +++ b/engines/titanic/star_control/surface_fader.cpp @@ -29,9 +29,9 @@ namespace Titanic { CSurfaceFader::CSurfaceFader() : CSurfaceFaderBase() { _dataP = new byte[_count]; - for (int idx = 0; idx < _count; ++idx) { - // TODO: Setup data bytes - } + for (int idx = 0; idx < _count; ++idx) + _dataP[idx] = (byte)(pow((double)idx / (double)_count, 1.299999952316284) + * (double)_count + 0.5); } CSurfaceFader::~CSurfaceFader() { diff --git a/engines/titanic/support/credit_text.cpp b/engines/titanic/support/credit_text.cpp index 0e9715aaa6..009c3f4944 100644 --- a/engines/titanic/support/credit_text.cpp +++ b/engines/titanic/support/credit_text.cpp @@ -28,7 +28,7 @@ namespace Titanic { CCreditText::CCreditText() : _screenManagerP(nullptr), _field14(0), _ticks(0), _fontHeight(1), _objectP(nullptr), _totalHeight(0), _field40(0), _field44(0), _field48(0), _field4C(0), _field50(0), - _field54(0), _field58(0), _field5C(0) { + _field54(0), _field58(0), _counter(0) { } void CCreditText::clear() { @@ -52,7 +52,7 @@ void CCreditText::load(CGameObject *obj, CScreenManager *screenManager, _field50 = 0; _field54 = 0; _field58 = 0; - _field5C = 0; + _counter = 0; } void CCreditText::setup() { @@ -87,8 +87,11 @@ void CCreditText::setup() { } _groups.push_back(group); + if (hasDots) + handleDots(group); } + _screenManagerP->setFontNumber(oldFontNumber); _groupIt = _groups.begin(); _lineIt = (*_groupIt)->_lines.begin(); _totalHeight = _objectP->getBounds().height() + _fontHeight * 2; @@ -147,7 +150,108 @@ void CCreditText::handleDots(CCreditLineGroup *group) { } bool CCreditText::draw() { - return false; + if (_groupIt == _groups.end()) + return false; + + if (++_counter > 200) { + _field44 += _field50; + _field48 += _field54; + _field4C += _field58; + _field50 = g_vm->getRandomNumber(63) + 192 - _field44; + _field54 = g_vm->getRandomNumber(63) + 192 - _field48; + _field58 = g_vm->getRandomNumber(63) + 192 - _field4C; + _counter = 0; + } + + // Positioning adjustment, changing lines and/or group if necessary + int yDiff = (int)(g_vm->_events->getTicksCount() - _ticks) / 22 - _field40; + while (yDiff > 0) { + if (_totalHeight > 0) { + if (yDiff < _totalHeight) { + _totalHeight -= yDiff; + _field40 += yDiff; + yDiff = 0; + } else { + yDiff -= _totalHeight; + _field40 += _totalHeight; + _totalHeight = 0; + } + } else { + if (yDiff < _fontHeight) + break; + + ++_lineIt; + yDiff -= _fontHeight; + _field40 += _fontHeight; + + if (_lineIt == (*_groupIt)->_lines.end()) { + // Move to next line group + ++_groupIt; + if (_groupIt == _groups.end()) + // Reached end of groups + return false; + + _lineIt = (*_groupIt)->_lines.begin(); + _totalHeight = _fontHeight * 3 / 2; + } + } + } + + int oldFontNumber = _screenManagerP->setFontNumber(3); + CCreditLineGroups::iterator groupIt = _groupIt; + CCreditLines::iterator lineIt = _lineIt; + + Point textPos; + for (textPos.y = _rect.top + _totalHeight; textPos.y <= _rect.bottom; + textPos.y += _fontHeight) { + int textR = _field44 + _field50 * _counter / 200; + int textG = _field48 + _field54 * _counter / 200; + int textB = _field4C + _field58 * _counter / 200; + + // Single iteration loop to figure out RGB values for the line + do { + int percent = 0; + if (textPos.y < (_rect.top + 2 * _fontHeight)) { + percent = (textPos.y - _rect.top) * 100 / (_fontHeight * 2); + if (percent < 0) + percent = 0; + } else { + int bottom = _rect.bottom - 2 * _fontHeight; + if (textPos.y < bottom) + break; + + percent = (_rect.bottom - textPos.y) * 100 + / (_fontHeight * 2); + } + + // Adjust the RGB to the specified percentage intensity + textR = textR * percent / 100; + textG = textG * percent / 100; + textB = textB * percent / 100; + } while (0); + + // Write out the line + _screenManagerP->setFontColor(textR, textG, textB); + textPos.x = _rect.left + (_rect.width() - (*lineIt)->_lineWidth) / 2; + _screenManagerP->writeString(SURFACE_BACKBUFFER, textPos, + _rect, (*lineIt)->_line, (*lineIt)->_lineWidth); + + // Move to next line + ++lineIt; + if (lineIt == (*groupIt)->_lines.end()) { + ++groupIt; + if (groupIt == _groups.end()) + // Finished all lines + break; + + lineIt = (*groupIt)->_lines.begin(); + textPos.y += _fontHeight * 3 / 2; + } + } + + _objectP->makeDirty(); + _screenManagerP->setFontNumber(oldFontNumber); + return true; } } // End of namespace Titanic diff --git a/engines/titanic/support/credit_text.h b/engines/titanic/support/credit_text.h index ec8fc22cda..3e5bfca0c2 100644 --- a/engines/titanic/support/credit_text.h +++ b/engines/titanic/support/credit_text.h @@ -68,11 +68,11 @@ public: int _field14; CCreditLineGroups _groups; uint _ticks; - uint _fontHeight; + int _fontHeight; CGameObject *_objectP; CCreditLineGroups::iterator _groupIt; CCreditLines::iterator _lineIt; - uint _totalHeight; + int _totalHeight; int _field40; int _field44; int _field48; @@ -80,7 +80,7 @@ public: int _field50; int _field54; int _field58; - int _field5C; + int _counter; public: CCreditText(); diff --git a/engines/titanic/support/direct_draw.cpp b/engines/titanic/support/direct_draw.cpp index 6958896077..3cec9377bb 100644 --- a/engines/titanic/support/direct_draw.cpp +++ b/engines/titanic/support/direct_draw.cpp @@ -75,18 +75,6 @@ void DirectDrawManager::initVideo(int width, int height, int bpp, int numBackSur } } -void DirectDrawManager::setResolution() { - // TODO -} - -void DirectDrawManager::proc2() { - -} - -void DirectDrawManager::proc3() { - -} - void DirectDrawManager::initFullScreen() { debugC(ERROR_BASIC, kDebugGraphics, "Creating surfaces"); _directDraw.setDisplayMode(_directDraw._width, _directDraw._height, diff --git a/engines/titanic/support/direct_draw.h b/engines/titanic/support/direct_draw.h index 85c344c600..4b5596896a 100644 --- a/engines/titanic/support/direct_draw.h +++ b/engines/titanic/support/direct_draw.h @@ -78,12 +78,6 @@ public: */ void initVideo(int width, int height, int bpp, int numBackSurfaces); - void setResolution(); - - void proc2(); - - void proc3(); - /** * Initializes the surfaces in windowed mode */ diff --git a/engines/titanic/support/files_manager.cpp b/engines/titanic/support/files_manager.cpp index 89e0a1d10e..3ee17e9769 100644 --- a/engines/titanic/support/files_manager.cpp +++ b/engines/titanic/support/files_manager.cpp @@ -104,8 +104,9 @@ void CFilesManager::loadDrive() { resetView(); } -void CFilesManager::debug(CScreenManager *screenManager) { - warning("TODO: CFilesManager::debug"); +void CFilesManager::insertCD(CScreenManager *screenManager) { + // We not support running game directly from the original CDs, + // so this method can remain stubbed } void CFilesManager::resetView() { @@ -115,10 +116,6 @@ void CFilesManager::resetView() { } } -void CFilesManager::fn4(const CString &name) { - warning("TODO: CFilesManager::fn4"); -} - void CFilesManager::preload(const CString &name) { // We don't currently do any preloading of resources } diff --git a/engines/titanic/support/files_manager.h b/engines/titanic/support/files_manager.h index ec0c7fc008..c530b05ece 100644 --- a/engines/titanic/support/files_manager.h +++ b/engines/titanic/support/files_manager.h @@ -84,15 +84,16 @@ public: */ void loadDrive(); - void debug(CScreenManager *screenManager); + /** + * Shows a dialog for inserting a new CD + */ + void insertCD(CScreenManager *screenManager); /** * Resets the view being displayed */ void resetView(); - void fn4(const CString &name); - /** * Preloads and caches a file for access shortly */ diff --git a/engines/titanic/support/font.cpp b/engines/titanic/support/font.cpp index 69c0efe504..e519237c3b 100644 --- a/engines/titanic/support/font.cpp +++ b/engines/titanic/support/font.cpp @@ -179,6 +179,67 @@ int STFont::writeString(CVideoSurface *surface, const Rect &rect1, const Rect &d return endP ? endP - str.c_str() : 0; } +void STFont::writeString(CVideoSurface *surface, const Point &destPos, Rect &clipRect, + const CString &str, int lineWidth) { + if (!_fontHeight || !_dataPtr || str.empty()) + return; + if (!lineWidth) + // No line width specified, so get in the width + lineWidth = stringWidth(str); + + Rect textRect(0, 0, lineWidth, _fontHeight); + Point textPt = destPos; + + // Perform clipping as necessary if the text will fall outside clipping area + if (textPt.y > clipRect.bottom) + return; + + if ((textPt.y + textRect.height()) > clipRect.bottom) + textRect.bottom = textRect.top - textPt.y + clipRect.bottom; + + if (textPt.y < clipRect.top) { + if ((textPt.y + textRect.height()) < clipRect.top) + return; + + textRect.top += clipRect.top - textPt.y; + textPt.y = clipRect.top; + } + + // Iterate through each character of the string + for (const byte *srcP = (const byte *)str.c_str(); *srcP; ++srcP) { + byte c = *srcP; + if (c == 0xE9) + c = '$'; + + // Form a rect of the area of the next character to draw + Rect charRect(_chars[c]._offset, textRect.top, + _chars[c]._offset + _chars[c]._width, textRect.bottom); + + if (textPt.x < clipRect.left) { + // Character is either partially or entirely left off-screen + if ((textPt.x + charRect.width()) < clipRect.left) { + textPt.x += _chars[c]._width; + continue; + } + + // Partially clipped on left-hand side + charRect.left = clipRect.left - textPt.x; + textPt.x = clipRect.left; + } else if ((textPt.x + charRect.width()) > clipRect.right) { + if (textPt.x > clipRect.right) + // Now entirely off right-hand side, so stop drawing + break; + + // Partially clipped on right-hand side + charRect.right += clipRect.right - textPt.x - charRect.width(); + } + + // At this point, we know we've got to draw at least part of a character, + // and have figured out the area of the character to draw + copyRect(surface, textPt, charRect); + } +} + WriteCharacterResult STFont::writeChar(CVideoSurface *surface, unsigned char c, const Point &pt, const Rect &destRect, const Rect *srcRect) { if (c == 233) diff --git a/engines/titanic/support/font.h b/engines/titanic/support/font.h index 591fb4661c..6c4fe8e9c3 100644 --- a/engines/titanic/support/font.h +++ b/engines/titanic/support/font.h @@ -99,6 +99,12 @@ public: int yOffset, const CString &str, CTextCursor *textCursor); /** + * Write a string to the specified surface + */ + void writeString(CVideoSurface *surface, const Point &destPos, Rect &clipRect, + const CString &str, int lineWidth = 0); + + /** * Get the text area a string will fit into * @param str String * @param maxWidth Maximum width in pixels diff --git a/engines/titanic/support/mouse_cursor.cpp b/engines/titanic/support/mouse_cursor.cpp index 068267cb18..d342e6cccb 100644 --- a/engines/titanic/support/mouse_cursor.cpp +++ b/engines/titanic/support/mouse_cursor.cpp @@ -67,7 +67,6 @@ CMouseCursor::~CMouseCursor() { void CMouseCursor::loadCursorImages() { const CResourceKey key("ycursors.avi"); - g_vm->_filesManager->fn4(key.getString()); // Iterate through getting each cursor for (int idx = 0; idx < NUM_CURSORS; ++idx) { @@ -128,8 +127,11 @@ void CMouseCursor::unlockE4() { CScreenManager::_screenManagerPtr->_inputHandler->decLockCount(); } -void CMouseCursor::saveState(int v1, int v2, int v3) { - // TODO +void CMouseCursor::setPosition(const Point &pt, double rate) { + assert(rate >= 0.0 && rate <= 1.0); + + // TODO: Figure out use of the rate parameter + g_system->warpMouse(pt.x, pt.y); } } // End of namespace Titanic diff --git a/engines/titanic/support/mouse_cursor.h b/engines/titanic/support/mouse_cursor.h index 7a81ad43fa..74fb1f6113 100644 --- a/engines/titanic/support/mouse_cursor.h +++ b/engines/titanic/support/mouse_cursor.h @@ -24,8 +24,8 @@ #define TITANIC_MOUSE_CURSOR_H #include "common/scummsys.h" -#include "common/rect.h" #include "graphics/managed_surface.h" +#include "titanic/support/rect.h" namespace Titanic { @@ -105,7 +105,10 @@ public: void lockE4(); void unlockE4(); - void saveState(int v1, int v2, int v3); + /** + * Sets the mouse to a new position + */ + void setPosition(const Point &pt, double rate); }; diff --git a/engines/titanic/support/screen_manager.cpp b/engines/titanic/support/screen_manager.cpp index b0d852104c..bcf43fc8cb 100644 --- a/engines/titanic/support/screen_manager.cpp +++ b/engines/titanic/support/screen_manager.cpp @@ -239,10 +239,25 @@ int OSScreenManager::writeString(int surfaceNum, const Rect &destRect, yOffset, str, textCursor); } -int OSScreenManager::writeString(int surfaceNum, const Rect &srcRect, - const Rect &destRect, const CString &str, CTextCursor *textCursor) { - // TODO - return 0; +void OSScreenManager::writeString(int surfaceNum, const Point &destPos, + const Rect &clipRect, const CString &str, int lineWidth) { + CVideoSurface *surface; + Rect bounds; + + if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) { + surface = _backSurfaces[surfaceNum]._surface; + bounds = _backSurfaces[surfaceNum]._bounds; + } else if (surfaceNum == -1) { + surface = _frontRenderSurface; + bounds = Rect(0, 0, surface->getWidth(), surface->getHeight()); + } else { + return; + } + + Rect destRect = clipRect; + destRect.constrain(bounds); + + _fonts[_fontNumber].writeString(surface, destPos, destRect, str, lineWidth); } void OSScreenManager::setFontColor(byte r, byte g, byte b) { diff --git a/engines/titanic/support/screen_manager.h b/engines/titanic/support/screen_manager.h index 0736f1393c..cad6901b02 100644 --- a/engines/titanic/support/screen_manager.h +++ b/engines/titanic/support/screen_manager.h @@ -140,13 +140,13 @@ public: /** * Write a string * @param surfaceNum Destination surface - * @param srcRect Drawing area - * @param destRect Bounds of dest surface + * @param destPos Position to start writing text at + * @param clipRect Clipping area to constrain text to * @param str Line or lines to write - * @param textCursor Optional text cursor pointer + * @param maxWidth Maximum allowed line width */ - virtual int writeString(int surfaceNum, const Rect &srcRect, - const Rect &destRect, const CString &str, CTextCursor *textCursor) = 0; + virtual void writeString(int surfaceNum, const Point &destPos, + const Rect &clipRect, const CString &str, int maxWidth) = 0; /** * Set the font color @@ -322,13 +322,13 @@ public: /** * Write a string * @param surfaceNum Destination surface - * @param srcRect Drawing area - * @param destRect Bounds of dest surface + * @param destPos Position to start writing text at + * @param clipRect Clipping area to constrain text to * @param str Line or lines to write - * @param textCursor Optional text cursor pointer + * @param lineWidth Width in pixels of the string, if known. */ - virtual int writeString(int surfaceNum, const Rect &srcRect, - const Rect &destRect, const CString &str, CTextCursor *textCursor); + virtual void writeString(int surfaceNum, const Point &destPos, + const Rect &clipRect, const CString &str, int lineWidth = 0); /** * Set the font color diff --git a/engines/titanic/support/string_parser.cpp b/engines/titanic/support/string_parser.cpp new file mode 100644 index 0000000000..496440a973 --- /dev/null +++ b/engines/titanic/support/string_parser.cpp @@ -0,0 +1,97 @@ +/* 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 "titanic/support/string_parser.h" +#include "common/util.h" + +namespace Titanic { + +void CStringParser::skipSeperators(const CString &seperatorChars) { + for (; _index < size(); ++_index) { + char c = (*this)[_index]; + if (seperatorChars.indexOf(c) == -1) + break; + } +} + +bool CStringParser::parse(CString &resultStr, const CString &seperatorChars, bool allowQuotes) { + if (_index >= size()) + return false; + + resultStr.clear(); + bool quoteFlag = false; + while (_index < size()) { + char c = (*this)[_index]; + if (!quoteFlag && seperatorChars.indexOf(c) >= 0) + break; + + if (allowQuotes) { + if (quoteFlag) { + if (c == '"') { + // End of quoted string + ++_index; + break; + } + } else { + if (c == '"') { + // Start of quoted string + ++_index; + quoteFlag = true; + continue; + } + } + } + + resultStr += c; + ++_index; + } + + return true; +} + +uint CStringParser::readInt() { + // Get digits from the string + CString numStr; + while (Common::isDigit(currentChar())) + numStr += getNextChar(); + + // Throw a wobbly if there wasn't a number + if (numStr.empty()) + error("ReadInt(): No number to read"); + + return atoi(numStr.c_str()); +} + +char CStringParser::currentChar() const { + return (_index >= size()) ? '\0' : (*this)[_index]; +} + +char CStringParser::getNextChar() { + return (_index >= size()) ? '\0' : (*this)[_index++]; +} + +void CStringParser::skipSpaces() { + while (_index < size() && Common::isSpace(currentChar())) + ++_index; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/string_parser.h b/engines/titanic/support/string_parser.h new file mode 100644 index 0000000000..f89caacfb5 --- /dev/null +++ b/engines/titanic/support/string_parser.h @@ -0,0 +1,76 @@ +/* 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 TITANIC_STRING_PARSER_H +#define TITANIC_STRING_PARSER_H + +#include "titanic/support/string.h" + +namespace Titanic { + +class CStringParser : public CString { +private: + uint _index; +private: + /** + * Gets the character at the current index + */ + char currentChar() const; + + /** + * Gets the next character, and increments the parsing index + */ + char getNextChar(); + + /** + * Skips over any spaces + */ + void skipSpaces(); +public: + CStringParser() : CString(), _index(0) {} + CStringParser(const CString &str) : CString(str), _index(0) {} + + /** + * Skips over any specified seperator characters in our string + * at the current index + */ + void skipSeperators(const CString &seperatorChars); + + /** + * Parses out a string from a source string at the current index + * @param resultStr String to hold the resulting sring + * @param seperatorChras List of characters that seperate string values + * @param allowQuotes If true, handles double-quoted substrings + * @returns True if a string entry was extracted + */ + bool parse(CString &resultStr, const CString &seperatorChars, bool allowQuotes = false); + + /** + * Reads an integer from the string + */ + uint readInt(); + +}; + +} // End of namespace Titanic + +#endif /* TITANIC_STRING_PARSER_H */ diff --git a/engines/titanic/support/video_surface.cpp b/engines/titanic/support/video_surface.cpp index 594f660937..b5f668793a 100644 --- a/engines/titanic/support/video_surface.cpp +++ b/engines/titanic/support/video_surface.cpp @@ -163,7 +163,19 @@ void CVideoSurface::blitRect2(const Rect &srcRect, const Rect &destRect, CVideoS } void CVideoSurface::movieBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { - // TODO + if (lock()) { + if (src->lock()) { + Graphics::ManagedSurface *srcSurface = src->_rawSurface; + Graphics::ManagedSurface *destSurface = _rawSurface; + + // TODO: Handle the transparency mode correctly + destSurface->blitFrom(*srcSurface, srcRect, Point(srcRect.left, srcRect.top)); + + src->unlock(); + } + + unlock(); + } } uint CVideoSurface::getTransparencyColor() { diff --git a/engines/titanic/true_talk/title_engine.cpp b/engines/titanic/true_talk/title_engine.cpp index 4dd45ba335..363cc3454c 100644 --- a/engines/titanic/true_talk/title_engine.cpp +++ b/engines/titanic/true_talk/title_engine.cpp @@ -66,10 +66,6 @@ int STtitleEngine::setResponse(TTscriptBase *script, TTresponse *response) { return 0; } -void STtitleEngine::dump(int val1, int val2) { - // TODO -} - SimpleFile *STtitleEngine::open(const CString &name) { Common::SeekableReadStream *stream = g_vm->_filesManager->getResource( CString::format("TEXT/%s", name.c_str())); diff --git a/engines/titanic/true_talk/title_engine.h b/engines/titanic/true_talk/title_engine.h index afd2d3b92f..a980e52215 100644 --- a/engines/titanic/true_talk/title_engine.h +++ b/engines/titanic/true_talk/title_engine.h @@ -57,12 +57,6 @@ public: * Sets a conversation reponse */ virtual int setResponse(TTscriptBase *script, TTresponse *response) { return SS_4; } - - virtual int proc4(int unused) const = 0; - virtual int proc5(int64 unused) const = 0; - virtual int proc6(int64 unused) const = 0; - virtual int proc7(int64 unused) const = 0; - virtual int proc8() const = 0; /** * Open a designated file @@ -94,14 +88,6 @@ public: */ virtual int setResponse(TTscriptBase *script, TTresponse *response); - virtual void dump(int val1, int val2); - - virtual int proc4(int unused) const { return 0; } - virtual int proc5(int64 unused) const { return 0; } - virtual int proc6(int64 unused) const { return 0; } - virtual int proc7(int64 unused) const { return 0; } - virtual int proc8() const { return 0; } - /** * Open a designated file */ diff --git a/engines/titanic/true_talk/true_talk_manager.cpp b/engines/titanic/true_talk/true_talk_manager.cpp index 19beee9796..c5fd43ebfd 100644 --- a/engines/titanic/true_talk/true_talk_manager.cpp +++ b/engines/titanic/true_talk/true_talk_manager.cpp @@ -219,10 +219,6 @@ void CTrueTalkManager::removeCompleted() { } } -void CTrueTalkManager::update2() { - //warning("CTrueTalkManager::update2"); -} - void CTrueTalkManager::start(CTrueTalkNPC *npc, uint id, CViewItem *view) { TTnpcScript *npcScript = getNpcScript(npc); TTroomScript *roomScript = getRoomScript(); @@ -589,9 +585,9 @@ int CTrueTalkManager::getPassengerClass() const { return gameState ? gameState->_passengerClass : 4; } -int CTrueTalkManager::getState14() const { +Season CTrueTalkManager::getCurrentSeason() const { CGameState *gameState = getGameState(); - return gameState ? gameState->_field14 : 0; + return gameState ? gameState->_seasonNum : SEASON_SUMMER; } } // End of namespace Titanic diff --git a/engines/titanic/true_talk/true_talk_manager.h b/engines/titanic/true_talk/true_talk_manager.h index 8a8895917a..e891f6112a 100644 --- a/engines/titanic/true_talk/true_talk_manager.h +++ b/engines/titanic/true_talk/true_talk_manager.h @@ -31,6 +31,7 @@ #include "titanic/true_talk/tt_quotes_tree.h" #include "titanic/true_talk/tt_scripts.h" #include "titanic/true_talk/tt_talker.h" +#include "titanic/game_state.h" namespace Titanic { @@ -200,8 +201,6 @@ public: */ CGameManager *getGameManager() const; - void update2(); - /** * Start a TrueTalk conversation */ @@ -237,7 +236,7 @@ public: */ int getPassengerClass() const; - int getState14() const; + Season getCurrentSeason() const; }; } // End of namespace Titanic diff --git a/engines/titanic/true_talk/tt_npc_script.cpp b/engines/titanic/true_talk/tt_npc_script.cpp index 61c3b0e00c..280894c05a 100644 --- a/engines/titanic/true_talk/tt_npc_script.cpp +++ b/engines/titanic/true_talk/tt_npc_script.cpp @@ -579,14 +579,14 @@ int TTnpcScript::getValue(int testNum) const { case 4: if (g_vm->_trueTalkManager) { - switch (g_vm->_trueTalkManager->getState14()) { - case 1: + switch (g_vm->_trueTalkManager->getCurrentSeason()) { + case SEASON_AUTUMN: CTrueTalkManager::_v6 = 3; break; - case 2: + case SEASON_WINTER: CTrueTalkManager::_v6 = 0; break; - case 3: + case SEASON_SPRING: CTrueTalkManager::_v6 = 1; break; default: diff --git a/engines/wage/design.cpp b/engines/wage/design.cpp index 86b325e2b9..fd2a67b81e 100644 --- a/engines/wage/design.cpp +++ b/engines/wage/design.cpp @@ -235,9 +235,9 @@ void drawPixel(int x, int y, int color, void *data) { color : kColorWhite; } } else { - int x1 = x; + int x1 = x - p->thickness / 2; int x2 = x1 + p->thickness; - int y1 = y; + int y1 = y - p->thickness / 2; int y2 = y1 + p->thickness; for (y = y1; y < y2; y++) diff --git a/graphics/primitives.cpp b/graphics/primitives.cpp index ac1c58b1d8..8663a61606 100644 --- a/graphics/primitives.cpp +++ b/graphics/primitives.cpp @@ -108,15 +108,13 @@ void drawThickLine2(int x1, int y1, int x2, int y2, int thick, int color, void ( int dy = abs(y2 - y1); if (dx == 0) { - if (y1 > y2) - SWAP(y1, y2); - Common::Rect r(x1, y1, x1 + thick - 1, y2); + int xn = x1 - thick / 2; + Common::Rect r(xn, MIN(y1, y2), xn + thick - 1, MAX(y1, y2)); drawFilledRect(r, color, plotProc, data); return; } else if (dy == 0) { - if (x1 > x2) - SWAP(x1, x2); - Common::Rect r(x1, y1, x2, y1 + thick - 1); + int yn = y1 - thick / 2; + Common::Rect r(MIN(x1, x2), yn, MAX(x1, x2), yn + thick - 1); drawFilledRect(r, color, plotProc, data); return; } |