mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-15 16:58:01 +00:00
NANCY: Implement slider puzzle
Implemented the SliderPuzzle action record, which is used for the jewel box in the safe in nancy1.
This commit is contained in:
parent
d83edfdca3
commit
1cd406b5af
@ -29,6 +29,7 @@
|
||||
#include "engines/nancy/action/orderingpuzzle.h"
|
||||
#include "engines/nancy/action/rotatinglockpuzzle.h"
|
||||
#include "engines/nancy/action/telephone.h"
|
||||
#include "engines/nancy/action/sliderpuzzle.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
@ -122,7 +123,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
|
||||
case 0x6A:
|
||||
return new Telephone(_engine->scene->getViewport());
|
||||
case 0x6B:
|
||||
return new SliderPuzzle();
|
||||
return new SliderPuzzle(_engine->scene->getViewport());
|
||||
case 0x6C:
|
||||
return new PasswordPuzzle();
|
||||
case 0x6E:
|
||||
|
@ -387,10 +387,6 @@ uint16 LeverPuzzle::readData(Common::SeekableReadStream &stream) {
|
||||
return readRaw(stream, 0x192); // TODO
|
||||
}
|
||||
|
||||
uint16 SliderPuzzle::readData(Common::SeekableReadStream &stream) {
|
||||
return readRaw(stream, 0x544); // TODO
|
||||
}
|
||||
|
||||
uint16 PasswordPuzzle::readData(Common::SeekableReadStream &stream) {
|
||||
return readRaw(stream, 0xD7); // TODO
|
||||
}
|
||||
|
@ -278,11 +278,6 @@ public:
|
||||
virtual uint16 readData(Common::SeekableReadStream &stream) override;
|
||||
};
|
||||
|
||||
class SliderPuzzle : public ActionRecord {
|
||||
public:
|
||||
virtual uint16 readData(Common::SeekableReadStream &stream) override;
|
||||
};
|
||||
|
||||
class PasswordPuzzle : public ActionRecord {
|
||||
public:
|
||||
virtual uint16 readData(Common::SeekableReadStream &stream) override;
|
||||
|
308
engines/nancy/action/sliderpuzzle.cpp
Normal file
308
engines/nancy/action/sliderpuzzle.cpp
Normal file
@ -0,0 +1,308 @@
|
||||
/* 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 "engines/nancy/action/sliderpuzzle.h"
|
||||
|
||||
#include "engines/nancy/util.h"
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/resource.h"
|
||||
#include "engines/nancy/sound.h"
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace Action {
|
||||
|
||||
Common::Array<Common::Array<int16>> SliderPuzzle::playerTileOrder = Common::Array<Common::Array<int16>>();
|
||||
bool SliderPuzzle::playerHasTriedPuzzle = false;
|
||||
|
||||
void SliderPuzzle::init() {
|
||||
_drawSurface.create(_screenPosition.width(), _screenPosition.height(), GraphicsManager::pixelFormat);
|
||||
_drawSurface.clear(GraphicsManager::transColor);
|
||||
|
||||
Graphics::Surface surf;
|
||||
_engine->_res->loadImage("ciftree", imageName, surf);
|
||||
image.create(surf.w, surf.h, surf.format);
|
||||
image.blitFrom(surf);
|
||||
surf.free();
|
||||
}
|
||||
|
||||
uint16 SliderPuzzle::readData(Common::SeekableReadStream &stream) {
|
||||
char buf[10];
|
||||
stream.read(buf, 10);
|
||||
imageName = buf;
|
||||
|
||||
width = stream.readUint16LE();
|
||||
height = stream.readUint16LE();
|
||||
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
srcRects.push_back(Common::Array<Common::Rect>());
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
srcRects.back().push_back(Common::Rect());
|
||||
readRect(stream, srcRects.back().back());
|
||||
}
|
||||
stream.skip((6 - width) * 16);
|
||||
}
|
||||
|
||||
stream.skip((6 - height) * 6 * 16);
|
||||
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
destRects.push_back(Common::Array<Common::Rect>());
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
destRects.back().push_back(Common::Rect());
|
||||
readRect(stream, destRects.back().back());
|
||||
|
||||
if (x == 0 && y == 0) {
|
||||
_screenPosition = destRects.back().back();
|
||||
} else {
|
||||
_screenPosition.extend(destRects.back().back());
|
||||
}
|
||||
}
|
||||
stream.skip((6 - width) * 16);
|
||||
}
|
||||
|
||||
stream.skip((6 - height) * 6 * 16);
|
||||
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
correctTileOrder.push_back(Common::Array<int16>());
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
correctTileOrder.back().push_back(stream.readSint16LE());
|
||||
}
|
||||
stream.skip((6 - width) * 2);
|
||||
}
|
||||
|
||||
stream.skip((6 - height) * 6 * 2);
|
||||
|
||||
clickSound.read(stream, SoundManager::SoundDescription::kNormal);
|
||||
solveExitScene.readData(stream);
|
||||
stream.skip(2);
|
||||
flagOnSolve.label = stream.readUint16LE();
|
||||
flagOnSolve.flag = (NancyFlag)stream.readByte();
|
||||
solveSound.read(stream, SoundManager::SoundDescription::kNormal);
|
||||
exitScene.readData(stream);
|
||||
stream.skip(2);
|
||||
flagOnExit.label = stream.readUint16LE();
|
||||
flagOnExit.flag = (NancyFlag)stream.readByte();
|
||||
readRect(stream, exitHotspot);
|
||||
|
||||
return 0x544;
|
||||
}
|
||||
|
||||
void SliderPuzzle::execute(Nancy::NancyEngine *engine) {
|
||||
switch (state) {
|
||||
case kBegin:
|
||||
init();
|
||||
registerGraphics();
|
||||
if (!playerHasTriedPuzzle) {
|
||||
Common::SeekableReadStream *spuz = engine->getBootChunkStream("SPUZ");
|
||||
playerTileOrder.clear();
|
||||
spuz->seek(engine->scene->getDifficulty() * 0x48);
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
playerTileOrder.push_back(Common::Array<int16>());
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
playerTileOrder.back().push_back(spuz->readSint16LE());
|
||||
}
|
||||
spuz->skip((6 - width) * 2);
|
||||
}
|
||||
playerHasTriedPuzzle = true;
|
||||
}
|
||||
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
if (!srcRects[y][x].isEmpty()) {
|
||||
drawTile(playerTileOrder[y][x], x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engine->sound->loadSound(clickSound);
|
||||
state = kRun;
|
||||
// fall through
|
||||
case kRun:
|
||||
switch (solveState) {
|
||||
case kNotSolved:
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
if (playerTileOrder[y][x] != correctTileOrder[y][x]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engine->sound->loadSound(solveSound);
|
||||
engine->sound->playSound(solveSound.channelID);
|
||||
solveState = kWaitForSound;
|
||||
break;
|
||||
case kWaitForSound:
|
||||
if (!engine->sound->isSoundPlaying(solveSound.channelID)) {
|
||||
engine->sound->stopSound(solveSound.channelID);
|
||||
state = kActionTrigger;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case kActionTrigger:
|
||||
switch (solveState) {
|
||||
case kNotSolved:
|
||||
if (exitScene.sceneID != 9999) {
|
||||
engine->scene->changeScene(exitScene.sceneID, exitScene.frameID, exitScene.verticalOffset, exitScene.doNotStartSound);
|
||||
}
|
||||
|
||||
engine->scene->setEventFlag(flagOnExit.label, flagOnExit.flag);
|
||||
break;
|
||||
case kWaitForSound:
|
||||
if (exitScene.sceneID != 9999) {
|
||||
engine->scene->changeScene(solveExitScene.sceneID, solveExitScene.frameID, solveExitScene.verticalOffset, solveExitScene.doNotStartSound);
|
||||
}
|
||||
|
||||
engine->scene->setEventFlag(flagOnSolve.label, flagOnSolve.flag);
|
||||
playerHasTriedPuzzle = false;
|
||||
break;
|
||||
}
|
||||
|
||||
engine->sound->stopSound(clickSound.channelID);
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SliderPuzzle::handleInput(NancyInput &input) {
|
||||
if (solveState != kNotSolved) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_engine->scene->getViewport().convertViewportToScreen(exitHotspot).contains(input.mousePos)) {
|
||||
_engine->cursorManager->setCursorType(CursorManager::kExitArrow);
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
state = kActionTrigger;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int currentTileX = -1;
|
||||
int currentTileY = -1;
|
||||
uint direction = 0;
|
||||
for (uint y = 0; y < height; ++y) {
|
||||
bool shouldBreak = false;
|
||||
for (uint x = 0; x < width; ++x) {
|
||||
if (x > 0 && playerTileOrder[y][x - 1] < 0) {
|
||||
if (_engine->scene->getViewport().convertViewportToScreen(destRects[y][x]).contains(input.mousePos)) {
|
||||
currentTileX = x;
|
||||
currentTileY = y;
|
||||
direction = kLeft;
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
} else if ((int)x < width - 1 && playerTileOrder[y][x + 1] < 0) {
|
||||
if (_engine->scene->getViewport().convertViewportToScreen(destRects[y][x]).contains(input.mousePos)) {
|
||||
currentTileX = x;
|
||||
currentTileY = y;
|
||||
direction = kRight;
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
} else if (y > 0 && playerTileOrder[y - 1][x] < 0) {
|
||||
if (_engine->scene->getViewport().convertViewportToScreen(destRects[y][x]).contains(input.mousePos)) {
|
||||
currentTileX = x;
|
||||
currentTileY = y;
|
||||
direction = kUp;
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
} else if ((int)y < height - 1 && playerTileOrder[y + 1][x] < 0) {
|
||||
if (_engine->scene->getViewport().convertViewportToScreen(destRects[y][x]).contains(input.mousePos)) {
|
||||
currentTileX = x;
|
||||
currentTileY = y;
|
||||
direction = kDown;
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldBreak) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTileX != -1) {
|
||||
_engine->cursorManager->setCursorType(CursorManager::kHotspot);
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
_engine->sound->playSound(clickSound.channelID);
|
||||
switch (direction) {
|
||||
case kUp: {
|
||||
uint curTileID = playerTileOrder[currentTileY][currentTileX];
|
||||
drawTile(curTileID, currentTileX, currentTileY - 1);
|
||||
undrawTile(currentTileX, currentTileY);
|
||||
playerTileOrder[currentTileY - 1][currentTileX] = curTileID;
|
||||
playerTileOrder[currentTileY][currentTileX] = -10;
|
||||
break;
|
||||
}
|
||||
case kDown: {
|
||||
uint curTileID = playerTileOrder[currentTileY][currentTileX];
|
||||
drawTile(curTileID, currentTileX, currentTileY + 1);
|
||||
undrawTile(currentTileX, currentTileY);
|
||||
playerTileOrder[currentTileY + 1][currentTileX] = curTileID;
|
||||
playerTileOrder[currentTileY][currentTileX] = -10;
|
||||
break;
|
||||
}
|
||||
case kLeft: {
|
||||
uint curTileID = playerTileOrder[currentTileY][currentTileX];
|
||||
drawTile(curTileID, currentTileX - 1, currentTileY);
|
||||
undrawTile(currentTileX, currentTileY);
|
||||
playerTileOrder[currentTileY][currentTileX - 1] = curTileID;
|
||||
playerTileOrder[currentTileY][currentTileX] = -10;
|
||||
break;
|
||||
}
|
||||
case kRight: {
|
||||
uint curTileID = playerTileOrder[currentTileY][currentTileX];
|
||||
drawTile(curTileID, currentTileX + 1, currentTileY);
|
||||
undrawTile(currentTileX, currentTileY);
|
||||
playerTileOrder[currentTileY][currentTileX + 1] = curTileID;
|
||||
playerTileOrder[currentTileY][currentTileX] = -10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SliderPuzzle::drawTile(uint tileID, uint posX, uint posY) {
|
||||
Common::Point destPoint(destRects[posY][posX].left - _screenPosition.left, destRects[posY][posX].top - _screenPosition.top);
|
||||
_drawSurface.blitFrom(image, srcRects[tileID / height][tileID % width], destPoint);
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
void SliderPuzzle::undrawTile(uint posX, uint posY) {
|
||||
Common::Rect bounds = destRects[posY][posX];
|
||||
bounds.translate(-_screenPosition.left, -_screenPosition.top);
|
||||
_drawSurface.fillRect(bounds, GraphicsManager::transColor);
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
} // End of namespace Action
|
||||
} // End of namespace Nancy
|
84
engines/nancy/action/sliderpuzzle.h
Normal file
84
engines/nancy/action/sliderpuzzle.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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 NANCY_ACTION_SLIDERPUZZLE_H
|
||||
#define NANCY_ACTION_SLIDERPUZZLE_H
|
||||
|
||||
#include "engines/nancy/action/recordtypes.h"
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
#include "engines/nancy/sound.h"
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace Action {
|
||||
|
||||
class SliderPuzzle: public ActionRecord, public RenderObject {
|
||||
public:
|
||||
enum SolveState { kNotSolved, kWaitForSound };
|
||||
SliderPuzzle(RenderObject &redrawFrom) : RenderObject(redrawFrom) {}
|
||||
virtual ~SliderPuzzle() {}
|
||||
|
||||
virtual void init() override;
|
||||
|
||||
virtual uint16 readData(Common::SeekableReadStream &stream) override;
|
||||
virtual void execute(Nancy::NancyEngine *engine) override;
|
||||
virtual void handleInput(NancyInput &input) override;
|
||||
|
||||
Common::String imageName; // 0x00
|
||||
uint16 width; // 0xA
|
||||
uint16 height; // 0xC
|
||||
Common::Array<Common::Array<Common::Rect>> srcRects; // 0x0E, size 0x240
|
||||
Common::Array<Common::Array<Common::Rect>> destRects; // 0x24E, size 0x240
|
||||
Common::Array<Common::Array<int16>> correctTileOrder; // 0x48E, size 0x48
|
||||
SoundManager::SoundDescription clickSound; // 0x4D6
|
||||
SceneChangeDesc solveExitScene; // 0x4F8
|
||||
FlagDesc flagOnSolve; // 0x502
|
||||
SoundManager::SoundDescription solveSound; // 0x505
|
||||
SceneChangeDesc exitScene; // 0x527
|
||||
FlagDesc flagOnExit; // 0x531
|
||||
Common::Rect exitHotspot; // 0x534
|
||||
|
||||
SolveState solveState = kNotSolved;
|
||||
Graphics::ManagedSurface image;
|
||||
|
||||
static Common::Array<Common::Array<int16>> playerTileOrder;
|
||||
static bool playerHasTriedPuzzle;
|
||||
|
||||
protected:
|
||||
virtual uint16 getZOrder() const override { return 7; }
|
||||
virtual BlitType getBlitType() const override { return kTrans; }
|
||||
virtual bool isViewportRelative() const override { return true; }
|
||||
|
||||
void drawTile(uint tileID, uint posX, uint posY);
|
||||
void undrawTile(uint posX, uint posY);
|
||||
};
|
||||
|
||||
} // End of namespace Action
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_ACTION_SLIDERPUZZLE_H
|
@ -8,6 +8,7 @@ MODULE_OBJS = \
|
||||
action/recordtypes.o \
|
||||
action/rotatinglockpuzzle.o \
|
||||
action/secondaryvideo.o \
|
||||
action/sliderpuzzle.o \
|
||||
action/staticbitmapanim.o \
|
||||
action/telephone.o \
|
||||
ui/frame.o \
|
||||
|
@ -28,10 +28,10 @@
|
||||
namespace Nancy {
|
||||
|
||||
static void readRect(Common::SeekableReadStream &stream, Common::Rect &inRect) {
|
||||
inRect.left = stream.readUint32LE();
|
||||
inRect.top = stream.readUint32LE();
|
||||
inRect.right = stream.readUint32LE();
|
||||
inRect.bottom = stream.readUint32LE();
|
||||
inRect.left = stream.readSint32LE();
|
||||
inRect.top = stream.readSint32LE();
|
||||
inRect.right = stream.readSint32LE();
|
||||
inRect.bottom = stream.readSint32LE();
|
||||
}
|
||||
|
||||
} // End of namespace Nancy
|
||||
|
Loading…
x
Reference in New Issue
Block a user