[Scummvm-cvs-logs] scummvm master -> c414baa35d4cc4b11929d9c4995a1027d16f59e6

DrMcCoy drmccoy at drmccoy.de
Fri Jun 8 05:18:14 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:
c414baa35d GOB: Implement shooting in Penetration


Commit: c414baa35d4cc4b11929d9c4995a1027d16f59e6
    https://github.com/scummvm/scummvm/commit/c414baa35d4cc4b11929d9c4995a1027d16f59e6
Author: Sven Hesse (drmccoy at users.sourceforge.net)
Date: 2012-06-07T20:16:01-07:00

Commit Message:
GOB: Implement shooting in Penetration

Geisha's Penetration minigame should be complete now.
This also means that Geisha is now basically complete.

The only thing missing is the MDYPlayer, but since the
music is only played once during the title screen, and it
has a PCM-based fallback (which is currently played), this
is low priority.

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



diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp
index 656e90a..3be9f1f 100644
--- a/engines/gob/minigames/geisha/penetration.cpp
+++ b/engines/gob/minigames/geisha/penetration.cpp
@@ -55,7 +55,15 @@ enum Sprite {
 	kSpriteFloor       = 30,
 	kSpriteWall        = 31,
 	kSpriteMouthBite   = 32,
-	kSpriteMouthKiss   = 33
+	kSpriteMouthKiss   = 33,
+	kSpriteBulletN     = 65,
+	kSpriteBulletS     = 66,
+	kSpriteBulletW     = 67,
+	kSpriteBulletE     = 68,
+	kSpriteBulletSW    = 85,
+	kSpriteBulletSE    = 86,
+	kSpriteBulletNW    = 87,
+	kSpriteBulletNE    = 88
 };
 
 enum Animation {
@@ -437,6 +445,20 @@ void Penetration::ManagedEnemy::clear() {
 }
 
 
+Penetration::ManagedBullet::ManagedBullet() : MapObject(0, 0, 0, 0), bullet(0) {
+}
+
+Penetration::ManagedBullet::~ManagedBullet() {
+	delete bullet;
+}
+
+void Penetration::ManagedBullet::clear() {
+	delete bullet;
+
+	bullet = 0;
+}
+
+
 Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0),
 	_shieldMeter(0), _healthMeter(0), _floor(0), _isPlaying(false) {
 
@@ -477,6 +499,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
 
 	while (!_vm->shouldQuit() && !_quit && !isDead() && !hasWon()) {
 		enemiesCreate();
+		bulletsMove();
 		updateAnims();
 
 		// Draw, fade in if necessary and wait for the end of the frame
@@ -494,6 +517,9 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) {
 		enemiesMove();
 
 		checkExited();
+
+		if (_shotCoolDown > 0)
+			_shotCoolDown--;
 	}
 
 	deinit();
@@ -543,6 +569,8 @@ void Penetration::init() {
 
 	_floor = 0;
 
+	_shotCoolDown = 0;
+
 	createMap();
 }
 
@@ -576,6 +604,8 @@ void Penetration::clearMap() {
 
 	for (int i = 0; i < kEnemyCount; i++)
 		_enemies[i].clear();
+	for (int i = 0; i < kMaxBulletCount; i++)
+		_bullets[i].clear();
 
 	delete _sub;
 
@@ -716,6 +746,18 @@ void Penetration::createMap() {
 		_blockingObjects.push_back(&_enemies[i]);
 		_mapAnims.push_back(_enemies[i].enemy);
 	}
+
+	// Bullets
+	for (int i = 0; i < kMaxBulletCount; i++) {
+		_bullets[i].bullet = new ANIObject(*_sprites);
+
+		_bullets[i].bullet->setPause(true);
+		_bullets[i].bullet->setVisible(false);
+
+		_bullets[i].isBlocking = false;
+
+		_mapAnims.push_back(_bullets[i].bullet);
+	}
 }
 
 void Penetration::drawFloorText() {
@@ -868,8 +910,8 @@ void Penetration::enemyMove(ManagedEnemy &enemy, int x, int y) {
 	if ((x == 0) && (y == 0))
 		return;
 
-	bool touchedSub;
-	findPath(enemy, x, y, _sub, &touchedSub);
+	MapObject *blockedBy;
+	findPath(enemy, x, y, &blockedBy);
 
 	enemy.setTileFromMapPosition();
 
@@ -878,7 +920,7 @@ void Penetration::enemyMove(ManagedEnemy &enemy, int x, int y) {
 
 	enemy.enemy->setPosition(posX, posY);
 
-	if (touchedSub)
+	if (blockedBy == _sub)
 		enemyAttack(enemy);
 }
 
@@ -918,7 +960,8 @@ void Penetration::enemyAttack(ManagedEnemy &enemy) {
 }
 
 void Penetration::enemyExplode(ManagedEnemy &enemy) {
-	enemy.dead = true;
+	enemy.dead       = true;
+	enemy.isBlocking = false;
 
 	bool isSquare = enemy.enemy->getAnimation() == kAnimationEnemySquare;
 
@@ -982,8 +1025,7 @@ void Penetration::handleSub() {
 		subShoot();
 }
 
-bool Penetration::isBlocked(const MapObject &self, int16 x, int16 y,
-                            const MapObject *checkBlockedBy, bool *blockedBy) const {
+bool Penetration::isBlocked(const MapObject &self, int16 x, int16 y, MapObject **blockedBy) {
 
 	if ((x < 0) || (y < 0))
 		return true;
@@ -996,9 +1038,8 @@ bool Penetration::isBlocked(const MapObject &self, int16 x, int16 y,
 	checkSelf.mapX = x;
 	checkSelf.mapY = y;
 
-	bool blocked = false;
-	for (Common::List<MapObject *>::const_iterator o = _blockingObjects.begin(); o != _blockingObjects.end(); ++o) {
-		const MapObject &obj = **o;
+	for (Common::List<MapObject *>::iterator o = _blockingObjects.begin(); o != _blockingObjects.end(); ++o) {
+		MapObject &obj = **o;
 
 		if (&obj == &self)
 			continue;
@@ -1007,21 +1048,19 @@ bool Penetration::isBlocked(const MapObject &self, int16 x, int16 y,
 			continue;
 
 		if (obj.isIn(checkSelf) || checkSelf.isIn(obj)) {
-			blocked = true;
+			if (blockedBy && !*blockedBy)
+				*blockedBy = &obj;
 
-			if (checkBlockedBy && blockedBy && (&obj == checkBlockedBy))
-				*blockedBy = true;
+			return true;
 		}
 	}
 
-	return blocked;
+	return false;
 }
 
-void Penetration::findPath(MapObject &obj, int x, int y,
-                           const MapObject *checkBlockedBy, bool *blockedBy) const {
-
+void Penetration::findPath(MapObject &obj, int x, int y, MapObject **blockedBy) {
 	if (blockedBy)
-		*blockedBy = false;
+		*blockedBy = 0;
 
 	while ((x != 0) || (y != 0)) {
 		uint16 oldX = obj.mapX;
@@ -1036,7 +1075,7 @@ void Penetration::findPath(MapObject &obj, int x, int y,
 			x++;
 		}
 
-		if (!isBlocked(obj, newX, obj.mapY, checkBlockedBy, blockedBy))
+		if (!isBlocked(obj, newX, obj.mapY, blockedBy))
 			obj.mapX = newX;
 
 		uint16 newY = obj.mapY;
@@ -1048,7 +1087,7 @@ void Penetration::findPath(MapObject &obj, int x, int y,
 			y++;
 		}
 
-		if (!isBlocked(obj, obj.mapX, newY, checkBlockedBy, blockedBy))
+		if (!isBlocked(obj, obj.mapX, newY, blockedBy))
 			obj.mapY = newY;
 
 		if ((obj.mapX == oldX) && (obj.mapY == oldY))
@@ -1078,9 +1117,185 @@ void Penetration::subShoot() {
 	if (!_sub->sub->canMove() || _sub->sub->isShooting())
 		return;
 
-	_sub->sub->shoot();
+	if (_shotCoolDown > 0)
+		return;
+
+	// Creating a bullet
+	int slot = findEmptyBulletSlot();
+	if (slot < 0)
+		return;
+
+	ManagedBullet &bullet = _bullets[slot];
 
+	bullet.bullet->setAnimation(directionToBullet(_sub->sub->getDirection()));
+
+	setBulletPosition(*_sub, bullet);
+
+	const int posX = kPlayAreaBorderWidth  + bullet.mapX;
+	const int posY = kPlayAreaBorderHeight + bullet.mapY;
+
+	bullet.bullet->setPosition(posX, posY);
+	bullet.bullet->setVisible(true);
+
+	// Shooting
+	_sub->sub->shoot();
 	_vm->_sound->blasterPlay(&_soundShoot, 1, 0);
+
+	_shotCoolDown = 3;
+}
+
+void Penetration::setBulletPosition(const ManagedSub &sub, ManagedBullet &bullet) const {
+	bullet.mapX = sub.mapX;
+	bullet.mapY= sub.mapY;
+
+	int16 sWidth, sHeight;
+	sub.sub->getFrameSize(sWidth, sHeight);
+
+	int16 bWidth, bHeight;
+	bullet.bullet->getFrameSize(bWidth, bHeight);
+
+	switch (sub.sub->getDirection()) {
+	case Submarine::kDirectionN:
+		bullet.mapX += sWidth / 2;
+		bullet.mapY -= bHeight;
+
+		bullet.deltaX =  0;
+		bullet.deltaY = -8;
+		break;
+
+	case Submarine::kDirectionNE:
+		bullet.mapX += sWidth;
+		bullet.mapY -= bHeight * 2;
+
+		bullet.deltaX =  8;
+		bullet.deltaY = -8;
+		break;
+
+	case Submarine::kDirectionE:
+		bullet.mapX += sWidth;
+		bullet.mapY += sHeight / 2 - bHeight;
+
+		bullet.deltaX =  8;
+		bullet.deltaY =  0;
+		break;
+
+	case Submarine::kDirectionSE:
+		bullet.mapX += sWidth;
+		bullet.mapY += sHeight;
+
+		bullet.deltaX =  8;
+		bullet.deltaY =  8;
+		break;
+
+	case Submarine::kDirectionS:
+		bullet.mapX += sWidth / 2;
+		bullet.mapY += sHeight;
+
+		bullet.deltaX =  0;
+		bullet.deltaY =  8;
+		break;
+
+	case Submarine::kDirectionSW:
+		bullet.mapX -= bWidth;
+		bullet.mapY += sHeight;
+
+		bullet.deltaX = -8;
+		bullet.deltaY =  8;
+		break;
+
+	case Submarine::kDirectionW:
+		bullet.mapX -= bWidth;
+		bullet.mapY += sHeight / 2 - bHeight;
+
+		bullet.deltaX = -8;
+		bullet.deltaY =  0;
+		break;
+
+	case Submarine::kDirectionNW:
+		bullet.mapX -= bWidth;
+		bullet.mapY -= bHeight;
+
+		bullet.deltaX = -8;
+		bullet.deltaY = -8;
+		break;
+
+	default:
+		break;
+	}
+}
+
+uint16 Penetration::directionToBullet(Submarine::Direction direction) const {
+	switch (direction) {
+	case Submarine::kDirectionN:
+		return kSpriteBulletN;
+
+	case Submarine::kDirectionNE:
+		return kSpriteBulletNE;
+
+	case Submarine::kDirectionE:
+		return kSpriteBulletE;
+
+	case Submarine::kDirectionSE:
+		return kSpriteBulletSE;
+
+	case Submarine::kDirectionS:
+		return kSpriteBulletS;
+
+	case Submarine::kDirectionSW:
+		return kSpriteBulletSW;
+
+	case Submarine::kDirectionW:
+		return kSpriteBulletW;
+
+	case Submarine::kDirectionNW:
+		return kSpriteBulletNW;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int Penetration::findEmptyBulletSlot() const {
+	for (int i = 0; i < kMaxBulletCount; i++)
+		if (!_bullets[i].bullet->isVisible())
+			return i;
+
+	return -1;
+}
+
+void Penetration::bulletsMove() {
+	for (int i = 0; i < kMaxBulletCount; i++)
+		if (_bullets[i].bullet->isVisible())
+			bulletMove(_bullets[i]);
+}
+
+void Penetration::bulletMove(ManagedBullet &bullet) {
+	MapObject *blockedBy;
+	findPath(bullet, bullet.deltaX, bullet.deltaY, &blockedBy);
+
+	if (blockedBy) {
+		checkShotEnemy(*blockedBy);
+		bullet.bullet->setVisible(false);
+		return;
+	}
+
+	const int posX = kPlayAreaBorderWidth  + bullet.mapX;
+	const int posY = kPlayAreaBorderHeight + bullet.mapY;
+
+	bullet.bullet->setPosition(posX, posY);
+}
+
+void Penetration::checkShotEnemy(MapObject &shotObject) {
+	for (int i = 0; i < kEnemyCount; i++) {
+		ManagedEnemy &enemy = _enemies[i];
+
+		if ((&enemy == &shotObject) && !enemy.dead && enemy.enemy->isVisible()) {
+			enemyExplode(enemy);
+			return;
+		}
+	}
 }
 
 Submarine::Direction Penetration::getDirection(int &x, int &y) const {
diff --git a/engines/gob/minigames/geisha/penetration.h b/engines/gob/minigames/geisha/penetration.h
index 9abae25..50004eb 100644
--- a/engines/gob/minigames/geisha/penetration.h
+++ b/engines/gob/minigames/geisha/penetration.h
@@ -65,7 +65,8 @@ private:
 	static const byte kPalettes[kFloorCount][3 * kPaletteSize];
 	static const byte kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight];
 
-	static const int kEnemyCount = 9;
+	static const int kEnemyCount     =  9;
+	static const int kMaxBulletCount = 10;
 
 	struct MapObject {
 		uint16 tileX;
@@ -122,6 +123,18 @@ private:
 		void clear();
 	};
 
+	struct ManagedBullet : public MapObject {
+		ANIObject *bullet;
+
+		int16 deltaX;
+		int16 deltaY;
+
+		ManagedBullet();
+		~ManagedBullet();
+
+		void clear();
+	};
+
 	enum Keys {
 		kKeyUp = 0,
 		kKeyDown,
@@ -163,10 +176,13 @@ private:
 	Common::List<MapObject>    _shields;
 	Common::List<ManagedMouth> _mouths;
 
-	ManagedEnemy _enemies[kEnemyCount];
+	ManagedEnemy  _enemies[kEnemyCount];
+	ManagedBullet _bullets[kMaxBulletCount];
 
 	Common::List<MapObject *> _blockingObjects;
 
+	uint8 _shotCoolDown;
+
 	SoundDesc _soundShield;
 	SoundDesc _soundBite;
 	SoundDesc _soundKiss;
@@ -191,10 +207,8 @@ 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;
+	bool isBlocked(const MapObject &self, int16 x, int16 y, MapObject **blockedBy = 0);
+	void findPath(MapObject &obj, int x, int y, MapObject **blockedBy = 0);
 
 	void updateAnims();
 
@@ -206,6 +220,14 @@ private:
 	void subMove(int x, int y, Submarine::Direction direction);
 	void subShoot();
 
+	int findEmptyBulletSlot() const;
+	uint16 directionToBullet(Submarine::Direction direction) const;
+	void setBulletPosition(const ManagedSub &sub, ManagedBullet &bullet) const;
+
+	void bulletsMove();
+	void bulletMove(ManagedBullet &bullet);
+	void checkShotEnemy(MapObject &shotObject);
+
 	void checkExits();
 	void checkShields();
 	void checkMouths();
diff --git a/engines/gob/minigames/geisha/submarine.cpp b/engines/gob/minigames/geisha/submarine.cpp
index cbe5f21..d16761c 100644
--- a/engines/gob/minigames/geisha/submarine.cpp
+++ b/engines/gob/minigames/geisha/submarine.cpp
@@ -58,6 +58,10 @@ Submarine::Submarine(const ANIFile &ani) : ANIObject(ani), _state(kStateMove) {
 Submarine::~Submarine() {
 }
 
+Submarine::Direction Submarine::getDirection() const {
+	return _direction;
+}
+
 void Submarine::turn(Direction to) {
 	// Nothing to do
 	if ((to == kDirectionNone) || ((_state == kStateMove) && (_direction == to)))
diff --git a/engines/gob/minigames/geisha/submarine.h b/engines/gob/minigames/geisha/submarine.h
index 8a6d679..a6eae57 100644
--- a/engines/gob/minigames/geisha/submarine.h
+++ b/engines/gob/minigames/geisha/submarine.h
@@ -47,6 +47,8 @@ public:
 	Submarine(const ANIFile &ani);
 	~Submarine();
 
+	Direction getDirection() const;
+
 	/** Turn to the specified direction. */
 	void turn(Direction to);
 






More information about the Scummvm-git-logs mailing list