aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorSven Hesse2012-06-06 02:52:19 +0200
committerSven Hesse2012-06-06 03:33:35 +0200
commitb83ac21f6008287414d59ad7f9c88b63bd93bac5 (patch)
tree9b87a703053367bcf8c20de47bfe732abbdcdc10 /engines
parent93dda1b227fa11d1da2d923ca63a580343f6ba4e (diff)
downloadscummvm-rg350-b83ac21f6008287414d59ad7f9c88b63bd93bac5.tar.gz
scummvm-rg350-b83ac21f6008287414d59ad7f9c88b63bd93bac5.tar.bz2
scummvm-rg350-b83ac21f6008287414d59ad7f9c88b63bd93bac5.zip
GOB: Implement Penetration submarine shooting and dying
Shots don't result in bullets yet, though
Diffstat (limited to 'engines')
-rw-r--r--engines/gob/minigames/geisha/mouth.cpp1
-rw-r--r--engines/gob/minigames/geisha/penetration.cpp149
-rw-r--r--engines/gob/minigames/geisha/penetration.h29
-rw-r--r--engines/gob/minigames/geisha/submarine.cpp233
-rw-r--r--engines/gob/minigames/geisha/submarine.h96
-rw-r--r--engines/gob/module.mk1
6 files changed, 435 insertions, 74 deletions
diff --git a/engines/gob/minigames/geisha/mouth.cpp b/engines/gob/minigames/geisha/mouth.cpp
index 605ffe420f..7ba9f86f8c 100644
--- a/engines/gob/minigames/geisha/mouth.cpp
+++ b/engines/gob/minigames/geisha/mouth.cpp
@@ -21,7 +21,6 @@
*/
#include "common/util.h"
-#include "common/textconsole.h"
#include "gob/minigames/geisha/mouth.h"
diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index a188995372..2c1a4918b9 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -73,27 +73,6 @@ enum Sprite {
};
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,
kAnimationMouthKiss = 33,
kAnimationMouthBite = 34
};
@@ -220,9 +199,18 @@ Penetration::ManagedMouth::~ManagedMouth() {
}
+Penetration::ManagedSub::ManagedSub(uint16 pX, uint16 pY) : Position(pX, pY), sub(0) {
+ mapX = x * kMapTileWidth;
+ mapY = y * kMapTileHeight;
+}
+
+Penetration::ManagedSub::~ManagedSub() {
+ delete sub;
+}
+
+
Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0),
- _shieldMeter(0), _healthMeter(0), _floor(0), _mapX(0), _mapY(0),
- _subTileX(0), _subTileY(0) {
+ _shieldMeter(0), _healthMeter(0), _floor(0) {
_background = new Surface(320, 200, 1);
@@ -255,7 +243,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
_vm->_draw->blitInvalidated();
_vm->_video->retrace();
- while (!_vm->shouldQuit()) {
+ while (!_vm->shouldQuit() && !isDead() && !hasWon()) {
updateAnims();
// Draw and wait for the end of the frame
@@ -278,7 +266,8 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
}
deinit();
- return false;
+
+ return hasWon();
}
void Penetration::init() {
@@ -286,6 +275,7 @@ void Penetration::init() {
_vm->_sound->sampleLoad(&_soundShield, SOUND_SND, "boucl.snd");
_vm->_sound->sampleLoad(&_soundBite , SOUND_SND, "pervet.snd");
_vm->_sound->sampleLoad(&_soundKiss , SOUND_SND, "baise.snd");
+ _vm->_sound->sampleLoad(&_soundShoot , SOUND_SND, "tirgim.snd");
_background->clear();
@@ -310,19 +300,14 @@ void Penetration::init() {
for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); m++)
_mapAnims.push_back(m->mouth);
- _sub = new ANIObject(*_objects);
-
- _sub->setAnimation(kAnimationDriveN);
- _sub->setPosition(kPlayAreaX + kPlayAreaBorderWidth, kPlayAreaY + kPlayAreaBorderHeight);
- _sub->setVisible(true);
-
- _anims.push_back(_sub);
+ _anims.push_back(_sub->sub);
}
void Penetration::deinit() {
_soundShield.free();
_soundBite.free();
_soundKiss.free();
+ _soundShoot.free();
_mapAnims.clear();
_anims.clear();
@@ -349,8 +334,10 @@ void Penetration::createMap() {
// Copy the correct map
memcpy(_mapTiles, kMaps[_testMode ? 1 : 0][_floor], kMapWidth * kMapHeight);
- _shields.clear();
+ delete _sub;
+ _sub = 0;
+ _shields.clear();
_mouths.clear();
_map->fill(kColorBlack);
@@ -441,17 +428,22 @@ void Penetration::createMap() {
case 57: // Start position
_sprites->draw(*_map, kSpriteFloor, posX, posY);
+
*mapTile = 0;
- _subTileX = x;
- _subTileY = y;
+ delete _sub;
+
+ _sub = new ManagedSub(x, y);
- _mapX = _subTileX * kMapTileWidth;
- _mapY = _subTileY * kMapTileHeight;
+ _sub->sub = new Submarine(*_objects);
+ _sub->sub->setPosition(kPlayAreaX + kPlayAreaBorderWidth, kPlayAreaY + kPlayAreaBorderHeight);
break;
}
}
}
+
+ if (!_sub)
+ error("Geisha: No starting position in floor %d (testmode: %d", _floor, _testMode);
}
void Penetration::initScreen() {
@@ -491,51 +483,64 @@ bool Penetration::isWalkable(byte tile) const {
void Penetration::handleSub(int16 key) {
if (key == kKeyLeft)
- moveSub(-5, 0, kAnimationDriveW);
+ subMove(-5, 0, Submarine::kDirectionW);
else if (key == kKeyRight)
- moveSub( 5, 0, kAnimationDriveE);
+ subMove( 5, 0, Submarine::kDirectionE);
else if (key == kKeyUp)
- moveSub( 0, -5, kAnimationDriveN);
+ subMove( 0, -5, Submarine::kDirectionN);
else if (key == kKeyDown)
- moveSub( 0, 5, kAnimationDriveS);
+ subMove( 0, 5, Submarine::kDirectionS);
+ else if (key == kKeySpace)
+ subShoot();
}
-void Penetration::moveSub(int x, int y, uint16 animation) {
+void Penetration::subMove(int x, int y, Submarine::Direction direction) {
+ if (!_sub->sub->canMove())
+ return;
+
// Limit the movement to walkable tiles
int16 minX = 0;
- if ((_subTileX > 0) && !isWalkable(_mapTiles[_subTileY * kMapWidth + (_subTileX - 1)]))
- minX = _subTileX * kMapTileWidth;
+ if ((_sub->x > 0) && !isWalkable(_mapTiles[_sub->y * kMapWidth + (_sub->x - 1)]))
+ minX = _sub->x * kMapTileWidth;
int16 maxX = kMapWidth * kMapTileWidth;
- if ((_subTileX < (kMapWidth - 1)) && !isWalkable(_mapTiles[_subTileY * kMapWidth + (_subTileX + 1)]))
- maxX = _subTileX * kMapTileWidth;
+ if ((_sub->x < (kMapWidth - 1)) && !isWalkable(_mapTiles[_sub->y * kMapWidth + (_sub->x + 1)]))
+ maxX = _sub->x * kMapTileWidth;
int16 minY = 0;
- if ((_subTileY > 0) && !isWalkable(_mapTiles[(_subTileY - 1) * kMapWidth + _subTileX]))
- minY = _subTileY * kMapTileHeight;
+ if ((_sub->y > 0) && !isWalkable(_mapTiles[(_sub->y - 1) * kMapWidth + _sub->x]))
+ minY = _sub->y * kMapTileHeight;
int16 maxY = kMapHeight * kMapTileHeight;
- if ((_subTileY < (kMapHeight - 1)) && !isWalkable(_mapTiles[(_subTileY + 1) * kMapWidth + _subTileX]))
- maxY = _subTileY * kMapTileHeight;
+ if ((_sub->y < (kMapHeight - 1)) && !isWalkable(_mapTiles[(_sub->y + 1) * kMapWidth + _sub->x]))
+ maxY = _sub->y * kMapTileHeight;
- _mapX = CLIP<int16>(_mapX + x, minX, maxX);
- _mapY = CLIP<int16>(_mapY + y, minY, maxY);
+ _sub->mapX = CLIP<int16>(_sub->mapX + x, minX, maxX);
+ _sub->mapY = CLIP<int16>(_sub->mapY + y, minY, maxY);
// The tile the sub is on is where its mid-point is
- _subTileX = (_mapX + (kMapTileWidth / 2)) / kMapTileWidth;
- _subTileY = (_mapY + (kMapTileHeight / 2)) / kMapTileHeight;
+ _sub->x = (_sub->mapX + (kMapTileWidth / 2)) / kMapTileWidth;
+ _sub->y = (_sub->mapY + (kMapTileHeight / 2)) / kMapTileHeight;
- if (_sub->getAnimation() != animation)
- _sub->setAnimation(animation);
+ _sub->sub->turn(direction);
checkShields();
checkMouths();
}
+void Penetration::subShoot() {
+ if (!_sub->sub->canMove())
+ return;
+
+ _sub->sub->shoot();
+
+ _vm->_sound->blasterPlay(&_soundShoot, 1, 0);
+}
+
void Penetration::checkShields() {
for (Common::List<Position>::iterator pos = _shields.begin(); pos != _shields.end(); ++pos) {
- if ((pos->x == _subTileX) && (pos->y == _subTileY)) {
+ if ((pos->x == _sub->x) && (pos->y == _sub->y)) {
// Charge shields
_shieldMeter->setMaxValue();
@@ -558,13 +563,13 @@ void Penetration::checkMouths() {
if (!m->mouth->isDeactivated())
continue;
- if ((( m->x == _subTileX) && (m->y == _subTileY)) ||
- (((m->x + 1) == _subTileX) && (m->y == _subTileY))) {
+ if ((( m->x == _sub->x) && (m->y == _sub->y)) ||
+ (((m->x + 1) == _sub->x) && (m->y == _sub->y))) {
m->mouth->activate();
// Play the mouth sound and do health gain/loss
- if (m->type == kMouthTypeBite) {
+ if (m->type == kMouthTypeBite) {
_vm->_sound->blasterPlay(&_soundBite, 1, 0);
healthLose(230);
} else if (m->type == kMouthTypeKiss) {
@@ -584,6 +589,17 @@ void Penetration::healthGain(int amount) {
void Penetration::healthLose(int amount) {
_healthMeter->decrease(_shieldMeter->decrease(amount));
+
+ if (_healthMeter->getValue() == 0)
+ _sub->sub->die();
+}
+
+bool Penetration::isDead() const {
+ return _sub && _sub->sub->isDead();
+}
+
+bool Penetration::hasWon() const {
+ return _floor > kFloorCount;
}
void Penetration::updateAnims() {
@@ -612,11 +628,14 @@ void Penetration::updateAnims() {
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
}
- // 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);
+ if (_sub) {
+ // Draw the map
+
+ _vm->_draw->_backSurface->blit(*_map, _sub->mapX, _sub->mapY,
+ _sub->mapX + kPlayAreaWidth - 1, _sub->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 488396ea32..0582b99e83 100644
--- a/engines/gob/minigames/geisha/penetration.h
+++ b/engines/gob/minigames/geisha/penetration.h
@@ -28,6 +28,8 @@
#include "gob/sound/sounddesc.h"
+#include "gob/minigames/geisha/submarine.h"
+
namespace Gob {
class GobEngine;
@@ -77,6 +79,18 @@ private:
~ManagedMouth();
};
+ struct ManagedSub : public Position {
+ Submarine *sub;
+
+ uint16 mapX;
+ uint16 mapY;
+
+ ManagedSub(uint16 pX, uint16 pY);
+ ~ManagedSub();
+
+ void setPosition(uint16 pX, uint16 pY);
+ };
+
GobEngine *_vm;
bool _hasAccessPass;
@@ -87,8 +101,6 @@ private:
CMPFile *_sprites;
ANIFile *_objects;
- ANIObject *_sub;
-
Common::List<ANIObject *> _anims;
Common::List<ANIObject *> _mapAnims;
@@ -100,11 +112,7 @@ private:
Surface *_map;
byte _mapTiles[kMapWidth * kMapHeight];
- uint16 _mapX;
- uint16 _mapY;
-
- uint8 _subTileX;
- uint8 _subTileY;
+ ManagedSub *_sub;
Common::List<Position> _shields;
Common::List<ManagedMouth> _mouths;
@@ -112,6 +120,7 @@ private:
SoundDesc _soundShield;
SoundDesc _soundBite;
SoundDesc _soundKiss;
+ SoundDesc _soundShoot;
void init();
@@ -126,7 +135,8 @@ private:
int16 checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons);
void handleSub(int16 key);
- void moveSub(int x, int y, uint16 animation);
+ void subMove(int x, int y, Submarine::Direction direction);
+ void subShoot();
bool isWalkable(byte tile) const;
@@ -135,6 +145,9 @@ private:
void healthGain(int amount);
void healthLose(int amount);
+
+ bool isDead() const;
+ bool hasWon() const;
};
} // End of namespace Geisha
diff --git a/engines/gob/minigames/geisha/submarine.cpp b/engines/gob/minigames/geisha/submarine.cpp
new file mode 100644
index 0000000000..4a18c6e043
--- /dev/null
+++ b/engines/gob/minigames/geisha/submarine.cpp
@@ -0,0 +1,233 @@
+/* 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 "gob/minigames/geisha/submarine.h"
+
+namespace Gob {
+
+namespace Geisha {
+
+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
+};
+
+
+Submarine::Submarine(const ANIFile &ani) : ANIObject(ani), _state(kStateNone) {
+ turn(kDirectionN);
+}
+
+Submarine::~Submarine() {
+}
+
+void Submarine::turn(Direction to) {
+ // Nothing to do
+ if ((_state == kStateMove) && (_direction == to))
+ return;
+
+ _state = kStateMove;
+ _direction = to;
+
+ setAnimation(directionToMove(_direction));
+ setMode(kModeContinuous);
+ setPause(false);
+ setVisible(true);
+}
+
+void Submarine::shoot() {
+ _state = kStateShoot;
+
+ setAnimation(directionToShoot(_direction));
+ setMode(kModeOnce);
+ setPause(false);
+ setVisible(true);
+}
+
+void Submarine::die() {
+ _state = kStateDie;
+
+ setAnimation(directionToExplode(_direction));
+ setMode(kModeOnce);
+ setPause(false);
+ setVisible(true);
+}
+
+void Submarine::leave() {
+ _state = kStateExit;
+
+ setAnimation(kAnimationExit);
+ setMode(kModeOnce);
+ setPause(false);
+ setVisible(true);
+}
+
+void Submarine::advance() {
+ ANIObject::advance();
+
+ switch (_state) {
+ case kStateShoot:
+ if (isPaused())
+ turn(_direction);
+ break;
+
+ case kStateExit:
+ if (isPaused()) {
+ _state = kStateExited;
+
+ setVisible(true);
+ }
+
+ break;
+
+ case kStateDie:
+ if (isPaused())
+ _state = kStateDead;
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool Submarine::canMove() const {
+ return (_state == kStateMove) || (_state == kStateShoot);
+}
+
+bool Submarine::isDead() const {
+ return _state == kStateDead;
+}
+
+uint16 Submarine::directionToMove(Direction direction) const {
+ switch (direction) {
+ case kDirectionN:
+ return kAnimationDriveN;
+
+ case kDirectionNE:
+ return kAnimationDriveNE;
+
+ case kDirectionE:
+ return kAnimationDriveE;
+
+ case kDirectionSE:
+ return kAnimationDriveSE;
+
+ case kDirectionS:
+ return kAnimationDriveS;
+
+ case kDirectionSW:
+ return kAnimationDriveSW;
+
+ case kDirectionW:
+ return kAnimationDriveW;
+
+ case kDirectionNW:
+ return kAnimationDriveNW;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+uint16 Submarine::directionToShoot(Direction direction) const {
+ switch (direction) {
+ case kDirectionN:
+ return kAnimationShootN;
+
+ case kDirectionNE:
+ return kAnimationShootNE;
+
+ case kDirectionE:
+ return kAnimationShootE;
+
+ case kDirectionSE:
+ return kAnimationShootSE;
+
+ case kDirectionS:
+ return kAnimationShootS;
+
+ case kDirectionSW:
+ return kAnimationShootSW;
+
+ case kDirectionW:
+ return kAnimationShootW;
+
+ case kDirectionNW:
+ return kAnimationShootNW;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+uint16 Submarine::directionToExplode(Direction direction) const {
+ // Only 4 exploding animations (spinning clockwise)
+
+ switch (direction) {
+ case kDirectionNW:
+ case kDirectionN:
+ return kAnimationExplodeN;
+
+ case kDirectionNE:
+ case kDirectionE:
+ return kAnimationExplodeE;
+
+ case kDirectionSE:
+ case kDirectionS:
+ return kAnimationExplodeS;
+
+ case kDirectionSW:
+ case kDirectionW:
+ return kAnimationExplodeW;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+} // End of namespace Geisha
+
+} // End of namespace Gob
diff --git a/engines/gob/minigames/geisha/submarine.h b/engines/gob/minigames/geisha/submarine.h
new file mode 100644
index 0000000000..e8ae72d996
--- /dev/null
+++ b/engines/gob/minigames/geisha/submarine.h
@@ -0,0 +1,96 @@
+/* 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_SUBMARINE_H
+#define GOB_MINIGAMES_GEISHA_SUBMARINE_H
+
+#include "gob/aniobject.h"
+
+namespace Gob {
+
+namespace Geisha {
+
+/** The submarine Geisha's "Penetration" minigame. */
+class Submarine : public ANIObject {
+public:
+ enum Direction {
+ kDirectionN,
+ kDirectionNE,
+ kDirectionE,
+ kDirectionSE,
+ kDirectionS,
+ kDirectionSW,
+ kDirectionW,
+ kDirectionNW
+ };
+
+ Submarine(const ANIFile &ani);
+ ~Submarine();
+
+ /** Turn to the specified direction. */
+ void turn(Direction to);
+
+ /** Play the shoot animation. */
+ void shoot();
+
+ /** Play the exploding animation. */
+ void die();
+
+ /** Play the exiting animation. */
+ void leave();
+
+ /** Advance the animation to the next frame. */
+ void advance();
+
+ /** Can the submarine move at the moment? */
+ bool canMove() const;
+
+ /** Is the submarine dead? */
+ bool isDead() const;
+
+private:
+ enum State {
+ kStateNone = 0,
+ kStateMove,
+ kStateShoot,
+ kStateExit,
+ kStateExited,
+ kStateDie,
+ kStateDead
+ };
+
+ State _state;
+ Direction _direction;
+
+ /** Map the directions to move animation indices. */
+ uint16 directionToMove(Direction direction) const;
+ /** Map the directions to shoot animation indices. */
+ uint16 directionToShoot(Direction direction) const;
+ /** Map the directions to explode animation indices. */
+ uint16 directionToExplode(Direction direction) const;
+};
+
+} // End of namespace Geisha
+
+} // End of namespace Gob
+
+#endif // GOB_MINIGAMES_GEISHA_SUBMARINE_H
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index c5ae947a1c..b9680fad6b 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -81,6 +81,7 @@ MODULE_OBJS := \
minigames/geisha/meter.o \
minigames/geisha/diving.o \
minigames/geisha/mouth.o \
+ minigames/geisha/submarine.o \
minigames/geisha/penetration.o \
save/savefile.o \
save/savehandler.o \