From 3eeb3d74163f2682bc27968df5e5e389174cdc1e Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sat, 2 Jun 2012 20:50:18 +0200 Subject: GOB: Correctly name the Penetration script variables --- engines/gob/minigames/geisha/penetration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 121a45bc40..153f2a6766 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -62,7 +62,7 @@ Penetration::~Penetration() { delete _background; } -bool Penetration::play(uint16 var1, uint16 var2, uint16 var3) { +bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { init(); initScreen(); -- cgit v1.2.3 From 585ceb566f27880ae7ea426efc70192b03a26d8d Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sat, 2 Jun 2012 22:12:25 +0200 Subject: GOB: Add animation handling frame to Penetration --- engines/gob/minigames/geisha/penetration.cpp | 60 ++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 153f2a6766..1bdc574aa3 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -25,7 +25,9 @@ #include "gob/draw.h" #include "gob/video.h" #include "gob/decfile.h" +#include "gob/cmpfile.h" #include "gob/anifile.h" +#include "gob/aniobject.h" #include "gob/minigames/geisha/penetration.h" @@ -52,7 +54,7 @@ static const byte kPalette[48] = { 0x15, 0x3F, 0x15 }; -Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _objects(0) { +Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0) { _background = new Surface(320, 200, 1); } @@ -68,11 +70,28 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { _vm->_draw->blitInvalidated(); _vm->_video->retrace(); - while (!_vm->_util->keyPressed() && !_vm->shouldQuit()) - _vm->_util->longDelay(1); + + while (!_vm->shouldQuit()) { + updateAnims(); + + // Draw and wait for the end of the frame + _vm->_draw->blitInvalidated(); + _vm->_util->waitEndFrame(); + + // Handle input + _vm->_util->processInput(); + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + // Aborting the game + if (key == kKeyEscape) + break; + } deinit(); - return true; + return false; } void Penetration::init() { @@ -80,13 +99,18 @@ void Penetration::init() { _vm->_video->drawPackedSprite("hyprmef2.cmp", *_background); + _sprites = new CMPFile(_vm, "tcifplai.cmp", 320, 200); _objects = new ANIFile(_vm, "tcite.ani", 320); } void Penetration::deinit() { + _anims.clear(); + delete _objects; + delete _sprites; _objects = 0; + _sprites = 0; } void Penetration::initScreen() { @@ -101,6 +125,34 @@ void Penetration::initScreen() { _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); } +int16 Penetration::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) { + _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons); + + return _vm->_util->checkKey(); +} + +void Penetration::updateAnims() { + int16 left, top, right, bottom; + + // Clear the previous animation frames + for (Common::List::iterator a = _anims.reverse_begin(); + a != _anims.end(); --a) { + + (*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + } + + // Draw the current animation frames + for (Common::List::iterator a = _anims.begin(); + a != _anims.end(); ++a) { + + (*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + (*a)->advance(); + } +} + } // End of namespace Geisha } // End of namespace Gob -- cgit v1.2.3 From 030509c8eb4544885dabf67b85f83d3b296230de Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sat, 2 Jun 2012 23:12:25 +0200 Subject: GOB: Draw the shield and health meters in Penetration --- engines/gob/minigames/geisha/penetration.cpp | 39 +++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 1bdc574aa3..8b5de27ad2 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -30,6 +30,7 @@ #include "gob/aniobject.h" #include "gob/minigames/geisha/penetration.h" +#include "gob/minigames/geisha/meter.h" namespace Gob { @@ -54,17 +55,29 @@ static const byte kPalette[48] = { 0x15, 0x3F, 0x15 }; -Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0) { +Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), + _shieldMeter(0), _healthMeter(0) { + _background = new Surface(320, 200, 1); + + _shieldMeter = new Meter(11, 119, 92, 3, 11, 10, 1020, Meter::kFillToRight); + _healthMeter = new Meter(11, 137, 92, 3, 15, 10, 1020, Meter::kFillToRight); } Penetration::~Penetration() { deinit(); + delete _shieldMeter; + delete _healthMeter; + delete _background; } bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { + _hasAccessPass = hasAccessPass; + _hasMaxEnergy = hasMaxEnergy; + _testMode = testMode; + init(); initScreen(); @@ -101,6 +114,23 @@ void Penetration::init() { _sprites = new CMPFile(_vm, "tcifplai.cmp", 320, 200); _objects = new ANIFile(_vm, "tcite.ani", 320); + + // Draw the shield meter + _sprites->draw(*_background, 0, 0, 95, 6, 9, 117, 0); // Meter frame + _sprites->draw(*_background, 271, 176, 282, 183, 9, 108, 0); // Shield + + // Draw the health meter + _sprites->draw(*_background, 0, 0, 95, 6, 9, 135, 0); // Meter frame + _sprites->draw(*_background, 283, 176, 292, 184, 9, 126, 0); // Heart + + // The shield starts down + _shieldMeter->setValue(0); + + // If we don't have the max energy tokens, the health starts at 1/3 strength + if (_hasMaxEnergy) + _healthMeter->setMaxValue(); + else + _healthMeter->setValue(_healthMeter->getMaxValue() / 3); } void Penetration::deinit() { @@ -151,6 +181,13 @@ void Penetration::updateAnims() { (*a)->advance(); } + + // Draw the meters + _shieldMeter->draw(*_vm->_draw->_backSurface, left, top, right, bottom); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + + _healthMeter->draw(*_vm->_draw->_backSurface, left, top, right, bottom); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); } } // End of namespace Geisha -- cgit v1.2.3 From 43abb525d4004cb0816c8ea506b0b963d784ccf3 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 3 Jun 2012 00:20:39 +0200 Subject: GOB: Draw the map in a separate surface Still hidden for now. --- engines/gob/minigames/geisha/penetration.cpp | 236 +++++++++++++++++++++++++-- 1 file changed, 226 insertions(+), 10 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 8b5de27ad2..77edebce48 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -55,18 +55,137 @@ static const byte kPalette[48] = { 0x15, 0x3F, 0x15 }; +static const int kColorShield = 11; +static const int kColorHealth = 15; +static const int kColorBlack = 10; +static const int kColorFloor = 13; + +static const int kMapTileWidth = 24; +static const int kMapTileHeight = 24; + +static const int kPlayAreaX = 120; +static const int kPlayAreaY = 7; +static const int kPlayAreaWidth = 192; +static const int kPlayAreaHeight = 113; + +static const int kPlayAreaBorderWidth = kPlayAreaWidth / 2; +static const int kPlayAreaBorderHeight = kPlayAreaHeight / 2; + +const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = { + { + { // Real mode, floor 0 + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, + 50, 50, 0, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50, + 50, 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 0, 50, 0, 0, 52, 53, 0, 0, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 50, 0, 0, 50, 50, 50, 50, 0, 54, 55, 0, 0, 50, 0, 50, + 50, 0, 50, 49, 0, 50, 0, 52, 53, 0, 50, 50, 50, 0, 0, 0, 50, + 50, 57, 0, 50, 0, 0, 0, 50, 50, 50, 0, 0, 56, 50, 54, 55, 50, + 50, 50, 0, 0, 50, 50, 50, 0, 0, 0, 0, 50, 0, 0, 50, 0, 50, + 50, 51, 50, 0, 54, 55, 0, 0, 50, 50, 50, 50, 52, 53, 50, 0, 50, + 50, 0, 50, 0, 0, 0, 0, 0, 54, 55, 0, 0, 0, 50, 0, 0, 50, + 50, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 0, 50, + 50, 50, 0, 52, 53, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, 50, 50, + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0 + }, + { // Real mode, floor 1 + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, + 50, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, + 50, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 50, 51, 52, 53, 0, 0, 52, 53, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 50, 0, 50, 0, 50, 0, 50, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 52, 53, 0, 0, 0, 0, 0, 52, 53, 0, 52, 53, 50, + 50, 57, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 50, 52, 53, 0, 0, 52, 53, 0, 0, 0, 0, 0, 54, 55, 50, + 50, 0, 50, 0, 50, 0, 50, 50, 0, 50, 50, 0, 50, 0, 50, 50, 50, + 50, 0, 50, 49, 0, 0, 52, 53, 0, 52, 53, 0, 0, 0, 50, 56, 50, + 50, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 0, 50, + 50, 0, 0, 0, 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 0, 0, 50, + 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0 + }, + { // Real mode, floor 2 + 0, 50, 50, 50, 50, 50, 50, 50, 0, 50, 50, 50, 50, 50, 50, 50, 0, + 50, 52, 53, 0, 0, 0, 0, 50, 50, 50, 0, 0, 0, 0, 52, 53, 50, + 50, 0, 50, 50, 50, 0, 0, 0, 50, 0, 0, 0, 50, 50, 50, 0, 50, + 50, 0, 50, 52, 53, 50, 50, 52, 53, 0, 50, 50, 54, 55, 50, 0, 50, + 50, 0, 50, 0, 0, 0, 0, 50, 0, 50, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 52, 53, 50, + 0, 50, 0, 50, 50, 50, 0, 57, 50, 51, 0, 50, 50, 50, 0, 50, 0, + 50, 0, 0, 0, 50, 0, 0, 0, 50, 0, 52, 53, 50, 0, 0, 0, 50, + 50, 0, 50, 0, 0, 0, 0, 50, 56, 50, 0, 0, 0, 0, 50, 0, 50, + 50, 0, 50, 54, 55, 50, 50, 0, 0, 0, 50, 50, 54, 55, 50, 0, 50, + 50, 0, 50, 50, 50, 0, 0, 0, 50, 0, 0, 0, 50, 50, 50, 0, 50, + 50, 52, 53, 0, 0, 0, 0, 50, 50, 50, 0, 0, 0, 0, 52, 53, 50, + 0, 50, 50, 50, 50, 50, 50, 50, 0, 50, 50, 50, 50, 50, 50, 50, 0 + } + }, + { + { // Test mode, floor 0 + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 56, 0, 50, 0, 0, 52, 53, 0, 0, 0, 0, 52, 53, 0, 51, 50, + 50, 0, 0, 50, 0, 0, 0, 50, 0, 54, 55, 50, 0, 50, 50, 50, 50, + 50, 52, 53, 50, 50, 0, 0, 50, 50, 50, 50, 50, 0, 50, 0, 0, 50, + 50, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 50, 49, 50, 0, 0, 50, + 50, 0, 54, 55, 0, 50, 50, 54, 55, 0, 50, 50, 50, 0, 0, 0, 50, + 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, 54, 55, 50, + 50, 0, 50, 0, 50, 0, 0, 50, 0, 0, 0, 50, 0, 0, 0, 0, 50, + 50, 0, 50, 0, 50, 54, 55, 50, 0, 50, 50, 50, 0, 50, 0, 0, 50, + 50, 50, 50, 50, 50, 0, 0, 50, 0, 0, 0, 0, 0, 50, 54, 55, 50, + 50, 0, 0, 0, 0, 0, 0, 0, 50, 50, 50, 50, 50, 0, 0, 0, 50, + 50, 57, 0, 52, 53, 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + }, + { // Test mode, floor 1 + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, + 50, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 54, 55, 0, 50, + 50, 0, 50, 52, 53, 0, 0, 50, 0, 0, 54, 55, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 0, 52, 53, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 50, 50, 50, 50, 49, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 0, 50, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 51, 0, 0, 52, 53, 50, 0, 50, 0, 50, + 50, 57, 50, 0, 50, 0, 50, 50, 50, 50, 50, 50, 50, 0, 50, 0, 50, + 50, 50, 50, 0, 50, 56, 0, 0, 0, 54, 55, 0, 0, 0, 50, 0, 50, + 50, 56, 0, 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, 50, + 50, 50, 50, 50, 0, 0, 0, 0, 52, 53, 0, 0, 0, 0, 0, 0, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + }, + { // Test mode, floor 2 + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 57, 50, 54, 55, 0, 50, 54, 55, 0, 50, 0, 52, 53, 50, 51, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 0, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 52, 53, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, 0, 50, + 50, 0, 0, 0, 50, 0, 50, 0, 50, 0, 0, 0, 50, 0, 50, 0, 50, + 50, 0, 0, 0, 50, 52, 53, 0, 50, 52, 53, 56, 50, 0, 54, 55, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + } + } +}; + + Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _shieldMeter(0), _healthMeter(0) { _background = new Surface(320, 200, 1); - _shieldMeter = new Meter(11, 119, 92, 3, 11, 10, 1020, Meter::kFillToRight); - _healthMeter = new Meter(11, 137, 92, 3, 15, 10, 1020, Meter::kFillToRight); + _shieldMeter = new Meter(11, 119, 92, 3, kColorShield, kColorBlack, 1020, Meter::kFillToRight); + _healthMeter = new Meter(11, 137, 92, 3, kColorHealth, kColorBlack, 1020, Meter::kFillToRight); + + _map = new Surface(kMapWidth * kMapTileWidth + kPlayAreaWidth , + kMapHeight * kMapTileHeight + kPlayAreaHeight, 1); } Penetration::~Penetration() { deinit(); + delete _map; + delete _shieldMeter; delete _healthMeter; @@ -115,14 +234,6 @@ void Penetration::init() { _sprites = new CMPFile(_vm, "tcifplai.cmp", 320, 200); _objects = new ANIFile(_vm, "tcite.ani", 320); - // Draw the shield meter - _sprites->draw(*_background, 0, 0, 95, 6, 9, 117, 0); // Meter frame - _sprites->draw(*_background, 271, 176, 282, 183, 9, 108, 0); // Shield - - // Draw the health meter - _sprites->draw(*_background, 0, 0, 95, 6, 9, 135, 0); // Meter frame - _sprites->draw(*_background, 283, 176, 292, 184, 9, 126, 0); // Heart - // The shield starts down _shieldMeter->setValue(0); @@ -131,6 +242,10 @@ void Penetration::init() { _healthMeter->setMaxValue(); else _healthMeter->setValue(_healthMeter->getMaxValue() / 3); + + _floor = 0; + + createMap(); } void Penetration::deinit() { @@ -143,6 +258,99 @@ void Penetration::deinit() { _sprites = 0; } +void Penetration::createMap() { + if (_floor >= kFloorCount) + error("Geisha: Invalid floor %d in minigame penetration", _floor); + + // Copy the correct map + memcpy(_mapTiles, kMaps[_testMode ? 1 : 0][_floor], kMapWidth * kMapHeight); + + _map->fill(kColorBlack); + + // Draw the map tiles + for (int y = 0; y < kMapHeight; y++) { + for (int x = 0; x < kMapWidth; x++) { + byte *mapTile = _mapTiles + (y * kMapWidth + x); + + const int posX = kPlayAreaBorderWidth + x * kMapTileWidth; + const int posY = kPlayAreaBorderHeight + y * kMapTileHeight; + + switch (*mapTile) { + case 0: // Floor + _sprites->draw(*_map, 30, posX, posY); + break; + + case 49: // Emergency exit (needs access pass) + + if (_hasAccessPass) { + // Draw an exit. Now works like a regular exit + _sprites->draw(*_map, 29, posX, posY); + *mapTile = 51; + } else + // Draw a wall + _sprites->draw(*_map, 31, posX, posY); + + break; + + case 50: // Wall + _sprites->draw(*_map, 31, posX, posY); + break; + + case 51: // Regular exit + + if (!_testMode) { + // When we're not in test mode, the last exit only works with an access pass + + if (_floor == 2) { + if (!_hasAccessPass) { + // It's now a wall + _sprites->draw(*_map, 31, posX, posY); + *mapTile = 50; + } else + _sprites->draw(*_map, 29, posX, posY); + + } else + _sprites->draw(*_map, 29, posX, posY); + + } else + // Always works in test mode + _sprites->draw(*_map, 29, posX, posY); + + break; + + case 52: // Left side of biting mouth + _sprites->draw(*_map, 32, posX, posY); + break; + + case 53: // Right side of biting mouth + *mapTile = 0; // Works like a floor + break; + + case 54: // Left side of kissing mouth + _sprites->draw(*_map, 33, posX, posY); + break; + + case 55: // Right side of kissing mouth + *mapTile = 0; // Works like a floor + break; + + case 56: // Shield lying on the floor + _sprites->draw(*_map, 30, posX , posY ); // Floor + _sprites->draw(*_map, 25, posX + 4, posY + 8); // Shield + + _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 + break; + + case 57: // Start position + _sprites->draw(*_map, 30, posX, posY); + *mapTile = 0; + break; + } + } + } +} + void Penetration::initScreen() { _vm->_util->setFrameRate(15); @@ -151,6 +359,14 @@ void Penetration::initScreen() { _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + // Draw the shield meter + _sprites->draw(*_background, 0, 0, 95, 6, 9, 117, 0); // Meter frame + _sprites->draw(*_background, 271, 176, 282, 183, 9, 108, 0); // Shield + + // Draw the health meter + _sprites->draw(*_background, 0, 0, 95, 6, 9, 135, 0); // Meter frame + _sprites->draw(*_background, 283, 176, 292, 184, 9, 126, 0); // Heart + _vm->_draw->_backSurface->blit(*_background); _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); } -- cgit v1.2.3 From 8dcb93f2ce04df49dea38f56bc97aef900a05122 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 3 Jun 2012 01:12:21 +0200 Subject: GOB: Draw the Penetration map and do basic movement --- engines/gob/minigames/geisha/penetration.cpp | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 77edebce48..41346a896f 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -170,7 +170,8 @@ const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), - _shieldMeter(0), _healthMeter(0) { + _shieldMeter(0), _healthMeter(0), _floor(0), _mapUpdate(false), _mapX(0), _mapY(0), + _subTileX(0), _subTileY(0) { _background = new Surface(320, 200, 1); @@ -220,6 +221,9 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { // Aborting the game if (key == kKeyEscape) break; + + // Handle the sub movement + handleSub(key); } deinit(); @@ -345,10 +349,18 @@ void Penetration::createMap() { case 57: // Start position _sprites->draw(*_map, 30, posX, posY); *mapTile = 0; + + _subTileX = x; + _subTileY = y; + + _mapX = _subTileX * kMapTileWidth; + _mapY = _subTileY * kMapTileHeight; break; } } } + + _mapUpdate = true; } void Penetration::initScreen() { @@ -377,6 +389,27 @@ int16 Penetration::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseB return _vm->_util->checkKey(); } +void Penetration::handleSub(int16 key) { + if (key == kKeyLeft) + moveSub(-5, 0); + else if (key == kKeyRight) + moveSub( 5, 0); + else if (key == kKeyUp) + moveSub( 0, -5); + else if (key == kKeyDown) + moveSub( 0, 5); +} + +void Penetration::moveSub(int x, int y) { + _mapX = CLIP(_mapX + x, 0, kMapWidth * kMapTileWidth); + _mapY = CLIP(_mapY + y, 0, kMapHeight * kMapTileHeight); + + _subTileX = _mapX / kMapTileWidth; + _subTileY = _mapY / kMapTileHeight; + + _mapUpdate = true; +} + void Penetration::updateAnims() { int16 left, top, right, bottom; @@ -388,6 +421,15 @@ void Penetration::updateAnims() { _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); } + if (_mapUpdate) { + _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); + } + + _mapUpdate = false; + // Draw the current animation frames for (Common::List::iterator a = _anims.begin(); a != _anims.end(); ++a) { -- cgit v1.2.3 From 95e467d82cb36ee0d98624dd2cdd6d79b544c50c Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 3 Jun 2012 01:29:09 +0200 Subject: GOB: Display the Penetration submarine --- engines/gob/minigames/geisha/penetration.cpp | 49 ++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 41346a896f..377835c45f 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -60,6 +60,30 @@ static const int kColorHealth = 15; static const int kColorBlack = 10; static const int kColorFloor = 13; +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 +}; + static const int kMapTileWidth = 24; static const int kMapTileHeight = 24; @@ -169,7 +193,7 @@ const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = }; -Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), +Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0), _shieldMeter(0), _healthMeter(0), _floor(0), _mapUpdate(false), _mapX(0), _mapY(0), _subTileX(0), _subTileY(0) { @@ -250,11 +274,21 @@ void Penetration::init() { _floor = 0; createMap(); + + _sub = new ANIObject(*_objects); + + _sub->setAnimation(kAnimationDriveN); + _sub->setPosition(kPlayAreaX + kPlayAreaBorderWidth, kPlayAreaY + kPlayAreaBorderHeight); + _sub->setVisible(true); + + _anims.push_back(_sub); } void Penetration::deinit() { _anims.clear(); + delete _sub; + delete _objects; delete _sprites; @@ -391,16 +425,16 @@ int16 Penetration::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseB void Penetration::handleSub(int16 key) { if (key == kKeyLeft) - moveSub(-5, 0); + moveSub(-5, 0, kAnimationDriveW); else if (key == kKeyRight) - moveSub( 5, 0); + moveSub( 5, 0, kAnimationDriveE); else if (key == kKeyUp) - moveSub( 0, -5); + moveSub( 0, -5, kAnimationDriveN); else if (key == kKeyDown) - moveSub( 0, 5); + moveSub( 0, 5, kAnimationDriveS); } -void Penetration::moveSub(int x, int y) { +void Penetration::moveSub(int x, int y, uint16 animation) { _mapX = CLIP(_mapX + x, 0, kMapWidth * kMapTileWidth); _mapY = CLIP(_mapY + y, 0, kMapHeight * kMapTileHeight); @@ -408,6 +442,9 @@ void Penetration::moveSub(int x, int y) { _subTileY = _mapY / kMapTileHeight; _mapUpdate = true; + + if (_sub->getAnimation() != animation) + _sub->setAnimation(animation); } void Penetration::updateAnims() { -- cgit v1.2.3 From 627e870629cdab1009d3279453d082a3c44acd03 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 3 Jun 2012 03:29:35 +0200 Subject: GOB: Limit Penetration movement to walkable tiles --- engines/gob/minigames/geisha/penetration.cpp | 36 ++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 377835c45f..c8fbe31249 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -423,6 +423,15 @@ int16 Penetration::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseB return _vm->_util->checkKey(); } +bool Penetration::isWalkable(byte tile) const { + // Only walls are nonwalkable + + if (tile == 50) + return false; + + return true; +} + void Penetration::handleSub(int16 key) { if (key == kKeyLeft) moveSub(-5, 0, kAnimationDriveW); @@ -435,11 +444,30 @@ void Penetration::handleSub(int16 key) { } void Penetration::moveSub(int x, int y, uint16 animation) { - _mapX = CLIP(_mapX + x, 0, kMapWidth * kMapTileWidth); - _mapY = CLIP(_mapY + y, 0, kMapHeight * kMapTileHeight); + // Limit the movement to walkable tiles + + int16 minX = 0; + if ((_subTileX > 0) && !isWalkable(_mapTiles[_subTileY * kMapWidth + (_subTileX - 1)])) + minX = _subTileX * kMapTileWidth; + + int16 maxX = kMapWidth * kMapTileWidth; + if ((_subTileX < (kMapWidth - 1)) && !isWalkable(_mapTiles[_subTileY * kMapWidth + (_subTileX + 1)])) + maxX = _subTileX * kMapTileWidth; + + int16 minY = 0; + if ((_subTileY > 0) && !isWalkable(_mapTiles[(_subTileY - 1) * kMapWidth + _subTileX])) + minY = _subTileY * kMapTileHeight; + + int16 maxY = kMapHeight * kMapTileHeight; + if ((_subTileY < (kMapHeight - 1)) && !isWalkable(_mapTiles[(_subTileY + 1) * kMapWidth + _subTileX])) + maxY = _subTileY * kMapTileHeight; + + _mapX = CLIP(_mapX + x, minX, maxX); + _mapY = CLIP(_mapY + y, minY, maxY); - _subTileX = _mapX / kMapTileWidth; - _subTileY = _mapY / kMapTileHeight; + // The tile the sub is on is where its mid-point is + _subTileX = (_mapX + (kMapTileWidth / 2)) / kMapTileWidth; + _subTileY = (_mapY + (kMapTileHeight / 2)) / kMapTileHeight; _mapUpdate = true; -- cgit v1.2.3 From 5a245bd4f2cbac8aee4efe7220533f41d6418312 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 3 Jun 2012 03:40:04 +0200 Subject: GOB: Consume shields in Penetration --- engines/gob/minigames/geisha/penetration.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index c8fbe31249..e4e7798216 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -193,6 +193,10 @@ const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = }; +Penetration::Position::Position(uint16 pX, uint16 pY) : x(pX), y(pY) { +} + + Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0), _shieldMeter(0), _healthMeter(0), _floor(0), _mapUpdate(false), _mapX(0), _mapY(0), _subTileX(0), _subTileY(0) { @@ -303,6 +307,8 @@ void Penetration::createMap() { // Copy the correct map memcpy(_mapTiles, kMaps[_testMode ? 1 : 0][_floor], kMapWidth * kMapHeight); + _shields.clear(); + _map->fill(kColorBlack); // Draw the map tiles @@ -378,6 +384,8 @@ 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)); break; case 57: // Start position @@ -473,6 +481,25 @@ void Penetration::moveSub(int x, int y, uint16 animation) { if (_sub->getAnimation() != animation) _sub->setAnimation(animation); + + checkShields(); +} + +void Penetration::checkShields() { + for (Common::List::iterator pos = _shields.begin(); pos != _shields.end(); ++pos) { + if ((pos->x == _subTileX) && (pos->y == _subTileY)) { + // Charge shields + _shieldMeter->setMaxValue(); + + // 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); + break; + } + } } void Penetration::updateAnims() { -- cgit v1.2.3 From db99d23717ce4f39f9d9f55ce1abf0d8b73cc630 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 3 Jun 2012 18:58:03 +0200 Subject: GOB: Fix invalid reads in Geisha's minigames --- engines/gob/minigames/geisha/penetration.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index e4e7798216..35802e6733 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -298,6 +298,8 @@ void Penetration::deinit() { _objects = 0; _sprites = 0; + + _sub = 0; } void Penetration::createMap() { @@ -503,14 +505,14 @@ void Penetration::checkShields() { } void Penetration::updateAnims() { - int16 left, top, right, bottom; + int16 left = 0, top = 0, right = 0, bottom = 0; // Clear the previous animation frames for (Common::List::iterator a = _anims.reverse_begin(); a != _anims.end(); --a) { - (*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom); - _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + if ((*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); } if (_mapUpdate) { @@ -526,8 +528,8 @@ void Penetration::updateAnims() { for (Common::List::iterator a = _anims.begin(); a != _anims.end(); ++a) { - (*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom); - _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); + if ((*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom)) + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); (*a)->advance(); } -- cgit v1.2.3 From 25938316a881679a923bce1986f3a978432b0e76 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Tue, 5 Jun 2012 16:18:05 +0200 Subject: GOB: Animate mouths in Geisha's Penetration --- engines/gob/minigames/geisha/penetration.cpp | 164 ++++++++++++++++++--------- 1 file changed, 112 insertions(+), 52 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 35802e6733..c8f96f825a 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -31,6 +31,7 @@ #include "gob/minigames/geisha/penetration.h" #include "gob/minigames/geisha/meter.h" +#include "gob/minigames/geisha/mouth.h" namespace Gob { @@ -60,28 +61,39 @@ static const int kColorHealth = 15; static const int kColorBlack = 10; static const int kColorFloor = 13; +enum Sprite { + kSpriteFloorShield = 25, + kSpriteExit = 29, + kSpriteFloor = 30, + kSpriteWall = 31, + kSpriteMouthBite = 32, + kSpriteMouthKiss = 33 +}; + 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 + 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 }; static const int kMapTileWidth = 24; @@ -197,8 +209,17 @@ Penetration::Position::Position(uint16 pX, uint16 pY) : x(pX), y(pY) { } +Penetration::ManagedMouth::ManagedMouth(uint16 pX, uint16 pY, MouthType t) : + Position(pX, pY), mouth(0), type(t) { +} + +Penetration::ManagedMouth::~ManagedMouth() { + delete mouth; +} + + Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0), - _shieldMeter(0), _healthMeter(0), _floor(0), _mapUpdate(false), _mapX(0), _mapY(0), + _shieldMeter(0), _healthMeter(0), _floor(0), _mapX(0), _mapY(0), _subTileX(0), _subTileY(0) { _background = new Surface(320, 200, 1); @@ -279,6 +300,9 @@ void Penetration::init() { createMap(); + for (Common::List::iterator m = _mouths.begin(); m != _mouths.end(); m++) + _mapAnims.push_back(m->mouth); + _sub = new ANIObject(*_objects); _sub->setAnimation(kAnimationDriveN); @@ -289,8 +313,13 @@ void Penetration::init() { } void Penetration::deinit() { + _mapAnims.clear(); _anims.clear(); + _shields.clear(); + + _mouths.clear(); + delete _sub; delete _objects; @@ -311,6 +340,8 @@ void Penetration::createMap() { _shields.clear(); + _mouths.clear(); + _map->fill(kColorBlack); // Draw the map tiles @@ -323,23 +354,21 @@ void Penetration::createMap() { switch (*mapTile) { case 0: // Floor - _sprites->draw(*_map, 30, posX, posY); + _sprites->draw(*_map, kSpriteFloor, posX, posY); break; case 49: // Emergency exit (needs access pass) if (_hasAccessPass) { - // Draw an exit. Now works like a regular exit - _sprites->draw(*_map, 29, posX, posY); - *mapTile = 51; + _sprites->draw(*_map, kSpriteExit, posX, posY); + *mapTile = 51; // Now works like a normal exit } else - // Draw a wall - _sprites->draw(*_map, 31, posX, posY); + _sprites->draw(*_map, kSpriteWall, posX, posY); break; case 50: // Wall - _sprites->draw(*_map, 31, posX, posY); + _sprites->draw(*_map, kSpriteWall, posX, posY); break; case 51: // Regular exit @@ -349,23 +378,27 @@ void Penetration::createMap() { if (_floor == 2) { if (!_hasAccessPass) { - // It's now a wall - _sprites->draw(*_map, 31, posX, posY); - *mapTile = 50; + _sprites->draw(*_map, kSpriteWall, posX, posY); + *mapTile = 50; // It's now a wall } else - _sprites->draw(*_map, 29, posX, posY); + _sprites->draw(*_map, kSpriteExit, posX, posY); } else - _sprites->draw(*_map, 29, posX, posY); + _sprites->draw(*_map, kSpriteExit, posX, posY); } else // Always works in test mode - _sprites->draw(*_map, 29, posX, posY); + _sprites->draw(*_map, kSpriteExit, posX, posY); break; case 52: // Left side of biting mouth - _sprites->draw(*_map, 32, posX, posY); + _mouths.push_back(ManagedMouth(x, y, kMouthTypeBite)); + + _mouths.back().mouth = + new Mouth(*_objects, *_sprites, kAnimationMouthBite, kSpriteMouthBite, kSpriteFloor); + + _mouths.back().mouth->setPosition(posX, posY); break; case 53: // Right side of biting mouth @@ -373,7 +406,12 @@ void Penetration::createMap() { break; case 54: // Left side of kissing mouth - _sprites->draw(*_map, 33, posX, posY); + _mouths.push_back(ManagedMouth(x, y, kMouthTypeKiss)); + + _mouths.back().mouth = + new Mouth(*_objects, *_sprites, kAnimationMouthKiss, kSpriteMouthKiss, kSpriteFloor); + + _mouths.back().mouth->setPosition(posX, posY); break; case 55: // Right side of kissing mouth @@ -381,8 +419,8 @@ void Penetration::createMap() { break; case 56: // Shield lying on the floor - _sprites->draw(*_map, 30, posX , posY ); // Floor - _sprites->draw(*_map, 25, posX + 4, posY + 8); // Shield + _sprites->draw(*_map, kSpriteFloor , posX , posY ); // Floor + _sprites->draw(*_map, kSpriteFloorShield, posX + 4, posY + 8); // Shield _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 @@ -391,7 +429,7 @@ void Penetration::createMap() { break; case 57: // Start position - _sprites->draw(*_map, 30, posX, posY); + _sprites->draw(*_map, kSpriteFloor, posX, posY); *mapTile = 0; _subTileX = x; @@ -403,8 +441,6 @@ void Penetration::createMap() { } } } - - _mapUpdate = true; } void Penetration::initScreen() { @@ -479,12 +515,11 @@ void Penetration::moveSub(int x, int y, uint16 animation) { _subTileX = (_mapX + (kMapTileWidth / 2)) / kMapTileWidth; _subTileY = (_mapY + (kMapTileHeight / 2)) / kMapTileHeight; - _mapUpdate = true; - if (_sub->getAnimation() != animation) _sub->setAnimation(animation); checkShields(); + checkMouths(); } void Penetration::checkShields() { @@ -504,9 +539,37 @@ void Penetration::checkShields() { } } +void Penetration::checkMouths() { + for (Common::List::iterator m = _mouths.begin(); m != _mouths.end(); ++m) { + if (!m->mouth->isDeactivated()) + continue; + + if ((( m->x == _subTileX) && (m->y == _subTileY)) || + (((m->x + 1) == _subTileX) && (m->y == _subTileY))) { + + m->mouth->activate(); + } + } +} + void Penetration::updateAnims() { int16 left = 0, top = 0, right = 0, bottom = 0; + // Clear the previous map animation frames + for (Common::List::iterator a = _mapAnims.reverse_begin(); + a != _mapAnims.end(); --a) { + + (*a)->clear(*_map, left, top, right, bottom); + } + + // Draw the current map animation frames + for (Common::List::iterator a = _mapAnims.begin(); + a != _mapAnims.end(); ++a) { + + (*a)->draw(*_map, left, top, right, bottom); + (*a)->advance(); + } + // Clear the previous animation frames for (Common::List::iterator a = _anims.reverse_begin(); a != _anims.end(); --a) { @@ -515,14 +578,11 @@ void Penetration::updateAnims() { _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); } - if (_mapUpdate) { - _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); - } - - _mapUpdate = false; + // 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); // Draw the current animation frames for (Common::List::iterator a = _anims.begin(); -- cgit v1.2.3 From 73776406686709bc79ff9c6423937dce0e43c5d6 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Tue, 5 Jun 2012 16:21:36 +0200 Subject: GOB: Play sounds for mouths and shields in Penetration --- engines/gob/minigames/geisha/penetration.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index c8f96f825a..1321842d07 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -29,6 +29,8 @@ #include "gob/anifile.h" #include "gob/aniobject.h" +#include "gob/sound/sound.h" + #include "gob/minigames/geisha/penetration.h" #include "gob/minigames/geisha/meter.h" #include "gob/minigames/geisha/mouth.h" @@ -280,6 +282,11 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { } 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"); + _background->clear(); _vm->_video->drawPackedSprite("hyprmef2.cmp", *_background); @@ -313,6 +320,10 @@ void Penetration::init() { } void Penetration::deinit() { + _soundShield.free(); + _soundBite.free(); + _soundKiss.free(); + _mapAnims.clear(); _anims.clear(); @@ -528,6 +539,9 @@ void Penetration::checkShields() { // Charge shields _shieldMeter->setMaxValue(); + // Play the shield sound + _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; @@ -548,6 +562,12 @@ void Penetration::checkMouths() { (((m->x + 1) == _subTileX) && (m->y == _subTileY))) { m->mouth->activate(); + + // Play the mouth sound + if (m->type == kMouthTypeBite) + _vm->_sound->blasterPlay(&_soundBite, 1, 0); + else if (m->type == kMouthTypeKiss) + _vm->_sound->blasterPlay(&_soundKiss, 1, 0); } } } -- cgit v1.2.3 From 4392e4d7aab9114ff66a1fcda34d21f404b4ebcd Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Tue, 5 Jun 2012 17:01:40 +0200 Subject: GOB: Implement health gain/loss for mouths --- engines/gob/minigames/geisha/penetration.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 1321842d07..a188995372 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -226,8 +226,8 @@ Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _background = new Surface(320, 200, 1); - _shieldMeter = new Meter(11, 119, 92, 3, kColorShield, kColorBlack, 1020, Meter::kFillToRight); - _healthMeter = new Meter(11, 137, 92, 3, kColorHealth, kColorBlack, 1020, Meter::kFillToRight); + _shieldMeter = new Meter(11, 119, 92, 3, kColorShield, kColorBlack, 920, Meter::kFillToRight); + _healthMeter = new Meter(11, 137, 92, 3, kColorHealth, kColorBlack, 920, Meter::kFillToRight); _map = new Surface(kMapWidth * kMapTileWidth + kPlayAreaWidth , kMapHeight * kMapTileHeight + kPlayAreaHeight, 1); @@ -563,15 +563,29 @@ void Penetration::checkMouths() { m->mouth->activate(); - // Play the mouth sound - if (m->type == kMouthTypeBite) + // Play the mouth sound and do health gain/loss + if (m->type == kMouthTypeBite) { _vm->_sound->blasterPlay(&_soundBite, 1, 0); - else if (m->type == kMouthTypeKiss) + healthLose(230); + } else if (m->type == kMouthTypeKiss) { _vm->_sound->blasterPlay(&_soundKiss, 1, 0); + healthGain(120); + } } } } +void Penetration::healthGain(int amount) { + if (_shieldMeter->getValue() > 0) + _healthMeter->increase(_shieldMeter->increase(amount)); + else + _healthMeter->increase(amount); +} + +void Penetration::healthLose(int amount) { + _healthMeter->decrease(_shieldMeter->decrease(amount)); +} + void Penetration::updateAnims() { int16 left = 0, top = 0, right = 0, bottom = 0; -- cgit v1.2.3 From b83ac21f6008287414d59ad7f9c88b63bd93bac5 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 6 Jun 2012 02:52:19 +0200 Subject: GOB: Implement Penetration submarine shooting and dying Shots don't result in bullets yet, though --- engines/gob/minigames/geisha/penetration.cpp | 149 +++++++++++++++------------ 1 file changed, 84 insertions(+), 65 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') 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::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(_mapX + x, minX, maxX); - _mapY = CLIP(_mapY + y, minY, maxY); + _sub->mapX = CLIP(_sub->mapX + x, minX, maxX); + _sub->mapY = CLIP(_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::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::iterator a = _anims.begin(); -- cgit v1.2.3 From 1782012f9f9ec368689fb2e232543a5aea3c1073 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 6 Jun 2012 03:12:12 +0200 Subject: GOB: Clean up the Penetration map handling a bit --- engines/gob/minigames/geisha/penetration.cpp | 92 ++++++++++++++-------------- 1 file changed, 45 insertions(+), 47 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 2c1a4918b9..22cb06fed8 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -309,84 +309,88 @@ void Penetration::deinit() { _soundKiss.free(); _soundShoot.free(); + clearMap(); + + delete _objects; + delete _sprites; + + _objects = 0; + _sprites = 0; +} + +void Penetration::clearMap() { _mapAnims.clear(); _anims.clear(); + _exits.clear(); _shields.clear(); - _mouths.clear(); delete _sub; - delete _objects; - delete _sprites; - - _objects = 0; - _sprites = 0; - _sub = 0; + + _map->fill(kColorBlack); } void Penetration::createMap() { if (_floor >= kFloorCount) error("Geisha: Invalid floor %d in minigame penetration", _floor); - // Copy the correct map - memcpy(_mapTiles, kMaps[_testMode ? 1 : 0][_floor], kMapWidth * kMapHeight); - - delete _sub; - _sub = 0; + clearMap(); - _shields.clear(); - _mouths.clear(); + const byte *mapTiles = kMaps[_testMode ? 1 : 0][_floor]; - _map->fill(kColorBlack); + bool exitWorks; // Draw the map tiles for (int y = 0; y < kMapHeight; y++) { for (int x = 0; x < kMapWidth; x++) { - byte *mapTile = _mapTiles + (y * 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; - switch (*mapTile) { + *walkMap = true; + + switch (mapTile) { case 0: // Floor _sprites->draw(*_map, kSpriteFloor, posX, posY); break; case 49: // Emergency exit (needs access pass) - if (_hasAccessPass) { + exitWorks = _hasAccessPass; + if (exitWorks) { + _exits.push_back(Position(x, y)); _sprites->draw(*_map, kSpriteExit, posX, posY); - *mapTile = 51; // Now works like a normal exit - } else + } else { _sprites->draw(*_map, kSpriteWall, posX, posY); + *walkMap = false; + } break; case 50: // Wall _sprites->draw(*_map, kSpriteWall, posX, posY); + *walkMap = false; break; case 51: // Regular exit - if (!_testMode) { - // When we're not in test mode, the last exit only works with an access pass - - if (_floor == 2) { - if (!_hasAccessPass) { - _sprites->draw(*_map, kSpriteWall, posX, posY); - *mapTile = 50; // It's now a wall - } else - _sprites->draw(*_map, kSpriteExit, posX, posY); - - } else - _sprites->draw(*_map, kSpriteExit, posX, posY); + // A regular exit works always in test mode. + // But if we're in real mode, and on the last floor, it needs an access pass + exitWorks = _testMode || (_floor < 2) || _hasAccessPass; - } else - // Always works in test mode + if (exitWorks) { + _exits.push_back(Position(x, y)); _sprites->draw(*_map, kSpriteExit, posX, posY); + } else { + _sprites->draw(*_map, kSpriteWall, posX, posY); + *walkMap = false; + } break; @@ -400,7 +404,6 @@ void Penetration::createMap() { break; case 53: // Right side of biting mouth - *mapTile = 0; // Works like a floor break; case 54: // Left side of kissing mouth @@ -413,7 +416,6 @@ void Penetration::createMap() { break; case 55: // Right side of kissing mouth - *mapTile = 0; // Works like a floor break; case 56: // Shield lying on the floor @@ -429,8 +431,6 @@ void Penetration::createMap() { case 57: // Start position _sprites->draw(*_map, kSpriteFloor, posX, posY); - *mapTile = 0; - delete _sub; _sub = new ManagedSub(x, y); @@ -472,13 +472,11 @@ int16 Penetration::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseB return _vm->_util->checkKey(); } -bool Penetration::isWalkable(byte tile) const { - // Only walls are nonwalkable - - if (tile == 50) +bool Penetration::isWalkable(int16 x, int16 y) const { + if ((x < 0) || (x >= kMapWidth) || (y < 0) || (y >= kMapHeight)) return false; - return true; + return _walkMap[y * kMapWidth + x]; } void Penetration::handleSub(int16 key) { @@ -501,19 +499,19 @@ void Penetration::subMove(int x, int y, Submarine::Direction direction) { // Limit the movement to walkable tiles int16 minX = 0; - if ((_sub->x > 0) && !isWalkable(_mapTiles[_sub->y * kMapWidth + (_sub->x - 1)])) + if (!isWalkable(_sub->x - 1, _sub->y)) minX = _sub->x * kMapTileWidth; int16 maxX = kMapWidth * kMapTileWidth; - if ((_sub->x < (kMapWidth - 1)) && !isWalkable(_mapTiles[_sub->y * kMapWidth + (_sub->x + 1)])) + if (!isWalkable(_sub->x + 1, _sub->y)) maxX = _sub->x * kMapTileWidth; int16 minY = 0; - if ((_sub->y > 0) && !isWalkable(_mapTiles[(_sub->y - 1) * kMapWidth + _sub->x])) + if (!isWalkable(_sub->x, _sub->y - 1)) minY = _sub->y * kMapTileHeight; int16 maxY = kMapHeight * kMapTileHeight; - if ((_sub->y < (kMapHeight - 1)) && !isWalkable(_mapTiles[(_sub->y + 1) * kMapWidth + _sub->x])) + if (!isWalkable(_sub->x, _sub->y + 1)) maxY = _sub->y * kMapTileHeight; _sub->mapX = CLIP(_sub->mapX + x, minX, maxX); -- cgit v1.2.3 From 04d0ec8d03d46f59f950929321fef43b52ea740a Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 6 Jun 2012 03:27:40 +0200 Subject: GOB: Implement exiting floors --- engines/gob/minigames/geisha/penetration.cpp | 47 +++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 22cb06fed8..856c063edf 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -263,6 +263,8 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { // Handle the sub movement handleSub(key); + + checkExited(); } deinit(); @@ -276,6 +278,7 @@ void Penetration::init() { _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"); _background->clear(); @@ -296,11 +299,6 @@ void Penetration::init() { _floor = 0; createMap(); - - for (Common::List::iterator m = _mouths.begin(); m != _mouths.end(); m++) - _mapAnims.push_back(m->mouth); - - _anims.push_back(_sub->sub); } void Penetration::deinit() { @@ -308,6 +306,7 @@ void Penetration::deinit() { _soundBite.free(); _soundKiss.free(); _soundShoot.free(); + _soundExit.free(); clearMap(); @@ -443,7 +442,12 @@ void Penetration::createMap() { } if (!_sub) - error("Geisha: No starting position in floor %d (testmode: %d", _floor, _testMode); + error("Geisha: No starting position in floor %d (testmode: %d)", _floor, _testMode); + + for (Common::List::iterator m = _mouths.begin(); m != _mouths.end(); m++) + _mapAnims.push_back(m->mouth); + + _anims.push_back(_sub->sub); } void Penetration::initScreen() { @@ -525,6 +529,7 @@ void Penetration::subMove(int x, int y, Submarine::Direction direction) { checkShields(); checkMouths(); + checkExits(); } void Penetration::subShoot() { @@ -578,6 +583,23 @@ void Penetration::checkMouths() { } } +void Penetration::checkExits() { + if (!_sub->sub->canMove()) + return; + + for (Common::List::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; + + _sub->sub->leave(); + + _vm->_sound->blasterPlay(&_soundExit, 1, 0); + break; + } + } +} + void Penetration::healthGain(int amount) { if (_shieldMeter->getValue() > 0) _healthMeter->increase(_shieldMeter->increase(amount)); @@ -592,12 +614,23 @@ void Penetration::healthLose(int amount) { _sub->sub->die(); } +void Penetration::checkExited() { + if (_sub->sub->hasExited()) { + _floor++; + + if (_floor >= kFloorCount) + return; + + createMap(); + } +} + bool Penetration::isDead() const { return _sub && _sub->sub->isDead(); } bool Penetration::hasWon() const { - return _floor > kFloorCount; + return _floor >= kFloorCount; } void Penetration::updateAnims() { -- cgit v1.2.3 From 78c9c72691957ea8c6ed823b76b67a1c0e1d9a93 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 6 Jun 2012 16:50:22 +0200 Subject: GOB: Set Penetration floor palettes and fade in/out --- engines/gob/minigames/geisha/penetration.cpp | 106 +++++++++++++++++++++------ 1 file changed, 82 insertions(+), 24 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 856c063edf..6d18a230a8 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -22,6 +22,7 @@ #include "gob/global.h" #include "gob/util.h" +#include "gob/palanim.h" #include "gob/draw.h" #include "gob/video.h" #include "gob/decfile.h" @@ -39,25 +40,6 @@ namespace Gob { namespace Geisha { -static const byte kPalette[48] = { - 0x16, 0x16, 0x16, - 0x12, 0x14, 0x16, - 0x34, 0x00, 0x25, - 0x1D, 0x1F, 0x22, - 0x24, 0x27, 0x2A, - 0x2C, 0x0D, 0x22, - 0x2B, 0x2E, 0x32, - 0x12, 0x09, 0x20, - 0x3D, 0x3F, 0x00, - 0x3F, 0x3F, 0x3F, - 0x00, 0x00, 0x00, - 0x15, 0x15, 0x3F, - 0x25, 0x22, 0x2F, - 0x1A, 0x14, 0x28, - 0x3F, 0x00, 0x00, - 0x15, 0x3F, 0x15 -}; - static const int kColorShield = 11; static const int kColorHealth = 15; static const int kColorBlack = 10; @@ -88,6 +70,63 @@ static const int kPlayAreaHeight = 113; static const int kPlayAreaBorderWidth = kPlayAreaWidth / 2; static const int kPlayAreaBorderHeight = kPlayAreaHeight / 2; +const byte Penetration::kPalettes[kFloorCount][3 * kPaletteSize] = { + { + 0x16, 0x16, 0x16, + 0x12, 0x14, 0x16, + 0x34, 0x00, 0x25, + 0x1D, 0x1F, 0x22, + 0x24, 0x27, 0x2A, + 0x2C, 0x0D, 0x22, + 0x2B, 0x2E, 0x32, + 0x12, 0x09, 0x20, + 0x3D, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x25, 0x22, 0x2F, + 0x1A, 0x14, 0x28, + 0x3F, 0x00, 0x00, + 0x15, 0x3F, 0x15 + }, + { + 0x16, 0x16, 0x16, + 0x12, 0x14, 0x16, + 0x37, 0x00, 0x24, + 0x1D, 0x1F, 0x22, + 0x24, 0x27, 0x2A, + 0x30, 0x0E, 0x16, + 0x2B, 0x2E, 0x32, + 0x22, 0x0E, 0x26, + 0x3D, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x36, 0x28, 0x36, + 0x30, 0x1E, 0x2A, + 0x3F, 0x00, 0x00, + 0x15, 0x3F, 0x15 + }, + { + 0x16, 0x16, 0x16, + 0x12, 0x14, 0x16, + 0x3F, 0x14, 0x22, + 0x1D, 0x1F, 0x22, + 0x24, 0x27, 0x2A, + 0x30, 0x10, 0x10, + 0x2B, 0x2E, 0x32, + 0x2A, 0x12, 0x12, + 0x3D, 0x3F, 0x00, + 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, + 0x15, 0x15, 0x3F, + 0x3F, 0x23, 0x31, + 0x39, 0x20, 0x2A, + 0x3F, 0x00, 0x00, + 0x15, 0x3F, 0x15 + } +}; + const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = { { { // Real mode, floor 0 @@ -246,8 +285,9 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { while (!_vm->shouldQuit() && !isDead() && !hasWon()) { updateAnims(); - // Draw and wait for the end of the frame + // Draw, fade in if necessary and wait for the end of the frame _vm->_draw->blitInvalidated(); + fadeIn(); _vm->_util->waitEndFrame(); // Handle input @@ -450,13 +490,30 @@ void Penetration::createMap() { _anims.push_back(_sub->sub); } +void Penetration::fadeIn() { + if (!_needFadeIn) + return; + + // Fade to palette + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0); + _needFadeIn = false; +} + +void Penetration::setPalette() { + // Fade to black + _vm->_palAnim->fade(0, 0, 0); + + // Set palette + memcpy(_vm->_draw->_vgaPalette , kPalettes[_floor], 3 * kPaletteSize); + memcpy(_vm->_draw->_vgaSmallPalette, kPalettes[_floor], 3 * kPaletteSize); + + _needFadeIn = true; +} + void Penetration::initScreen() { _vm->_util->setFrameRate(15); - memcpy(_vm->_draw->_vgaPalette , kPalette, 48); - memcpy(_vm->_draw->_vgaSmallPalette, kPalette, 48); - - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + setPalette(); // Draw the shield meter _sprites->draw(*_background, 0, 0, 95, 6, 9, 117, 0); // Meter frame @@ -621,6 +678,7 @@ void Penetration::checkExited() { if (_floor >= kFloorCount) return; + setPalette(); createMap(); } } -- cgit v1.2.3 From 5913b9b839edc2a2bb6caecaee3336bd4de5a673 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 6 Jun 2012 19:03:23 +0200 Subject: GOB: Draw info texts in Penetration The German strings have been changed from the original, to fix the horribly broken German. Someone should probably check the Italian and Spanish strings too. --- engines/gob/minigames/geisha/penetration.cpp | 219 ++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 4 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 6d18a230a8..8fe75b083e 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -40,10 +40,12 @@ namespace Gob { namespace Geisha { -static const int kColorShield = 11; -static const int kColorHealth = 15; -static const int kColorBlack = 10; -static const int kColorFloor = 13; +static const int kColorShield = 11; +static const int kColorHealth = 15; +static const int kColorBlack = 10; +static const int kColorFloor = 13; +static const int kColorFloorText = 14; +static const int kColorExitText = 15; enum Sprite { kSpriteFloorShield = 25, @@ -70,6 +72,13 @@ static const int kPlayAreaHeight = 113; static const int kPlayAreaBorderWidth = kPlayAreaWidth / 2; static const int kPlayAreaBorderHeight = kPlayAreaHeight / 2; +static const int kTextAreaLeft = 9; +static const int kTextAreaTop = 7; +static const int kTextAreaRight = 104; +static const int kTextAreaBottom = 107; + +static const int kTextAreaBigBottom = 142; + const byte Penetration::kPalettes[kFloorCount][3 * kPaletteSize] = { { 0x16, 0x16, 0x16, @@ -224,6 +233,122 @@ const byte Penetration::kMaps[kModeCount][kFloorCount][kMapWidth * kMapHeight] = } }; +static const int kLanguageCount = 5; +static const int kFallbackLanguage = 2; // English + +enum String { + kString3rdBasement = 0, + kString2ndBasement, + kString1stBasement, + kStringNoExit, + kStringYouHave, + kString2Exits, + kString1Exit, + kStringToReach, + kStringUpperLevel1, + kStringUpperLevel2, + kStringLevel0, + kStringPenetration, + kStringSuccessful, + kStringDanger, + kStringGynoides, + kStringActivated, + kStringCount +}; + +static const char *kStrings[kLanguageCount][kStringCount] = { + { // French + "3EME SOUS-SOL", + "2EME SOUS-SOL", + "1ER SOUS-SOL", + "SORTIE REFUSEE", + "Vous disposez", + "de deux sorties", + "d\'une sortie", + "pour l\'acc\212s au", + "niveau", + "sup\202rieur", + "- NIVEAU 0 -", + "PENETRATION", + "REUSSIE", + "DANGER", + "GYNOIDES", + "ACTIVEES" + }, + { // German + // NOTE: The original had very broken German there. We provide proper(ish) German instead. + "3. UNTERGESCHOSS", + "2. UNTERGESCHOSS", + "1. UNTERGESCHOSS", + "AUSGANG GESPERRT", + "Sie haben", + "zwei Ausg\204nge", + "einen Ausgang", + "um das obere", + "Stockwerk zu", + "erreichen", + "- STOCKWERK 0 -", + "PENETRATION", + "ERFOLGREICH", + "GEFAHR", + "GYNOIDE", + "AKTIVIERT", + }, + { // English + "3RD BASEMENT", + "2ND BASEMENT", + "1ST BASEMENT", + "NO EXIT", + "You have", + "2 exits", + "1 exit", + "to reach upper", + "level", + "", + "- 0 LEVEL -", + "PENETRATION", + "SUCCESSFUL", + "DANGER", + "GYNOIDES", + "ACTIVATED", + }, + { // Spanish + "3ER. SUBSUELO", + "2D. SUBSUELO", + "1ER. SUBSUELO", + "SALIDA RECHAZADA", + "Dispones", + "de dos salidas", + "de una salida", + "para acceso al", + "nivel", + "superior", + "- NIVEL 0 -", + "PENETRACION", + "CONSEGUIDA", + "PELIGRO", + "GYNOIDAS", + "ACTIVADAS", + }, + { // Italian + "SOTTOSUOLO 3", + "SOTTOSUOLO 2", + "SOTTOSUOLO 1", + "NON USCITA", + "avete", + "due uscite", + "un\' uscita", + "per accedere al", + "livello", + "superiore", + "- LIVELLO 0 -", + "PENETRAZIONE", + "RIUSCITA", + "PERICOLO", + "GYNOIDI", + "ATTIVATE", + } +}; Penetration::Position::Position(uint16 pX, uint16 pY) : x(pX), y(pY) { } @@ -279,6 +404,8 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { init(); initScreen(); + drawFloorText(); + _vm->_draw->blitInvalidated(); _vm->_video->retrace(); @@ -308,6 +435,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { } deinit(); + drawEndText(); return hasWon(); } @@ -490,6 +618,81 @@ void Penetration::createMap() { _anims.push_back(_sub->sub); } +void Penetration::drawFloorText() { + _vm->_draw->_backSurface->fillRect(kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBottom, kColorBlack); + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBottom); + + const Font *font = _vm->_draw->_fonts[2]; + if (!font) + return; + + const char **strings = kStrings[getLanguage()]; + + const char *floorString = 0; + if (_floor == 0) + floorString = strings[kString3rdBasement]; + else if (_floor == 1) + floorString = strings[kString2ndBasement]; + else if (_floor == 2) + floorString = strings[kString1stBasement]; + + if (floorString) + _vm->_draw->drawString(floorString, 10, 15, kColorFloorText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + + if (_exits.size() > 0) { + int exitCount = kString2Exits; + if (_exits.size() == 1) + exitCount = kString1Exit; + + _vm->_draw->drawString(strings[kStringYouHave] , 10, 38, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[exitCount] , 10, 53, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringToReach] , 10, 68, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringUpperLevel1], 10, 84, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringUpperLevel2], 10, 98, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + + } else + _vm->_draw->drawString(strings[kStringNoExit], 10, 53, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); +} + +void Penetration::drawEndText() { + // Only draw the end text when we've won and this isn't a test run + if (!hasWon() || _testMode) + return; + + _vm->_draw->_backSurface->fillRect(kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBigBottom, kColorBlack); + + const Font *font = _vm->_draw->_fonts[2]; + if (!font) + return; + + const char **strings = kStrings[getLanguage()]; + + _vm->_draw->drawString(strings[kStringLevel0] , 11, 21, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringPenetration], 11, 42, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringSuccessful] , 11, 58, kColorExitText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + + _vm->_draw->drawString(strings[kStringDanger] , 11, 82, kColorFloorText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringGynoides] , 11, 98, kColorFloorText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + _vm->_draw->drawString(strings[kStringActivated], 11, 113, kColorFloorText, kColorBlack, 1, + *_vm->_draw->_backSurface, *font); + + _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, kTextAreaLeft, kTextAreaTop, kTextAreaRight, kTextAreaBigBottom); + _vm->_draw->blitInvalidated(); + _vm->_video->retrace(); +} + void Penetration::fadeIn() { if (!_needFadeIn) return; @@ -680,6 +883,7 @@ void Penetration::checkExited() { setPalette(); createMap(); + drawFloorText(); } } @@ -691,6 +895,13 @@ bool Penetration::hasWon() const { return _floor >= kFloorCount; } +int Penetration::getLanguage() const { + if (_vm->_global->_language < kLanguageCount) + return _vm->_global->_language; + + return kFallbackLanguage; +} + void Penetration::updateAnims() { int16 left = 0, top = 0, right = 0, bottom = 0; -- cgit v1.2.3 From 4288edd5236cb0c232dea0bd818779539e9bc6f2 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Wed, 6 Jun 2012 19:21:21 +0200 Subject: GOB: Add the original broken German as comments --- engines/gob/minigames/geisha/penetration.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 8fe75b083e..1bcc42a329 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -277,19 +277,20 @@ static const char *kStrings[kLanguageCount][kStringCount] = { }, { // German // NOTE: The original had very broken German there. We provide proper(ish) German instead. - "3. UNTERGESCHOSS", - "2. UNTERGESCHOSS", - "1. UNTERGESCHOSS", + // B0rken text in the comments after each line + "3. UNTERGESCHOSS", // "3. U.-GESCHOSS"" + "2. UNTERGESCHOSS", // "2. U.-GESCHOSS" + "1. UNTERGESCHOSS", // "1. U.-GESCHOSS" "AUSGANG GESPERRT", "Sie haben", - "zwei Ausg\204nge", - "einen Ausgang", - "um das obere", - "Stockwerk zu", - "erreichen", - "- STOCKWERK 0 -", - "PENETRATION", - "ERFOLGREICH", + "zwei Ausg\204nge", // "zwei Ausgang" + "einen Ausgang", // "Fortsetztung" + "um das obere", // "" + "Stockwerk zu", // "" + "erreichen", // "" + "- STOCKWERK 0 -", // "0 - HOHE" + "PENETRATION", // "DURCHDRIGEN" + "ERFOLGREICH", // "ERFOLG" "GEFAHR", "GYNOIDE", "AKTIVIERT", -- cgit v1.2.3 From 95454ab52c3e8f251b08aa62b18f071374de85b9 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 7 Jun 2012 04:02:42 +0200 Subject: GOB: Better controls in Geisha's Penetration You can actually move diagonally now --- engines/gob/minigames/geisha/penetration.cpp | 103 ++++++++++++++++++++------- 1 file changed, 78 insertions(+), 25 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 1bcc42a329..72c53cb5c3 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -20,6 +20,8 @@ * */ +#include "common/events.h" + #include "gob/global.h" #include "gob/util.h" #include "gob/palanim.h" @@ -410,7 +412,7 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { _vm->_draw->blitInvalidated(); _vm->_video->retrace(); - while (!_vm->shouldQuit() && !isDead() && !hasWon()) { + while (!_vm->shouldQuit() && !_quit && !isDead() && !hasWon()) { updateAnims(); // Draw, fade in if necessary and wait for the end of the frame @@ -418,19 +420,11 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { fadeIn(); _vm->_util->waitEndFrame(); - // Handle input - _vm->_util->processInput(); - - int16 mouseX, mouseY; - MouseButtons mouseButtons; - - int16 key = checkInput(mouseX, mouseY, mouseButtons); - // Aborting the game - if (key == kKeyEscape) - break; + // Handle the input + checkInput(); // Handle the sub movement - handleSub(key); + handleSub(); checkExited(); } @@ -449,6 +443,10 @@ void Penetration::init() { _vm->_sound->sampleLoad(&_soundShoot , SOUND_SND, "tirgim.snd"); _vm->_sound->sampleLoad(&_soundExit , SOUND_SND, "trouve.snd"); + _quit = false; + for (int i = 0; i < kKeyCount; i++) + _keys[i] = false; + _background->clear(); _vm->_video->drawPackedSprite("hyprmef2.cmp", *_background); @@ -731,10 +729,44 @@ void Penetration::initScreen() { _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199); } -int16 Penetration::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) { - _vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons); +void Penetration::checkInput() { + Common::Event event; + Common::EventManager *eventMan = g_system->getEventManager(); + + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + if (event.kbd.keycode == Common::KEYCODE_ESCAPE) + _quit = true; + else if (event.kbd.keycode == Common::KEYCODE_UP) + _keys[kKeyUp ] = true; + else if (event.kbd.keycode == Common::KEYCODE_DOWN) + _keys[kKeyDown ] = true; + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _keys[kKeyLeft ] = true; + else if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _keys[kKeyRight] = true; + else if (event.kbd.keycode == Common::KEYCODE_SPACE) + _keys[kKeySpace] = true; + break; + + case Common::EVENT_KEYUP: + if (event.kbd.keycode == Common::KEYCODE_UP) + _keys[kKeyUp ] = false; + else if (event.kbd.keycode == Common::KEYCODE_DOWN) + _keys[kKeyDown ] = false; + else if (event.kbd.keycode == Common::KEYCODE_LEFT) + _keys[kKeyLeft ] = false; + else if (event.kbd.keycode == Common::KEYCODE_RIGHT) + _keys[kKeyRight] = false; + else if (event.kbd.keycode == Common::KEYCODE_SPACE) + _keys[kKeySpace] = false; + break; - return _vm->_util->checkKey(); + default: + break; + } + } } bool Penetration::isWalkable(int16 x, int16 y) const { @@ -744,16 +776,13 @@ bool Penetration::isWalkable(int16 x, int16 y) const { return _walkMap[y * kMapWidth + x]; } -void Penetration::handleSub(int16 key) { - if (key == kKeyLeft) - subMove(-5, 0, Submarine::kDirectionW); - else if (key == kKeyRight) - subMove( 5, 0, Submarine::kDirectionE); - else if (key == kKeyUp) - subMove( 0, -5, Submarine::kDirectionN); - else if (key == kKeyDown) - subMove( 0, 5, Submarine::kDirectionS); - else if (key == kKeySpace) +void Penetration::handleSub() { + int x, y; + Submarine::Direction direction = getDirection(x, y); + + subMove(x, y, direction); + + if (_keys[kKeySpace]) subShoot(); } @@ -802,6 +831,30 @@ void Penetration::subShoot() { _vm->_sound->blasterPlay(&_soundShoot, 1, 0); } +Submarine::Direction Penetration::getDirection(int &x, int &y) const { + x = _keys[kKeyRight] ? 3 : (_keys[kKeyLeft] ? -3 : 0); + y = _keys[kKeyDown ] ? 3 : (_keys[kKeyUp ] ? -3 : 0); + + if ((x > 0) && (y > 0)) + return Submarine::kDirectionSE; + if ((x > 0) && (y < 0)) + return Submarine::kDirectionNE; + if ((x < 0) && (y > 0)) + return Submarine::kDirectionSW; + if ((x < 0) && (y < 0)) + return Submarine::kDirectionNW; + if (x > 0) + return Submarine::kDirectionE; + if (x < 0) + return Submarine::kDirectionW; + if (y > 0) + return Submarine::kDirectionS; + if (y < 0) + return Submarine::kDirectionN; + + return Submarine::kDirectionNone; +} + void Penetration::checkShields() { for (Common::List::iterator pos = _shields.begin(); pos != _shields.end(); ++pos) { if ((pos->x == _sub->x) && (pos->y == _sub->y)) { -- cgit v1.2.3 From 3d537e763c85bb3f16825c8b47894335568278a0 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 7 Jun 2012 04:20:41 +0200 Subject: GOB: Handle Penetration shooting animations more cleverly Still no bullets, though :P --- engines/gob/minigames/geisha/penetration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 72c53cb5c3..e260d3cae2 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -823,7 +823,7 @@ void Penetration::subMove(int x, int y, Submarine::Direction direction) { } void Penetration::subShoot() { - if (!_sub->sub->canMove()) + if (!_sub->sub->canMove() || _sub->sub->isShooting()) return; _sub->sub->shoot(); -- cgit v1.2.3 From c37577a950f7337889d5c705c9bc67d434ed3670 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 7 Jun 2012 04:29:10 +0200 Subject: GOB: Hook up the Penetration minigame in the cheater --- engines/gob/minigames/geisha/penetration.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index e260d3cae2..9791757984 100644 --- a/engines/gob/minigames/geisha/penetration.cpp +++ b/engines/gob/minigames/geisha/penetration.cpp @@ -377,7 +377,7 @@ Penetration::ManagedSub::~ManagedSub() { Penetration::Penetration(GobEngine *vm) : _vm(vm), _background(0), _sprites(0), _objects(0), _sub(0), - _shieldMeter(0), _healthMeter(0), _floor(0) { + _shieldMeter(0), _healthMeter(0), _floor(0), _isPlaying(false) { _background = new Surface(320, 200, 1); @@ -404,6 +404,8 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { _hasMaxEnergy = hasMaxEnergy; _testMode = testMode; + _isPlaying = true; + init(); initScreen(); @@ -432,9 +434,19 @@ bool Penetration::play(bool hasAccessPass, bool hasMaxEnergy, bool testMode) { deinit(); drawEndText(); + _isPlaying = false; + return hasWon(); } +bool Penetration::isPlaying() const { + return _isPlaying; +} + +void Penetration::cheatWin() { + _floor = 3; +} + void Penetration::init() { // Load sounds _vm->_sound->sampleLoad(&_soundShield, SOUND_SND, "boucl.snd"); @@ -748,6 +760,10 @@ void Penetration::checkInput() { _keys[kKeyRight] = true; else if (event.kbd.keycode == Common::KEYCODE_SPACE) _keys[kKeySpace] = true; + else if (event.kbd.keycode == Common::KEYCODE_d) { + _vm->getDebugger()->attach(); + _vm->getDebugger()->onFrame(); + } break; case Common::EVENT_KEYUP: -- cgit v1.2.3 From 421b93ce0574b76eeae0ffe0598f1f6858ddf1f1 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Fri, 8 Jun 2012 03:11:44 +0200 Subject: GOB: Rewrite "pathfinding" and implement moving enemies Since shooting does not yet work, we're just getting mauled by them... --- engines/gob/minigames/geisha/penetration.cpp | 362 ++++++++++++++++++++++----- 1 file changed, 297 insertions(+), 65 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') diff --git a/engines/gob/minigames/geisha/penetration.cpp b/engines/gob/minigames/geisha/penetration.cpp index 9791757984..656e90a45b 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::iterator m = _mouths.begin(); m != _mouths.end(); m++) + // Walls + for (Common::List::iterator w = _walls.begin(); w != _walls.end(); ++w) + _blockingObjects.push_back(&*w); + + // Mouths + for (Common::List::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::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(_sub->mapX + x, minX, maxX); - _sub->mapY = CLIP(_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::iterator pos = _shields.begin(); pos != _shields.end(); ++pos) { - if ((pos->x == _sub->x) && (pos->y == _sub->y)) { + for (Common::List::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::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::iterator e = _exits.begin(); e != _exits.end(); ++e) { + if ((e->tileX == _sub->tileX) && (e->tileY == _sub->tileY)) { + _sub->setMapFromTilePosition(); _sub->sub->leave(); -- cgit v1.2.3 From c414baa35d4cc4b11929d9c4995a1027d16f59e6 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Fri, 8 Jun 2012 05:16:01 +0200 Subject: 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. --- engines/gob/minigames/geisha/penetration.cpp | 257 ++++++++++++++++++++++++--- 1 file changed, 236 insertions(+), 21 deletions(-) (limited to 'engines/gob/minigames/geisha/penetration.cpp') 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::const_iterator o = _blockingObjects.begin(); o != _blockingObjects.end(); ++o) { - const MapObject &obj = **o; + for (Common::List::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 { -- cgit v1.2.3