diff options
-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); |