300 lines
8.4 KiB
C++
300 lines
8.4 KiB
C++
/* 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/util.h"
|
|
|
|
#include "engines/nancy/state/scene.h"
|
|
|
|
#include "engines/nancy/action/puzzle/bballpuzzle.h"
|
|
|
|
namespace Nancy {
|
|
namespace Action {
|
|
|
|
void BBallPuzzle::init() {
|
|
Common::Rect screenBounds = NancySceneState.getViewport().getBounds();
|
|
_drawSurface.create(screenBounds.width(), screenBounds.height(), g_nancy->_graphics->getInputPixelFormat());
|
|
_drawSurface.clear(g_nancy->_graphics->getTransColor());
|
|
setTransparent(true);
|
|
setVisible(true);
|
|
moveTo(screenBounds);
|
|
|
|
g_nancy->_resource->loadImage(_imageName, _image);
|
|
_image.setTransparentColor(_drawSurface.getTransparentColor());
|
|
|
|
// Set up flags
|
|
if (NancySceneState.getEventFlag(_goodShootFlag, g_nancy->_true)) {
|
|
// Last shot entered the hoop
|
|
for (uint i = 0; i < _playerPositionFlags.size(); ++i) {
|
|
if (NancySceneState.getEventFlag(_playerPositionFlags[i], g_nancy->_true)) {
|
|
_curPosition = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Unset last position flag
|
|
NancySceneState.setEventFlag(_playerPositionFlags[_curPosition], g_nancy->_false);
|
|
|
|
if ((int)_curPosition == _positions - 1) {
|
|
// Beat the game once, reset to initial
|
|
_curPosition = 0;
|
|
} else {
|
|
// In the middle of the game, move to next position
|
|
++_curPosition;
|
|
}
|
|
|
|
NancySceneState.setEventFlag(_playerPositionFlags[_curPosition], g_nancy->_true);
|
|
} else {
|
|
// Last shot did not enter the hoop, reset to initial position
|
|
NancySceneState.setEventFlag(_playerPositionFlags[0], g_nancy->_true);
|
|
|
|
for (uint i = 1; i < _playerPositionFlags.size(); ++i) {
|
|
NancySceneState.setEventFlag(_playerPositionFlags[i], g_nancy->_false);
|
|
}
|
|
}
|
|
|
|
// Reset shot type flags
|
|
for (uint i = 0; i < _badShootFlags.size(); ++i) {
|
|
NancySceneState.setEventFlag(_badShootFlags[i], g_nancy->_false);
|
|
}
|
|
|
|
NancySceneState.setEventFlag(_goodShootFlag, g_nancy->_false);
|
|
|
|
// Draw the current player position
|
|
if (_curPosition > 0) {
|
|
_drawSurface.blitFrom(_image, _playerSrcs[_curPosition - 1], _playerDest);
|
|
}
|
|
}
|
|
|
|
void BBallPuzzle::readData(Common::SeekableReadStream &stream) {
|
|
readFilename(stream, _imageName);
|
|
|
|
_positions = stream.readUint16LE();
|
|
_powers = stream.readUint16LE();
|
|
_angles = stream.readUint16LE();
|
|
|
|
_correctVals.resize(_positions);
|
|
for (uint i = 0; i < _positions; ++i) {
|
|
_correctVals[i].x = stream.readUint16LE();
|
|
_correctVals[i].y = stream.readUint16LE();
|
|
}
|
|
|
|
readRect(stream, _shootButtonDest);
|
|
readRect(stream, _minusButtonDest);
|
|
readRect(stream, _plusButtonDest);
|
|
|
|
readRect(stream, _playerDest);
|
|
readRect(stream, _powerDest);
|
|
readRect(stream, _angleDest);
|
|
|
|
readRectArray(stream, _angleSliderHotspots, 3);
|
|
|
|
readRect(stream, _shootButtonSrc);
|
|
readRect(stream, _minusButtonSrc);
|
|
readRect(stream, _plusButtonSrc);
|
|
|
|
readRectArray(stream, _playerSrcs, 3);
|
|
readRectArray(stream, _powerSrcs, 5);
|
|
readRectArray(stream, _anglesSrcs, 2);
|
|
|
|
_shootSound.readNormal(stream);
|
|
_minusSound.readNormal(stream);
|
|
_plusSound.readNormal(stream);
|
|
|
|
_shootSceneChange.readData(stream);
|
|
stream.skip(2);
|
|
|
|
_badShootFlags.resize(3);
|
|
for (uint i = 0; i < 3; ++i) {
|
|
_badShootFlags[i] = stream.readSint16LE();
|
|
}
|
|
|
|
_goodShootFlag = stream.readSint16LE();
|
|
|
|
_playerPositionFlags.resize(_positions);
|
|
for (uint i = 0; i < _positions; ++i) {
|
|
_playerPositionFlags[i] = stream.readSint16LE();
|
|
}
|
|
|
|
_winFlag = stream.readUint16LE();
|
|
|
|
_exitScene.readData(stream);
|
|
readRect(stream, _exitHotspot);
|
|
}
|
|
|
|
void BBallPuzzle::execute() {
|
|
switch (_state) {
|
|
case kBegin:
|
|
init();
|
|
registerGraphics();
|
|
|
|
g_nancy->_sound->loadSound(_plusSound);
|
|
g_nancy->_sound->loadSound(_minusSound);
|
|
g_nancy->_sound->loadSound(_shootSound);
|
|
|
|
_state = kRun;
|
|
// fall through
|
|
case kRun:
|
|
if (_pressedButton) {
|
|
if (g_nancy->_sound->isSoundPlaying(_plusSound) || g_nancy->_sound->isSoundPlaying(_minusSound)) {
|
|
return;
|
|
}
|
|
|
|
_pressedButton = false;
|
|
_drawSurface.fillRect(_powerDest, _drawSurface.getTransparentColor());
|
|
_drawSurface.fillRect(_plusButtonDest, _drawSurface.getTransparentColor());
|
|
_drawSurface.fillRect(_minusButtonDest, _drawSurface.getTransparentColor());
|
|
|
|
if (_curPower > 0) {
|
|
_drawSurface.blitFrom(_image, _powerSrcs[_curPower - 1], _powerDest);
|
|
}
|
|
|
|
_needsRedraw = true;
|
|
}
|
|
|
|
break;
|
|
case kActionTrigger:
|
|
if (_pressedButton) {
|
|
// Pressed the shoot button
|
|
if (g_nancy->_sound->isSoundPlaying(_shootSound)) {
|
|
return;
|
|
}
|
|
|
|
int16 flagToSet = -1;
|
|
|
|
if ((int)_curPower == _correctVals[_curPosition].x && (int)_curAngle == _correctVals[_curPosition].y) {
|
|
// Selected correct values
|
|
flagToSet = _goodShootFlag;
|
|
|
|
if ((int)_curPosition == _positions - 1) {
|
|
// Last throw, mark puzzle as solved
|
|
NancySceneState.setEventFlag(_winFlag, g_nancy->_true);
|
|
}
|
|
} else if (_curPower == 0) {
|
|
// Low throw
|
|
flagToSet = _badShootFlags[2];
|
|
} else if ((int)_curPower >= _correctVals[_curPosition].x && (int)_curAngle <= _correctVals[_curPosition].y) {
|
|
// High throw
|
|
flagToSet = _badShootFlags[0];
|
|
} else {
|
|
// Mid throw
|
|
flagToSet = _badShootFlags[1];
|
|
}
|
|
|
|
NancySceneState.setEventFlag(flagToSet, g_nancy->_true);
|
|
NancySceneState.changeScene(_shootSceneChange);
|
|
} else {
|
|
// Exited the puzzle
|
|
_exitScene.execute();
|
|
}
|
|
|
|
g_nancy->_sound->stopSound(_plusSound);
|
|
g_nancy->_sound->stopSound(_minusSound);
|
|
g_nancy->_sound->stopSound(_shootSound);
|
|
|
|
finishExecution();
|
|
}
|
|
}
|
|
|
|
void BBallPuzzle::handleInput(NancyInput &input) {
|
|
Common::Point localMousePos = input.mousePos;
|
|
Common::Rect vpPos = NancySceneState.getViewport().getScreenPosition();
|
|
localMousePos -= { vpPos.left, vpPos.top };
|
|
|
|
if (_exitHotspot.contains(localMousePos)) {
|
|
g_nancy->_cursor->setCursorType(g_nancy->_cursor->_puzzleExitCursor);
|
|
|
|
if (!_pressedButton &&input.input & NancyInput::kLeftMouseButtonUp) {
|
|
_state = kActionTrigger;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
for (uint i = 0; i < _angleSliderHotspots.size(); ++i) {
|
|
if (_curAngle != i && _angleSliderHotspots[i].contains(localMousePos)) {
|
|
g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
|
|
|
|
if (!_pressedButton && input.input & NancyInput::kLeftMouseButtonUp) {
|
|
_drawSurface.fillRect(_angleDest, _drawSurface.getTransparentColor());
|
|
|
|
if (i > 0) {
|
|
_drawSurface.blitFrom(_image, _anglesSrcs[i - 1], _angleDest);
|
|
}
|
|
|
|
_curAngle = i;
|
|
_needsRedraw = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (_curPower > 0 && _minusButtonDest.contains(localMousePos)) {
|
|
g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
|
|
|
|
if (!_pressedButton && input.input & NancyInput::kLeftMouseButtonUp) {
|
|
--_curPower;
|
|
_drawSurface.blitFrom(_image, _minusButtonSrc, _minusButtonDest);
|
|
g_nancy->_sound->playSound(_minusSound);
|
|
_pressedButton = true;
|
|
_needsRedraw = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ((int)_curPower < _powers - 1 && _plusButtonDest.contains(localMousePos)) {
|
|
g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
|
|
|
|
if (!_pressedButton && input.input & NancyInput::kLeftMouseButtonUp) {
|
|
++_curPower;
|
|
_drawSurface.blitFrom(_image, _plusButtonSrc, _plusButtonDest);
|
|
g_nancy->_sound->playSound(_plusSound);
|
|
_pressedButton = true;
|
|
_needsRedraw = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (_shootButtonDest.contains(localMousePos)) {
|
|
g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
|
|
|
|
if (!_pressedButton && input.input & NancyInput::kLeftMouseButtonUp) {
|
|
_drawSurface.blitFrom(_image, _shootButtonSrc, _shootButtonDest);
|
|
g_nancy->_sound->playSound(_shootSound);
|
|
_pressedButton = true;
|
|
_needsRedraw = true;
|
|
_state = kActionTrigger;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
} // End of namespace Action
|
|
} // End of namespace Nancy
|