[Scummvm-git-logs] scummvm master -> a26e5cfb3e82cfd3f6be068d9601a4822a08e0e5
bluegr
noreply at scummvm.org
Sat Jul 18 00:19:52 UTC 2026
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
a26e5cfb3e NANCY: NANCY13: Implement WordFindPuzzle
Commit: a26e5cfb3e82cfd3f6be068d9601a4822a08e0e5
https://github.com/scummvm/scummvm/commit/a26e5cfb3e82cfd3f6be068d9601a4822a08e0e5
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-18T03:12:43+03:00
Commit Message:
NANCY: NANCY13: Implement WordFindPuzzle
Word-find puzzle. Despite the name it is not a free grid drag-select:
the player works one target word at a time (progressing across scene
visits), building a connected chain of orthogonally-adjacent letter
cells; once the chain has the word's length and matches the answer
path, the word's animation plays and the next word becomes active.
Changed paths:
A engines/nancy/action/puzzle/wordfindpuzzle.cpp
A engines/nancy/action/puzzle/wordfindpuzzle.h
engines/nancy/action/arfactory.cpp
engines/nancy/module.mk
engines/nancy/puzzledata.cpp
engines/nancy/puzzledata.h
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 86fa7b7dc3c..386be86607a 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -86,6 +86,7 @@
#include "engines/nancy/action/puzzle/twodialpuzzle.h"
#include "engines/nancy/action/puzzle/typingquizpuzzle.h"
#include "engines/nancy/action/puzzle/whalesurvivorpuzzle.h"
+#include "engines/nancy/action/puzzle/wordfindpuzzle.h"
#include "engines/nancy/state/scene.h"
@@ -194,6 +195,11 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
return new StartPlayerScrolling();
case 32: // Nancy10
return new UIPopupPrepScene();
+ case 40:
+ if (g_nancy->getGameType() <= kGameTypeNancy1)
+ return new LightningOn(); // Only used in TVD
+ else
+ return new SpecialEffect();
case 41: // Nancy14
case 44: // Nancy14 (adds a trailing volume byte)
return new PlaySecondaryMovie();
@@ -207,11 +213,6 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
case 47: // Nancy14 - PlaySecondaryMovie subclass with a per-frame flag list
// TODO: not yet implemented
return nullptr;
- case 40:
- if (g_nancy->getGameType() <= kGameTypeNancy1)
- return new LightningOn(); // Only used in TVD
- else
- return new SpecialEffect();
case 50:
return new ConversationVideo(); // PlayPrimaryVideoChan0
case 51:
@@ -471,12 +472,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
case 169:
return new StepObjectsPuzzle();
case 170:
- if (g_nancy->getGameType() >= kGameTypeNancy13) {
- // WordFindPuzzle, new in Nancy13. This reuses the slot that used
- // to hold SetPlayerClock (which itself moved to 140 in Nancy12).
- // TODO: not yet implemented
- return nullptr;
- }
+ if (g_nancy->getGameType() >= kGameTypeNancy13)
+ return new WordFindPuzzle();
return new SetPlayerClock(); // moved to 140 in Nancy12
case 171:
return new TurningPuzzle(); // moved from 209 in Nancy13
diff --git a/engines/nancy/action/puzzle/wordfindpuzzle.cpp b/engines/nancy/action/puzzle/wordfindpuzzle.cpp
new file mode 100644
index 00000000000..fd9c0eebfa7
--- /dev/null
+++ b/engines/nancy/action/puzzle/wordfindpuzzle.cpp
@@ -0,0 +1,404 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/graphics.h"
+#include "engines/nancy/resource.h"
+#include "engines/nancy/sound.h"
+#include "engines/nancy/input.h"
+#include "engines/nancy/cursor.h"
+#include "engines/nancy/util.h"
+#include "engines/nancy/puzzledata.h"
+
+#include "engines/nancy/state/scene.h"
+#include "engines/nancy/action/puzzle/wordfindpuzzle.h"
+
+namespace Nancy {
+namespace Action {
+
+WordFindPuzzleData *WordFindPuzzle::getPuzzleData() const {
+ return (WordFindPuzzleData *)NancySceneState.getPuzzleData(WordFindPuzzleData::getTag());
+}
+
+void WordFindPuzzle::readData(Common::SeekableReadStream &stream) {
+ // 82-byte base header.
+ _cursorType = stream.readUint16LE(); // 0x00
+ stream.skip(4); // 0x02
+ _cellGapX = stream.readUint16LE(); // 0x06
+ _cellGapY = stream.readUint16LE(); // 0x08
+ stream.skip(0x20); // 0x0a
+ _solveScene.sceneID = stream.readUint16LE(); // 0x2a - shown once every word is found
+ stream.skip(3); // 0x2c
+ readFilename(stream, _solutionImageName); // 0x2f
+ uint16 numWords = stream.readUint16LE(); // 0x50
+
+ _words.resize(numWords);
+ for (uint i = 0; i < numWords; ++i) {
+ Word &w = _words[i];
+ readFilename(stream, w.gridImageName);
+ readFilename(stream, w.overlayImageName);
+ readFilename(stream, w.animName);
+
+ uint16 coordCount = stream.readUint16LE();
+ w.answerCoords.resize(coordCount);
+ for (uint16 j = 0; j < coordCount; ++j) {
+ w.answerCoords[j].x = stream.readSint16LE();
+ w.answerCoords[j].y = stream.readSint16LE();
+ }
+
+ w.eventFlagLabel = stream.readSint16LE();
+ uint16 rectCount = stream.readUint16LE();
+ readRectArray(stream, w.letterRects, rectCount);
+ }
+
+ // The shared 23-byte exit-hotspot record.
+ int16 numZones = stream.readSint16LE();
+ for (int16 i = 0; i < numZones; ++i) {
+ Common::Rect r;
+ readRect(stream, r);
+ uint16 cursorType = stream.readUint16LE();
+ uint16 sceneID = stream.readUint16LE();
+ uint16 frameID = stream.readUint16LE();
+ stream.skip(1);
+
+ if (i == 0) {
+ _exitHotspot = r;
+ _exitCursorType = cursorType;
+ _exitScene.sceneID = sceneID;
+ _exitScene.frameID = (frameID == 0xffff) ? 0 : frameID;
+ }
+ }
+
+ _sounds.resize(4);
+ for (uint i = 0; i < 4; ++i) {
+ _sounds[i].readData(stream);
+ }
+}
+
+Common::Point WordFindPuzzle::gridCoord(const Common::Rect &rect) const {
+ // The grid is anchored at the very first word's first letter (a global origin in the
+ // original), with the pitch being a letter's size plus the header's gap.
+ if (_words.empty() || _words[0].letterRects.empty()) {
+ return Common::Point(0, 0);
+ }
+
+ // The original derives the pitch from the raw (inclusive) rect: cellGap + (right - left).
+ // readRect() has already made our rects exclusive (++right/++bottom), so subtract that
+ // back out, otherwise the pitch is one pixel too large and the integer division lands on
+ // the wrong row/column for every cell past the origin.
+ const Common::Rect &origin = _words[0].letterRects[0];
+ int pitchX = _cellGapX + (origin.right - origin.left - 1);
+ int pitchY = _cellGapY + (origin.bottom - origin.top - 1);
+ if (pitchX <= 0) {
+ pitchX = 1;
+ }
+ if (pitchY <= 0) {
+ pitchY = 1;
+ }
+
+ return Common::Point((rect.left - origin.left) / pitchX, (rect.top - origin.top) / pitchY);
+}
+
+bool WordFindPuzzle::isAdjacent(const Common::Point &a, const Common::Point &b) const {
+ int dx = ABS(a.x - b.x);
+ int dy = ABS(a.y - b.y);
+ return (dx + dy) == 1;
+}
+
+int WordFindPuzzle::letterAtCursor(const Common::Point &mousePos) const {
+ if ((uint)_currentWord >= _words.size()) {
+ return -1;
+ }
+
+ const Common::Array<Common::Rect> &rects = _words[_currentWord].letterRects;
+ for (uint i = 0; i < rects.size(); ++i) {
+ if (NancySceneState.getViewport().convertViewportToScreen(rects[i]).contains(mousePos)) {
+ return (int)i;
+ }
+ }
+ return -1;
+}
+
+int WordFindPuzzle::numSelected() const {
+ int count = 0;
+ for (uint i = 0; i < _selected.size(); ++i) {
+ if (_selected[i]) {
+ ++count;
+ }
+ }
+ return count;
+}
+
+bool WordFindPuzzle::chainMatchesAnswer() const {
+ // A word is spelled correctly when every selected letter's grid cell is one of the
+ // word's answer cells (and the counts already match).
+ const Word &w = _words[_currentWord];
+ for (uint i = 0; i < _selected.size(); ++i) {
+ if (!_selected[i]) {
+ continue;
+ }
+
+ Common::Point c = gridCoord(w.letterRects[i]);
+ bool found = false;
+ for (uint j = 0; j < w.answerCoords.size(); ++j) {
+ if (w.answerCoords[j] == c) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void WordFindPuzzle::loadWord() {
+ if ((uint)_currentWord >= _words.size()) {
+ _allFound = true;
+ return;
+ }
+
+ const Word &w = _words[_currentWord];
+ _gridImage.free();
+ _overlayImage.free();
+ g_nancy->_resource->loadImage(w.gridImageName, _gridImage);
+ if (!w.overlayImageName.empty()) {
+ g_nancy->_resource->loadImage(w.overlayImageName, _overlayImage);
+ }
+
+ _selected.clear();
+ _selected.resize(w.letterRects.size(), false);
+}
+
+void WordFindPuzzle::init() {
+ Common::Rect vpBounds = NancySceneState.getViewport().getBounds();
+ _drawSurface.create(vpBounds.width(), vpBounds.height(), g_nancy->_graphics->getInputPixelFormat());
+ _drawSurface.clear(g_nancy->_graphics->getTransColor());
+ setTransparent(true);
+ setVisible(true);
+ moveTo(vpBounds);
+
+ // The active word carries over from earlier visits to this puzzle.
+ WordFindPuzzleData *data = getPuzzleData();
+ _currentWord = data ? data->currentWord : 0;
+ if (_currentWord < 0) {
+ _currentWord = 0;
+ }
+
+ _allFound = ((uint)_currentWord >= _words.size());
+ if (!_allFound) {
+ loadWord();
+ }
+
+ NancySceneState.setNoHeldItem();
+ redraw();
+ registerGraphics();
+}
+
+void WordFindPuzzle::redraw() {
+ _drawSurface.clear(g_nancy->_graphics->getTransColor());
+
+ if (!_allFound && (uint)_currentWord < _words.size() && !_gridImage.empty()) {
+ _drawSurface.blitFrom(_gridImage, Common::Point(0, 0));
+
+ // Show the overlay art at each selected letter (the overlay image lines up with the
+ // grid, so a selected cell's region is its highlighted version).
+ const Word &w = _words[_currentWord];
+ for (uint i = 0; i < _selected.size(); ++i) {
+ if (_selected[i] && !_overlayImage.empty()) {
+ const Common::Rect &r = w.letterRects[i];
+ if (r.left >= 0 && r.top >= 0 && r.right <= _overlayImage.w && r.bottom <= _overlayImage.h) {
+ _drawSurface.blitFrom(_overlayImage, r, Common::Point(r.left, r.top));
+ }
+ }
+ }
+
+ // While the "found" animation plays it is drawn on top of the grid.
+ if (_playingMovie && _movie.isVideoLoaded()) {
+ _movie.drawFrame(_drawSurface, Common::Point(0, 0));
+ }
+ }
+
+ _needsRedraw = true;
+}
+
+void WordFindPuzzle::startFoundAnimation() {
+ const Word &w = _words[_currentWord];
+ if (!w.animName.empty() && _movie.loadFile(w.animName) && _movie.getFrameCount() > 0) {
+ _movie.playRange(0, _movie.getFrameCount() - 1);
+ _playingMovie = true;
+ redraw();
+ } else {
+ // No animation available: just resolve the word.
+ finishCurrentWord();
+ }
+}
+
+void WordFindPuzzle::finishCurrentWord() {
+ const Word &w = _words[_currentWord];
+ if (w.eventFlagLabel != -1) {
+ NancySceneState.setEventFlag(w.eventFlagLabel, g_nancy->_true);
+ }
+
+ ++_currentWord;
+ WordFindPuzzleData *data = getPuzzleData();
+ if (data) {
+ data->currentWord = _currentWord;
+ }
+
+ if ((uint)_currentWord >= _words.size()) {
+ _allFound = true;
+ } else {
+ loadWord();
+ }
+
+ redraw();
+}
+
+void WordFindPuzzle::execute() {
+ switch (_state) {
+ case kBegin:
+ init();
+ _state = kRun;
+ // fall through
+ case kRun: {
+ if (_allFound) {
+ _state = kActionTrigger;
+ break;
+ }
+
+ // While the found-word animation is playing, no input is taken; when it ends the
+ // word's event flag is set and the puzzle advances.
+ if (_playingMovie) {
+ if (_movie.update()) {
+ _movie.drawFrame(_drawSurface, Common::Point(0, 0));
+ _needsRedraw = true;
+ }
+
+ if (!_movie.isRangePlaying()) {
+ _playingMovie = false;
+ _movie.close();
+ finishCurrentWord();
+ }
+
+ break;
+ }
+
+ const Word &w = _words[_currentWord];
+ if (numSelected() == (int)w.answerCoords.size() && !w.answerCoords.empty()) {
+ if (chainMatchesAnswer()) {
+ startFoundAnimation();
+ } else {
+ // A wrong path: clear it so the player can try again.
+ for (uint i = 0; i < _selected.size(); ++i) {
+ _selected[i] = false;
+ }
+ redraw();
+ }
+ }
+
+ break;
+ }
+ case kActionTrigger: {
+ const SceneChangeDescription &sc = _allFound ? _solveScene : _exitScene;
+ if (sc.sceneID != kNoScene) {
+ NancySceneState.changeScene(sc);
+ }
+
+ finishExecution();
+ break;
+ }
+ }
+}
+
+void WordFindPuzzle::handleInput(NancyInput &input) {
+ if (_state != kRun || _allFound || _playingMovie) {
+ return;
+ }
+
+ int letter = letterAtCursor(input.mousePos);
+ if (letter >= 0) {
+ g_nancy->_cursor->setCursorType((CursorManager::CursorType)_cursorType, true);
+
+ if (input.input & NancyInput::kLeftMouseButtonUp) {
+ const Word &w = _words[_currentWord];
+ Common::Point c = gridCoord(w.letterRects[letter]);
+
+ if (_selected[letter]) {
+ // The clicked letter is always removed; removing one from the middle of the chain
+ // (adjacent to 2+ selected letters) breaks it, so the whole selection is reset.
+ int neighbors = 0;
+ for (uint i = 0; i < _selected.size(); ++i) {
+ if (_selected[i] && i != (uint)letter && isAdjacent(c, gridCoord(w.letterRects[i]))) {
+ ++neighbors;
+ }
+ }
+ _selected[letter] = false;
+ if (neighbors >= 2) {
+ for (uint i = 0; i < _selected.size(); ++i) {
+ _selected[i] = false;
+ }
+ }
+ } else {
+ // Extend the chain: valid as the first letter, or next to at least one already-
+ // selected letter (a winding word can touch two of them).
+ int neighbors = 0;
+ for (uint i = 0; i < _selected.size(); ++i) {
+ if (_selected[i] && isAdjacent(c, gridCoord(w.letterRects[i]))) {
+ ++neighbors;
+ }
+ }
+ if (numSelected() == 0 || neighbors >= 1) {
+ _selected[letter] = true;
+ if (!_sounds.empty()) {
+ SoundDescription desc;
+ desc.name = _sounds[0].names.empty() ? "" : _sounds[0].names[0];
+ desc.channelID = _sounds[0].channel;
+ desc.numLoops = 1;
+ desc.volume = _sounds[0].volume;
+ if (!desc.name.empty() && desc.name != "NO SOUND") {
+ g_nancy->_sound->loadSound(desc);
+ g_nancy->_sound->playSound(desc);
+ }
+ }
+ }
+ }
+
+ redraw();
+ }
+
+ input.eatMouseInput();
+ return;
+ }
+
+ if (!_exitHotspot.isEmpty() &&
+ NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
+ g_nancy->_cursor->setCursorType((CursorManager::CursorType)_exitCursorType, true);
+ if (input.input & NancyInput::kLeftMouseButtonUp) {
+ _state = kActionTrigger;
+ }
+ }
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/puzzle/wordfindpuzzle.h b/engines/nancy/action/puzzle/wordfindpuzzle.h
new file mode 100644
index 00000000000..2d8fb9ecd6c
--- /dev/null
+++ b/engines/nancy/action/puzzle/wordfindpuzzle.h
@@ -0,0 +1,108 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NANCY_ACTION_WORDFINDPUZZLE_H
+#define NANCY_ACTION_WORDFINDPUZZLE_H
+
+#include "engines/nancy/commontypes.h"
+#include "engines/nancy/movieplayer.h"
+#include "engines/nancy/action/actionrecord.h"
+
+namespace Nancy {
+
+struct WordFindPuzzleData;
+
+namespace Action {
+
+// Word-find puzzle, new in Nancy13 (AR 170). Despite the name it is not a free
+// grid drag-select: the player works one target word at a time (progressing across
+// scene visits), building a connected chain of orthogonally-adjacent letter cells;
+// once the chain has the word's length and matches the answer path, the word's
+// animation plays and the next word becomes active.
+class WordFindPuzzle : public RenderActionRecord {
+public:
+ WordFindPuzzle() : RenderActionRecord(7) {}
+ virtual ~WordFindPuzzle() {}
+
+ void init() override;
+
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+ void handleInput(NancyInput &input) override;
+
+ bool isViewportRelative() const override { return true; }
+
+protected:
+ Common::String getRecordTypeName() const override { return "WordFindPuzzle"; }
+
+ struct Word {
+ Common::Path gridImageName; // +0x55 - the letter grid for this word
+ Common::Path overlayImageName; // +0x76 - overlay drawn on top
+ Common::Path animName; // +0x97 - the "found" animation (a movie)
+ Common::Array<Common::Point> answerCoords; // +0xb8 - the correct letter path (grid cells)
+ int16 eventFlagLabel = -1; // +0x10a - set when the word is found
+ Common::Array<Common::Rect> letterRects; // +0x10c - clickable letter cells
+ };
+
+ // Grid (col,row) of a letter rect, using the same pixel maths as the original.
+ Common::Point gridCoord(const Common::Rect &rect) const;
+ bool isAdjacent(const Common::Point &a, const Common::Point &b) const;
+ int letterAtCursor(const Common::Point &mousePos) const;
+ int numSelected() const;
+ bool chainMatchesAnswer() const;
+ void loadWord();
+ void startFoundAnimation();
+ void finishCurrentWord();
+ void redraw();
+ WordFindPuzzleData *getPuzzleData() const;
+
+ // -- File data --
+ uint16 _cursorType = 0; // base 0x00
+ uint16 _cellGapX = 0; // base 0x06 - added to a letter's width to get the column pitch
+ uint16 _cellGapY = 0; // base 0x08 - row pitch component
+ SceneChangeDescription _solveScene; // base 0x2a - shown once every word is found
+ Common::Path _solutionImageName; // base 0x2f
+ Common::Array<Word> _words;
+
+ Common::Rect _exitHotspot;
+ uint16 _exitCursorType = 0;
+ SceneChangeDescription _exitScene;
+
+ Common::Array<RandomSoundBlock> _sounds; // 4 blocks
+
+ // -- Runtime state --
+ // The active word persists across scene visits (and saves) via WordFindPuzzleData.
+ int _currentWord = 0;
+ Common::Array<bool> _selected; // per letter of the current word
+ bool _allFound = false;
+
+ // The "found word" animation that plays before advancing to the next word.
+ MoviePlayer _movie;
+ bool _playingMovie = false;
+
+ Graphics::ManagedSurface _gridImage;
+ Graphics::ManagedSurface _overlayImage;
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_WORDFINDPUZZLE_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index 75e044b8228..97625d02f65 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -70,6 +70,7 @@ MODULE_OBJS = \
action/puzzle/twodialpuzzle.o \
action/puzzle/typingquizpuzzle.o \
action/puzzle/whalesurvivorpuzzle.o \
+ action/puzzle/wordfindpuzzle.o \
ui/fullscreenimage.o \
ui/animatedbutton.o \
ui/button.o \
diff --git a/engines/nancy/puzzledata.cpp b/engines/nancy/puzzledata.cpp
index fb27477f6db..e4f0036d52d 100644
--- a/engines/nancy/puzzledata.cpp
+++ b/engines/nancy/puzzledata.cpp
@@ -409,8 +409,14 @@ void TaskbarData::synchronize(Common::Serializer &ser) {
}
}
+void WordFindPuzzleData::synchronize(Common::Serializer &ser) {
+ ser.syncAsSint16LE(currentWord);
+}
+
PuzzleData *makePuzzleData(const uint32 tag) {
switch(tag) {
+ case WordFindPuzzleData::getTag():
+ return new WordFindPuzzleData();
case SliderPuzzleData::getTag():
return new SliderPuzzleData();
case RippedLetterPuzzleData::getTag():
diff --git a/engines/nancy/puzzledata.h b/engines/nancy/puzzledata.h
index 429cf6b94b0..1d8965de105 100644
--- a/engines/nancy/puzzledata.h
+++ b/engines/nancy/puzzledata.h
@@ -320,6 +320,19 @@ struct TaskbarData : public PuzzleData {
bool notifications[kNumButtons][kNumNotificationSubCategories] = {};
};
+// Nancy13+ WordFindPuzzle (AR 170). The puzzle is solved one word at a time across
+// several scene visits; this remembers which word is currently active so progress
+// survives leaving and re-entering the scene (and saving/loading).
+struct WordFindPuzzleData : public PuzzleData {
+ WordFindPuzzleData() {}
+ virtual ~WordFindPuzzleData() {}
+
+ static constexpr uint32 getTag() { return MKTAG('W', 'F', 'N', 'D'); }
+ virtual void synchronize(Common::Serializer &ser);
+
+ int16 currentWord = 0;
+};
+
PuzzleData *makePuzzleData(const uint32 tag);
} // End of namespace Nancy
More information about the Scummvm-git-logs
mailing list