NANCY: Fix RippedLetterPuzzle breakage on exit

The puzzle may be left in a broken state when a save is
initiated or when clicking a scene item while holding a
puzzle piece. The held piece is now tracked inside the
puzzle state object, and put in its place whenever the
game is saved/the puzzle is reopened.
This commit is contained in:
Kaloyan Chehlarski 2024-07-21 21:51:28 +02:00
parent 0dd0e487e9
commit c07720c1c0
4 changed files with 31 additions and 8 deletions

View File

@ -203,6 +203,14 @@ void RippedLetterPuzzle::execute() {
_puzzleState->order = _initOrder;
_puzzleState->rotations = _initRotations;
_puzzleState->playerHasTriedPuzzle = true;
} else if (_puzzleState->_pickedUpPieceID != -1) {
// Puzzle was left while still holding a piece (e.g. by clicking a scene item).
// Make sure we put the held piece back in its place
_puzzleState->order[_puzzleState->_pickedUpPieceLastPos] = _puzzleState->_pickedUpPieceID;
_puzzleState->rotations[_puzzleState->_pickedUpPieceLastPos] = _puzzleState->_pickedUpPieceRot;
_puzzleState->_pickedUpPieceID = -1;
_puzzleState->_pickedUpPieceLastPos = -1;
_puzzleState->_pickedUpPieceRot = 0;
}
for (uint i = 0; i < _puzzleState->order.size(); ++i) {
@ -275,7 +283,7 @@ void RippedLetterPuzzle::handleInput(NancyInput &input) {
Common::Rect screenHotspot = NancySceneState.getViewport().convertViewportToScreen(_destRects[i]);
if (screenHotspot.contains(input.mousePos)) {
Common::Rect insideRect;
if (_pickedUpPieceID == -1) {
if (_puzzleState->_pickedUpPieceID == -1) {
// No piece picked up
// Check if the mouse is inside the rotation hotspot
@ -320,9 +328,10 @@ void RippedLetterPuzzle::handleInput(NancyInput &input) {
_pickedUpPiece.pickUp();
// ...then change the data...
_pickedUpPieceID = _puzzleState->order[i];
_pickedUpPieceRot = _puzzleState->rotations[i];
_puzzleState->_pickedUpPieceID = _puzzleState->order[i];
_puzzleState->_pickedUpPieceRot = _puzzleState->rotations[i];
_puzzleState->order[i] = -1;
_puzzleState->_pickedUpPieceLastPos = i;
// ...then clear the piece from the drawSurface
drawPiece(i, 0);
@ -360,8 +369,9 @@ void RippedLetterPuzzle::handleInput(NancyInput &input) {
_pickedUpPiece.setTransparent(true);
}
SWAP<int8>(_puzzleState->order[i], _pickedUpPieceID);
SWAP<byte>(_puzzleState->rotations[i], _pickedUpPieceRot);
SWAP<int8>(_puzzleState->order[i], _puzzleState->_pickedUpPieceID);
SWAP<byte>(_puzzleState->rotations[i], _puzzleState->_pickedUpPieceRot);
_puzzleState->_pickedUpPieceLastPos = -1;
// Draw the newly placed piece
drawPiece(i, _puzzleState->rotations[i], _puzzleState->order[i]);
@ -377,7 +387,7 @@ void RippedLetterPuzzle::handleInput(NancyInput &input) {
_pickedUpPiece.handleInput(input);
if (_pickedUpPieceID == -1) {
if (_puzzleState->_pickedUpPieceID == -1) {
// No piece picked up, check the exit hotspot
if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
g_nancy->_cursor->setCursorType(_customCursorID != -1 ? (CursorManager::CursorType)_customCursorID : g_nancy->_cursor->_puzzleExitCursor);

View File

@ -80,8 +80,6 @@ public:
int16 _customCursorID = -1;
Misc::MouseFollowObject _pickedUpPiece;
int8 _pickedUpPieceID = -1;
byte _pickedUpPieceRot = 0;
Graphics::ManagedSurface _image;
SolveState _solveState = kNotSolved;

View File

@ -61,6 +61,16 @@ void RippedLetterPuzzleData::synchronize(Common::Serializer &ser) {
if (ser.isLoading()) {
order.resize(24);
rotations.resize(24);
} else {
// A piece may still be held while saving; make sure the saved data
// has it back in the last place it was picked up from
if (_pickedUpPieceID != -1) {
order[_pickedUpPieceLastPos] = _pickedUpPieceID;
rotations[_pickedUpPieceLastPos] = _pickedUpPieceRot;
_pickedUpPieceID = -1;
_pickedUpPieceLastPos = -1;
_pickedUpPieceRot = 0;
}
}
ser.syncArray(order.data(), 24, Common::Serializer::Byte);

View File

@ -61,6 +61,11 @@ struct RippedLetterPuzzleData : public PuzzleData {
Common::Array<int8> order;
Common::Array<byte> rotations;
bool playerHasTriedPuzzle;
// Temporary values, do not save to file
int8 _pickedUpPieceID = -1;
byte _pickedUpPieceRot = 0;
int _pickedUpPieceLastPos = -1;
};
struct TowerPuzzleData : public PuzzleData {