[Scummvm-cvs-logs] scummvm master -> 421b93ce0574b76eeae0ffe0598f1f6858ddf1f1

DrMcCoy drmccoy at drmccoy.de
Fri Jun 8 03:17:10 CEST 2012


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
421b93ce05 GOB: Rewrite "pathfinding" and implement moving enemies


Commit: 421b93ce0574b76eeae0ffe0598f1f6858ddf1f1
    https://github.com/scummvm/scummvm/commit/421b93ce0574b76eeae0ffe0598f1f6858ddf1f1
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-06-07T18:16:53-07:00

Commit Message:
GOB: Rewrite "pathfinding" and implement moving enemies

Since shooting does not yet work, we're just getting mauled by them...

Changed paths:
    engines/gob/minigames/geisha/penetration.cpp
    engines/gob/minigames/geisha/penetration.h
    engines/gob/minigames/geisha/submarine.cpp



diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index 9791757..656e90a 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -59,8 +59,12 @@ enum Sprite {
 };
 
 enum Animation {
-	kAnimationMouthKiss = 33,
-	kAnimationMouthBite = 34
+	kAnimationEnemyRound         =  0,
+	kAnimationEnemyRoundExplode  =  1,
+	kAnimationEnemySquare        =  2,
+	kAnimationEnemySquareExplode =  3,
+	kAnimationMouthKiss          = 33,
+	kAnimationMouthBite          = 34
 };
 
 static const int kMapTileWidth  = 24;
@@ -353,12 +357,55 @@ static const char *kStrings[kLanguageCount][kStringCount] = {
 	}
 };
 
-Penetration::Position::Position(uint16 pX, uint16 pY) : x(pX), y(pY) {
+
+Penetration::MapObject::MapObject(uint16 tX, uint16 tY, uint16 mX, uint16 mY, uint16 w, uint16 h) :
+	tileX(tX), tileY(tY), mapX(mX), mapY(mY), width(w), height(h) {
+
+	isBlocking = true;
+}
+
+Penetration::MapObject::MapObject(uint16 tX, uint16 tY, uint16 w, uint16 h) :
+	tileX(tX), tileY(tY), width(w), height(h) {
+
+	isBlocking = true;
+
+	setMapFromTilePosition();
 }
 
+void Penetration::MapObject::setTileFromMapPosition() {
+	tileX = (mapX + (width  / 2)) / kMapTileWidth;
+	tileY = (mapY + (height / 2)) / kMapTileHeight;
+}
+
+void Penetration::MapObject::setMapFromTilePosition() {
+	mapX = tileX * kMapTileWidth;
+	mapY = tileY * kMapTileHeight;
+}
+
+bool Penetration::MapObject::isIn(uint16 mX, uint16 mY) const {
+	if ((mX < mapX) || (mY < mapY))
+		return false;
+	if ((mX > (mapX + width - 1)) || (mY > (mapY + height - 1)))
+		return false;
+
+	return true;
+}
+
+bool Penetration::MapObject::isIn(uint16 mX, uint16 mY, uint16 w, uint16 h) const {
+	return isIn(mX        , mY        ) ||
+	       isIn(mX + w - 1, mY        ) ||
+	       isIn(mX        , mY + h - 1) ||
+	       isIn(mX + w - 1, mY + h - 1);
+}
+
+bool Penetration::MapObject::isIn(const MapObject &obj) const {
+	return isIn(obj.mapX, obj.mapY, obj.width, obj.height);
+}
+
+
+Penetration::ManagedMouth::ManagedMouth(uint16 tX, uint16 tY, MouthType t) :
+	MapObject(tX, tY, 0, 0), mouth(0), type(t) {
 
-Penetration::ManagedMouth::ManagedMouth(uint16 pX, uint16 pY, MouthType t) :
-	Position(pX, pY), mouth(0), type(t) {
 }
 
 Penetration::ManagedMouth::~ManagedMouth() {
@@ -366,9 +413,9 @@ Penetration::ManagedMouth::~ManagedMouth() {
 }
 
 
-Penetration::ManagedSub::ManagedSub(uint16 pX, uint16 pY) : Position(pX, pY), sub(0) {
-	mapX = x * kMapTileWidth;
-	mapY = y * kMapTileHeight;
+Penetration::ManagedSub::ManagedSub(uint16 tX, uint16 tY) :
+	MapObject(tX, tY, kMapTileWidth, kMapTileHeight), sub(0) {
+
 }
 
 Penetration::ManagedSub::~ManagedSub() {
@@ -376,6 +423,20 @@ Penetration::ManagedSub::~ManagedSub() {
 }
 
 
+Penetration::ManagedEnemy::ManagedEnemy() : MapObject(0, 0, 0, 0), enemy(0), dead(false) {
+}
+
+Penetration::ManagedEnemy::~ManagedEnemy() {
+	delete enemy;
+}
+
+void Penetration::ManagedEnemy::clear() {
+	delete enemy;
+
+	enemy = 0;
+}
+
+
 Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0),
 	_shieldMeter(0), _healthMeter(0), _floor(0), _isPlaying(false) {
 
@@ -415,6 +476,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
 	_vm->_video->retrace();
 
 	while (!_vm->shouldQuit() && !_quit && !isDead() && !hasWon()) {
+		enemiesCreate();
 		updateAnims();
 
 		// Draw, fade in if necessary and wait for the end of the frame
@@ -428,6 +490,9 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
 		// Handle the sub movement
 		handleSub();
 
+		// Handle the enemies movement
+		enemiesMove();
+
 		checkExited();
 	}
 
@@ -449,11 +514,12 @@ void Penetration::cheatWin() {
 
 void Penetration::init() {
 	// Load sounds
-	_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");
-	_vm->_sound->sampleLoad(&_soundExit  , SOUND_SND, "trouve.snd");
+	_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");
+	_vm->_sound->sampleLoad(&_soundExit   , SOUND_SND, "trouve.snd");
+	_vm->_sound->sampleLoad(&_soundExplode, SOUND_SND, "virmor.snd");
 
 	_quit = false;
 	for (int i = 0; i < kKeyCount; i++)
@@ -486,6 +552,7 @@ void Penetration::deinit() {
 	_soundKiss.free();
 	_soundShoot.free();
 	_soundExit.free();
+	_soundExplode.free();
 
 	clearMap();
 
@@ -500,10 +567,16 @@ void Penetration::clearMap() {
 	_mapAnims.clear();
 	_anims.clear();
 
+	_blockingObjects.clear();
+
+	_walls.clear();
 	_exits.clear();
 	_shields.clear();
 	_mouths.clear();
 
+	for (int i = 0; i < kEnemyCount; i++)
+		_enemies[i].clear();
+
 	delete _sub;
 
 	_sub = 0;
@@ -526,13 +599,9 @@ void Penetration::createMap() {
 		for (int x = 0; x < kMapWidth; x++) {
 			const byte mapTile = mapTiles[y * kMapWidth + x];
 
-			bool *walkMap = _walkMap + (y * kMapWidth + x);
-
 			const int posX = kPlayAreaBorderWidth  + x * kMapTileWidth;
 			const int posY = kPlayAreaBorderHeight + y * kMapTileHeight;
 
-			*walkMap = true;
-
 			switch (mapTile) {
 			case 0: // Floor
 				_sprites->draw(*_map, kSpriteFloor, posX, posY);
@@ -542,18 +611,18 @@ void Penetration::createMap() {
 
 				exitWorks = _hasAccessPass;
 				if (exitWorks) {
-					_exits.push_back(Position(x, y));
 					_sprites->draw(*_map, kSpriteExit, posX, posY);
+					_exits.push_back(MapObject(x, y, 0, 0));
 				} else {
 					_sprites->draw(*_map, kSpriteWall, posX, posY);
-					*walkMap = false;
+					_walls.push_back(MapObject(x, y, kMapTileWidth, kMapTileHeight));
 				}
 
 				break;
 
 			case 50: // Wall
 				_sprites->draw(*_map, kSpriteWall, posX, posY);
-				*walkMap = false;
+				_walls.push_back(MapObject(x, y, kMapTileWidth, kMapTileHeight));
 				break;
 
 			case 51: // Regular exit
@@ -563,11 +632,11 @@ void Penetration::createMap() {
 				exitWorks = _testMode || (_floor < 2) || _hasAccessPass;
 
 				if (exitWorks) {
-					_exits.push_back(Position(x, y));
 					_sprites->draw(*_map, kSpriteExit, posX, posY);
+					_exits.push_back(MapObject(x, y, 0, 0));
 				} else {
 					_sprites->draw(*_map, kSpriteWall, posX, posY);
-					*walkMap = false;
+					_walls.push_back(MapObject(x, y, kMapTileWidth, kMapTileHeight));
 				}
 
 				break;
@@ -603,7 +672,7 @@ void Penetration::createMap() {
 				_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
 
-				_shields.push_back(Position(x, y));
+				_shields.push_back(MapObject(x, y, 0, 0));
 				break;
 
 			case 57: // Start position
@@ -623,10 +692,30 @@ void Penetration::createMap() {
 	if (!_sub)
 		error("Geisha: No starting position in floor %d (testmode: %d)", _floor, _testMode);
 
-	for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); m++)
+	// Walls
+	for (Common::List<MapObject>::iterator w = _walls.begin(); w != _walls.end(); ++w)
+		_blockingObjects.push_back(&*w);
+
+	// Mouths
+	for (Common::List<ManagedMouth>::iterator m = _mouths.begin(); m != _mouths.end(); ++m)
 		_mapAnims.push_back(m->mouth);
 
+	// Sub
+	_blockingObjects.push_back(_sub);
 	_anims.push_back(_sub->sub);
+
+	// Moving enemies
+	for (int i = 0; i < kEnemyCount; i++) {
+		_enemies[i].enemy = new ANIObject(*_objects);
+
+		_enemies[i].enemy->setPause(true);
+		_enemies[i].enemy->setVisible(false);
+
+		_enemies[i].isBlocking = false;
+
+		_blockingObjects.push_back(&_enemies[i]);
+		_mapAnims.push_back(_enemies[i].enemy);
+	}
 }
 
 void Penetration::drawFloorText() {
@@ -741,6 +830,104 @@ void Penetration::initScreen() {
 	_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
 }
 
+void Penetration::enemiesCreate() {
+	for (int i = 0; i < kEnemyCount; i++) {
+		ManagedEnemy &enemy = _enemies[i];
+
+		if (enemy.enemy->isVisible())
+			continue;
+
+		enemy.enemy->setAnimation((i & 1) ? kAnimationEnemySquare : kAnimationEnemyRound);
+		enemy.enemy->setMode(ANIObject::kModeContinuous);
+		enemy.enemy->setPause(false);
+		enemy.enemy->setVisible(true);
+
+		int16 width, height;
+		enemy.enemy->getFrameSize(width, height);
+
+		enemy.width  = width;
+		enemy.height = height;
+
+		do {
+			enemy.mapX = _vm->_util->getRandom(kMapWidth)  * kMapTileWidth  + 2;
+			enemy.mapY = _vm->_util->getRandom(kMapHeight) * kMapTileHeight + 4;
+			enemy.setTileFromMapPosition();
+		} while (isBlocked(enemy, enemy.mapX, enemy.mapY));
+
+		const int posX = kPlayAreaBorderWidth  + enemy.mapX;
+		const int posY = kPlayAreaBorderHeight + enemy.mapY;
+
+		enemy.enemy->setPosition(posX, posY);
+
+		enemy.isBlocking = true;
+		enemy.dead       = false;
+	}
+}
+
+void Penetration::enemyMove(ManagedEnemy &enemy, int x, int y) {
+	if ((x == 0) && (y == 0))
+		return;
+
+	bool touchedSub;
+	findPath(enemy, x, y, _sub, &touchedSub);
+
+	enemy.setTileFromMapPosition();
+
+	const int posX = kPlayAreaBorderWidth  + enemy.mapX;
+	const int posY = kPlayAreaBorderHeight + enemy.mapY;
+
+	enemy.enemy->setPosition(posX, posY);
+
+	if (touchedSub)
+		enemyAttack(enemy);
+}
+
+void Penetration::enemiesMove() {
+	for (int i = 0; i < kEnemyCount; i++) {
+		ManagedEnemy &enemy = _enemies[i];
+
+		if (!enemy.enemy->isVisible() || enemy.dead)
+			continue;
+
+		int x = 0, y = 0;
+
+		if      (enemy.mapX > _sub->mapX)
+			x = -8;
+		else if (enemy.mapX < _sub->mapX)
+			x =  8;
+
+		if      (enemy.mapY > _sub->mapY)
+			y = -8;
+		else if (enemy.mapY < _sub->mapY)
+			y =  8;
+
+		enemyMove(enemy, x, y);
+	}
+}
+
+void Penetration::enemyAttack(ManagedEnemy &enemy) {
+	// If we have shields, the enemy explodes at them, taking a huge chunk of energy with it.
+	// Otherwise, the enemy nibbles a small amount of health away.
+
+	if (_shieldMeter->getValue() > 0) {
+		enemyExplode(enemy);
+
+		healthLose(80);
+	} else
+		healthLose(5);
+}
+
+void Penetration::enemyExplode(ManagedEnemy &enemy) {
+	enemy.dead = true;
+
+	bool isSquare = enemy.enemy->getAnimation() == kAnimationEnemySquare;
+
+	enemy.enemy->setAnimation(isSquare ? kAnimationEnemySquareExplode : kAnimationEnemyRoundExplode);
+	enemy.enemy->setMode(ANIObject::kModeOnce);
+
+	_vm->_sound->blasterPlay(&_soundExplode, 1, 0);
+}
+
 void Penetration::checkInput() {
 	Common::Event event;
 	Common::EventManager *eventMan = g_system->getEventManager();
@@ -785,13 +972,6 @@ void Penetration::checkInput() {
 	}
 }
 
-bool Penetration::isWalkable(int16 x, int16 y) const {
-	if ((x < 0) || (x >= kMapWidth) || (y < 0) || (y >= kMapHeight))
-		return false;
-
-	return _walkMap[y * kMapWidth + x];
-}
-
 void Penetration::handleSub() {
 	int x, y;
 	Submarine::Direction direction = getDirection(x, y);
@@ -802,34 +982,90 @@ void Penetration::handleSub() {
 		subShoot();
 }
 
-void Penetration::subMove(int x, int y, Submarine::Direction direction) {
-	if (!_sub->sub->canMove())
-		return;
+bool Penetration::isBlocked(const MapObject &self, int16 x, int16 y,
+                            const MapObject *checkBlockedBy, bool *blockedBy) const {
 
-	// Limit the movement to walkable tiles
+	if ((x < 0) || (y < 0))
+		return true;
+	if (((x + self.width  - 1) >= (kMapWidth  * kMapTileWidth)) ||
+	    ((y + self.height - 1) >= (kMapHeight * kMapTileHeight)))
+		return true;
 
-	int16 minX = 0;
-	if (!isWalkable(_sub->x - 1, _sub->y))
-		minX = _sub->x * kMapTileWidth;
+	MapObject checkSelf(0, 0, self.width, self.height);
 
-	int16 maxX = kMapWidth * kMapTileWidth;
-	if (!isWalkable(_sub->x + 1, _sub->y))
-		maxX = _sub->x * kMapTileWidth;
+	checkSelf.mapX = x;
+	checkSelf.mapY = y;
 
-	int16 minY = 0;
-	if (!isWalkable(_sub->x, _sub->y - 1))
-		minY = _sub->y * kMapTileHeight;
+	bool blocked = false;
+	for (Common::List<MapObject *>::const_iterator o = _blockingObjects.begin(); o != _blockingObjects.end(); ++o) {
+		const MapObject &obj = **o;
 
-	int16 maxY = kMapHeight * kMapTileHeight;
-	if (!isWalkable(_sub->x, _sub->y + 1))
-		maxY = _sub->y * kMapTileHeight;
+		if (&obj == &self)
+			continue;
 
-	_sub->mapX = CLIP<int16>(_sub->mapX + x, minX, maxX);
-	_sub->mapY = CLIP<int16>(_sub->mapY + y, minY, maxY);
+		if (!obj.isBlocking)
+			continue;
+
+		if (obj.isIn(checkSelf) || checkSelf.isIn(obj)) {
+			blocked = true;
+
+			if (checkBlockedBy && blockedBy && (&obj == checkBlockedBy))
+				*blockedBy = true;
+		}
+	}
+
+	return blocked;
+}
+
+void Penetration::findPath(MapObject &obj, int x, int y,
+                           const MapObject *checkBlockedBy, bool *blockedBy) const {
+
+	if (blockedBy)
+		*blockedBy = false;
+
+	while ((x != 0) || (y != 0)) {
+		uint16 oldX = obj.mapX;
+		uint16 oldY = obj.mapY;
+
+		uint16 newX = obj.mapX;
+		if        (x > 0) {
+			newX++;
+			x--;
+		} else if (x < 0) {
+			newX--;
+			x++;
+		}
+
+		if (!isBlocked(obj, newX, obj.mapY, checkBlockedBy, blockedBy))
+			obj.mapX = newX;
+
+		uint16 newY = obj.mapY;
+		if        (y > 0) {
+			newY++;
+			y--;
+		} else if (y < 0) {
+			newY--;
+			y++;
+		}
+
+		if (!isBlocked(obj, obj.mapX, newY, checkBlockedBy, blockedBy))
+			obj.mapY = newY;
+
+		if ((obj.mapX == oldX) && (obj.mapY == oldY))
+			break;
+	}
+}
+
+void Penetration::subMove(int x, int y, Submarine::Direction direction) {
+	if (!_sub->sub->canMove())
+		return;
 
-	// The tile the sub is on is where its mid-point is
-	_sub->x = (_sub->mapX + (kMapTileWidth  / 2)) / kMapTileWidth;
-	_sub->y = (_sub->mapY + (kMapTileHeight / 2)) / kMapTileHeight;
+	if ((x == 0) && (y == 0))
+		return;
+
+	findPath(*_sub, x, y);
+
+	_sub->setTileFromMapPosition();
 
 	_sub->sub->turn(direction);
 
@@ -872,8 +1108,8 @@ Submarine::Direction Penetration::getDirection(int &x, int &y) const {
 }
 
 void Penetration::checkShields() {
-	for (Common::List<Position>::iterator pos = _shields.begin(); pos != _shields.end(); ++pos) {
-		if ((pos->x == _sub->x) && (pos->y == _sub->y)) {
+	for (Common::List<MapObject>::iterator s = _shields.begin(); s != _shields.end(); ++s) {
+		if ((s->tileX == _sub->tileX) && (s->tileY == _sub->tileY)) {
 			// Charge shields
 			_shieldMeter->setMaxValue();
 
@@ -881,11 +1117,8 @@ void Penetration::checkShields() {
 			_vm->_sound->blasterPlay(&_soundShield, 1, 0);
 
 			// Erase the shield from the map
-			const int mapX = kPlayAreaBorderWidth  + pos->x * kMapTileWidth;
-			const int mapY = kPlayAreaBorderHeight + pos->y * kMapTileHeight;
-			_sprites->draw(*_map, 30, mapX, mapY);
-
-			_shields.erase(pos);
+			_sprites->draw(*_map, 30, s->mapX + kPlayAreaBorderWidth, s->mapY + kPlayAreaBorderHeight);
+			_shields.erase(s);
 			break;
 		}
 	}
@@ -896,8 +1129,8 @@ void Penetration::checkMouths() {
 		if (!m->mouth->isDeactivated())
 			continue;
 
-		if ((( m->x      == _sub->x) && (m->y == _sub->y)) ||
-		    (((m->x + 1) == _sub->x) && (m->y == _sub->y))) {
+		if ((( m->tileX      == _sub->tileX) && (m->tileY == _sub->tileY)) ||
+		    (((m->tileX + 1) == _sub->tileX) && (m->tileY == _sub->tileY))) {
 
 			m->mouth->activate();
 
@@ -917,10 +1150,9 @@ void Penetration::checkExits() {
 	if (!_sub->sub->canMove())
 		return;
 
-	for (Common::List<Position>::iterator e = _exits.begin(); e != _exits.end(); ++e) {
-		if ((e->x == _sub->x) && (e->y == _sub->y)) {
-			_sub->mapX = e->x * kMapTileWidth;
-			_sub->mapY = e->y * kMapTileHeight;
+	for (Common::List<MapObject>::iterator e = _exits.begin(); e != _exits.end(); ++e) {
+		if ((e->tileX == _sub->tileX) && (e->tileY == _sub->tileY)) {
+			_sub->setMapFromTilePosition();
 
 			_sub->sub->leave();
 
diff --git a/engines/gob/minigames/geisha/penetration.h b/engines/gob/minigames/geisha/penetration.h
index 0336ef8..9abae25 100644
--- a/engines/gob/minigames/geisha/penetration.h
+++ b/engines/gob/minigames/geisha/penetration.h
@@ -65,11 +65,29 @@ private:
 	static const byte kPalettes[kFloorCount][3 * kPaletteSize];
 	static const byte kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight];
 
-	struct Position {
-		uint16 x;
-		uint16 y;
+	static const int kEnemyCount = 9;
 
-		Position(uint16 pX, uint16 pY);
+	struct MapObject {
+		uint16 tileX;
+		uint16 tileY;
+
+		uint16 mapX;
+		uint16 mapY;
+
+		uint16 width;
+		uint16 height;
+
+		bool isBlocking;
+
+		MapObject(uint16 tX, uint16 tY, uint16 mX, uint16 mY, uint16 w, uint16 h);
+		MapObject(uint16 tX, uint16 tY, uint16 w, uint16 h);
+
+		void setTileFromMapPosition();
+		void setMapFromTilePosition();
+
+		bool isIn(uint16 mX, uint16 mY) const;
+		bool isIn(uint16 mX, uint16 mY, uint16 w, uint16 h) const;
+		bool isIn(const MapObject &obj) const;
 	};
 
 	enum MouthType {
@@ -77,24 +95,31 @@ private:
 		kMouthTypeKiss
 	};
 
-	struct ManagedMouth : public Position {
+	struct ManagedMouth : public MapObject {
 		Mouth *mouth;
+
 		MouthType type;
 
-		ManagedMouth(uint16 pX, uint16 pY, MouthType t);
+		ManagedMouth(uint16 tX, uint16 tY, MouthType t);
 		~ManagedMouth();
 	};
 
-	struct ManagedSub : public Position {
+	struct ManagedSub : public MapObject {
 		Submarine *sub;
 
-		uint16 mapX;
-		uint16 mapY;
-
-		ManagedSub(uint16 pX, uint16 pY);
+		ManagedSub(uint16 tX, uint16 tY);
 		~ManagedSub();
+	};
 
-		void setPosition(uint16 pX, uint16 pY);
+	struct ManagedEnemy : public MapObject {
+		ANIObject *enemy;
+
+		bool dead;
+
+		ManagedEnemy();
+		~ManagedEnemy();
+
+		void clear();
 	};
 
 	enum Keys {
@@ -130,19 +155,24 @@ private:
 	uint8 _floor;
 
 	Surface *_map;
-	bool _walkMap[kMapWidth * kMapHeight];
 
 	ManagedSub *_sub;
 
-	Common::List<Position>     _exits;
-	Common::List<Position>     _shields;
+	Common::List<MapObject>    _walls;
+	Common::List<MapObject>    _exits;
+	Common::List<MapObject>    _shields;
 	Common::List<ManagedMouth> _mouths;
 
+	ManagedEnemy _enemies[kEnemyCount];
+
+	Common::List<MapObject *> _blockingObjects;
+
 	SoundDesc _soundShield;
 	SoundDesc _soundBite;
 	SoundDesc _soundKiss;
 	SoundDesc _soundShoot;
 	SoundDesc _soundExit;
+	SoundDesc _soundExplode;
 
 	bool _isPlaying;
 
@@ -161,18 +191,21 @@ private:
 	void drawFloorText();
 	void drawEndText();
 
+	bool isBlocked(const MapObject &self, int16 x, int16 y,
+	               const MapObject *checkBlockedBy = 0, bool *blockedBy = 0) const;
+	void findPath(MapObject &obj, int x, int y,
+	              const MapObject *checkBlockedBy = 0, bool *blockedBy = 0) const;
+
 	void updateAnims();
 
 	void checkInput();
 
+	Submarine::Direction getDirection(int &x, int &y) const;
+
 	void handleSub();
 	void subMove(int x, int y, Submarine::Direction direction);
 	void subShoot();
 
-	Submarine::Direction getDirection(int &x, int &y) const;
-
-	bool isWalkable(int16 x, int16 y) const;
-
 	void checkExits();
 	void checkShields();
 	void checkMouths();
@@ -182,6 +215,12 @@ private:
 
 	void checkExited();
 
+	void enemiesCreate();
+	void enemiesMove();
+	void enemyMove(ManagedEnemy &enemy, int x, int y);
+	void enemyAttack(ManagedEnemy &enemy);
+	void enemyExplode(ManagedEnemy &enemy);
+
 	bool isDead() const;
 	bool hasWon() const;
 
diff --git a/engines/gob/minigames/geisha/submarine.cpp b/engines/gob/minigames/geisha/submarine.cpp
index 9c12a56..cbe5f21 100644
--- a/engines/gob/minigames/geisha/submarine.cpp
+++ b/engines/gob/minigames/geisha/submarine.cpp
@@ -90,6 +90,9 @@ void Submarine::shoot() {
 }
 
 void Submarine::die() {
+	if (!canMove())
+		return;
+
 	_state = kStateDie;
 
 	setAnimation(directionToExplode(_direction));






More information about the Scummvm-git-logs mailing list