aboutsummaryrefslogtreecommitdiff
path: root/engines/gob/minigames
diff options
context:
space:
mode:
Diffstat (limited to 'engines/gob/minigames')
-rw-r--r--engines/gob/minigames/geisha/mouth.cpp170
-rw-r--r--engines/gob/minigames/geisha/mouth.h75
-rw-r--r--engines/gob/minigames/geisha/penetration.cpp164
-rw-r--r--engines/gob/minigames/geisha/penetration.h20
4 files changed, 375 insertions, 54 deletions
diff --git a/engines/gob/minigames/geisha/mouth.cpp b/engines/gob/minigames/geisha/mouth.cpp
new file mode 100644
index 0000000000..605ffe420f
--- /dev/null
+++ b/engines/gob/minigames/geisha/mouth.cpp
@@ -0,0 +1,170 @@
+/* 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 "common/util.h"
+#include "common/textconsole.h"
+
+#include "gob/minigames/geisha/mouth.h"
+
+namespace Gob {
+
+namespace Geisha {
+
+Mouth::Mouth(const ANIFile &ani, const CMPFile &cmp,
+ uint16 mouthAnim, uint16 mouthSprite, uint16 floorSprite) : ANIObject(ani) {
+
+ _sprite = new ANIObject(cmp);
+ _sprite->setAnimation(mouthSprite);
+ _sprite->setVisible(true);
+
+ for (int i = 0; i < kFloorCount; i++) {
+ _floor[i] = new ANIObject(cmp);
+ _floor[i]->setAnimation(floorSprite);
+ _floor[i]->setVisible(true);
+ }
+
+ _state = kStateDeactivated;
+
+ setAnimation(mouthAnim);
+ setMode(kModeOnce);
+ setPause(true);
+ setVisible(true);
+}
+
+Mouth::~Mouth() {
+ for (int i = 0; i < kFloorCount; i++)
+ delete _floor[i];
+
+ delete _sprite;
+}
+
+void Mouth::advance() {
+ if (_state != kStateActivated)
+ return;
+
+ // Animation finished, set state to dead
+ if (isPaused()) {
+ _state = kStateDead;
+ return;
+ }
+
+ ANIObject::advance();
+}
+
+void Mouth::activate() {
+ if (_state != kStateDeactivated)
+ return;
+
+ _state = kStateActivated;
+
+ setPause(false);
+}
+
+bool Mouth::isDeactivated() const {
+ return _state == kStateDeactivated;
+}
+
+void Mouth::setPosition(int16 x, int16 y) {
+ ANIObject::setPosition(x, y);
+
+ int16 floorWidth, floorHeight;
+ _floor[0]->getFrameSize(floorWidth, floorHeight);
+
+ _sprite->setPosition(x, y);
+
+ for (int i = 0; i < kFloorCount; i++)
+ _floor[i]->setPosition(x + (i * floorWidth), y);
+}
+
+bool Mouth::draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ // If the mouth is deactivated, draw the default mouth sprite
+ if (_state == kStateDeactivated)
+ return _sprite->draw(dest, left, top, right, bottom);
+
+ // If the mouth is activated, draw the current mouth animation sprite
+ if (_state == kStateActivated)
+ return ANIObject::draw(dest, left, top, right, bottom);
+
+ // If the mouth is dead, draw the floor tiles
+ if (_state == kStateDead) {
+ int16 fLeft, fRight, fTop, fBottom;
+ bool drawn = false;
+
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0;
+ bottom = 0;
+
+ for (int i = 0; i < kFloorCount; i++) {
+ if (_floor[i]->draw(dest, fLeft, fTop, fRight, fBottom)) {
+ drawn = true;
+ left = MIN(left , fLeft);
+ top = MIN(top , fTop);
+ right = MAX(right , fRight);
+ bottom = MAX(bottom, fBottom);
+ }
+ }
+
+ return drawn;
+ }
+
+ return false;
+}
+
+bool Mouth::clear(Surface &dest, int16 &left , int16 &top, int16 &right, int16 &bottom) {
+ // If the mouth is deactivated, clear the default mouth sprite
+ if (_state == kStateDeactivated)
+ return _sprite->clear(dest, left, top, right, bottom);
+
+ // If the mouth is activated, clear the current mouth animation sprite
+ if (_state == kStateActivated)
+ return ANIObject::clear(dest, left, top, right, bottom);
+
+ // If the mouth is clear, draw the floor tiles
+ if (_state == kStateDead) {
+ int16 fLeft, fRight, fTop, fBottom;
+ bool cleared = false;
+
+ left = 0x7FFF;
+ top = 0x7FFF;
+ right = 0;
+ bottom = 0;
+
+ for (int i = 0; i < kFloorCount; i++) {
+ if (_floor[i]->clear(dest, fLeft, fTop, fRight, fBottom)) {
+ cleared = true;
+ left = MIN(left , fLeft);
+ top = MIN(top , fTop);
+ right = MAX(right , fRight);
+ bottom = MAX(bottom, fBottom);
+ }
+ }
+
+ return cleared;
+ }
+
+ return false;
+}
+
+} // End of namespace Geisha
+
+} // End of namespace Gob
diff --git a/engines/gob/minigames/geisha/mouth.h b/engines/gob/minigames/geisha/mouth.h
new file mode 100644
index 0000000000..2e0cfcd5d0
--- /dev/null
+++ b/engines/gob/minigames/geisha/mouth.h
@@ -0,0 +1,75 @@
+/* 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 GOB_MINIGAMES_GEISHA_MOUTH_H
+#define GOB_MINIGAMES_GEISHA_MOUTH_H
+
+#include "gob/aniobject.h"
+
+namespace Gob {
+
+namespace Geisha {
+
+/** A kissing/biting mouth in Geisha's "Penetration" minigame. */
+class Mouth : public ANIObject {
+public:
+ Mouth(const ANIFile &ani, const CMPFile &cmp,
+ uint16 mouthAnim, uint16 mouthSprite, uint16 floorSprite);
+ ~Mouth();
+
+ /** Advance the animation to the next frame. */
+ void advance();
+
+ /** Active the mouth's animation. */
+ void activate();
+
+ /** Is the mouth deactivated? */
+ bool isDeactivated() const;
+
+ /** Set the current position. */
+ void setPosition(int16 x, int16 y);
+
+ /** Draw the current frame onto the surface and return the affected rectangle. */
+ bool draw(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+ /** Draw the current frame from the surface and return the affected rectangle. */
+ bool clear(Surface &dest, int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+private:
+ static const int kFloorCount = 2;
+
+ enum State {
+ kStateDeactivated,
+ kStateActivated,
+ kStateDead
+ };
+
+ ANIObject *_sprite;
+ ANIObject *_floor[kFloorCount];
+
+ State _state;
+};
+
+} // End of namespace Geisha
+
+} // End of namespace Gob
+
+#endif // GOB_MINIGAMES_GEISHA_MOUTH_H
diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index 35802e6733..c8f96f825a 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -31,6 +31,7 @@
#include "gob/minigames/geisha/penetration.h"
#include "gob/minigames/geisha/meter.h"
+#include "gob/minigames/geisha/mouth.h"
namespace Gob {
@@ -60,28 +61,39 @@ static const int kColorHealth = 15;
static const int kColorBlack = 10;
static const int kColorFloor = 13;
+enum Sprite {
+ kSpriteFloorShield = 25,
+ kSpriteExit = 29,
+ kSpriteFloor = 30,
+ kSpriteWall = 31,
+ kSpriteMouthBite = 32,
+ kSpriteMouthKiss = 33
+};
+
enum Animation {
- kAnimationDriveS = 4,
- kAnimationDriveE = 5,
- kAnimationDriveN = 6,
- kAnimationDriveW = 7,
- kAnimationDriveSE = 8,
- kAnimationDriveNE = 9,
- kAnimationDriveSW = 10,
- kAnimationDriveNW = 11,
- kAnimationShootS = 12,
- kAnimationShootN = 13,
- kAnimationShootW = 14,
- kAnimationShootE = 15,
- kAnimationShootNE = 16,
- kAnimationShootSE = 17,
- kAnimationShootSW = 18,
- kAnimationShootNW = 19,
- kAnimationExplodeN = 28,
- kAnimationExplodeS = 29,
- kAnimationExplodeW = 30,
- kAnimationExplodeE = 31,
- kAnimationExit = 32
+ kAnimationDriveS = 4,
+ kAnimationDriveE = 5,
+ kAnimationDriveN = 6,
+ kAnimationDriveW = 7,
+ kAnimationDriveSE = 8,
+ kAnimationDriveNE = 9,
+ kAnimationDriveSW = 10,
+ kAnimationDriveNW = 11,
+ kAnimationShootS = 12,
+ kAnimationShootN = 13,
+ kAnimationShootW = 14,
+ kAnimationShootE = 15,
+ kAnimationShootNE = 16,
+ kAnimationShootSE = 17,
+ kAnimationShootSW = 18,
+ kAnimationShootNW = 19,
+ kAnimationExplodeN = 28,
+ kAnimationExplodeS = 29,
+ kAnimationExplodeW = 30,
+ kAnimationExplodeE = 31,
+ kAnimationExit = 32,
+ kAnimationMouthKiss = 33,
+ kAnimationMouthBite = 34
};
static const int kMapTileWidth = 24;
@@ -197,8 +209,17 @@ Penetration::Position::Position(uint16 pX, uint16 pY) : x(pX), y(pY) {
}
+Penetration::ManagedMouth::ManagedMouth(uint16 pX, uint16 pY, MouthType t) :
+ Position(pX, pY), mouth(0), type(t) {
+}
+
+Penetration::ManagedMouth::~ManagedMouth() {
+ delete mouth;
+}
+
+
Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0),
- _shieldMeter(0), _healthMeter(0), _floor(0), _mapUpdate(false), _mapX(0), _mapY(0),
+ _shieldMeter(0), _healthMeter(0), _floor(0), _mapX(0), _mapY(0),
_subTileX(0), _subTileY(0) {
_background = new Surface(320, 200, 1);
@@ -279,6 +300,9 @@ void Penetration::init() {
createMap();
+ for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); m++)
+ _mapAnims.push_back(m->mouth);
+
_sub = new ANIObject(*_objects);
_sub->setAnimation(kAnimationDriveN);
@@ -289,8 +313,13 @@ void Penetration::init() {
}
void Penetration::deinit() {
+ _mapAnims.clear();
_anims.clear();
+ _shields.clear();
+
+ _mouths.clear();
+
delete _sub;
delete _objects;
@@ -311,6 +340,8 @@ void Penetration::createMap() {
_shields.clear();
+ _mouths.clear();
+
_map->fill(kColorBlack);
// Draw the map tiles
@@ -323,23 +354,21 @@ void Penetration::createMap() {
switch (*mapTile) {
case 0: // Floor
- _sprites->draw(*_map, 30, posX, posY);
+ _sprites->draw(*_map, kSpriteFloor, posX, posY);
break;
case 49: // Emergency exit (needs access pass)
if (_hasAccessPass) {
- // Draw an exit. Now works like a regular exit
- _sprites->draw(*_map, 29, posX, posY);
- *mapTile = 51;
+ _sprites->draw(*_map, kSpriteExit, posX, posY);
+ *mapTile = 51; // Now works like a normal exit
} else
- // Draw a wall
- _sprites->draw(*_map, 31, posX, posY);
+ _sprites->draw(*_map, kSpriteWall, posX, posY);
break;
case 50: // Wall
- _sprites->draw(*_map, 31, posX, posY);
+ _sprites->draw(*_map, kSpriteWall, posX, posY);
break;
case 51: // Regular exit
@@ -349,23 +378,27 @@ void Penetration::createMap() {
if (_floor == 2) {
if (!_hasAccessPass) {
- // It's now a wall
- _sprites->draw(*_map, 31, posX, posY);
- *mapTile = 50;
+ _sprites->draw(*_map, kSpriteWall, posX, posY);
+ *mapTile = 50; // It's now a wall
} else
- _sprites->draw(*_map, 29, posX, posY);
+ _sprites->draw(*_map, kSpriteExit, posX, posY);
} else
- _sprites->draw(*_map, 29, posX, posY);
+ _sprites->draw(*_map, kSpriteExit, posX, posY);
} else
// Always works in test mode
- _sprites->draw(*_map, 29, posX, posY);
+ _sprites->draw(*_map, kSpriteExit, posX, posY);
break;
case 52: // Left side of biting mouth
- _sprites->draw(*_map, 32, posX, posY);
+ _mouths.push_back(ManagedMouth(x, y, kMouthTypeBite));
+
+ _mouths.back().mouth =
+ new Mouth(*_objects, *_sprites, kAnimationMouthBite, kSpriteMouthBite, kSpriteFloor);
+
+ _mouths.back().mouth->setPosition(posX, posY);
break;
case 53: // Right side of biting mouth
@@ -373,7 +406,12 @@ void Penetration::createMap() {
break;
case 54: // Left side of kissing mouth
- _sprites->draw(*_map, 33, posX, posY);
+ _mouths.push_back(ManagedMouth(x, y, kMouthTypeKiss));
+
+ _mouths.back().mouth =
+ new Mouth(*_objects, *_sprites, kAnimationMouthKiss, kSpriteMouthKiss, kSpriteFloor);
+
+ _mouths.back().mouth->setPosition(posX, posY);
break;
case 55: // Right side of kissing mouth
@@ -381,8 +419,8 @@ void Penetration::createMap() {
break;
case 56: // Shield lying on the floor
- _sprites->draw(*_map, 30, posX , posY ); // Floor
- _sprites->draw(*_map, 25, posX + 4, posY + 8); // Shield
+ _sprites->draw(*_map, kSpriteFloor , posX , posY ); // Floor
+ _sprites->draw(*_map, kSpriteFloorShield, posX + 4, posY + 8); // Shield
_map->fillRect(posX + 4, posY + 8, posX + 7, posY + 18, kColorFloor); // Area left to shield
_map->fillRect(posX + 17, posY + 8, posX + 20, posY + 18, kColorFloor); // Area right to shield
@@ -391,7 +429,7 @@ void Penetration::createMap() {
break;
case 57: // Start position
- _sprites->draw(*_map, 30, posX, posY);
+ _sprites->draw(*_map, kSpriteFloor, posX, posY);
*mapTile = 0;
_subTileX = x;
@@ -403,8 +441,6 @@ void Penetration::createMap() {
}
}
}
-
- _mapUpdate = true;
}
void Penetration::initScreen() {
@@ -479,12 +515,11 @@ void Penetration::moveSub(int x, int y, uint16 animation) {
_subTileX = (_mapX + (kMapTileWidth / 2)) / kMapTileWidth;
_subTileY = (_mapY + (kMapTileHeight / 2)) / kMapTileHeight;
- _mapUpdate = true;
-
if (_sub->getAnimation() != animation)
_sub->setAnimation(animation);
checkShields();
+ checkMouths();
}
void Penetration::checkShields() {
@@ -504,9 +539,37 @@ void Penetration::checkShields() {
}
}
+void Penetration::checkMouths() {
+ for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); ++m) {
+ if (!m->mouth->isDeactivated())
+ continue;
+
+ if ((( m->x == _subTileX) && (m->y == _subTileY)) ||
+ (((m->x + 1) == _subTileX) && (m->y == _subTileY))) {
+
+ m->mouth->activate();
+ }
+ }
+}
+
void Penetration::updateAnims() {
int16 left = 0, top = 0, right = 0, bottom = 0;
+ // Clear the previous map animation frames
+ for (Common::List<ANIObject *>::iterator a = _mapAnims.reverse_begin();
+ a != _mapAnims.end(); --a) {
+
+ (*a)->clear(*_map, left, top, right, bottom);
+ }
+
+ // Draw the current map animation frames
+ for (Common::List<ANIObject *>::iterator a = _mapAnims.begin();
+ a != _mapAnims.end(); ++a) {
+
+ (*a)->draw(*_map, left, top, right, bottom);
+ (*a)->advance();
+ }
+
// Clear the previous animation frames
for (Common::List<ANIObject *>::iterator a = _anims.reverse_begin();
a != _anims.end(); --a) {
@@ -515,14 +578,11 @@ void Penetration::updateAnims() {
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
}
- if (_mapUpdate) {
- _vm->_draw->_backSurface->blit(*_map, _mapX, _mapY,
- _mapX + kPlayAreaWidth - 1, _mapY + kPlayAreaHeight - 1, kPlayAreaX, kPlayAreaY);
- _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kPlayAreaX, kPlayAreaY,
- kPlayAreaX + kPlayAreaWidth - 1, kPlayAreaY + kPlayAreaHeight - 1);
- }
-
- _mapUpdate = false;
+ // Draw the map
+ _vm->_draw->_backSurface->blit(*_map, _mapX, _mapY,
+ _mapX + kPlayAreaWidth - 1, _mapY + kPlayAreaHeight - 1, kPlayAreaX, kPlayAreaY);
+ _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kPlayAreaX, kPlayAreaY,
+ kPlayAreaX + kPlayAreaWidth - 1, kPlayAreaY + kPlayAreaHeight - 1);
// Draw the current animation frames
for (Common::List<ANIObject *>::iterator a = _anims.begin();
diff --git a/engines/gob/minigames/geisha/penetration.h b/engines/gob/minigames/geisha/penetration.h
index 4d3455b638..ef0e3b10f0 100644
--- a/engines/gob/minigames/geisha/penetration.h
+++ b/engines/gob/minigames/geisha/penetration.h
@@ -36,6 +36,7 @@ class ANIFile;
namespace Geisha {
class Meter;
+class Mouth;
/** Geisha's "Penetration" minigame. */
class Penetration {
@@ -61,6 +62,19 @@ private:
Position(uint16 pX, uint16 pY);
};
+ enum MouthType {
+ kMouthTypeBite,
+ kMouthTypeKiss
+ };
+
+ struct ManagedMouth : public Position {
+ Mouth *mouth;
+ MouthType type;
+
+ ManagedMouth(uint16 pX, uint16 pY, MouthType t);
+ ~ManagedMouth();
+ };
+
GobEngine *_vm;
bool _hasAccessPass;
@@ -74,6 +88,7 @@ private:
ANIObject *_sub;
Common::List<ANIObject *> _anims;
+ Common::List<ANIObject *> _mapAnims;
Meter *_shieldMeter;
Meter *_healthMeter;
@@ -83,14 +98,14 @@ private:
Surface *_map;
byte _mapTiles[kMapWidth * kMapHeight];
- bool _mapUpdate;
uint16 _mapX;
uint16 _mapY;
uint8 _subTileX;
uint8 _subTileY;
- Common::List<Position> _shields;
+ Common::List<Position> _shields;
+ Common::List<ManagedMouth> _mouths;
void init();
@@ -110,6 +125,7 @@ private:
bool isWalkable(byte tile) const;
void checkShields();
+ void checkMouths();
};
} // End of namespace Geisha