diff options
author | Sven Hesse | 2012-06-08 05:16:01 +0200 |
---|---|---|
committer | Sven Hesse | 2012-06-08 05:16:01 +0200 |
commit | c414baa35d4cc4b11929d9c4995a1027d16f59e6 (patch) | |
tree | 0c0346e7f5e673c3490fe9879a73dda02a463559 | |
parent | 421b93ce0574b76eeae0ffe0598f1f6858ddf1f1 (diff) | |
download | scummvm-rg350-c414baa35d4cc4b11929d9c4995a1027d16f59e6.tar.gz scummvm-rg350-c414baa35d4cc4b11929d9c4995a1027d16f59e6.tar.bz2 scummvm-rg350-c414baa35d4cc4b11929d9c4995a1027d16f59e6.zip |
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.
-rw-r--r-- | engines/gob/minigames/geisha/penetration.cpp | 257 | ||||
-rw-r--r-- | engines/gob/minigames/geisha/penetration.h | 34 | ||||
-rw-r--r-- | engines/gob/minigames/geisha/submarine.cpp | 4 | ||||
-rw-r--r-- | engines/gob/minigames/geisha/submarine.h | 2 |
4 files changed, 270 insertions, 27 deletions
diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 656e90a45b..3be9f1f651 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 9abae258b2..50004eba8e 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 cbe5f21eff..d16761cb7c 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 8a6d679bdd..a6eae57095 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); |