From 80583b079b8aebccdedbd6ce4e449bb7caa932e8 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 14 Jul 2011 04:35:45 +0800 Subject: [PATCH] ASYLUM: Pipes puzzle: add spiders --- engines/asylum/puzzles/pipes.cpp | 123 ++++++++++++++++++++++++++----- engines/asylum/puzzles/pipes.h | 37 +++++++++- 2 files changed, 141 insertions(+), 19 deletions(-) diff --git a/engines/asylum/puzzles/pipes.cpp b/engines/asylum/puzzles/pipes.cpp index c7225cbd4d0..ee2c01e76ef 100644 --- a/engines/asylum/puzzles/pipes.cpp +++ b/engines/asylum/puzzles/pipes.cpp @@ -103,19 +103,13 @@ const Common::Point peepholePoints[] = { const uint32 peepholeResources[] = {15, 15, 15, 15, 32, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 32, 32, 15, 15, 32, 32, 15, 15, 15, 15,15, 15, 15, 15, 32, 15, 15, 15, 15, 15, 15, 15}; +const double LOG2 = 0.6931471; + ////////////////////////////////////////////////////////////////////////// // Peephole ////////////////////////////////////////////////////////////////////////// bool Peephole::marks[peepholesCount]; -void Peephole::connect(Connector *connector) { - _connectors.push_back(connector); -} - -void Peephole::disconnect(Connector *connector) { - _connectors.remove(connector); -} - void Peephole::startUpWater(bool flag) { if (flag) memset(marks, false, sizeof(marks)); @@ -183,8 +177,8 @@ void Connector::turn() { oldIndex[1] = 2; } } else { - newIndex[0] = log((double)(newState & delta)) / log((double)2); - oldIndex[0] = log((double)(_state & delta)) / log((double)2); + newIndex[0] = log((double)(newState & delta)) / LOG2; + oldIndex[0] = log((double)(_state & delta)) / LOG2; } for (uint32 i = 0; i < (uint32)(delta == kBinNum1111 ? 2 : 1); ++i) { @@ -259,6 +253,49 @@ void Connector::disconnect(Connector *connector) { _isConnected = connector->_isConnected = false; } +////////////////////////////////////////////////////////////////////////// +// Spider +////////////////////////////////////////////////////////////////////////// +Spider::Spider(Common::Rect rect, Common::String id) { + _boundingBox = rect; + _rnd = new Common::RandomSource(Common::String("pipes_spider") + id); + _isAlive = true; + _location.x = _rnd->getRandomNumber(_boundingBox.right - _boundingBox.left) + _boundingBox.left; + _location.y = _rnd->getRandomNumber(_boundingBox.bottom - _boundingBox.top) + _boundingBox.top; + _direction = Direction(1 << _rnd->getRandomNumber(3)); + + randomize(); +} + +void Spider::randomize(Direction excluded) { + if (_rnd->getRandomNumber(5) == 5) + _delta = Common::Point(0, 0); + else { + while (_direction == excluded) + _direction = Direction(1 << _rnd->getRandomNumber(3)); + _delta = Common::Point((_direction & kBinNum0010 ? 1 : 0) - (_direction & kBinNum1000 ? 1 : 0), (_direction & kBinNum0100 ? 1 : 0) - (_direction & kBinNum0001 ? 1 : 0)); + } + + _stepsNumber = _rnd->getRandomNumber(maxStepsNumber - minStepsNumber) + minStepsNumber; + _steps = 0; +} + +Common::Point Spider::move() { + Common::Point previousLocation(_location); + + if (_isAlive) { + if (_steps++ > _stepsNumber) + randomize(); + + if (!_boundingBox.contains(_location + _delta)) + randomize(_direction); + else + _location += _delta; + } + + return previousLocation; +} + ////////////////////////////////////////////////////////////////////////// // PuzzlePipes ////////////////////////////////////////////////////////////////////////// @@ -272,6 +309,9 @@ PuzzlePipes::PuzzlePipes(AsylumEngine *engine) : Puzzle(engine) { } PuzzlePipes::~PuzzlePipes() { + for (uint32 i = 0; i < _spiders.size(); ++i) + delete _spiders[i]; + delete [] _frameIndexSpider; } void PuzzlePipes::reset() { @@ -324,8 +364,10 @@ bool PuzzlePipes::update(const AsylumEvent &evt) { _isLeverReady = false; if (_frameIndexLever) { _frameIndexLever = (_frameIndexLever + 1) % GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[2]); - if (!_frameIndexLever) + if (!_frameIndexLever) { _isLeverReady = true; + getCursor()->show(); + } } // TODO: turn the fountain on @@ -340,6 +382,32 @@ bool PuzzlePipes::update(const AsylumEvent &evt) { if (!_levelFlags[4]) getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[45], 0, Common::Point(518, 108), kDrawFlagNone, 0, 2); + for (uint32 i = 0; i < _spiders.size(); ++i) { + uint32 spiderResourceId; + + switch (_spiders[i]->getDirection()) { + case kDirectionNh: + spiderResourceId = _spiders[i]->isAlive() ? 34 : 37; + break; + case kDirectionEt: + spiderResourceId = _spiders[i]->isAlive() ? 35 : 38; // FIXME + break; + case kDirectionSh: + spiderResourceId = _spiders[i]->isAlive() ? 36 : 39; + break; + case kDirectionWt: + spiderResourceId = _spiders[i]->isAlive() ? 35 : 38; + break; + default: ; + } + + if (_spiders[i]->isVisible(Common::Rect(-10, -10, 650, 490))) { + uint32 frameCountSpider = GraphicResource::getFrameCount(_vm, getWorld()->graphicResourceIds[spiderResourceId]); + _frameIndexSpider[i] = _spiders[i]->isActive() ? (_frameIndexSpider[i] + 1) % frameCountSpider : 0; + getScreen()->addGraphicToQueue(getWorld()->graphicResourceIds[spiderResourceId], _frameIndexSpider[i], _spiders[i]->move(), kDrawFlagNone, 0, 1); + } + } + getScreen()->drawGraphicsInQueue(); getScreen()->copyBackBufferToScreen(); updateCursor(); @@ -361,16 +429,22 @@ bool PuzzlePipes::mouseLeftDown(const AsylumEvent &evt) { if (Common::Rect(540, 90, 590, 250).contains(mousePos)) { if (!_frameIndexLever) ++_frameIndexLever; - + getCursor()->hide(); getSound()->playSound(getWorld()->graphicResourceIds[43], false, Config.sfxVolume - 10); } else { if (_rectIndex != -1) { - getSound()->playSound(getWorld()->graphicResourceIds[42], false, Config.sfxVolume - 10); + if (_rectIndex < ARRAYSIZE(connectorPoints)) { + getSound()->playSound(getWorld()->graphicResourceIds[42], false, Config.sfxVolume - 10); - _connectors[_rectIndex].turn(); - startUpWater(); - memset(_levelFlags, false, sizeof(_levelFlags)); - _levelFlags[checkFlags()] = true; + _connectors[_rectIndex].turn(); + startUpWater(); + memset(_levelFlags, false, sizeof(_levelFlags)); + _levelFlags[checkFlags()] = true; + } else { + getSound()->playSound(getWorld()->graphicResourceIds[44], false, Config.sfxVolume - 10); + _spiders[_rectIndex - ARRAYSIZE(connectorPoints)]->smash(); + _frameIndexSpider[_rectIndex - ARRAYSIZE(connectorPoints)] = 0; + } } } @@ -447,6 +521,17 @@ void PuzzlePipes::setup() { _connectors[10].initGroup(); _connectors[11].initGroup(); + uint32 i = rnd(7); + if (i & kBinNum0001) + _spiders.push_back(new Spider(Common::Rect(-10, 45, 92, 315), "1")); + if (i & kBinNum0010) + _spiders.push_back(new Spider(Common::Rect(-10, 389, 149, 476), "2")); + if (i & kBinNum0100) + _spiders.push_back(new Spider(Common::Rect(544, 225, 650, 490), "3")); + + _frameIndexSpider = new uint32[_spiders.size()]; + memset(_frameIndexSpider, 0, sizeof(_frameIndexSpider)); + startUpWater(); } @@ -469,6 +554,10 @@ int32 PuzzlePipes::findRect() { if (Common::Rect(connectorPoints[i].x - 5, connectorPoints[i].y - 5, connectorPoints[i].x + 30, connectorPoints[i].y + 30).contains(getCursor()->position())) return i; + for (uint32 i = 0; i < _spiders.size(); ++i) + if (_spiders[i]->getPolygon(Common::Rect(10, 10, 30, 30)).contains(getCursor()->position())) + return ARRAYSIZE(connectorPoints) + i; + return -1; } diff --git a/engines/asylum/puzzles/pipes.h b/engines/asylum/puzzles/pipes.h index ae3f6407703..ac5b00fc779 100644 --- a/engines/asylum/puzzles/pipes.h +++ b/engines/asylum/puzzles/pipes.h @@ -27,6 +27,9 @@ #include "common/list.h" #include "common/hashmap.h" +#include "common/array.h" +#include "common/random.h" +#include "common/str.h" namespace Asylum { @@ -76,8 +79,8 @@ public: uint32 getLevel1() { return _flowValues[0] + _flowValues[1] + _flowValues[2] + _flowValues[3]; } bool isConnected() { return isConnected(0) || isConnected(1) || isConnected(2) || isConnected(3); } - void connect(Connector *connector); - void disconnect(Connector *connector); + void connect(Connector *connector) { _connectors.push_back(connector); } + void disconnect(Connector *connector) { _connectors.remove(connector); } void startUpWater(bool flag = false); private: @@ -118,6 +121,34 @@ private: friend void Peephole::startUpWater(bool); }; +class Spider { +public: + Spider(Common::Rect rect, Common::String id); + ~Spider() { delete _rnd; } + + bool isAlive() const { return _isAlive; } + bool isActive() const { return _delta != Common::Point(0, 0); } + bool isVisible(Common::Rect rect) const { return rect.contains(_location); } + + Direction getDirection() const { return _direction; } + Common::Rect getPolygon(Common::Rect frame) const { return Common::Rect(_location.x - frame.left, _location.y - frame.top, _location.x + frame.right, _location.y + frame.bottom); } + + Common::Point move(); + void smash() { _isAlive = false; } +private: + static const uint32 minStepsNumber = 20, maxStepsNumber = 200; + Common::RandomSource *_rnd; + bool _isAlive; + Common::Point _location; + Common::Point _delta; + Common::Rect _boundingBox; + Direction _direction; + uint32 _stepsNumber; + uint32 _steps; + + void randomize(Direction excluded = kDirectionNowhere); +}; + class PuzzlePipes : public Puzzle { public: PuzzlePipes(AsylumEngine *engine); @@ -136,6 +167,8 @@ private: Connector _connectors[connectorsCount]; Peephole _peepholes[peepholesCount]; Peephole *_sinks[4], *_sources[4]; + Common::Array _spiders; + uint32 *_frameIndexSpider; ////////////////////////////////////////////////////////////////////////// // Event Handling