[Scummvm-git-logs] scummvm master -> 0e192ba542f818f4551aa5f6f2b0dee11e74d68e
fracturehill
noreply at scummvm.org
Sun Sep 24 14:44:10 UTC 2023
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
c20f765032 NANCY: Add console command to display hotspots
4bceadfb6a NANCY: Fix movies in The Vampire Diaries
4e20ddd030 NANCY: Do not add a single item multiple times
82c3d2ae0b NANCY: Implement table indexing record types
9dd73a5edb NANCY: Only set minimum volume in nancy3 and up
0e192ba542 NANCY: Describe all ActionRecords
Commit: c20f7650320c65a9eb51758cce7904ed5fc2aca7
https://github.com/scummvm/scummvm/commit/c20f7650320c65a9eb51758cce7904ed5fc2aca7
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-24T17:43:28+03:00
Commit Message:
NANCY: Add console command to display hotspots
Changed paths:
engines/nancy/action/actionmanager.cpp
engines/nancy/action/actionmanager.h
engines/nancy/console.cpp
engines/nancy/console.h
engines/nancy/state/scene.cpp
engines/nancy/state/scene.h
diff --git a/engines/nancy/action/actionmanager.cpp b/engines/nancy/action/actionmanager.cpp
index 1534cff080a..abc284a9909 100644
--- a/engines/nancy/action/actionmanager.cpp
+++ b/engines/nancy/action/actionmanager.cpp
@@ -27,6 +27,8 @@
#include "engines/nancy/nancy.h"
#include "engines/nancy/input.h"
#include "engines/nancy/sound.h"
+#include "engines/nancy/font.h"
+#include "engines/nancy/graphics.h"
#include "engines/nancy/action/actionmanager.h"
#include "engines/nancy/action/actionrecord.h"
@@ -72,6 +74,8 @@ void ActionManager::handleInput(NancyInput &input) {
} else {
rec->_state = ActionRecord::ExecutionState::kActionTrigger;
+ input.eatMouseInput();
+
if (rec->_cursorDependency) {
int16 item = rec->_cursorDependency->label;
if (item > 100 && item <= (100 + g_nancy->getStaticData().numItems)) {
@@ -245,6 +249,8 @@ void ActionManager::processActionRecords() {
record->execute();
}
}
+
+ debugDrawHotspots();
}
void ActionManager::processDependency(DependencyRecord &dep, ActionRecord &record, bool doNotCheckCursor) {
@@ -529,5 +535,39 @@ void ActionManager::synchronize(Common::Serializer &ser) {
}
}
+void ActionManager::debugDrawHotspots() {
+ // Draws a rectangle around (non-puzzle) hotspots as well as the id
+ // and type of the owning ActionRecord. Hardcoded to font 0 since that's
+ // the smallest one available in the engine.
+ RenderObject &obj = NancySceneState._hotspotDebug;
+ if (ConfMan.getBool("debug_hotspots", ConfMan.kTransientDomain)) {
+ const Font *font = g_nancy->_graphicsManager->getFont(0);
+ assert(font);
+ uint16 yOffset = NancySceneState.getViewport().getCurVerticalScroll();
+ obj.setVisible(true);
+ obj._drawSurface.clear(obj._drawSurface.getTransparentColor());
+
+ for (uint i = 0; i < _records.size(); ++i) {
+ ActionRecord *rec = _records[i];
+ if (rec->_hasHotspot) {
+ Common::Rect hotspot = rec->_hotspot;
+ hotspot.translate(0, -yOffset);
+ hotspot.clip(obj._drawSurface.getBounds());
+
+ if (!hotspot.isEmpty()) {
+ font->drawString(&obj._drawSurface, Common::String::format("%u, %s", i, rec->getRecordTypeName().c_str()),
+ hotspot.left, hotspot.bottom - font->getFontHeight() - 2, hotspot.width(), 0,
+ Graphics::kTextAlignCenter, 0, true);
+ obj._drawSurface.frameRect(hotspot, 0xFFFFFF);
+ }
+ }
+ }
+ } else {
+ if (obj.isVisible()) {
+ obj.setVisible(false);
+ }
+ }
+}
+
} // End of namespace Action
} // End of namespace Nancy
diff --git a/engines/nancy/action/actionmanager.h b/engines/nancy/action/actionmanager.h
index dd293560958..1bfad205dfa 100644
--- a/engines/nancy/action/actionmanager.h
+++ b/engines/nancy/action/actionmanager.h
@@ -75,6 +75,8 @@ protected:
static ActionRecord *createActionRecord(uint16 type);
static ActionRecord *createAndLoadNewRecord(Common::SeekableReadStream &inputData);
+ void debugDrawHotspots();
+
Common::Array<ActionRecord *> _records;
};
diff --git a/engines/nancy/console.cpp b/engines/nancy/console.cpp
index 3d16ceb7e89..59fc9b85d91 100644
--- a/engines/nancy/console.cpp
+++ b/engines/nancy/console.cpp
@@ -21,6 +21,7 @@
#include "common/system.h"
#include "common/events.h"
+#include "common/config-manager.h"
#include "audio/audiostream.h"
@@ -66,6 +67,7 @@ NancyConsole::NancyConsole() : GUI::Debugger() {
registerCmd("get_difficulty", WRAP_METHOD(NancyConsole, Cmd_getDifficulty));
registerCmd("set_difficulty", WRAP_METHOD(NancyConsole, Cmd_setDifficulty));
registerCmd("sound_info", WRAP_METHOD(NancyConsole, Cmd_soundInfo));
+ registerCmd("debug_hotspots", WRAP_METHOD(NancyConsole, Cmd_showHotspots));
}
@@ -1013,4 +1015,11 @@ bool NancyConsole::Cmd_soundInfo(int argc, const char **argv) {
return true;
}
+bool NancyConsole::Cmd_showHotspots(int argc, const char **argv) {
+ ConfMan.setBool("debug_hotspots", !ConfMan.getBool("debug_hotspots", ConfMan.kTransientDomain), ConfMan.kTransientDomain);
+
+ return cmdExit(0, nullptr);
+}
+
+
} // End of namespace Nancy
diff --git a/engines/nancy/console.h b/engines/nancy/console.h
index d4dca79d872..48b00d13e3d 100644
--- a/engines/nancy/console.h
+++ b/engines/nancy/console.h
@@ -66,6 +66,7 @@ private:
bool Cmd_getDifficulty(int argc, const char **argv);
bool Cmd_setDifficulty(int argc, const char **argv);
bool Cmd_soundInfo(int argc, const char **argv);
+ bool Cmd_showHotspots(int argc, const char **argv);
void printActionRecord(const Nancy::Action::ActionRecord *record, bool noDependencies = false);
void recursePrintDependencies(const Nancy::Action::DependencyRecord &record);
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index 7a900e9ae0e..f888055ea75 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -119,7 +119,8 @@ Scene::Scene() :
_difficulty(0),
_activeConversation(nullptr),
_lightning(nullptr),
- _destroyOnExit(false) {}
+ _destroyOnExit(false),
+ _hotspotDebug(50) {}
Scene::~Scene() {
delete _helpButton;
@@ -497,6 +498,7 @@ void Scene::registerGraphics() {
_viewport.registerGraphics();
_textbox.registerGraphics();
_inventoryBox.registerGraphics();
+ _hotspotDebug.registerGraphics();
if (_menuButton) {
_menuButton->registerGraphics();
@@ -718,6 +720,11 @@ void Scene::init() {
_lightning = new Misc::Lightning();
}
+ Common::Rect vpPos = _viewport.getScreenPosition();
+ _hotspotDebug._drawSurface.create(vpPos.width(), vpPos.height(), g_nancy->_graphicsManager->getScreenPixelFormat());
+ _hotspotDebug.moveTo(vpPos);
+ _hotspotDebug.setTransparent(true);
+
registerGraphics();
g_nancy->_graphicsManager->redrawAll();
}
diff --git a/engines/nancy/state/scene.h b/engines/nancy/state/scene.h
index 81592c22e6a..363b6dec8b2 100644
--- a/engines/nancy/state/scene.h
+++ b/engines/nancy/state/scene.h
@@ -290,6 +290,8 @@ private:
// Contains a screenshot of the Scene state from the last time it was exited
Graphics::ManagedSurface _lastScreenshot;
+ RenderObject _hotspotDebug;
+
bool _destroyOnExit;
State _state;
Commit: 4bceadfb6afc9ada770675f19240602a5cc2d025
https://github.com/scummvm/scummvm/commit/4bceadfb6afc9ada770675f19240602a5cc2d025
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-24T17:43:28+03:00
Commit Message:
NANCY: Fix movies in The Vampire Diaries
This fixes a regression that would cause small-size movies
(like the ones in TVD) to not display correctly.
Changed paths:
engines/nancy/action/secondarymovie.cpp
engines/nancy/action/secondarymovie.h
diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index 6637652c449..ae4d7d9d073 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -50,7 +50,7 @@ void PlaySecondaryMovie::readData(Common::SeekableReadStream &stream) {
readFilename(ser, _bitmapOverlayName);
ser.skip(2); // videoPlaySource
- ser.skip(2); // smallSize
+ ser.syncAsUint16LE(_videoFormat);
ser.skip(4, kGameTypeVampire, kGameTypeVampire); // paletteStart, paletteSize
ser.skip(2); // hasBitmapOverlaySurface
ser.skip(2); // VIDEO_STOP_RENDERING, VIDEO_CONTINUE_RENDERING
@@ -173,8 +173,8 @@ void PlaySecondaryMovie::execute() {
}
}
- GraphicsManager::copyToManaged(*_decoder.decodeNextFrame(), _fullFrame, _paletteName.size() > 0);
- _drawSurface.create(_fullFrame, _videoDescs[_curViewportFrame].srcRect);
+ GraphicsManager::copyToManaged(*_decoder.decodeNextFrame(), _fullFrame, g_nancy->getGameType() == kGameTypeVampire, _videoFormat == kSmallVideoFormat);
+ _drawSurface.create(_fullFrame, _videoDescs[descID].srcRect);
moveTo(_videoDescs[descID].destRect);
_needsRedraw = true;
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index c412e6134a9..72831cf9578 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -57,6 +57,7 @@ public:
Common::String _paletteName;
Common::String _bitmapOverlayName;
+ uint16 _videoFormat = kLargeVideoFormat;
uint16 _videoSceneChange = kMovieNoSceneChange;
byte _playerCursorAllowed = kPlayerCursorAllowed;
byte _playDirection = kPlayMovieForward;
Commit: 4e20ddd03015471320d22d06f84d78aae54f28be
https://github.com/scummvm/scummvm/commit/4e20ddd03015471320d22d06f84d78aae54f28be
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-24T17:43:28+03:00
Commit Message:
NANCY: Do not add a single item multiple times
Fixed a silly bug in TVD where a cutscene can give the player
multiple copies of the same item.
Changed paths:
engines/nancy/state/scene.cpp
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index f888055ea75..ffacc9df2b3 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -273,28 +273,32 @@ byte Scene::getPlayerTOD() const {
}
void Scene::addItemToInventory(uint16 id) {
- _flags.items[id] = g_nancy->_true;
- if (_flags.heldItem == id) {
- setHeldItem(-1);
- }
-
- g_nancy->_sound->playSound("BUOK");
+ if (_flags.items[id] == g_nancy->_false) {
+ _flags.items[id] = g_nancy->_true;
+ if (_flags.heldItem == id) {
+ setHeldItem(-1);
+ }
+
+ g_nancy->_sound->playSound("BUOK");
- _inventoryBox.addItem(id);
+ _inventoryBox.addItem(id);
+ }
}
void Scene::removeItemFromInventory(uint16 id, bool pickUp) {
- _flags.items[id] = g_nancy->_false;
+ if (_flags.items[id] == g_nancy->_true || getHeldItem() == id) {
+ _flags.items[id] = g_nancy->_false;
- if (pickUp) {
- setHeldItem(id);
- } else if (getHeldItem() == id) {
- setHeldItem(-1);
- }
-
- g_nancy->_sound->playSound("BUOK");
+ if (pickUp) {
+ setHeldItem(id);
+ } else if (getHeldItem() == id) {
+ setHeldItem(-1);
+ }
+
+ g_nancy->_sound->playSound("BUOK");
- _inventoryBox.removeItem(id);
+ _inventoryBox.removeItem(id);
+ }
}
void Scene::setHeldItem(int16 id) {
Commit: 82c3d2ae0b6360662c8846c8dc01784f9d75feff
https://github.com/scummvm/scummvm/commit/82c3d2ae0b6360662c8846c8dc01784f9d75feff
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-24T17:43:28+03:00
Commit Message:
NANCY: Implement table indexing record types
Added support for three different action records types
(TableIndexOverlay, TableIndexPlaySound, and
TableIndexSetValueHS), all of which use nancy6's newly-
introduced TABL chunk, which describes a table of values
that can be changed through interaction. This is used
in nancy6's museum narrations puzzle.
Changed paths:
engines/nancy/action/arfactory.cpp
engines/nancy/action/miscrecords.cpp
engines/nancy/action/miscrecords.h
engines/nancy/action/overlay.cpp
engines/nancy/action/overlay.h
engines/nancy/action/soundrecords.cpp
engines/nancy/action/soundrecords.h
engines/nancy/commontypes.h
engines/nancy/enginedata.cpp
engines/nancy/enginedata.h
engines/nancy/nancy.cpp
engines/nancy/puzzledata.cpp
engines/nancy/puzzledata.h
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 225f2345f4e..05b5b3814f6 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -113,7 +113,10 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
case 53:
return new PlaySecondaryMovie();
case 54:
- return new Overlay(false); // PlayStaticBitmapAnimation
+ if (g_nancy->getGameType() <= kGameTypeNancy1) {
+ return new Overlay(false); // PlayStaticBitmapAnimation
+ }
+ // fall through
case 55:
return new Overlay(true); // PlayIntStaticBitmapAnimation
case 56:
@@ -140,6 +143,12 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
}
case 62:
return new MapCallHotMultiframe();
+ case 65:
+ return new TableIndexOverlay();
+ case 66:
+ return new TableIndexPlaySound();
+ case 67:
+ return new TableIndexSetValueHS();
case 75:
return new TextBoxWrite();
case 76:
diff --git a/engines/nancy/action/miscrecords.cpp b/engines/nancy/action/miscrecords.cpp
index 0031134b6f5..fbca13c8b77 100644
--- a/engines/nancy/action/miscrecords.cpp
+++ b/engines/nancy/action/miscrecords.cpp
@@ -89,6 +89,90 @@ void SpecialEffect::execute() {
_isDone = true;
}
+void TableIndexSetValueHS::readData(Common::SeekableReadStream &stream) {
+ _tableIndex = stream.readUint16LE();
+ _valueChangeType = stream.readByte();
+ _entryCorrectFlagID = stream.readSint16LE();
+ _allEntriesCorrectFlagID = stream.readSint16LE();
+
+ _flags.readData(stream);
+ _cursorType = stream.readUint16LE();
+ uint16 numHotspots = stream.readUint16LE();
+ _hotspots.resize(numHotspots);
+ for (uint i = 0; i < numHotspots; ++i) {
+ _hotspots[i].readData(stream);
+ }
+}
+
+void TableIndexSetValueHS::execute() {
+ switch (_state) {
+ case kBegin:
+ _state = kRun;
+ // fall through
+ case kRun:
+ _hasHotspot = false;
+ for (uint i = 0; i < _hotspots.size(); ++i) {
+ if (_hotspots[i].frameID == NancySceneState.getSceneInfo().frameID) {
+ _hasHotspot = true;
+ _hotspot = _hotspots[i].coords;
+ }
+ }
+ break;
+ case kActionTrigger: {
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+ const TABL *tabl = (const TABL *)g_nancy->getEngineData("TABL");
+ assert(tabl);
+
+ // Edit table. Values start from 1!
+ switch (_valueChangeType) {
+ case kNoChangeTableValue:
+ break;
+ case kIncrementTableValue:
+ ++playerTable->currentIDs[_tableIndex - 1];
+ if (playerTable->currentIDs[_tableIndex - 1] >= playerTable->currentIDs.size() + 1) {
+ playerTable->currentIDs[_tableIndex - 1] = 1;
+ }
+ break;
+ case kDecrementTableValue:
+ --playerTable->currentIDs[_tableIndex - 1];
+ if (playerTable->currentIDs[_tableIndex - 1] == 0) {
+ playerTable->currentIDs[_tableIndex - 1] = playerTable->currentIDs.size();
+ }
+
+ break;
+ }
+
+ // Check for correctness...
+
+ // ...of current index only...
+ if (playerTable->currentIDs[_tableIndex] == tabl->correctIDs[_tableIndex]) {
+ NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_true);
+ } else {
+ NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_false);
+ }
+
+ // ..and of all indices
+ bool allCorrect = true;
+ for (uint i = 0; i < tabl->correctIDs.size(); ++i) {
+ if (playerTable->currentIDs[i] != tabl->correctIDs[i]) {
+ allCorrect = false;
+ break;
+ }
+ }
+
+ if (allCorrect) {
+ NancySceneState.setEventFlag(_allEntriesCorrectFlagID, g_nancy->_true);
+ } else {
+ NancySceneState.setEventFlag(_allEntriesCorrectFlagID, g_nancy->_false);
+ }
+
+ _flags.execute();
+ finishExecution();
+ }
+ }
+}
+
void LightningOn::execute() {
NancySceneState.beginLightning(_distance, _pulseTime, _rgbPercent);
_isDone = true;
diff --git a/engines/nancy/action/miscrecords.h b/engines/nancy/action/miscrecords.h
index 9d5fa5bf9a2..ce5782a2192 100644
--- a/engines/nancy/action/miscrecords.h
+++ b/engines/nancy/action/miscrecords.h
@@ -85,6 +85,26 @@ protected:
Common::String getRecordTypeName() const override { return "SpecialEffect"; }
};
+class TableIndexSetValueHS : public ActionRecord {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+ CursorManager::CursorType getHoverCursor() const override { return (CursorManager::CursorType)_cursorType; }
+
+protected:
+ Common::String getRecordTypeName() const override { return "TableIndexSetValueHS"; }
+
+ uint16 _tableIndex = 0;
+ byte _valueChangeType = kNoChangeTableValue;
+ int16 _entryCorrectFlagID = -1;
+ int16 _allEntriesCorrectFlagID = -1;
+
+ MultiEventFlagDescription _flags;
+ uint16 _cursorType = 1;
+ Common::Array<HotspotDescription> _hotspots;
+};
+
class TextBoxWrite : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index c6915e66c71..77544017f95 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -104,13 +104,9 @@ void Overlay::readData(Common::SeekableReadStream &stream) {
ser.syncAsUint16LE(_z, kGameTypeNancy1, kGameTypeNancy1);
- if (ser.getVersion() > kGameTypeNancy1) {
- _isInterruptible = true;
-
- if (ser.getVersion() > kGameTypeNancy2) {
- if (_overlayType == kPlayOverlayStatic) {
- _enableHotspot = (_hasSceneChange == kPlayOverlaySceneChange) ? kPlayOverlayWithHotspot : kPlayOverlayNoHotspot;
- }
+ if (ser.getVersion() > kGameTypeNancy2) {
+ if (_overlayType == kPlayOverlayStatic) {
+ _enableHotspot = (_hasSceneChange == kPlayOverlaySceneChange) ? kPlayOverlayWithHotspot : kPlayOverlayNoHotspot;
}
}
@@ -351,5 +347,32 @@ void Overlay::setFrame(uint frame) {
_needsRedraw = true;
}
+void TableIndexOverlay::readData(Common::SeekableReadStream &stream) {
+ _tableIndex = stream.readUint16LE();
+ Overlay::readData(stream);
+}
+
+void TableIndexOverlay::execute() {
+ if (_state == kBegin) {
+ Overlay::execute();
+ }
+
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+ const TABL *tabl = (const TABL *)g_nancy->getEngineData("TABL");
+ assert(tabl);
+
+ if (_lastIndexVal != playerTable->currentIDs[_tableIndex - 1]) {
+ _lastIndexVal = playerTable->currentIDs[_tableIndex - 1];
+ _srcRects.clear();
+ _srcRects.push_back(tabl->srcRects[_lastIndexVal - 1]);
+ _currentViewportFrame = -1; // Force redraw
+ }
+
+ if (_state != kBegin) {
+ Overlay::execute();
+ }
+}
+
} // End of namespace Action
} // End of namespace Nancy
diff --git a/engines/nancy/action/overlay.h b/engines/nancy/action/overlay.h
index b71a7df15f6..f2748932069 100644
--- a/engines/nancy/action/overlay.h
+++ b/engines/nancy/action/overlay.h
@@ -85,6 +85,21 @@ protected:
Graphics::ManagedSurface _staticModeIntermediate;
};
+class TableIndexOverlay : public Overlay {
+public:
+ TableIndexOverlay() : Overlay(true) {}
+ virtual ~TableIndexOverlay() {}
+
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+protected:
+ Common::String getRecordTypeName() const override { return "TableIndexOverlay"; }
+
+ uint16 _tableIndex = 0;
+ int16 _lastIndexVal = -1;
+};
+
} // End of namespace Action
} // End of namespace Nancy
diff --git a/engines/nancy/action/soundrecords.cpp b/engines/nancy/action/soundrecords.cpp
index ec6ae23e42a..443c87cd7bc 100644
--- a/engines/nancy/action/soundrecords.cpp
+++ b/engines/nancy/action/soundrecords.cpp
@@ -196,5 +196,27 @@ void PlayRandomSound::execute() {
PlayDigiSound::execute();
}
+void TableIndexPlaySound::readData(Common::SeekableReadStream &stream) {
+ _tableIndex = stream.readUint16LE();
+ PlayDigiSound::readData(stream); // Data does NOT contain captions, so we call the PlayDigiSound version
+}
+
+void TableIndexPlaySound::execute() {
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+ const TABL *tabl = (const TABL *)g_nancy->getEngineData("TABL");
+ assert(tabl);
+
+ if (_lastIndexVal != playerTable->currentIDs[_tableIndex - 1]) {
+ g_nancy->_sound->stopSound(_sound);
+ NancySceneState.getTextbox().clear();
+ _lastIndexVal = playerTable->currentIDs[_tableIndex - 1];
+ _sound.name = Common::String::format("%s%u", tabl->soundBaseName.c_str(), playerTable->currentIDs[_tableIndex - 1]);
+ _ccText = tabl->strings[playerTable->currentIDs[_tableIndex - 1] - 1];
+ }
+
+ PlayDigiSoundCC::execute();
+}
+
} // End of namespace Action
} // End of namespace Nancy
diff --git a/engines/nancy/action/soundrecords.h b/engines/nancy/action/soundrecords.h
index 2fb4be28a83..09d8ea64144 100644
--- a/engines/nancy/action/soundrecords.h
+++ b/engines/nancy/action/soundrecords.h
@@ -106,6 +106,18 @@ protected:
Common::String getRecordTypeName() const override { return "PlayRandomSound"; }
};
+class TableIndexPlaySound : public PlayDigiSoundCC {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+protected:
+ Common::String getRecordTypeName() const override { return "TableIndexPlaySound"; }
+
+ uint16 _tableIndex = 0;
+ int16 _lastIndexVal = -1;
+};
+
} // End of namespace Action
} // End of namespace Nancy
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 32b2aa57d10..d145b5d79c3 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -103,6 +103,11 @@ static const byte kPlayOverlayReverse = 2;
static const byte kPlayOverlayWithHotspot = 1;
static const byte kPlayOverlayNoHotspot = 2;
+// Table access
+static const byte kNoChangeTableValue = 0;
+static const byte kIncrementTableValue = 1;
+static const byte kDecrementTableValue = 2;
+
enum MovementDirection : byte { kUp = 1, kDown = 2, kLeft = 4, kRight = 8, kMoveFast = 16 };
// Separate namespace to remove possible clashes
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index c805cae6160..07c4ca6949b 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -734,4 +734,32 @@ CVTX::CVTX(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
delete[] buf;
}
+TABL::TABL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
+ uint numEntries = chunkStream->readUint16LE();
+
+ readFilename(*chunkStream, soundBaseName);
+
+ startIDs.resize(numEntries);
+ for (uint i = 0; i < numEntries; ++i) {
+ startIDs[i] = chunkStream->readUint16LE();
+ }
+ chunkStream->skip((20 - numEntries) * 2);
+
+ correctIDs.resize(numEntries);
+ for (uint i = 0; i < numEntries; ++i) {
+ correctIDs[i] = chunkStream->readUint16LE();
+ }
+ chunkStream->skip((20 - numEntries) * 2);
+
+ readRectArray(*chunkStream, srcRects, numEntries, 20);
+
+ char buf[1000];
+ strings.resize(numEntries);
+ for (uint i = 0; i < numEntries; ++i) {
+ chunkStream->read(buf, 1000);
+ assembleTextLine(buf, strings[i], 1000);
+ }
+ chunkStream->skip((20 - numEntries) * 1000);
+}
+
} // End of namespace Nancy
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 76f0d67bfe9..7a54dedf738 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -430,6 +430,16 @@ struct CVTX : public EngineData {
Common::HashMap<Common::String, Common::String> texts;
};
+struct TABL : public EngineData {
+ TABL(Common::SeekableReadStream *chunkStream);
+
+ Common::String soundBaseName;
+ Common::Array<uint16> startIDs;
+ Common::Array<uint16> correctIDs;
+ Common::Array<Common::Rect> srcRects;
+ Common::Array<Common::String> strings;
+};
+
} // End of namespace Nancy
#endif // NANCY_ENGINEDATA_H
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 44a7e0043bc..3e40ccb46bd 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -422,6 +422,7 @@ void NancyEngine::bootGameEngine() {
LOAD_BOOT(SPEC)
LOAD_BOOT(RCPR)
LOAD_BOOT(RCLB)
+ LOAD_BOOT(TABL)
LOAD_BOOT_L(ImageChunk, "OB0")
LOAD_BOOT_L(ImageChunk, "FR0")
diff --git a/engines/nancy/puzzledata.cpp b/engines/nancy/puzzledata.cpp
index 722cc9e5f68..7a0a6199784 100644
--- a/engines/nancy/puzzledata.cpp
+++ b/engines/nancy/puzzledata.cpp
@@ -20,6 +20,8 @@
*/
#include "engines/nancy/puzzledata.h"
+#include "engines/nancy/enginedata.h"
+#include "engines/nancy/nancy.h"
namespace Nancy {
@@ -134,6 +136,24 @@ void JournalData::synchronize(Common::Serializer &ser) {
}
}
+TableData::TableData() {
+ const TABL *tabl = (const TABL *)g_nancy->getEngineData("TABL");
+ assert(tabl);
+
+ currentIDs = tabl->startIDs;
+}
+
+void TableData::synchronize(Common::Serializer &ser) {
+ byte num = currentIDs.size();
+ ser.syncAsByte(num);
+
+ if (ser.isLoading()) {
+ currentIDs.resize(num);
+ }
+
+ ser.syncArray(currentIDs.data(), num, Common::Serializer::Uint16LE);
+}
+
PuzzleData *makePuzzleData(const uint32 tag) {
switch(tag) {
case SliderPuzzleData::getTag():
@@ -148,6 +168,8 @@ PuzzleData *makePuzzleData(const uint32 tag) {
return new SoundEqualizerPuzzleData();
case JournalData::getTag():
return new JournalData();
+ case TableData::getTag():
+ return new TableData();
default:
return nullptr;
}
diff --git a/engines/nancy/puzzledata.h b/engines/nancy/puzzledata.h
index 4d71012e082..95a89ee7230 100644
--- a/engines/nancy/puzzledata.h
+++ b/engines/nancy/puzzledata.h
@@ -40,6 +40,7 @@ struct PuzzleData {
struct SliderPuzzleData : public PuzzleData {
SliderPuzzleData();
+ virtual ~SliderPuzzleData() {}
static constexpr uint32 getTag() { return MKTAG('S', 'L', 'I', 'D'); }
virtual void synchronize(Common::Serializer &ser);
@@ -50,6 +51,7 @@ struct SliderPuzzleData : public PuzzleData {
struct RippedLetterPuzzleData : public PuzzleData {
RippedLetterPuzzleData();
+ virtual ~RippedLetterPuzzleData() {}
static constexpr uint32 getTag() { return MKTAG('R', 'I', 'P', 'L'); }
virtual void synchronize(Common::Serializer &ser);
@@ -61,6 +63,7 @@ struct RippedLetterPuzzleData : public PuzzleData {
struct TowerPuzzleData : public PuzzleData {
TowerPuzzleData();
+ virtual ~TowerPuzzleData() {}
static constexpr uint32 getTag() { return MKTAG('T', 'O', 'W', 'R'); }
virtual void synchronize(Common::Serializer &ser);
@@ -71,6 +74,7 @@ struct TowerPuzzleData : public PuzzleData {
struct RiddlePuzzleData : public PuzzleData {
RiddlePuzzleData();
+ virtual ~RiddlePuzzleData() {}
static constexpr uint32 getTag() { return MKTAG('R', 'I', 'D', 'L'); }
virtual void synchronize(Common::Serializer &ser);
@@ -81,6 +85,7 @@ struct RiddlePuzzleData : public PuzzleData {
struct SoundEqualizerPuzzleData : public PuzzleData {
SoundEqualizerPuzzleData();
+ virtual ~SoundEqualizerPuzzleData() {}
static constexpr uint32 getTag() { return MKTAG('S', 'E', 'Q', 'L'); }
virtual void synchronize(Common::Serializer &ser);
@@ -98,6 +103,18 @@ struct JournalData : public PuzzleData {
Common::HashMap<uint16, Common::Array<Common::String>> journalEntries;
};
+// Contains data related to nancy6's exhibit puzzle, which
+// spans multiple scenes and uses several special-purpose AR types
+struct TableData : public PuzzleData {
+ TableData();
+ virtual ~TableData() {}
+
+ static constexpr uint32 getTag() { return MKTAG('T', 'A', 'B', 'L'); }
+ virtual void synchronize(Common::Serializer &ser);
+
+ Common::Array<uint16> currentIDs;
+};
+
PuzzleData *makePuzzleData(const uint32 tag);
} // End of namespace Nancy
Commit: 9dd73a5edb14c2ee82478a0ad48f1adf0e5c2b02
https://github.com/scummvm/scummvm/commit/9dd73a5edb14c2ee82478a0ad48f1adf0e5c2b02
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-24T17:43:29+03:00
Commit Message:
NANCY: Only set minimum volume in nancy3 and up
It seems the addition of a minimum volume for sounds only
got added when the sound system was revamped in nancy3.
This fixes an incorrect clock sound playing in the diner
in nancy1.
Changed paths:
engines/nancy/sound.cpp
diff --git a/engines/nancy/sound.cpp b/engines/nancy/sound.cpp
index 16f73c6d005..fb0b9eb6a17 100644
--- a/engines/nancy/sound.cpp
+++ b/engines/nancy/sound.cpp
@@ -304,7 +304,9 @@ void SoundManager::playSound(uint16 channelID) {
// Set a minimum volume (10 percent was chosen arbitrarily, but sounds reasonably close)
// Fix for nancy3 scene 6112, but NOT a hack; the original engine also set a minimum volume for all sounds
- chan.volume = 10 + ((int)chan.volume * 90) / 100;
+ if (g_nancy->getGameType() >= kGameTypeNancy3) {
+ chan.volume = 10 + ((int)chan.volume * 90) / 100;
+ }
// Init 3D sound
if (chan.playCommands & ~kPlaySequential && chan.effectData) {
Commit: 0e192ba542f818f4551aa5f6f2b0dee11e74d68e
https://github.com/scummvm/scummvm/commit/0e192ba542f818f4551aa5f6f2b0dee11e74d68e
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-24T17:43:29+03:00
Commit Message:
NANCY: Describe all ActionRecords
Added comments describing the uses of all currently
implemented non-puzzle ActionRecords.
Changed paths:
engines/nancy/action/autotext.h
engines/nancy/action/conversation.h
engines/nancy/action/miscrecords.h
engines/nancy/action/navigationrecords.h
engines/nancy/action/overlay.h
engines/nancy/action/secondarymovie.h
engines/nancy/action/secondaryvideo.h
engines/nancy/action/soundrecords.h
diff --git a/engines/nancy/action/autotext.h b/engines/nancy/action/autotext.h
index 5eb0c794eec..4d3bd90e63f 100644
--- a/engines/nancy/action/autotext.h
+++ b/engines/nancy/action/autotext.h
@@ -28,8 +28,7 @@
namespace Nancy {
namespace Action {
-// Action record used for rendering text inside the game viewport
-// (before its introduction all text outside the textbox was prerendered)
+// Action record used for rendering text inside the game viewport.
// Can be used in two ways: for single-use texts that get thrown away
// after a scene change, or for permanent storage (used in nancy's journal)
// Does not own or display any image data; it draws to a surface inside
diff --git a/engines/nancy/action/conversation.h b/engines/nancy/action/conversation.h
index bf8ec111603..535242fe8fb 100644
--- a/engines/nancy/action/conversation.h
+++ b/engines/nancy/action/conversation.h
@@ -28,7 +28,17 @@
namespace Nancy {
namespace Action {
-// The base class for conversations, with no video data
+// The base class for conversations, with no video data. Contains the following:
+// - a base sound for the NPC's speech and its caption (mandatory)
+// - a list of possible player responses, also with sounds and captions (optional)
+// Captions are displayed in the Textbox, and player responses are also selectable there.
+// Captions are hypertext; meaning, they contain extra data related to the text (see misc/hypertext.h)
+// A conversation will auto-advance to a next scene when no responses are available; the next scene
+// can either be described within the Conversation data, or can be whatever's pushed onto the scene "stack".
+// Also supports branching scenes depending on a condition, though that is only used in older games.
+// Player responses can also be conditional; the original engine had special-purpose "infocheck"
+// functions, two per character ID, which were used to evaluate those conditions. We replace that with
+// the data bundled inside nancy.dat (see devtools/create_nancy).
class ConversationSound : public RenderActionRecord {
public:
ConversationSound();
diff --git a/engines/nancy/action/miscrecords.h b/engines/nancy/action/miscrecords.h
index ce5782a2192..8be01a9f8f6 100644
--- a/engines/nancy/action/miscrecords.h
+++ b/engines/nancy/action/miscrecords.h
@@ -34,6 +34,7 @@ class Unimplemented : public ActionRecord {
void execute() override;
};
+// Changes the palette for the current scene's background. TVD only.
class PaletteThisScene : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -48,6 +49,7 @@ protected:
Common::String getRecordTypeName() const override { return "PaletteThisScene"; }
};
+// Changes the palette for the next scene's background. TVD only.
class PaletteNextScene : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -59,6 +61,7 @@ protected:
Common::String getRecordTypeName() const override { return "PaletteNextScene"; }
};
+// Turns on (temporary) lightning effect. TVD Only.
class LightningOn : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -72,6 +75,7 @@ protected:
Common::String getRecordTypeName() const override { return "LightningOn"; }
};
+// Requests either a fade between two scenes, or a fade to black; fade executes when scene is changed. Nancy2 and up.
class SpecialEffect : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -85,6 +89,8 @@ protected:
Common::String getRecordTypeName() const override { return "SpecialEffect"; }
};
+// Changes the selected value inside the TableData. Value can be incremented, decremented, or not changed.
+// Also responsible for checking whether all values are correct (as described in the TABL chunk). Nancy6 and up.
class TableIndexSetValueHS : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -105,6 +111,7 @@ protected:
Common::Array<HotspotDescription> _hotspots;
};
+// Adds a caption to the textbox.
class TextBoxWrite : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -116,6 +123,7 @@ protected:
Common::String getRecordTypeName() const override { return "TextBoxWrite"; }
};
+// Clears the textbox. Used very rarely.
class TextboxClear : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -125,6 +133,7 @@ protected:
Common::String getRecordTypeName() const override { return "TextboxClear"; }
};
+// Changes the in-game time. Used prior to the introduction of SetPlayerClock.
class BumpPlayerClock : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -138,6 +147,7 @@ protected:
Common::String getRecordTypeName() const override { return "BumpPlayerClock"; }
};
+// Creates a Second Chance save.
class SaveContinueGame : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -147,6 +157,8 @@ protected:
Common::String getRecordTypeName() const override { return "SaveContinueGame"; }
};
+// Stops the screen from rendering. Our rendering system is different from the original engine's,
+// so we have no use for this.
class TurnOffMainRendering : public Unimplemented {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -155,6 +167,8 @@ protected:
Common::String getRecordTypeName() const override { return "TurnOffMainRendering"; }
};
+// Restarts screen rendering. Our rendering system is different from the original engine's,
+// so we have no use for this.
class TurnOnMainRendering : public Unimplemented {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -163,6 +177,8 @@ protected:
Common::String getRecordTypeName() const override { return "TurnOnMainRendering"; }
};
+// Starts the timer. Used in combination with Dependency types that check for
+// how much time has passed since the timer was started.
class ResetAndStartTimer : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -172,6 +188,7 @@ protected:
Common::String getRecordTypeName() const override { return "ResetAndStartTimer"; }
};
+// Stops the timer.
class StopTimer : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -181,6 +198,7 @@ protected:
Common::String getRecordTypeName() const override { return "StopTimer"; }
};
+// Sets up to 10 flags at once.
class EventFlags : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -192,6 +210,7 @@ protected:
Common::String getRecordTypeName() const override { return "EventFlags"; }
};
+// Sets up to 10 flags when clicked. Hotspot can move alongside background frame.
class EventFlagsMultiHS : public EventFlags {
public:
EventFlagsMultiHS(bool isCursor) : _isCursor(isCursor) {}
@@ -212,6 +231,9 @@ protected:
Common::String getRecordTypeName() const override { return _isCursor ? "EventFlagsCursorHS" : "EventFlagsMultiHS"; }
};
+// Stops the game and boots the player back to the Menu screen, while also making sure
+// they can't Continue. The devs took care to add Second Chance saves before every one
+// of these, to make sure the player can return to a state just before the dangerous part.
class LoseGame : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -221,6 +243,7 @@ protected:
Common::String getRecordTypeName() const override { return "LoseGame"; }
};
+// Adds a scene to the "stack" (which is just a single value). Used in combination with PopScene.
class PushScene : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -230,6 +253,7 @@ protected:
Common::String getRecordTypeName() const override { return "PushScene"; }
};
+// Changes to the scene pushed onto the "stack". Scenes can be pushed via PushScene, or Conversation types.
class PopScene : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -239,6 +263,11 @@ protected:
Common::String getRecordTypeName() const override { return "PopScene"; }
};
+// Ends the game and boots the player to the Credits screen.
+// TODO: The original engine also sets a config option called PlayerWonTheGame,
+// which in turn is used to trigger whichever event flag marks that the player
+// has beat the game at least once, which in turn allows easter eggs to be shown.
+// We currently support none of this.
class WinGame : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -248,6 +277,7 @@ protected:
Common::String getRecordTypeName() const override { return "WinGame"; }
};
+// Simply adds an item to the player's inventory.
class AddInventoryNoHS : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -259,6 +289,7 @@ protected:
Common::String getRecordTypeName() const override { return "AddInventoryNoHS"; }
};
+// Simply removes an item from the player's inventory.
class RemoveInventoryNoHS : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -270,6 +301,9 @@ protected:
Common::String getRecordTypeName() const override { return "RemoveInventoryNoHS"; }
};
+// Sets the difficulty level for the current save. Only appears at the start of the game.
+// First appears in nancy1. Nancy1 and nancy2 have three difficulty values, while later games
+// only have two: 0 and 2.
class DifficultyLevel : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -282,6 +316,9 @@ protected:
Common::String getRecordTypeName() const override { return "DifficultyLevel"; }
};
+// Displays a static image inside the viewport. The static image corresponds to an
+// inventory item, and is only displayed if the item is not in the player's possesion.
+// On click, it hides the image and adds the item to the inventory.
class ShowInventoryItem : public RenderActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -305,6 +342,10 @@ protected:
bool isViewportRelative() const override { return true; }
};
+// When clicking an ActionRecord hotspot with a kItem dependency, the engine
+// checks if the required item is currently being held; when it isn't, it plays
+// a specific sound to inform the player they need some item. This AR changes that
+// sound and its related caption (or stops it from playing entirely).
class InventorySoundOverride : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -319,6 +360,9 @@ protected:
Common::String getRecordTypeName() const override { return "InventorySoundOverride"; }
};
+// Checks how many hints the player is allowed to get. If they are still allowed hints,
+// it selects an appropriate one and plays its sound/displays its caption in the Textbox.
+// The hint system was _only_ used in nancy1, since it's pretty limited and overly punishing.
class HintSystem : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
diff --git a/engines/nancy/action/navigationrecords.h b/engines/nancy/action/navigationrecords.h
index 90978e6ef6b..c88f38922a5 100644
--- a/engines/nancy/action/navigationrecords.h
+++ b/engines/nancy/action/navigationrecords.h
@@ -27,6 +27,7 @@
namespace Nancy {
namespace Action {
+// Simply changes the scene
class SceneChange : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -38,6 +39,9 @@ protected:
Common::String getRecordTypeName() const override { return "SceneChange"; }
};
+// Changes the scene when clicked. Hotspot can move along with scene background frame.
+// Nancy4 introduced several sub-types with a specific mouse cursor to show when
+// hovering; all of them are handled in this class as well.
class HotMultiframeSceneChange : public SceneChange {
public:
HotMultiframeSceneChange(CursorManager::CursorType hoverCursor) : _hoverCursor(hoverCursor) {}
@@ -68,6 +72,9 @@ protected:
CursorManager::CursorType _hoverCursor;
};
+// Changes the scene when clicked; does _not_ move with scene background.
+// Nancy4 introduced several sub-types with a specific mouse cursor to show when
+// hovering; all of them are handled in this class as well.
class Hot1FrSceneChange : public SceneChange {
public:
Hot1FrSceneChange(CursorManager::CursorType hoverCursor) : _hoverCursor(hoverCursor) {}
@@ -106,6 +113,9 @@ protected:
CursorManager::CursorType _hoverCursor;
};
+// Changes the scene when clicked. Hotspot can move along with scene background frame.
+// However, the scene it changes to can be one of two options, picked based on
+// a provided condition.
class HotMultiframeMultisceneChange : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -123,6 +133,9 @@ protected:
Common::String getRecordTypeName() const override { return "HotMultiframeMultisceneChange"; }
};
+// Changes the scene when clicked. Hotspot can move along with scene background frame.
+// However, the scene it changes to can be one of several options, picked based on
+// the item the player is currently holding.
class HotMultiframeMultisceneCursorTypeSceneChange : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -138,6 +151,7 @@ protected:
Common::String getRecordTypeName() const override { return "HotMultiframeMultisceneCursorTypeSceneChange"; }
};
+// Simply switches to the Map state. TVD/nancy1 only.
class MapCall : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -149,6 +163,7 @@ protected:
Common::String getRecordTypeName() const override { return "MapCall"; }
};
+// Switches to the Map state when clicked; does _not_ move with background frame. TVD/nancy1 only.
class MapCallHot1Fr : public MapCall {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -161,6 +176,7 @@ protected:
Common::String getRecordTypeName() const override { return "MapCallHot1Fr"; }
};
+// Switches to the Map state when clicked. Hotspot can move along with scene background frame. TVD/nancy1 only.
class MapCallHotMultiframe : public MapCall {
public:
void readData(Common::SeekableReadStream &stream) override;
diff --git a/engines/nancy/action/overlay.h b/engines/nancy/action/overlay.h
index f2748932069..5a34b0221b3 100644
--- a/engines/nancy/action/overlay.h
+++ b/engines/nancy/action/overlay.h
@@ -27,13 +27,20 @@
namespace Nancy {
namespace Action {
-// ActionRecord describing an overlay on top of the viewport.
-// That overlay can be either a short animation, or a static bitmap
-// that changes depending on the current viewport frame.
-// This class covers three different ActionRecord types:
-// - PlayStaticBitmapAnimation: nancy1 only, does not support static mode
-// - PlayIntStaticBitmapAnimation: nancy1 only, same as above but supports being interrupted by an event flag
-// - Overlay: nancy2 and above, supports static mode
+// Places a static image or a looping animation on top of the background
+// Can move along with the scene's background frame, however:
+// - in animation mode, the animation is the same for every background frame
+// - in static mode, every background frame gets its own static image
+// Also supports:
+// - playing a sound;
+// - playing backwards;
+// - looping (non-looping animated overlays are very rare);
+// - getting interrupted by an event flag;
+// - changing the scene/setting flags when clicked/interrupted
+// Originally introduced in nancy1, where it was split into two different types:
+// PlayStaticBitmapAnimation and PlayIntStaticBitmapAnimation (the latter was interruptible)
+// In nancy2, the two got merged inside the newly-renamed Overlay;
+// that was also when static mode got introduced.
class Overlay : public RenderActionRecord {
public:
Overlay(bool interruptible) : RenderActionRecord(7), _isInterruptible(interruptible) {}
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index 72831cf9578..856ec830f35 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -28,6 +28,14 @@
namespace Nancy {
namespace Action {
+// Plays an AVF video. Optionally supports:
+// - playing a sound;
+// - reverse playback;
+// - moving with the scene's background frame;
+// - hiding of player cursor (and thus, disabling input);
+// - setting event flags on a specific frame, as well as at the end of the video;
+// - changing the scene after playback ends
+// Mostly used for cinematics, with some occasional uses for background animations
class PlaySecondaryMovie : public RenderActionRecord {
public:
static const byte kMovieSceneChange = 5;
diff --git a/engines/nancy/action/secondaryvideo.h b/engines/nancy/action/secondaryvideo.h
index a1d04066f6d..92edd6f320e 100644
--- a/engines/nancy/action/secondaryvideo.h
+++ b/engines/nancy/action/secondaryvideo.h
@@ -28,8 +28,10 @@
namespace Nancy {
namespace Action {
-// ActionRecord that shows NPC animations outside of dialogue. Supports
-// different animations depending on whether the NPC is hovered by the mouse
+// Shows an (optionally) looping AVF video, which can move around
+// the screen with the background frame. When hovered, the video can
+// play a special animation instead of the normal looping one.
+// Used for character animations _outside_ of conversations.
class PlaySecondaryVideo : public RenderActionRecord {
public:
static const byte kNoVideoHotspots = 1;
diff --git a/engines/nancy/action/soundrecords.h b/engines/nancy/action/soundrecords.h
index 09d8ea64144..d579b8cc29e 100644
--- a/engines/nancy/action/soundrecords.h
+++ b/engines/nancy/action/soundrecords.h
@@ -27,6 +27,9 @@
namespace Nancy {
namespace Action {
+// Used for sound effects. From nancy3 up it includes 3D sound data, which lets
+// the sound move in 3D space as the player rotates/changes scenes. Also supports
+// changing the scene and/or setting a flag
class PlayDigiSound : public ActionRecord {
public:
PlayDigiSound() {}
@@ -45,6 +48,8 @@ protected:
Common::String getRecordTypeName() const override;
};
+// The same as PlayDigiSound, but with the addition of captioning text,
+// which gets displayed inside the Textbox.
class PlayDigiSoundCC : public PlayDigiSound {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -56,6 +61,8 @@ protected:
Common::String getRecordTypeName() const override { return "PlayDigiSoundCC"; }
};
+// Used for sounds that pan left-right depending on the scene background frame.
+// Only used in The Vampire Diaries; later games use PlayDigiSound's 3D sound capabilities instead
class PlaySoundPanFrameAnchorAndDie : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -67,6 +74,8 @@ protected:
Common::String getRecordTypeName() const override { return "PlaySoundPanFrameAnchorAndDie"; }
};
+// Plays a sound effect; has multiple hotspots, one per scene background frame.
+// Used in exactly two places; one scene in tvd, and one in nancy1
class PlaySoundMultiHS : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -81,6 +90,8 @@ protected:
Common::String getRecordTypeName() const override { return "PlaySoundMultiHS"; }
};
+// Stops a sound if it's loaded and playing. Used very rarely, as sounds (usually)
+// get auto-stopped on a scene change
class StopSound : public ActionRecord {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -93,6 +104,8 @@ protected:
Common::String getRecordTypeName() const override { return "StopSound"; }
};
+// Same as PlayDigiSound, except it randomly picks between one of several
+// provided sound files; all other settings for the sound are shared.
class PlayRandomSound : public PlayDigiSound {
public:
void readData(Common::SeekableReadStream &stream) override;
@@ -106,6 +119,10 @@ protected:
Common::String getRecordTypeName() const override { return "PlayRandomSound"; }
};
+// Same as PlayDigiSound, except it discards the filename provided in the data.
+// Instead, it takes the current value of an item in TableData, and appends that
+// value to the end of the base filename provided in the TABL chunk. Does not contain
+// any CC text inside the record data; instead, that also gets copied over from TABL.
class TableIndexPlaySound : public PlayDigiSoundCC {
public:
void readData(Common::SeekableReadStream &stream) override;
More information about the Scummvm-git-logs
mailing list