aboutsummaryrefslogtreecommitdiff
path: root/engines/avalanche
diff options
context:
space:
mode:
authorMarisa-Chan2014-06-13 21:43:04 +0700
committerMarisa-Chan2014-06-13 21:43:04 +0700
commit45589950c0fb1a449351e6a00ef10d42290d8bae (patch)
tree44e4eedcb7e69d5fc386155b000ed038af07251d /engines/avalanche
parent48360645dcd5f8fddb135b6e31ae5cae4be8d77f (diff)
parent5c005ad3a3f1df0bc968c85c1cf0fc48e36ab0b2 (diff)
downloadscummvm-rg350-45589950c0fb1a449351e6a00ef10d42290d8bae.tar.gz
scummvm-rg350-45589950c0fb1a449351e6a00ef10d42290d8bae.tar.bz2
scummvm-rg350-45589950c0fb1a449351e6a00ef10d42290d8bae.zip
Merge remote-tracking branch 'upstream/master' into zvision
Conflicts: engines/zvision/animation/rlf_animation.cpp engines/zvision/animation_control.h engines/zvision/core/console.cpp engines/zvision/core/events.cpp engines/zvision/cursors/cursor.cpp engines/zvision/cursors/cursor_manager.cpp engines/zvision/cursors/cursor_manager.h engines/zvision/fonts/truetype_font.cpp engines/zvision/graphics/render_manager.cpp engines/zvision/graphics/render_manager.h engines/zvision/inventory/inventory_manager.h engines/zvision/inventory_manager.h engines/zvision/meta_animation.h engines/zvision/module.mk engines/zvision/scripting/actions.cpp engines/zvision/scripting/control.h engines/zvision/scripting/controls/animation_control.cpp engines/zvision/scripting/controls/animation_control.h engines/zvision/scripting/controls/input_control.cpp engines/zvision/scripting/controls/lever_control.cpp engines/zvision/scripting/controls/timer_node.cpp engines/zvision/scripting/controls/timer_node.h engines/zvision/scripting/puzzle.h engines/zvision/scripting/scr_file_handling.cpp engines/zvision/scripting/script_manager.cpp engines/zvision/scripting/script_manager.h engines/zvision/sidefx.cpp engines/zvision/sound/zork_raw.cpp engines/zvision/sound/zork_raw.h engines/zvision/video/video.cpp engines/zvision/video/zork_avi_decoder.h engines/zvision/zvision.cpp engines/zvision/zvision.h
Diffstat (limited to 'engines/avalanche')
-rw-r--r--engines/avalanche/animation.cpp149
-rw-r--r--engines/avalanche/animation.h20
-rw-r--r--engines/avalanche/avalanche.cpp236
-rw-r--r--engines/avalanche/avalanche.h91
-rw-r--r--engines/avalanche/avalot.cpp246
-rw-r--r--engines/avalanche/avalot.h41
-rw-r--r--engines/avalanche/background.cpp73
-rw-r--r--engines/avalanche/background.h8
-rw-r--r--engines/avalanche/clock.cpp116
-rw-r--r--engines/avalanche/clock.h (renamed from engines/avalanche/pingo.h)47
-rw-r--r--engines/avalanche/closing.cpp4
-rw-r--r--engines/avalanche/closing.h4
-rw-r--r--engines/avalanche/configure.engine3
-rw-r--r--engines/avalanche/console.cpp11
-rw-r--r--engines/avalanche/console.h6
-rw-r--r--engines/avalanche/detection.cpp12
-rw-r--r--engines/avalanche/dialogs.cpp128
-rw-r--r--engines/avalanche/dialogs.h9
-rw-r--r--engines/avalanche/dropdown.cpp (renamed from engines/avalanche/menu.cpp)166
-rw-r--r--engines/avalanche/dropdown.h (renamed from engines/avalanche/menu.h)31
-rw-r--r--engines/avalanche/enums.h18
-rw-r--r--engines/avalanche/ghostroom.cpp398
-rw-r--r--engines/avalanche/ghostroom.h88
-rw-r--r--engines/avalanche/graphics.cpp588
-rw-r--r--engines/avalanche/graphics.h87
-rw-r--r--engines/avalanche/help.cpp270
-rw-r--r--engines/avalanche/help.h65
-rw-r--r--engines/avalanche/highscore.cpp110
-rw-r--r--engines/avalanche/highscore.h59
-rw-r--r--engines/avalanche/mainmenu.cpp116
-rw-r--r--engines/avalanche/mainmenu.h55
-rw-r--r--engines/avalanche/module.mk14
-rw-r--r--engines/avalanche/nim.cpp575
-rw-r--r--engines/avalanche/nim.h79
-rw-r--r--engines/avalanche/parser.cpp278
-rw-r--r--engines/avalanche/parser.h52
-rw-r--r--engines/avalanche/pingo.cpp106
-rw-r--r--engines/avalanche/sequence.cpp6
-rw-r--r--engines/avalanche/sequence.h4
-rw-r--r--engines/avalanche/shootemup.cpp693
-rw-r--r--engines/avalanche/shootemup.h134
-rw-r--r--engines/avalanche/sound.cpp5
-rw-r--r--engines/avalanche/sound.h4
-rw-r--r--engines/avalanche/timer.cpp161
-rw-r--r--engines/avalanche/timer.h8
45 files changed, 4341 insertions, 1033 deletions
diff --git a/engines/avalanche/animation.cpp b/engines/avalanche/animation.cpp
index ef30faa87c..451b4a1c68 100644
--- a/engines/avalanche/animation.cpp
+++ b/engines/avalanche/animation.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -48,6 +48,37 @@ const int32 Animation::kCatacombMap[8][8] = {
AnimationType::AnimationType(Animation *anim) {
_anim = anim;
+
+ _xLength = 0;
+ _yLength = 0;
+ for (int i = 0; i < 24; i++) {
+ _mani[i] = nullptr;
+ _sil[i] = nullptr;
+ }
+ _frameNum = 0;
+ _seq = 0;
+ _characterId = 0;
+ _count = 0;
+ _facingDir = kDirNone;
+ _stepNum = 0;
+ _x = 0;
+ _y = 0;
+ _moveX = 0;
+ _moveY = 0;
+ _quick = false;
+ _visible = false;
+ _homing = false;
+ _doCheck = false;
+ _homingX = 0;
+ _homingY = 0;
+ _speedX = 0;
+ _speedY = 0;
+ _vanishIfStill = false;
+ _callEachStepFl = false;
+ _eachStepProc = Animation::kProcNone;
+ _fgBubbleCol = kColorWhite;
+ _bgBubbleCol = kColorBlack;
+ _id = 177;
}
/**
@@ -217,7 +248,7 @@ void AnimationType::walk() {
break;
case kMagicUnfinished: {
bounce();
- Common::String tmpStr = Common::String::format("%c%cSorry.%cThis place is not available yet!",
+ Common::String tmpStr = Common::String::format("%c%cSorry.%cThis place is not available yet!",
kControlBell, kControlCenter, kControlRoman);
_anim->_vm->_dialogs->displayText(tmpStr);
}
@@ -370,6 +401,13 @@ Animation::Animation(AvalancheEngine *vm) {
for (int16 i = 0; i < kSpriteNumbMax; i++) {
_sprites[i] = new AnimationType(this);
}
+
+ _direction = kDirNone;
+ _oldDirection = kDirNone;
+ _arrowTriggered = false;
+ _geidaSpin = 0;
+ _geidaTime = 0;
+ _sayWhat = 0;
}
Animation::~Animation() {
@@ -726,7 +764,7 @@ void Animation::catacombMove(byte ped) {
spr1->init(5, true); // ...Load Geida.
appearPed(1, geidaPed(ped));
spr1->_callEachStepFl = true;
- spr1->_eachStepProc = kProcGeida;
+ spr1->_eachStepProc = kProcFollowAvvy;
}
}
@@ -754,7 +792,7 @@ void Animation::callSpecial(uint16 which) {
_vm->_magics[11]._data = 5;
_vm->_magics[3]._operation = kMagicBounce; // Now works as planned!
stopWalking();
- _vm->_dialogs->displayScrollChain('q', 26);
+ _vm->_dialogs->displayScrollChain('Q', 26);
_vm->_userMovesAvvy = true;
break;
case 3: // _vm->special 3: Room 71: triggers dart.
@@ -777,22 +815,20 @@ void Animation::callSpecial(uint16 which) {
}
break;
case 4: // This is the ghost room link.
- _vm->fadeOut();
- _sprites[0]->turn(kDirRight); // you'll see this after we get back from bootstrap
+ _sprites[0]->turn(kDirRight); // You'll see this after we get back.
_vm->_timer->addTimer(1, Timer::kProcGhostRoomPhew, Timer::kReasonGhostRoomPhew);
- //_vm->_enid->backToBootstrap(3); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then!
+ _vm->_ghostroom->run();
break;
case 5:
if (_vm->_friarWillTieYouUp) {
// _vm->special 5: Room 42: touched tree, and get tied up.
_vm->_magics[4]._operation = kMagicBounce; // Boundary effect is now working again.
- _vm->_dialogs->displayScrollChain('q', 35);
+ _vm->_dialogs->displayScrollChain('Q', 35);
_sprites[0]->remove();
- //tr[1].vanishifstill:=true;
AnimationType *spr1 = _sprites[1];
_vm->_background->draw(-1, -1, 1);
- _vm->_dialogs->displayScrollChain('q', 36);
+ _vm->_dialogs->displayScrollChain('Q', 36);
_vm->_tiedUp = true;
_vm->_friarWillTieYouUp = false;
spr1->walkTo(2);
@@ -825,7 +861,7 @@ void Animation::callSpecial(uint16 which) {
case 8: // _vm->special 8: leave du Lustie's room.
if (_vm->_geidaFollows && !_vm->_lustieIsAsleep) {
AnimationType *spr1 = _sprites[1];
- _vm->_dialogs->displayScrollChain('q', 63);
+ _vm->_dialogs->displayScrollChain('Q', 63);
spr1->turn(kDirDown);
spr1->stopWalk();
spr1->_callEachStepFl = false; // Geida
@@ -848,9 +884,9 @@ void Animation::callSpecial(uint16 which) {
if ((_vm->_catacombX == 4) && (_vm->_catacombY == 1)) {
// Into Geida's room.
if (_vm->_objects[kObjectKey - 1])
- _vm->_dialogs->displayScrollChain('q', 62);
+ _vm->_dialogs->displayScrollChain('Q', 62);
else {
- _vm->_dialogs->displayScrollChain('q', 61);
+ _vm->_dialogs->displayScrollChain('Q', 61);
return;
}
}
@@ -1031,7 +1067,7 @@ void Animation::arrowProcs(byte tripnum) {
void Animation::grabAvvy(byte tripnum) { // For Friar Tuck, in Nottingham.
AnimationType *tripSpr = _sprites[tripnum];
- AnimationType *avvy = _sprites[tripnum];
+ AnimationType *avvy = _sprites[0];
int16 tox = avvy->_x + 17;
int16 toy = avvy->_y - 1;
@@ -1085,7 +1121,7 @@ void Animation::spin(Direction dir, byte &tripnum) {
}
}
-void Animation::geidaProcs(byte tripnum) {
+void Animation::follow(byte tripnum) {
AnimationType *tripSpr = _sprites[tripnum];
AnimationType *avvy = _sprites[0];
@@ -1096,14 +1132,14 @@ void Animation::geidaProcs(byte tripnum) {
}
if (tripSpr->_y < (avvy->_y - 2)) {
- // Geida is further from the screen than Avvy.
+ // The following NPC is further from the screen than Avvy.
spin(kDirDown, tripnum);
tripSpr->_moveY = 1;
tripSpr->_moveX = 0;
takeAStep(tripnum);
return;
} else if (tripSpr->_y > (avvy->_y + 2)) {
- // Avvy is further from the screen than Geida.
+ // Avvy is further from the screen than the following NPC.
spin(kDirUp, tripnum);
tripSpr->_moveY = -1;
tripSpr->_moveX = 0;
@@ -1169,8 +1205,9 @@ void Animation::drawSprites() {
* @remarks Originally called 'trippancy_link'
*/
void Animation::animLink() {
- if (_vm->_menu->isActive() || _vm->_seeScroll)
+ if (_vm->_dropdown->isActive() || !_vm->_animationsEnabled)
return;
+
for (int16 i = 0; i < kSpriteNumbMax; i++) {
AnimationType *curSpr = _sprites[i];
if (curSpr->_quick && curSpr->_visible)
@@ -1199,8 +1236,10 @@ void Animation::animLink() {
case kProcGrabAvvy :
grabAvvy(i);
break;
- case kProcGeida :
- geidaProcs(i);
+ case kProcFollowAvvy :
+ follow(i);
+ break;
+ default:
break;
}
}
@@ -1208,7 +1247,7 @@ void Animation::animLink() {
if (_mustExclaim) {
_mustExclaim = false;
- _vm->_dialogs->displayScrollChain('x', _sayWhat);
+ _vm->_dialogs->displayScrollChain('X', _sayWhat);
}
}
@@ -1291,7 +1330,7 @@ void Animation::handleMoveKey(const Common::Event &event) {
if (!_vm->_userMovesAvvy)
return;
- if (_vm->_menu->_activeMenuItem._activeNow)
+ if (_vm->_dropdown->_activeMenuItem._activeNow)
_vm->_parser->tryDropdown();
else {
switch (event.kbd.keycode) {
@@ -1360,6 +1399,69 @@ void Animation::handleMoveKey(const Common::Event &event) {
}
}
+/**
+* Draws a part of the lightning bolt for thunder().
+* @remarks Originally called 'zl'
+*/
+void Animation::drawLightning(int16 x1, int16 y1, int16 x2, int16 y2) {
+ _vm->_graphics->drawLine(x1, y1 - 1, x2, y2 - 1, 1, 3, kColorBlue);
+ _vm->_graphics->drawLine(x1, y1, x2, y2, 1, 1, kColorLightcyan);
+}
+
+/**
+* Plays the actual thunder animation when Avvy (the player) swears too much.
+* @remarks Originally called 'zonk'
+*/
+void Animation::thunder() {
+ _vm->_graphics->setBackgroundColor(kColorYellow);
+
+ _vm->_graphics->saveScreen();
+
+ int x = _vm->_animation->_sprites[0]->_x + _vm->_animation->_sprites[0]->_xLength / 2;
+ int y = _vm->_animation->_sprites[0]->_y;
+
+ for (int i = 0; i < 256; i++) {
+ _vm->_sound->playNote(270 - i, 1);
+
+ drawLightning(640, 0, 0, y / 4);
+ drawLightning(0, y / 4, 640, y / 2);
+ drawLightning(640, y / 2, x, y);
+ _vm->_graphics->refreshScreen();
+
+ _vm->_sound->playNote(2700 - 10 * i, 5);
+ _vm->_system->delayMillis(5);
+ _vm->_sound->playNote(270 - i, 1);
+
+ _vm->_graphics->restoreScreen();
+ _vm->_sound->playNote(2700 - 10 * i, 5);
+ _vm->_system->delayMillis(5);
+ }
+
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+
+ _vm->_graphics->setBackgroundColor(kColorBlack);
+}
+
+/**
+* Makes the screen wobble.
+*/
+void Animation::wobble() {
+ _vm->_graphics->saveScreen();
+
+ for (int i = 0; i < 26; i++) {
+ _vm->_graphics->shiftScreen();
+ _vm->_graphics->refreshScreen();
+ _vm->_system->delayMillis(i * 7);
+
+ _vm->_graphics->restoreScreen();
+ _vm->_system->delayMillis(i * 7);
+ }
+
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+}
+
void Animation::setDirection(Direction dir) {
_direction = dir;
}
@@ -1394,6 +1496,7 @@ int Animation::getAvvyClothes() {
}
void Animation::resetVariables() {
+ setDirection(kDirUp);
_geidaSpin = 0;
_geidaTime = 0;
_arrowTriggered = false;
diff --git a/engines/avalanche/animation.h b/engines/avalanche/animation.h
index 33f6ab02a6..d1ee4a3ebd 100644
--- a/engines/avalanche/animation.h
+++ b/engines/avalanche/animation.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -97,13 +97,13 @@ public:
static const byte kSpriteNumbMax = 5; // current max no. of sprites
enum Proc {
- kProcFollowAvvyY = 1,
+ kProcNone = 0,
+ kProcFollowAvvyY,
kProcBackAndForth,
kProcFaceAvvy,
kProcArrow,
- kProcSpludwick, // Unused
kProcGrabAvvy,
- kProcGeida // Spludwick uses it as well for homing! TODO: Unify it with kProcSpludwick.
+ kProcFollowAvvy
};
AnimationType *_sprites[kSpriteNumbMax];
@@ -124,6 +124,12 @@ public:
void handleMoveKey(const Common::Event &event);
void hideInCupboard();
+ // These 2 functions are responsible for playing the thunder animation when the player swears too much.
+ void drawLightning(int16 x1, int16 y1, int16 x2, int16 y2);
+ void thunder();
+
+ void wobble();
+
void setDirection(Direction dir);
void setOldDirection(Direction dir);
Direction getDirection();
@@ -156,11 +162,11 @@ private:
void followAvalotY(byte tripnum);
void backAndForth(byte tripnum);
void faceAvvy(byte tripnum);
-
+
// Movements for Homing NPCs: Spludwick and Geida.
void spin(Direction dir, byte &tripnum);
void takeAStep(byte &tripnum);
- void geidaProcs(byte tripnum);
+ void follow(byte tripnum);
void drawSprites();
};
diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp
index 4f3868768a..6cfe4dfdb6 100644
--- a/engines/avalanche/avalanche.cpp
+++ b/engines/avalanche/avalanche.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -41,17 +41,26 @@ AvalancheEngine::AvalancheEngine(OSystem *syst, const AvalancheGameDescription *
TimeDate time;
_system->getTimeAndDate(time);
_rnd->setSeed(time.tm_sec + time.tm_min + time.tm_hour);
-
- // Needed because of Lucerna::load_also()
- for (int i = 0; i < 31; i++) {
- for (int j = 0; j < 2; j++)
- _also[i][j] = nullptr;
- }
-
- _totalTime = 0;
_showDebugLines = false;
- memset(_fxPal, 0, 16 * 16 * 3);
+ _clock = nullptr;
+ _graphics = nullptr;
+ _parser = nullptr;
+ _dialogs = nullptr;
+ _background = nullptr;
+ _sequence = nullptr;
+ _timer = nullptr;
+ _animation = nullptr;
+ _dropdown = nullptr;
+ _closing = nullptr;
+ _sound = nullptr;
+ _nim = nullptr;
+ _ghostroom = nullptr;
+ _help = nullptr;
+ _highscore = nullptr;
+
+ _platform = gd->desc.platform;
+ initVariables();
}
AvalancheEngine::~AvalancheEngine() {
@@ -62,15 +71,18 @@ AvalancheEngine::~AvalancheEngine() {
delete _parser;
delete _clock;
- delete _pingo;
delete _dialogs;
delete _background;
delete _sequence;
delete _timer;
delete _animation;
- delete _menu;
+ delete _dropdown;
delete _closing;
delete _sound;
+ delete _nim;
+ delete _ghostroom;
+ delete _help;
+ delete _highscore;
for (int i = 0; i < 31; i++) {
for (int j = 0; j < 2; j++) {
@@ -82,20 +94,80 @@ AvalancheEngine::~AvalancheEngine() {
}
}
+void AvalancheEngine::initVariables() {
+ for (int i = 0; i < 31; i++) {
+ _also[i][0] = nullptr;
+ _also[i][1] = nullptr;
+ }
+
+ memset(_fxPal, 0, 16 * 16 * 3);
+
+ for (int i = 0; i < 15; i++) {
+ _peds[i]._direction = kDirNone;
+ _peds[i]._x = 0;
+ _peds[i]._y = 0;
+ _magics[i]._operation = kMagicNothing;
+ _magics[i]._data = 0;
+ }
+
+ for (int i = 0; i < 7; i++) {
+ _portals[i]._operation = kMagicNothing;
+ _portals[i]._data = 0;
+ }
+
+ for (int i = 0; i < 30; i++) {
+ _fields[i]._x1 = 0;
+ _fields[i]._y1 = 0;
+ _fields[i]._x2 = 0;
+ _fields[i]._y2 = 0;
+ }
+
+ _fieldNum = 0;
+ _cp = 0;
+ _ledStatus = 177;
+ _alive = false;
+ _subjectNum = 0;
+ _him = kPeoplePardon;
+ _her = kPeoplePardon;
+ _it = Parser::kPardon;
+ _roomCycles = 0;
+ _doingSpriteRun = false;
+ _isLoaded = false;
+ _soundFx = true;
+ _holdTheDawn = false;
+
+ _lineNum = 0;
+ for (int i = 0; i < 50; i++)
+ _lines[i]._color = kColorWhite;
+ _dropsOk = false;
+ _cheat = false;
+ _letMeOut = false;
+ _thinks = 2;
+ _thinkThing = true;
+ _animationsEnabled = true;
+ _currentMouse = 177;
+ _holdLeftMouse = false;
+
+ resetVariables();
+}
+
Common::ErrorCode AvalancheEngine::initialize() {
_graphics = new GraphicManager(this);
_parser = new Parser(this);
_clock = new Clock(this);
- _pingo = new Pingo(this);
_dialogs = new Dialogs(this);
_background = new Background(this);
_sequence = new Sequence(this);
_timer = new Timer(this);
_animation = new Animation(this);
- _menu = new Menu(this);
+ _dropdown = new DropDownMenu(this);
_closing = new Closing(this);
_sound = new SoundHandler(this);
+ _nim = new Nim(this);
+ _ghostroom = new GhostRoom(this);
+ _help = new Help(this);
+ _highscore = new HighScore(this);
_graphics->init();
_dialogs->init();
@@ -124,13 +196,14 @@ const char *AvalancheEngine::getCopyrightString() const {
void AvalancheEngine::synchronize(Common::Serializer &sz) {
_animation->synchronize(sz);
_parser->synchronize(sz);
+ _nim->synchronize(sz);
_sequence->synchronize(sz);
_background->synchronize(sz);
sz.syncAsByte(_carryNum);
for (int i = 0; i < kObjectNum; i++)
sz.syncAsByte(_objects[i]);
- sz.syncAsSint16LE(_dnascore);
+ sz.syncAsSint16LE(_score);
sz.syncAsSint32LE(_money);
sz.syncAsByte(_room);
if (sz.isSaving())
@@ -166,17 +239,17 @@ void AvalancheEngine::synchronize(Common::Serializer &sz) {
sz.syncAsByte(_arrowInTheDoor);
if (sz.isSaving()) {
- uint16 like2drinkSize = _favouriteDrink.size();
+ uint16 like2drinkSize = _favoriteDrink.size();
sz.syncAsUint16LE(like2drinkSize);
for (uint16 i = 0; i < like2drinkSize; i++) {
- char actChr = _favouriteDrink[i];
+ char actChr = _favoriteDrink[i];
sz.syncAsByte(actChr);
}
- uint16 favourite_songSize = _favouriteSong.size();
- sz.syncAsUint16LE(favourite_songSize);
- for (uint16 i = 0; i < favourite_songSize; i++) {
- char actChr = _favouriteSong[i];
+ uint16 favoriteSongSize = _favoriteSong.size();
+ sz.syncAsUint16LE(favoriteSongSize);
+ for (uint16 i = 0; i < favoriteSongSize; i++) {
+ char actChr = _favoriteSong[i];
sz.syncAsByte(actChr);
}
@@ -194,23 +267,23 @@ void AvalancheEngine::synchronize(Common::Serializer &sz) {
sz.syncAsByte(actChr);
}
} else {
- if (!_favouriteDrink.empty())
- _favouriteDrink.clear();
+ if (!_favoriteDrink.empty())
+ _favoriteDrink.clear();
uint16 like2drinkSize = 0;
char actChr = ' ';
sz.syncAsUint16LE(like2drinkSize);
for (uint16 i = 0; i < like2drinkSize; i++) {
sz.syncAsByte(actChr);
- _favouriteDrink += actChr;
+ _favoriteDrink += actChr;
}
- if (!_favouriteSong.empty())
- _favouriteSong.clear();
- uint16 favourite_songSize = 0;
- sz.syncAsUint16LE(favourite_songSize);
- for (uint16 i = 0; i < favourite_songSize; i++) {
+ if (!_favoriteSong.empty())
+ _favoriteSong.clear();
+ uint16 favoriteSongSize = 0;
+ sz.syncAsUint16LE(favoriteSongSize);
+ for (uint16 i = 0; i < favoriteSongSize; i++) {
sz.syncAsByte(actChr);
- _favouriteSong += actChr;
+ _favoriteSong += actChr;
}
if (!_worstPlaceOnEarth.empty())
@@ -263,11 +336,11 @@ void AvalancheEngine::synchronize(Common::Serializer &sz) {
sz.syncAsByte(_timer->_times[i]._action);
sz.syncAsByte(_timer->_times[i]._reason);
}
-
+
}
-bool AvalancheEngine::canSaveGameStateCurrently() { // TODO: Refine these!!!
- return (!_seeScroll && _alive);
+bool AvalancheEngine::canSaveGameStateCurrently() {
+ return (_animationsEnabled && _alive);
}
Common::Error AvalancheEngine::saveGameState(int slot, const Common::String &desc) {
@@ -297,6 +370,8 @@ bool AvalancheEngine::saveGame(const int16 slot, const Common::String &desc) {
f->writeSint16LE(t.tm_mon);
f->writeSint16LE(t.tm_year);
+ _totalTime += getTimeInSeconds() - _startTime;
+
Common::Serializer sz(NULL, f);
synchronize(sz);
f->finalize();
@@ -309,8 +384,8 @@ Common::String AvalancheEngine::getSaveFileName(const int slot) {
return Common::String::format("%s.%03d", _targetName.c_str(), slot);
}
-bool AvalancheEngine::canLoadGameStateCurrently() { // TODO: Refine these!!!
- return (!_seeScroll);
+bool AvalancheEngine::canLoadGameStateCurrently() {
+ return (_animationsEnabled);
}
Common::Error AvalancheEngine::loadGameState(int slot) {
@@ -329,7 +404,7 @@ bool AvalancheEngine::loadGame(const int16 slot) {
// Check version. We can't restore from obsolete versions.
byte saveVersion = f->readByte();
- if (saveVersion != kSavegameVersion) {
+ if (saveVersion > kSavegameVersion) {
warning("Savegame of incompatible version!");
delete f;
return false;
@@ -352,14 +427,15 @@ bool AvalancheEngine::loadGame(const int16 slot) {
t.tm_mon = f->readSint16LE();
t.tm_year = f->readSint16LE();
- resetVariables();
+ resetAllVariables();
Common::Serializer sz(f, NULL);
synchronize(sz);
delete f;
_isLoaded = true;
- _seeScroll = true; // This prevents display of the new sprites before the new picture is loaded.
+
+ _animationsEnabled = false;
if (_holdTheDawn) {
_holdTheDawn = false;
@@ -368,7 +444,7 @@ bool AvalancheEngine::loadGame(const int16 slot) {
_background->release();
minorRedraw();
- _menu->setup();
+ _dropdown->setup();
setRoom(kPeopleAvalot, _room);
_alive = true;
refreshObjectList();
@@ -377,9 +453,9 @@ bool AvalancheEngine::loadGame(const int16 slot) {
_animation->animLink();
_background->update();
- Common::String tmpStr = Common::String::format("%cLoaded: %c%s.ASG%c%c%c%s%c%csaved on %s.",
- kControlItalic, kControlRoman, description.c_str(), kControlCenter, kControlNewLine,
- kControlNewLine, _roomnName.c_str(), kControlNewLine, kControlNewLine,
+ Common::String tmpStr = Common::String::format("%cLoaded: %c%s.ASG%c%c%c%s%c%csaved on %s.",
+ kControlItalic, kControlRoman, description.c_str(), kControlCenter, kControlNewLine,
+ kControlNewLine, _roomnName.c_str(), kControlNewLine, kControlNewLine,
expandDate(t.tm_mday, t.tm_mon, t.tm_year).c_str());
_dialogs->displayText(tmpStr);
@@ -416,6 +492,12 @@ Common::String AvalancheEngine::expandDate(int d, int m, int y) {
return day + ' ' + month + ' ' + intToStr(y + 1900);
}
+uint32 AvalancheEngine::getTimeInSeconds() {
+ TimeDate time;
+ _system->getTimeAndDate(time);
+ return time.tm_hour * 3600 + time.tm_min * 60 + time.tm_sec;
+}
+
void AvalancheEngine::updateEvents() {
Common::Event event;
@@ -456,75 +538,9 @@ Common::Error AvalancheEngine::run() {
do {
runAvalot();
-
-#if 0
- switch (_storage._operation) {
- case kRunShootemup:
- run("seu.avx", kJsb, kBflight, kNormal);
- break;
- case kRunDosshell:
- dosShell();
- break;
- case kRunGhostroom:
- run("g-room.avx", kJsb, kNoBflight, kNormal);
- break;
- case kRunGolden:
- run("golden.avx", kJsb, kBflight, kMusical);
- break;
- }
-#endif
-
} while (!_letMeOut && !shouldQuit());
return Common::kNoError;
}
-#if 0
-void AvalancheEngine::run(Common::String what, bool withJsb, bool withBflight, Elm how) {
- // Probably there'll be no need of this function, as all *.AVX-es will become classes.
- warning("STUB: run(%s)", what.c_str());
-}
-
-Common::String AvalancheEngine::elmToStr(Elm how) {
- switch (how) {
- case kNormal:
- case kMusical:
- return Common::String("jsb");
- case kRegi:
- return Common::String("REGI");
- case kElmpoyten:
- return Common::String("ELMPOYTEN");
- // Useless, but silent a warning
- default:
- return Common::String("");
- }
-}
-
-// Same as keypressed1().
-void AvalancheEngine::flushBuffer() {
- warning("STUB: flushBuffer()");
-}
-
-void AvalancheEngine::dosShell() {
- warning("STUB: dosShell()");
-}
-
-// Needed in dos_shell(). TODO: Remove later.
-Common::String AvalancheEngine::commandCom() {
- warning("STUB: commandCom()");
- return ("STUB: commandCom()");
-}
-
-// Needed for run_avalot()'s errors. TODO: Remove later.
-void AvalancheEngine::explain(byte error) {
- warning("STUB: explain()");
-}
-
-// Needed later.
-void AvalancheEngine::quit() {
- cursorOn();
-}
-
-#endif
-
} // End of namespace Avalanche
diff --git a/engines/avalanche/avalanche.h b/engines/avalanche/avalanche.h
index cc9a34d82b..6eb5e675cc 100644
--- a/engines/avalanche/avalanche.h
+++ b/engines/avalanche/avalanche.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -32,15 +32,21 @@
#include "avalanche/graphics.h"
#include "avalanche/parser.h"
#include "avalanche/avalot.h"
-#include "avalanche/pingo.h"
#include "avalanche/dialogs.h"
#include "avalanche/background.h"
#include "avalanche/sequence.h"
#include "avalanche/timer.h"
#include "avalanche/animation.h"
-#include "avalanche/menu.h"
+#include "avalanche/dropdown.h"
#include "avalanche/closing.h"
#include "avalanche/sound.h"
+#include "avalanche/nim.h"
+#include "avalanche/clock.h"
+#include "avalanche/ghostroom.h"
+#include "avalanche/help.h"
+#include "avalanche/shootemup.h"
+#include "avalanche/mainmenu.h"
+#include "avalanche/highscore.h"
#include "common/serializer.h"
@@ -55,9 +61,11 @@ class RandomSource;
namespace Avalanche {
-struct AvalancheGameDescription;
+struct AvalancheGameDescription {
+ ADGameDescription desc;
+};
-static const int kSavegameVersion = 1;
+static const int kSavegameVersion = 2;
enum Pitch {
kPitchInvalid,
@@ -73,15 +81,18 @@ public:
Clock *_clock;
GraphicManager *_graphics;
Parser *_parser;
- Pingo *_pingo;
Dialogs *_dialogs;
Background *_background;
Sequence *_sequence;
Timer *_timer;
Animation *_animation;
- Menu *_menu;
+ DropDownMenu *_dropdown;
Closing *_closing;
SoundHandler *_sound;
+ Nim *_nim;
+ GhostRoom *_ghostroom;
+ Help *_help;
+ HighScore *_highscore;
OSystem *_system;
@@ -109,6 +120,7 @@ public:
Common::Error loadGameState(int slot);
bool loadGame(const int16 slot);
Common::String expandDate(int d, int m, int y);
+ uint32 getTimeInSeconds();
void updateEvents();
bool getEvent(Common::Event &event); // A wrapper around _eventMan->pollEvent(), so we can use it in Scrolls::normscroll() for example.
@@ -122,43 +134,6 @@ private:
AvalancheConsole *_console;
Common::Platform _platform;
-#if 0
- struct {
- byte _operation;
- uint16 _skellern;
- byte _contents[1000];
- } _storage;
-
- static const int16 kRunShootemup = 1, kRunDosshell = 2, kRunGhostroom = 3, kRunGolden = 4;
- static const int16 kReset = 0;
-
- static const bool kJsb = true, kNoJsb = false, kBflight = true, kNoBflight = false;
-
- // From bootstrp:
- enum Elm {kNormal, kMusical, kElmpoyten, kRegi};
-
- Common::String _argsWithNoFilename;
- byte _originalMode;
- byte *_old1c;
- Common::String _segofs;
- int32 _soundcard, _speed, _baseaddr, _irq, _dma;
- bool _zoomy;
-
- void run(Common::String what, bool withJsb, bool withBflight, Elm how);
- void bFlightOn();
- void bFlightOff();
- Common::String elmToStr(Elm how);
- bool keyPressed();
- void flushBuffer();
- void dosShell();
- void bFlight();
- Common::String commandCom();
- void explain(byte error);
- void cursorOff();
- void cursorOn();
- void quit();
-#endif
-
public:
// For Thinkabout:
static const bool kThing = true;
@@ -167,7 +142,6 @@ public:
static const char kSpludwicksOrder[3];
static const uint16 kNotes[12];
- static const TuneType kTune;
bool _holdLeftMouse;
@@ -178,7 +152,7 @@ public:
// Former DNA structure
byte _carryNum; // How many objects you're carrying...
bool _objects[kObjectNum]; // ...and which ones they are.
- int16 _dnascore; // your score, of course
+ int16 _score; // your score, of course
int32 _money; // your current amount of dosh
Room _room; // your current room
bool _wonNim; // Have you *won* Nim? (That's harder.)
@@ -207,8 +181,9 @@ public:
bool _standingOnDais; // In room 71, inside Cardiff Castle.
bool _takenPen; // Have you taken the pen (in Cardiff?)
bool _arrowInTheDoor; // Did the arrow hit the wall?
- Common::String _favouriteDrink, _favouriteSong, _worstPlaceOnEarth, _spareEvening; // Personalisation str's
- uint32 _totalTime; // Your total time playing this game, in ticks.
+ Common::String _favoriteDrink, _favoriteSong, _worstPlaceOnEarth, _spareEvening; // Personalisation str's
+ uint32 _startTime; // When did you start playing this session?
+ uint32 _totalTime; // Your total time playing this game, in seconds. Updated only at saving and loading.
byte _jumpStatus; // Fixes how high you're jumping.
bool _mushroomGrowing; // Is the mushroom growing in 42?
bool _crapulusWillTell; // Will Crapulus tell you about Spludwick being away?
@@ -237,7 +212,7 @@ public:
bool _letMeOut;
byte _thinks;
bool _thinkThing;
- bool _seeScroll; // TODO: maybe this means we're interacting with the toolbar / a scroll?
+ bool _animationsEnabled; // If set to TRUE, it stops the animation system working. This prevents display of the new sprites before the new picture is loaded or during the display of a scroll. Original name: seescroll.
char _objectList[10];
// Called .free() for them in ~Gyro().
@@ -255,13 +230,15 @@ public:
byte _subjectNum; // The same thing.
People _him, _her;
byte _it;
- uint32 _roomTime; // Set to 0 when you enter a room, added to in every loop.
+ uint32 _roomCycles; // Set to 0 when you enter a room, added to in every loop. Cycles since you've been in this room.
bool _doingSpriteRun; // Only set to True if we're doing a sprite_run at this moment. This stops the trippancy system from moving any of the sprites.
- bool _isLoaded; // Is it a loaded gamestate?
bool _soundFx;
+ bool _isLoaded; // Is it a loaded gamestate?
+
void callVerb(VerbCode id);
+ void loadBackground(byte num);
void loadRoom(byte num);
void thinkAbout(byte object, bool type); // Hey!!! Get it and put it!!!
void incScore(byte num); // Add on no. of points
@@ -274,9 +251,9 @@ public:
void gameOver();
uint16 bearing(byte whichPed); // Returns the bearing from ped 'whichped' to Avvy, in degrees.
- // There are two kinds of redraw: Major and Minor. Minor is what happens when you load a game, etc. Major redraws EVERYTHING.
+ // There are two kinds of redraw: Major and Minor. Minor is what happens when you load a game, etc.
+ // Major was replaced with GraphicManager::refreshScreen(), it redraws EVERYTHING.
void minorRedraw();
- void majorRedraw();
void spriteRun();
@@ -284,7 +261,7 @@ public:
void newGame(); // This sets up the DNA for a completely new game.
bool getFlag(char x);
bool decreaseMoney(uint16 amount); // Called pennycheck in the original.
-
+
Common::String getName(People whose);
Common::String getItem(byte which); // Called get_better in the original.
Common::String f5Does(); // This procedure determines what f5 does.
@@ -316,6 +293,7 @@ private:
Common::String readAlsoStringFromFile(Common::File &file);
void runAvalot();
void init();
+ void initVariables();
void setup();
void scram(Common::String &str);
void unScramble();
@@ -332,6 +310,7 @@ private:
void checkClick();
void fixFlashers();
void loadAlso(byte num);
+ void resetAllVariables();
void resetVariables();
};
diff --git a/engines/avalanche/avalot.cpp b/engines/avalanche/avalot.cpp
index 8ef41a2c93..0ffe7d3f9d 100644
--- a/engines/avalanche/avalot.cpp
+++ b/engines/avalanche/avalot.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -76,11 +76,6 @@ namespace Avalanche {
const char AvalancheEngine::kSpludwicksOrder[3] = {kObjectOnion, kObjectInk, kObjectMushroom};
const uint16 AvalancheEngine::kNotes[12] = {196, 220, 247, 262, 294, 330, 350, 392, 440, 494, 523, 587};
-const TuneType AvalancheEngine::kTune = {
- kPitchHigher, kPitchHigher, kPitchLower, kPitchSame, kPitchHigher, kPitchHigher, kPitchLower, kPitchHigher, kPitchHigher, kPitchHigher,
- kPitchLower, kPitchHigher, kPitchHigher, kPitchSame, kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchHigher,
- kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchSame, kPitchLower, kPitchHigher, kPitchSame, kPitchLower, kPitchHigher
-};
Room AvalancheEngine::_whereIs[29] = {
// The Lads
@@ -116,83 +111,6 @@ Room AvalancheEngine::_whereIs[29] = {
kRoomWiseWomans // The Wise Woman.
};
-Clock::Clock(AvalancheEngine *vm) {
- _vm = vm;
- _oldHour = _oldHourAngle = _oldMinute = 17717;
-}
-
-void Clock::update() { // TODO: Move variables from Gyro to here (or at least somewhere nearby), rename them.
- TimeDate t;
- _vm->_system->getTimeAndDate(t);
- _hour = t.tm_hour;
- _minute = t.tm_min;
- _second = t.tm_sec;
-
- _hourAngle = (_hour % 12) * 30 + _minute / 2;
-
- if (_oldHour != _hour) {
- plotHands();
- chime();
- }
-
- if (_oldMinute != _minute)
- plotHands();
-
- if ((_hour == 0) && (_oldHour != 0) && (_oldHour != 17717)) {
- Common::String tmpStr = Common::String::format("Good morning!%c%cYes, it's just past " \
- "midnight. Are you having an all-night Avvy session? Glad you like the game that much!",
- kControlNewLine, kControlNewLine);
- _vm->_dialogs->displayText(tmpStr);
- }
- _oldHour = _hour;
- _oldHourAngle = _hourAngle;
- _oldMinute = _minute;
-}
-
-Common::Point Clock::calcHand(uint16 angle, uint16 length, Color color) {
- if (angle > 900) {
- return(Common::Point(177, 177));
- }
-
- return(_vm->_graphics->drawScreenArc(kCenterX, kCenterY, 449 - angle, 450 - angle, length, color));
-}
-
-void Clock::drawHand(const Common::Point &endPoint, Color color) {
- if (endPoint.x == 177)
- return;
-
- _vm->_graphics->drawScreenLine(kCenterX, kCenterY, endPoint.x, endPoint.y, color);
-}
-
-void Clock::plotHands() {
- _clockHandHour = calcHand(_oldHourAngle, 14, kColorYellow);
- _clockHandMinute = calcHand(_oldMinute * 6, 17, kColorYellow);
- drawHand(_clockHandHour, kColorBrown);
- drawHand(_clockHandMinute, kColorBrown);
-
- _clockHandHour = calcHand(_hourAngle, 14, kColorBrown);
- _clockHandMinute = calcHand(_minute * 6, 17, kColorBrown);
- drawHand(_clockHandHour, kColorYellow);
- drawHand(_clockHandMinute, kColorYellow);
-}
-
-void Clock::chime() {
- if ((_oldHour == 17717) || (!_vm->_soundFx)) // Too high - must be first time around
- return;
-
- byte hour = _hour % 12;
- if (hour == 0)
- hour = 12;
-
- _vm->_graphics->loadMouse(kCurWait);
-
- for (int i = 1; i <= hour; i++) {
- for (int j = 1; j <= 3; j++)
- _vm->_sound->playNote((i % 3) * 64 + 140 - j * 30, 50 - j * 12);
- if (i != hour)
- _vm->_system->delayMillis(100);
- }
-}
void AvalancheEngine::handleKeyDown(Common::Event &event) {
@@ -272,7 +190,6 @@ void AvalancheEngine::setup() {
_animation->resetAnims();
- drawToolbar();
_dialogs->setReadyLight(2);
fadeIn();
@@ -281,7 +198,11 @@ void AvalancheEngine::setup() {
_animation->_sprites[0]->_speedX = kWalk;
_animation->updateSpeed();
- _menu->init();
+ _dropdown->init();
+
+ _graphics->drawSoundLight(_sound->_soundFl);
+
+ drawToolbar();
int16 loadSlot = ConfMan.instance().getInt("save_slot");
if (loadSlot >= 0) {
@@ -290,27 +211,31 @@ void AvalancheEngine::setup() {
loadGame(loadSlot);
} else {
- _isLoaded = false; // Set to true in _vm->loadGame().
+ // We don't need the MainMenu during the whole game, only at the beginning of it.
+ MainMenu *mainmenu = new MainMenu(this);
+ mainmenu->run();
+ delete mainmenu;
+ if (_letMeOut)
+ return;
+
newGame();
- _soundFx = !_soundFx;
- fxToggle();
thinkAbout(kObjectMoney, kThing);
- _dialogs->displayScrollChain('q', 83); // Info on the game, etc.
+ _dialogs->displayScrollChain('Q', 83); // Info on the game, etc.
}
}
void AvalancheEngine::runAvalot() {
setup();
- do {
+ while (!_letMeOut && !shouldQuit()) {
uint32 beginLoop = _system->getMillis();
updateEvents(); // The event handler.
_clock->update();
- _menu->update();
+ _dropdown->update();
_background->update();
_animation->animLink();
checkClick();
@@ -322,9 +247,7 @@ void AvalancheEngine::runAvalot() {
uint32 delay = _system->getMillis() - beginLoop;
if (delay <= 55)
_system->delayMillis(55 - delay); // Replaces slowdown(); 55 comes from 18.2 Hz (B Flight).
- } while (!_letMeOut && !shouldQuit());
-
- warning("STUB: run()");
+ };
_closing->exitGame();
}
@@ -335,13 +258,6 @@ void AvalancheEngine::init() {
_also[i][j] = nullptr;
}
-#if 0
- if (_vm->_enhanced->atbios)
- atkey = "f1";
- else
- atkey = "alt-";
-#endif
-
_letMeOut = false;
_currentMouse = 177;
_dropsOk = true;
@@ -498,9 +414,7 @@ void AvalancheEngine::loadAlso(byte num) {
}
}
-void AvalancheEngine::loadRoom(byte num) {
- CursorMan.showMouse(false);
-
+void AvalancheEngine::loadBackground(byte num) {
Common::String filename = Common::String::format("place%d.avd", num);
Common::File file;
if (!file.open(filename))
@@ -522,9 +436,15 @@ void AvalancheEngine::loadRoom(byte num) {
_graphics->refreshBackground();
file.close();
+}
+
+void AvalancheEngine::loadRoom(byte num) {
+ CursorMan.showMouse(false);
+ loadBackground(num);
loadAlso(num);
- _background->load(num);
+ _background->loadSprites(num);
+
CursorMan.showMouse(true);
}
@@ -542,7 +462,7 @@ void AvalancheEngine::findPeople(byte room) {
void AvalancheEngine::exitRoom(byte x) {
_sound->stopSound();
_background->release();
- _seeScroll = true; // This stops the trippancy system working over the length of this procedure.
+ _animationsEnabled = false;
switch (x) {
case kRoomSpludwicks:
@@ -565,21 +485,20 @@ void AvalancheEngine::exitRoom(byte x) {
}
_interrogation = 0; // Leaving the room cancels all the questions automatically.
- _seeScroll = false; // Now it can work again!
+ _animationsEnabled = true;
_lastRoom = _room;
if (_room != kRoomMap)
_lastRoomNotMap = _room;
}
-
/**
* Only when entering a NEW town! Not returning to the last one,
* but choosing another from the map.
* @remarks Originally called 'new_town'
*/
void AvalancheEngine::enterNewTown() {
- _menu->setup();
+ _dropdown->setup();
switch (_room) {
case kRoomOutsideNottsPub: // Entry into Nottingham.
@@ -613,11 +532,11 @@ void AvalancheEngine::putGeidaAt(byte whichPed, byte ped) {
spr1->init(5, false); // load Geida
_animation->appearPed(1, whichPed);
spr1->_callEachStepFl = true;
- spr1->_eachStepProc = Animation::kProcGeida;
+ spr1->_eachStepProc = Animation::kProcFollowAvvy;
}
void AvalancheEngine::enterRoom(Room roomId, byte ped) {
- _seeScroll = true; // This stops the trippancy system working over the length of this procedure.
+ _animationsEnabled = false;
findPeople(roomId);
_room = roomId;
@@ -634,12 +553,13 @@ void AvalancheEngine::enterRoom(Room roomId, byte ped) {
if (_geidaFollows)
_whereIs[kPeopleGeida - 150] = roomId;
- _roomTime = 0;
-
+ _roomCycles = 0;
if ((_lastRoom == kRoomMap) && (_lastRoomNotMap != _room))
enterNewTown();
+ _animation->updateSpeed();
+
switch (roomId) {
case kRoomYours:
if (_avvyInBed) {
@@ -697,7 +617,7 @@ void AvalancheEngine::enterRoom(Room roomId, byte ped) {
}
spr1->_callEachStepFl = true;
- spr1->_eachStepProc = Animation::kProcGeida;
+ spr1->_eachStepProc = Animation::kProcFollowAvvy;
} else
_whereIs[kPeopleSpludwick - 150] = kRoomNowhere;
break;
@@ -806,12 +726,12 @@ void AvalancheEngine::enterRoom(Room roomId, byte ped) {
_graphics->zoomOut(_peds[ped - 1]._x, _peds[ped - 1]._y);
if ((_objects[kObjectWine - 1]) && (_wineState != 3)) {
- _dialogs->displayScrollChain('q', 9); // Don't want to waste the wine!
+ _dialogs->displayScrollChain('Q', 9); // Don't want to waste the wine!
_objects[kObjectWine - 1] = false;
refreshObjectList();
}
- _dialogs->displayScrollChain('q', 69);
+ _dialogs->displayScrollChain('Q', 69);
break;
case kRoomCatacombs:
@@ -994,14 +914,13 @@ void AvalancheEngine::enterRoom(Room roomId, byte ped) {
case kRoomDucks:
_npcFacing = 1; // Duck.
- break;
+ break;
default:
break;
}
- _seeScroll = false; // Now it can work again!
- _isLoaded = false;
+ _animationsEnabled = true;
}
void AvalancheEngine::thinkAbout(byte object, bool type) {
@@ -1036,7 +955,7 @@ void AvalancheEngine::drawToolbar() {
}
void AvalancheEngine::drawScore() {
- uint16 score = _dnascore;
+ uint16 score = _score;
int8 numbers[3] = {0, 0, 0};
for (int i = 0; i < 2; i++) {
byte divisor = 1;
@@ -1060,17 +979,16 @@ void AvalancheEngine::drawScore() {
_scoreToDisplay[i] = numbers[i];
}
-void AvalancheEngine::incScore(byte num) {
+void AvalancheEngine::incScore(byte num) {
for (int i = 1; i <= num; i++) {
- _dnascore++;
+ _score++;
if (_soundFx) {
for (int j = 1; j <= 97; j++)
- // Length os 2 is a guess, the original doesn't have a delay specified
- _sound->playNote(177 + _dnascore * 3, 2);
+ // Length of 2 is a guess, the original doesn't have a delay specified
+ _sound->playNote(177 + _score * 3, 2);
}
}
- warning("STUB: points()");
drawScore();
}
@@ -1195,7 +1113,7 @@ void AvalancheEngine::checkClick() {
_graphics->loadMouse(kCurIBeam); //I-beam
else if ((340 <= cursorPos.y) && (cursorPos.y <= 399))
_graphics->loadMouse(kCurScrewDriver); // screwdriver
- else if (!_menu->isActive()) { // Dropdown can handle its own pointers.
+ else if (!_dropdown->isActive()) { // Dropdown can handle its own pointers.
if (_holdLeftMouse) {
_graphics->loadMouse(kCurCrosshair); // Mark's crosshairs
guideAvvy(cursorPos); // Normally, if you click on the picture, you're guiding Avvy around.
@@ -1206,7 +1124,7 @@ void AvalancheEngine::checkClick() {
if (_holdLeftMouse) {
if ((0 <= cursorPos.y) && (cursorPos.y <= 21)) { // Click on the dropdown menu.
if (_dropsOk)
- _menu->update();
+ _dropdown->update();
} else if ((317 <= cursorPos.y) && (cursorPos.y <= 339)) { // Click on the command line.
_parser->_inputTextPos = (cursorPos.x - 23) / 8;
if (_parser->_inputTextPos > _parser->_inputText.size() + 1)
@@ -1229,7 +1147,7 @@ void AvalancheEngine::checkClick() {
_parser->_thing += 49;
_parser->_person = kPeoplePardon;
} else {
- _parser->_person = (People) _thinks;
+ _parser->_person = (People)_thinks;
_parser->_thing = _parser->kPardon;
}
callVerb(kVerbCodeExam);
@@ -1246,7 +1164,7 @@ void AvalancheEngine::checkClick() {
_animation->_sprites[0]->_speedX = kRun;
_animation->updateSpeed();
} else if ((396 <= cursorPos.x) && (cursorPos.x <= 483))
- fxToggle();
+ _sound->toggleSound();
else if ((535 <= cursorPos.x) && (cursorPos.x <= 640))
_mouseText.insertChar(kControlNewLine, 0);
} else if (!_dropsOk)
@@ -1255,7 +1173,14 @@ void AvalancheEngine::checkClick() {
}
void AvalancheEngine::errorLed() {
- warning("STUB: errorled()");
+ _dialogs->setReadyLight(0);
+ _graphics->drawErrorLight(true);
+ for (int i = 177; i >= 1; i--) {
+ _sound->playNote(177 + (i * 177177) / 999, 1);
+ _system->delayMillis(1);
+ }
+ _graphics->drawErrorLight(false);
+ _dialogs->setReadyLight(2);
}
/**
@@ -1307,9 +1232,9 @@ void AvalancheEngine::fadeOut() {
void AvalancheEngine::fadeIn() {
if (_holdTheDawn || !_fxHidden)
return;
-
+
_fxHidden = false;
-
+
byte pal[3];
for (int i = 15; i >= 0; i--) {
for (int j = 0; j < 16; j++) {
@@ -1337,7 +1262,6 @@ void AvalancheEngine::drawDirection() { // It's data is loaded in load_digits().
CursorMan.showMouse(true);
}
-
void AvalancheEngine::gameOver() {
_userMovesAvvy = false;
@@ -1366,17 +1290,13 @@ void AvalancheEngine::minorRedraw() {
fadeIn();
}
-void AvalancheEngine::majorRedraw() {
- warning("STUB: major_redraw()");
-}
-
uint16 AvalancheEngine::bearing(byte whichPed) {
AnimationType *avvy = _animation->_sprites[0];
PedType *curPed = &_peds[whichPed];
if (avvy->_x == curPed->_x)
return 0;
-
+
int16 deltaX = avvy->_x - curPed->_x;
int16 deltaY = avvy->_y - curPed->_y;
uint16 result = (uint16)(atan((float)(deltaY / deltaX)) * 180 / M_PI);
@@ -1387,7 +1307,7 @@ uint16 AvalancheEngine::bearing(byte whichPed) {
}
}
-/**
+/**
* @remarks Originally called 'sprite_run'
*/
void AvalancheEngine::spriteRun() {
@@ -1409,12 +1329,11 @@ Common::String AvalancheEngine::intToStr(int32 num) {
}
void AvalancheEngine::resetVariables() {
- _animation->setDirection(kDirUp);
_carryNum = 0;
for (int i = 0; i < kObjectNum; i++)
_objects[i] = false;
- _dnascore = 0;
+ _score = 0;
_money = 0;
_room = kRoomNowhere;
_saveNum = 0;
@@ -1448,16 +1367,16 @@ void AvalancheEngine::resetVariables() {
_standingOnDais = false;
_takenPen = false;
_arrowInTheDoor = false;
- _favouriteDrink = "";
- _favouriteSong = "";
+ _favoriteDrink = "";
+ _favoriteSong = "";
_worstPlaceOnEarth = "";
_spareEvening = "";
_totalTime = 0;
_jumpStatus = 0;
_mushroomGrowing = false;
_spludwickAtHome = false;
- _lastRoom = 0;
- _lastRoomNotMap = 0;
+ _lastRoom = kRoomDummy;
+ _lastRoomNotMap = kRoomDummy;
_crapulusWillTell = false;
_enterCatacombsFromLustiesRoom = false;
_teetotal = false;
@@ -1477,12 +1396,18 @@ void AvalancheEngine::resetVariables() {
_takenMushroom = false;
_givenPenToAyles = false;
_askedDogfoodAboutNim = false;
+ _startTime = getTimeInSeconds();
+}
+void AvalancheEngine::resetAllVariables() {
+ resetVariables();
_parser->resetVariables();
+ _nim->resetVariables();
_animation->resetVariables();
_sequence->resetVariables();
_background->resetVariables();
- _menu->resetVariables();
+ _dropdown->resetVariables();
+ _timer->resetVariables();
}
void AvalancheEngine::newGame() {
@@ -1497,12 +1422,12 @@ void AvalancheEngine::newGame() {
avvy->init(0, true);
_alive = true;
- resetVariables();
+ resetAllVariables();
_dialogs->setBubbleStateNatural();
_spareEvening = "answer a questionnaire";
- _favouriteDrink = "beer";
+ _favoriteDrink = "beer";
_money = 30; // 2/6
_animation->setDirection(kDirStopped);
_parser->_wearing = kObjectClothes;
@@ -1514,7 +1439,7 @@ void AvalancheEngine::newGame() {
_thinkThing = true;
_thinks = 2;
refreshObjectList();
- _seeScroll = false;
+ _animationsEnabled = true;
avvy->appear(300, 117, kDirRight); // Needed to initialize Avalot.
//for (gd = 0; gd <= 30; gd++) for (gm = 0; gm <= 1; gm++) also[gd][gm] = nil;
@@ -1527,10 +1452,12 @@ void AvalancheEngine::newGame() {
_doingSpriteRun = false;
_avvyInBed = true;
+ _isLoaded = false;
+
enterRoom(kRoomYours, 1);
avvy->_visible = false;
drawScore();
- _menu->setup();
+ _dropdown->setup();
_clock->update();
spriteRun();
}
@@ -1558,16 +1485,18 @@ Common::String AvalancheEngine::getName(People whose) {
static const char lads[17][20] = {
"Avalot", "Spludwick", "Crapulus", "Dr. Duck", "Malagauche",
"Friar Tuck", "Robin Hood", "Cwytalot", "du Lustie", "the Duke of Cardiff",
- "Dogfood", "A trader", "Ibythneth", "Ayles", "Port",
+ "Dogfood", "A trader", "Ibythneth", "Ayles", "Port",
"Spurge", "Jacques"
};
static const char lasses[4][15] = {"Arkata", "Geida", "\0xB1", "the Wise Woman"};
- if (whose < kPeopleArkata)
+ if (whose <= kPeopleJacques)
return Common::String(lads[whose - kPeopleAvalot]);
- else
+ else if ((whose >= kPeopleArkata) && (whose <= kPeopleWisewoman))
return Common::String(lasses[whose - kPeopleArkata]);
+ else
+ error("getName() - Unexpected character id %d", (byte) whose);
}
Common::String AvalancheEngine::getItem(byte which) {
@@ -1674,6 +1603,9 @@ void AvalancheEngine::flipRoom(Room room, byte ped) {
if (_room == kRoomLustiesRoom)
_enterCatacombsFromLustiesRoom = true;
+ if (room > kRoomMap)
+ return;
+
enterRoom(room, ped);
_animation->appearPed(0, ped - 1);
_enterCatacombsFromLustiesRoom = false;
@@ -1735,10 +1667,10 @@ void AvalancheEngine::openDoor(Room whither, byte ped, byte magicnum) {
}
void AvalancheEngine::setRoom(People persId, Room roomId) {
- _whereIs[persId - kPeopleAvalot] = roomId;
+ _whereIs[persId - kPeopleAvalot] = roomId;
}
Room AvalancheEngine::getRoom(People persId) {
- return _whereIs[persId - kPeopleAvalot];
+ return _whereIs[persId - kPeopleAvalot];
}
} // End of namespace Avalanche
diff --git a/engines/avalanche/avalot.h b/engines/avalanche/avalot.h
index ab78f5c385..04b945fd20 100644
--- a/engines/avalanche/avalot.h
+++ b/engines/avalanche/avalot.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -35,33 +35,9 @@
namespace Avalanche {
class AvalancheEngine;
-class Clock {
-public:
- Clock(AvalancheEngine *vm);
-
- void update();
-
-private:
- static const int kCenterX = 510;
- static const int kCenterY = 183;
-
- AvalancheEngine *_vm;
-
- uint16 _hour, _minute, _second, _hourAngle, _oldHour, _oldMinute, _oldHourAngle;
- Common::Point _clockHandHour, _clockHandMinute;
-
- Common::Point calcHand(uint16 angle, uint16 length, Color color);
- void drawHand(const Common::Point &endPoint, Color color);
- void plotHands();
- void chime();
-};
-
static const byte kObjectNum = 18; // always preface with a #
static const int16 kCarryLimit = 12; // carry limit
-static const int16 kNumlockCode = 32; // Code for Num Lock
-static const int16 kMouseSize = 134;
-
struct PedType {
int16 _x, _y;
Direction _direction;
@@ -80,8 +56,6 @@ struct LineType : public FieldType {
Color _color;
};
-typedef int8 TuneType[31];
-
struct QuasipedType {
byte _whichPed;
Color _textColor;
@@ -90,15 +64,6 @@ struct QuasipedType {
People _who;
};
-#if 0
-struct Sundry { // Things which must be saved over a backtobootstrap, outside DNA.
- Common::String _qEnidFilename;
- bool _qSoundFx;
- byte _qThinks;
- bool _qThinkThing;
-};
-#endif
-
} // End of namespace Avalanche
#endif // AVALANCHE_AVALOT_H
diff --git a/engines/avalanche/background.cpp b/engines/avalanche/background.cpp
index c84c049c8f..f1ba659a55 100644
--- a/engines/avalanche/background.cpp
+++ b/engines/avalanche/background.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -37,6 +37,7 @@ const int16 Background::kOnDisk = -1;
Background::Background(AvalancheEngine *vm) {
_vm = vm;
_spriteNum = 0;
+ _nextBell = 0;
}
Background::~Background() {
@@ -47,28 +48,28 @@ Background::~Background() {
* @remarks Originally called 'pics_link'
*/
void Background::update() {
- if (_vm->_menu->isActive())
+ if (_vm->_dropdown->isActive())
return; // No animation when the menus are up.
switch (_vm->_room) {
case kRoomOutsideArgentPub:
- if ((_vm->_roomTime % 12) == 0)
- draw(-1, -1, (_vm->_roomTime / 12) % 4);
+ if ((_vm->_roomCycles % 12) == 0)
+ draw(-1, -1, (_vm->_roomCycles / 12) % 4);
break;
case kRoomBrummieRoad:
- if ((_vm->_roomTime % 2) == 0)
- draw(-1, -1, (_vm->_roomTime / 2) % 4);
+ if ((_vm->_roomCycles % 2) == 0)
+ draw(-1, -1, (_vm->_roomCycles / 2) % 4);
break;
case kRoomBridge:
- if ((_vm->_roomTime % 2) == 0)
- draw(-1, -1, 3 + (_vm->_roomTime / 2) % 4);
+ if ((_vm->_roomCycles % 2) == 0)
+ draw(-1, -1, 3 + (_vm->_roomCycles / 2) % 4);
break;
case kRoomYours:
- if ((!_vm->_avvyIsAwake) && ((_vm->_roomTime % 4) == 0))
- draw(-1, -1, (_vm->_roomTime / 12) % 2);
+ if ((!_vm->_avvyIsAwake) && ((_vm->_roomCycles % 4) == 0))
+ draw(-1, -1, (_vm->_roomCycles / 12) % 2);
break;
case kRoomArgentPub:
- if (((_vm->_roomTime % 7) == 1) && (_vm->_malagauche != 177)) {
+ if (((_vm->_roomCycles % 7) == 1) && (_vm->_malagauche != 177)) {
// Malagauche cycle.
_vm->_malagauche++;
switch (_vm->_malagauche) {
@@ -92,7 +93,7 @@ void Background::update() {
}
}
- switch (_vm->_roomTime % 200) {
+ switch (_vm->_roomCycles % 200) {
case 179:
case 197:
draw(-1, -1, 4); // Dogfood's drinking cycle.
@@ -108,7 +109,7 @@ void Background::update() {
_vm->_npcFacing = 177; // Impossible value for this.
break;
default:
- if (_vm->_roomTime % 200 <= 178) { // Normally.
+ if (_vm->_roomCycles % 200 <= 178) { // Normally.
byte direction = 1;
uint16 angle = _vm->bearing(1);
if (((angle >= 1) && (angle <= 90)) || ((angle >= 358) && (angle <= 360)))
@@ -126,8 +127,8 @@ void Background::update() {
}
break;
case kRoomWestHall:
- if ((_vm->_roomTime % 3) == 0) {
- switch ((_vm->_roomTime / 3) % 6) {
+ if ((_vm->_roomCycles % 3) == 0) {
+ switch ((_vm->_roomCycles / 3) % 6) {
case 4:
draw(-1, -1, 0);
break;
@@ -147,7 +148,7 @@ void Background::update() {
if (!(_vm->_lustieIsAsleep)) {
byte direction = 0;
uint16 angle = _vm->bearing(1);
- if ((_vm->_roomTime % 45) > 42)
+ if ((_vm->_roomCycles % 45) > 42)
direction = 4; // du Lustie blinks.
// Bearing of Avvy from du Lustie.
else if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
@@ -164,8 +165,8 @@ void Background::update() {
}
break;
case kRoomAylesOffice:
- if ((!_vm->_aylesIsAwake) && (_vm->_roomTime % 14 == 0)) {
- switch ((_vm->_roomTime / 14) % 2) {
+ if ((!_vm->_aylesIsAwake) && (_vm->_roomCycles % 14 == 0)) {
+ switch ((_vm->_roomCycles / 14) % 2) {
case 0:
draw(-1, -1, 0); // Frame 2: EGA.
break;
@@ -177,7 +178,7 @@ void Background::update() {
break;
case kRoomRobins:
if (_vm->_tiedUp) {
- switch (_vm->_roomTime % 54) {
+ switch (_vm->_roomCycles % 54) {
case 20:
draw(-1, -1, 3); // Frame 4: Avalot blinks.
break;
@@ -198,7 +199,7 @@ void Background::update() {
else if ((angle >= 181) && (angle <= 314))
direction = 8; // Right.
- if ((_vm->_roomTime % 60) > 57)
+ if ((_vm->_roomCycles % 60) > 57)
direction--; // Blinks.
if (direction != _vm->_npcFacing) { // Port.
@@ -206,7 +207,7 @@ void Background::update() {
_vm->_npcFacing = direction;
}
- switch (_vm->_roomTime % 50) {
+ switch (_vm->_roomCycles % 50) {
case 45 :
draw(-1, -1, 8); // Spurge blinks.
break;
@@ -217,8 +218,8 @@ void Background::update() {
break;
}
case kRoomDucks: {
- if ((_vm->_roomTime % 3) == 0) // The fire flickers.
- draw(-1, -1, (_vm->_roomTime / 3) % 3);
+ if ((_vm->_roomCycles % 3) == 0) // The fire flickers.
+ draw(-1, -1, (_vm->_roomCycles / 3) % 3);
// Bearing of Avvy from Duck.
byte direction = 0;
@@ -230,7 +231,7 @@ void Background::update() {
else if ((angle >= 181) && (angle <= 314))
direction = 8; // Right.
- if ((_vm->_roomTime % 45) > 42)
+ if ((_vm->_roomCycles % 45) > 42)
direction++; // Duck blinks.
if (direction != _vm->_npcFacing) { // Duck.
@@ -245,12 +246,12 @@ void Background::update() {
if ((_vm->_bellsAreRinging) && (_vm->getFlag('B'))) {
// They're ringing the bells.
- switch (_vm->_roomTime % 4) {
+ switch (_vm->_roomCycles % 4) {
case 1:
if (_nextBell < 5)
_nextBell = 12;
_nextBell--;
- // CHECKME: 2 is a guess. No length in the original?
+ // CHECKME: 2 is a guess. No length in the original?
_vm->_sound->playNote(_vm->kNotes[_nextBell], 2);
break;
case 2:
@@ -260,7 +261,7 @@ void Background::update() {
}
}
-void Background::load(byte number) {
+void Background::loadSprites(byte number) {
Common::File f;
_filename = _filename.format("chunk%d.avd", number);
if (!f.open(_filename))
@@ -278,24 +279,24 @@ void Background::load(byte number) {
sprite._type = (PictureType)(f.readByte());
sprite._x = f.readSint16LE();
sprite._y = f.readSint16LE();
- sprite._xl = f.readSint16LE();
- sprite._yl = f.readSint16LE();
+ sprite._width = f.readSint16LE();
+ sprite._height = f.readSint16LE();
sprite._size = f.readSint32LE();
bool natural = f.readByte();
bool memorize = f.readByte();
if (memorize) {
_sprites[i]._x = sprite._x;
- _sprites[i]._xl = sprite._xl;
+ _sprites[i]._width = sprite._width;
_sprites[i]._y = sprite._y;
- _sprites[i]._yl = sprite._yl;
+ _sprites[i]._height = sprite._height;
_sprites[i]._type = sprite._type;
if (natural)
_vm->_graphics->getNaturalPicture(_sprites[i]);
else {
_sprites[i]._size = sprite._size;
- _sprites[i]._picture = _vm->_graphics->loadPictureRaw(f, _sprites[i]._xl * 8, _sprites[i]._yl + 1);
+ _sprites[i]._picture = _vm->_graphics->loadPictureRaw(f, _sprites[i]._width * 8, _sprites[i]._height + 1);
}
} else
_sprites[i]._x = kOnDisk;
@@ -334,11 +335,11 @@ void Background::draw(int16 destX, int16 destY, byte sprId) {
sprite._type = (PictureType)(f.readByte());
sprite._x = f.readSint16LE();
sprite._y = f.readSint16LE();
- sprite._xl = f.readSint16LE();
- sprite._yl = f.readSint16LE();
+ sprite._width = f.readSint16LE();
+ sprite._height = f.readSint16LE();
sprite._size = f.readSint32LE();
f.skip(2); // Natural and Memorize are used in Load()
- sprite._picture = _vm->_graphics->loadPictureRaw(f, sprite._xl * 8, sprite._yl + 1);
+ sprite._picture = _vm->_graphics->loadPictureRaw(f, sprite._width * 8, sprite._height + 1);
if (destX < 0) {
destX = sprite._x * 8;
diff --git a/engines/avalanche/background.h b/engines/avalanche/background.h
index 34d7a9a2cc..e994d9eae9 100644
--- a/engines/avalanche/background.h
+++ b/engines/avalanche/background.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -40,7 +40,7 @@ enum PictureType {kEga, kBgi, kNaturalImage};
struct SpriteType {
PictureType _type;
int16 _x, _y;
- int16 _xl, _yl;
+ int16 _width, _height;
int32 _size;
Graphics::Surface _picture;
};
@@ -51,7 +51,7 @@ public:
~Background();
void update();
- void load(byte number);
+ void loadSprites(byte number);
void release();
// Setting the destination to negative coordinates means the picture should be drawn to it's original position.
diff --git a/engines/avalanche/clock.cpp b/engines/avalanche/clock.cpp
new file mode 100644
index 0000000000..6d398d9921
--- /dev/null
+++ b/engines/avalanche/clock.cpp
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
+*/
+
+#include "avalanche/clock.h"
+#include "avalanche/avalanche.h"
+
+namespace Avalanche {
+
+Clock::Clock(AvalancheEngine *vm) {
+ _vm = vm;
+ // Magic value to determine if we just created the instance
+ _oldHour = _oldHourAngle = _oldMinute = 17717;
+ _hour = _minute = _second = 0;
+ _hourAngle = 0;
+}
+
+void Clock::update() {
+ TimeDate t;
+ _vm->_system->getTimeAndDate(t);
+ _hour = t.tm_hour;
+ _minute = t.tm_min;
+ _second = t.tm_sec;
+
+ _hourAngle = (_hour % 12) * 30 + _minute / 2;
+
+ if (_oldHour != _hour) {
+ plotHands();
+ chime();
+ }
+
+ if (_oldMinute != _minute)
+ plotHands();
+
+ if ((_hour == 0) && (_oldHour != 0) && (_oldHour != 17717)) {
+ Common::String tmpStr = Common::String::format("Good morning!%c%cYes, it's just past " \
+ "midnight. Are you having an all-night Avvy session? Glad you like the game that much!",
+ kControlNewLine, kControlNewLine);
+ _vm->_dialogs->displayText(tmpStr);
+ }
+ _oldHour = _hour;
+ _oldHourAngle = _hourAngle;
+ _oldMinute = _minute;
+}
+
+Common::Point Clock::calcHand(uint16 angle, uint16 length, Color color) {
+ if (angle > 900) {
+ return(Common::Point(177, 177));
+ }
+
+ return(_vm->_graphics->drawScreenArc(kCenterX, kCenterY, 449 - angle, 450 - angle, length, color));
+}
+
+void Clock::drawHand(const Common::Point &endPoint, Color color) {
+ if (endPoint.x == 177)
+ return;
+
+ _vm->_graphics->drawScreenLine(kCenterX, kCenterY, endPoint.x, endPoint.y, color);
+}
+
+void Clock::plotHands() {
+ _clockHandHour = calcHand(_oldHourAngle, 14, kColorYellow);
+ _clockHandMinute = calcHand(_oldMinute * 6, 17, kColorYellow);
+ drawHand(_clockHandHour, kColorBrown);
+ drawHand(_clockHandMinute, kColorBrown);
+
+ _clockHandHour = calcHand(_hourAngle, 14, kColorBrown);
+ _clockHandMinute = calcHand(_minute * 6, 17, kColorBrown);
+ drawHand(_clockHandHour, kColorYellow);
+ drawHand(_clockHandMinute, kColorYellow);
+}
+
+void Clock::chime() {
+ // Too high - must be first time around
+ // Mute - skip the sound generation
+ if ((_oldHour == 17717) || (!_vm->_soundFx))
+ return;
+
+ byte hour = _hour % 12;
+ if (hour == 0)
+ hour = 12;
+
+ _vm->_graphics->loadMouse(kCurWait);
+
+ for (int i = 1; i <= hour; i++) {
+ for (int j = 1; j <= 3; j++)
+ _vm->_sound->playNote((i % 3) * 64 + 140 - j * 30, 50 - j * 12);
+ if (i != hour)
+ _vm->_system->delayMillis(100);
+ }
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/pingo.h b/engines/avalanche/clock.h
index 72fdb54c2a..85ea508a80 100644
--- a/engines/avalanche/pingo.h
+++ b/engines/avalanche/clock.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -21,39 +21,40 @@
*/
/*
- * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
- * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
- */
-
-/* PINGO Full-screen sub-parts of the game. */
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
+*/
-#ifndef AVALANCHE_PINGO_H
-#define AVALANCHE_PINGO_H
+#ifndef AVALANCHE_CLOCK_H
+#define AVALANCHE_CLOCK_H
-#include "common/str.h"
+#include "common/rect.h"
+#include "avalanche/enums.h"
namespace Avalanche {
class AvalancheEngine;
-class Pingo {
+class Clock {
public:
- Pingo(AvalancheEngine *vm);
+ Clock(AvalancheEngine *vm);
- void bossKey();
- void copy02();
- void copy03();
- void copyPage(byte frp, byte top);
- void wobble();
- void zonk();
- void winningPic();
+ void update();
private:
+ static const int kCenterX = 510;
+ static const int kCenterY = 183;
+
AvalancheEngine *_vm;
- void dPlot(int16 x, int16 y, Common::String z);
- void zl(int16 x1, int16 y1, int16 x2, int16 y2);
+ uint16 _hour, _minute, _second, _hourAngle, _oldHour, _oldMinute, _oldHourAngle;
+ Common::Point _clockHandHour, _clockHandMinute;
+
+ Common::Point calcHand(uint16 angle, uint16 length, Color color);
+ void drawHand(const Common::Point &endPoint, Color color);
+ void plotHands();
+ void chime();
};
-} // End of namespace Avalanche.
+} // End of namespace Avalanche
-#endif // AVALANCHE_PINGO_H
+#endif // AVALANCHE_CLOCK_H
diff --git a/engines/avalanche/closing.cpp b/engines/avalanche/closing.cpp
index 1cb2e84218..552b71b563 100644
--- a/engines/avalanche/closing.cpp
+++ b/engines/avalanche/closing.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/engines/avalanche/closing.h b/engines/avalanche/closing.h
index 25217e347e..6e65deb310 100644
--- a/engines/avalanche/closing.h
+++ b/engines/avalanche/closing.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/engines/avalanche/configure.engine b/engines/avalanche/configure.engine
new file mode 100644
index 0000000000..28d6a558db
--- /dev/null
+++ b/engines/avalanche/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine avalanche "Lord Avalot d'Argent" no
diff --git a/engines/avalanche/console.cpp b/engines/avalanche/console.cpp
index 656cc1907c..d4923affc1 100644
--- a/engines/avalanche/console.cpp
+++ b/engines/avalanche/console.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -31,7 +31,7 @@
namespace Avalanche {
AvalancheConsole::AvalancheConsole(AvalancheEngine *vm) : GUI::Debugger(), _vm(vm) {
- DCmd_Register("magic_lines", WRAP_METHOD(AvalancheConsole, Cmd_MagicLines));
+ registerCmd("magic_lines", WRAP_METHOD(AvalancheConsole, Cmd_MagicLines));
}
AvalancheConsole::~AvalancheConsole() {
@@ -42,7 +42,7 @@ AvalancheConsole::~AvalancheConsole() {
*/
bool AvalancheConsole::Cmd_MagicLines(int argc, const char **argv) {
if (argc != 1) {
- DebugPrintf("Usage: %s\n", argv[0]);
+ debugPrintf("Usage: %s\n", argv[0]);
return true;
}
@@ -50,5 +50,4 @@ bool AvalancheConsole::Cmd_MagicLines(int argc, const char **argv) {
return false;
}
-
} // End of namespace Avalanche
diff --git a/engines/avalanche/console.h b/engines/avalanche/console.h
index 166515d913..b5b5fb63fc 100644
--- a/engines/avalanche/console.h
+++ b/engines/avalanche/console.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp
index 428e71f35a..028f167e70 100644
--- a/engines/avalanche/detection.cpp
+++ b/engines/avalanche/detection.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -35,10 +35,6 @@
namespace Avalanche {
-struct AvalancheGameDescription {
- ADGameDescription desc;
-};
-
uint32 AvalancheEngine::getFeatures() const {
return _gameDescription->desc.flags;
}
@@ -133,7 +129,7 @@ SaveStateList AvalancheMetaEngine::listSaves(const char *target) const {
// Check version.
byte saveVersion = file->readByte();
- if (saveVersion != kSavegameVersion) {
+ if (saveVersion > kSavegameVersion) {
warning("Savegame of incompatible version!");
delete file;
continue;
diff --git a/engines/avalanche/dialogs.cpp b/engines/avalanche/dialogs.cpp
index e5acd9cae2..f95440900b 100644
--- a/engines/avalanche/dialogs.cpp
+++ b/engines/avalanche/dialogs.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -34,6 +34,12 @@
namespace Avalanche {
+const Dialogs::TuneType Dialogs::kTune = {
+ kPitchHigher, kPitchHigher, kPitchLower, kPitchSame, kPitchHigher, kPitchHigher, kPitchLower, kPitchHigher, kPitchHigher, kPitchHigher,
+ kPitchLower, kPitchHigher, kPitchHigher, kPitchSame, kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchHigher,
+ kPitchHigher, kPitchLower, kPitchLower, kPitchLower, kPitchLower, kPitchSame, kPitchLower, kPitchHigher, kPitchSame, kPitchLower, kPitchHigher
+};
+
// A quasiped defines how people who aren't sprites talk. For example, quasiped
// "A" is Dogfood. The rooms aren't stored because I'm leaving that to context.
const QuasipedType Dialogs::kQuasipeds[16] = {
@@ -59,6 +65,19 @@ const QuasipedType Dialogs::kQuasipeds[16] = {
Dialogs::Dialogs(AvalancheEngine *vm) {
_vm = vm;
_noError = true;
+
+ _aboutBox = false;
+ _talkX = 0;
+ _talkY = 0;
+ _maxLineNum = 0;
+ _scReturn = false;
+ _currentFont = kFontStyleRoman;
+ _param = 0;
+ _useIcon = 0;
+ _scrollBells = 0;
+ _underScroll = 0;
+ _shadowBoxX = 0;
+ _shadowBoxY = 0;
}
void Dialogs::init() {
@@ -74,6 +93,7 @@ void Dialogs::setReadyLight(byte state) {
if (_vm->_ledStatus == state)
return; // Already like that!
+ // TODO: Implement different patterns for green color.
Color color = kColorBlack;
switch (state) {
case 0:
@@ -85,9 +105,7 @@ void Dialogs::setReadyLight(byte state) {
color = kColorGreen;
break; // Hit a key
}
- warning("STUB: Dialogs::setReadyLight()");
- CursorMan.showMouse(false);
_vm->_graphics->drawReadyLight(color);
CursorMan.showMouse(true);
_vm->_ledStatus = state;
@@ -139,7 +157,7 @@ void Dialogs::scrollModeNormal() {
Common::String e = "(c) 1994";
setReadyLight(3);
- _vm->_seeScroll = true;
+ _vm->_animationsEnabled = false;
_vm->_graphics->loadMouse(kCurFletch);
_vm->_graphics->saveScreen();
@@ -156,7 +174,8 @@ void Dialogs::scrollModeNormal() {
(event.kbd.keycode == Common::KEYCODE_PLUS)))) {
escape = true;
break;
- }
+ } else if (event.type == Common::EVENT_KEYDOWN)
+ _vm->errorLed();
}
}
@@ -177,7 +196,6 @@ void Dialogs::scrollModeNormal() {
break;
} while (!((mrelease > 0) || (buttona1()) || (buttonb1())));
-
if (mrelease == 0) {
inkey();
if (aboutscroll) {
@@ -198,10 +216,8 @@ void Dialogs::scrollModeNormal() {
#endif
setReadyLight(0);
- _vm->_seeScroll = false;
+ _vm->_animationsEnabled = true;
_vm->_holdLeftMouse = false; // Used in Lucerna::checkclick().
-
- warning("STUB: Scrolls::scrollModeNormal()");
}
/**
@@ -258,7 +274,7 @@ bool Dialogs::theyMatch(TuneType &played) {
byte mistakes = 0;
for (unsigned int i = 0; i < sizeof(played); i++) {
- if (played[i] != _vm->kTune[i])
+ if (played[i] != kTune[i])
mistakes++;
}
@@ -272,7 +288,7 @@ bool Dialogs::theyMatch(TuneType &played) {
*/
void Dialogs::scrollModeMusic() {
setReadyLight(3);
- _vm->_seeScroll = true;
+ _vm->_animationsEnabled = false;
CursorMan.showMouse(false);
_vm->_graphics->loadMouse(kCurFletch);
@@ -281,7 +297,7 @@ void Dialogs::scrollModeMusic() {
played[i] = kPitchInvalid;
int8 lastOne = -1, thisOne = -1; // Invalid values.
- _vm->_seeScroll = true;
+ _vm->_animationsEnabled = false;
_vm->_graphics->saveScreen();
_vm->_graphics->showScroll();
@@ -306,7 +322,7 @@ void Dialogs::scrollModeMusic() {
|| (event.kbd.keycode == Common::KEYCODE_u) || (event.kbd.keycode == Common::KEYCODE_i)
|| (event.kbd.keycode == Common::KEYCODE_o) || (event.kbd.keycode == Common::KEYCODE_p)
|| (event.kbd.keycode == Common::KEYCODE_LEFTBRACKET) || (event.kbd.keycode == Common::KEYCODE_RIGHTBRACKET))) {
- byte value;
+ byte value = 0;
switch (event.kbd.keycode) {
case Common::KEYCODE_q:
value = 0;
@@ -345,6 +361,7 @@ void Dialogs::scrollModeMusic() {
value = 11;
break;
default:
+ error("cannot happen");
break;
}
@@ -362,7 +379,7 @@ void Dialogs::scrollModeMusic() {
else
store(kPitchHigher, played);
}
-
+
if (theyMatch(played)) {
setReadyLight(0);
_vm->_timer->addTimer(8, Timer::kProcJacquesWakesUp, Timer::kReasonJacquesWakingUp);
@@ -374,7 +391,7 @@ void Dialogs::scrollModeMusic() {
_vm->_graphics->restoreScreen();
_vm->_graphics->removeBackup();
- _vm->_seeScroll = false;
+ _vm->_animationsEnabled = true;
CursorMan.showMouse(true);
}
@@ -437,7 +454,7 @@ void Dialogs::drawScroll(DialogFunctionType modeFunc) {
mx -= lx;
my -= ly + 2;
- bool centre = false;
+ bool center = false;
byte iconIndent = 0;
switch (_useIcon) {
@@ -463,11 +480,11 @@ void Dialogs::drawScroll(DialogFunctionType modeFunc) {
if (!_scroll[i].empty())
switch (_scroll[i][_scroll[i].size() - 1]) {
case kControlCenter:
- centre = true;
+ center = true;
_scroll[i].deleteLastChar();
break;
case kControlLeftJustified:
- centre = false;
+ center = false;
_scroll[i].deleteLastChar();
break;
case kControlQuestion:
@@ -479,7 +496,7 @@ void Dialogs::drawScroll(DialogFunctionType modeFunc) {
break;
}
- if (centre)
+ if (center)
say(320 - _scroll[i].size() * 4 + iconIndent, my, _scroll[i]);
else
say(mx + iconIndent, my, _scroll[i]);
@@ -489,7 +506,7 @@ void Dialogs::drawScroll(DialogFunctionType modeFunc) {
_underScroll = (my + 3) * 2; // Multiplying because of the doubled screen height.
ringBell();
-
+
_vm->_dropsOk = false;
dodgem();
@@ -497,7 +514,7 @@ void Dialogs::drawScroll(DialogFunctionType modeFunc) {
unDodgem();
_vm->_dropsOk = true;
-
+
resetScrollDriver();
}
@@ -584,7 +601,7 @@ Common::String Dialogs::displayMoney() {
else
result = Common::String::format("%d/%d", _vm->_money / 12, _vm->_money % 12);
} else { // L, s & d
- result = Common::String::format("\x9C%d.%d.%d", _vm->_money / 240, (_vm->_money / 12) % 20,
+ result = Common::String::format("\x9C%d.%d.%d", _vm->_money / 240, (_vm->_money / 12) % 20,
_vm->_money % 12);
}
if (_vm->_money > 12) {
@@ -623,13 +640,10 @@ void Dialogs::solidify(byte n) {
/**
* @remarks Originally called 'calldriver'
- * Display text by calling the dialog driver. It unifies the function of the original
+ * Display text by calling the dialog driver. It unifies the function of the original
* 'calldriver' and 'display' by using Common::String instead of a private buffer.
*/
void Dialogs::displayText(Common::String text) {
-// bool was_virtual; // Was the mouse cursor virtual on entry to this proc?
- warning("STUB: Scrolls::calldrivers()");
-
_vm->_sound->stopSound();
setReadyLight(0);
@@ -689,6 +703,7 @@ void Dialogs::displayText(Common::String text) {
if (_param == 0)
setBubbleStateNatural();
else if ((1 <= _param) && (_param <= 9)) {
+ assert(_param - 1 < _vm->_animation->kSpriteNumbMax);
AnimationType *spr = _vm->_animation->_sprites[_param - 1];
if ((_param > _vm->_animation->kSpriteNumbMax) || (!spr->_quick)) { // Not valid.
_vm->errorLed();
@@ -699,10 +714,11 @@ void Dialogs::displayText(Common::String text) {
// Quasi-peds. (This routine performs the same
// thing with QPs as triptype.chatter does with the
// sprites.)
+ assert(_param - 10 < 16);
PedType *quasiPed = &_vm->_peds[kQuasipeds[_param - 10]._whichPed];
_talkX = quasiPed->_x;
_talkY = quasiPed->_y; // Position.
-
+
_vm->_graphics->setDialogColor(kQuasipeds[_param - 10]._backgroundColor, kQuasipeds[_param - 10]._textColor);
} else {
_vm->errorLed(); // Not valid.
@@ -717,7 +733,7 @@ void Dialogs::displayText(Common::String text) {
return;
break;
- // CHECME: The whole kControlNegative block seems completely unused, as the only use (the easter egg check) is a false positive
+ // CHECME: The whole kControlNegative block seems completely unused, as the only use (the easter egg check) is a false positive
case kControlNegative:
switch (_param) {
case 1:
@@ -729,10 +745,10 @@ void Dialogs::displayText(Common::String text) {
}
break;
case 3:
- displayText(_vm->_favouriteDrink + kControlToBuffer);
+ displayText(_vm->_favoriteDrink + kControlToBuffer);
break;
case 4:
- displayText(_vm->_favouriteSong + kControlToBuffer);
+ displayText(_vm->_favoriteSong + kControlToBuffer);
break;
case 5:
displayText(_vm->_worstPlaceOnEarth + kControlToBuffer);
@@ -748,7 +764,7 @@ void Dialogs::displayText(Common::String text) {
case 10:
switch (_vm->_boxContent) {
case 0: // Sixpence.
- displayScrollChain('q', 37); // You find the sixpence.
+ displayScrollChain('Q', 37); // You find the sixpence.
_vm->_money += 6;
_vm->_boxContent = _vm->_parser->kNothing;
_vm->incScore(2);
@@ -762,7 +778,7 @@ void Dialogs::displayText(Common::String text) {
break;
case 11:
for (int j = 0; j < kObjectNum; j++) {
- if (_vm->_objects[j])
+ if (_vm->_objects[j])
displayText(_vm->getItem(j) + ", " + kControlToBuffer);
}
break;
@@ -802,6 +818,8 @@ void Dialogs::displayText(Common::String text) {
}
}
}
+
+ setReadyLight(2);
}
void Dialogs::setTalkPos(int16 x, int16 y) {
@@ -815,7 +833,7 @@ int16 Dialogs::getTalkPosX() {
bool Dialogs::displayQuestion(Common::String question) {
displayText(question + kControlNewLine + kControlQuestion);
-
+
if (_scReturn && (_vm->_rnd->getRandomNumber(1) == 0)) { // Half-and-half chance.
Common::String tmpStr = Common::String::format("...Positive about that?%cI%c%c%c", kControlRegister, kControlIcon, kControlNewLine, kControlQuestion);
displayText(tmpStr); // Be annoying!
@@ -859,7 +877,7 @@ void Dialogs::loadFont() {
* @remarks Originally called 'musical_scroll'
*/
void Dialogs::displayMusicalScroll() {
- Common::String tmpStr = Common::String::format("To play the harp...%c%cUse these keys:%c%cQ W E R T Y U I O P [ ]%c%cOr press Enter to stop playing.%c",
+ Common::String tmpStr = Common::String::format("To play the harp...%c%cUse these keys:%c%cQ W E R T Y U I O P [ ]%c%cOr press Enter to stop playing.%c",
kControlNewLine, kControlNewLine, kControlNewLine, kControlInsertSpaces, kControlNewLine, kControlNewLine, kControlToBuffer);
displayText(tmpStr);
@@ -891,7 +909,7 @@ void Dialogs::displayScrollChain(char block, byte point, bool report, bool bubbl
bool error = false;
- indexfile.seek((toupper(block) - 65) * 2);
+ indexfile.seek((toupper(block) - 'A') * 2);
uint16 idx_offset = indexfile.readUint16LE();
if (idx_offset == 0)
error = true;
@@ -938,7 +956,7 @@ void Dialogs::displayScrollChain(char block, byte point, bool report, bool bubbl
*/
void Dialogs::speak(byte who, byte subject) {
if (subject == 0) { // No subject.
- displayScrollChain('s', who, false, true);
+ displayScrollChain('S', who, false, true);
return;
}
@@ -992,7 +1010,7 @@ void Dialogs::talkTo(byte whom) {
switch (whom) {
case kPeopleSpludwick:
if ((_vm->_lustieIsAsleep) & (!_vm->_objects[kObjectPotion - 1])) {
- displayScrollChain('q', 68);
+ displayScrollChain('Q', 68);
_vm->_objects[kObjectPotion - 1] = true;
_vm->refreshObjectList();
_vm->incScore(3);
@@ -1004,64 +1022,64 @@ void Dialogs::talkTo(byte whom) {
case 1: // Fallthrough is intended.
case 2: {
Common::String objStr = _vm->getItem(AvalancheEngine::kSpludwicksOrder[_vm->_givenToSpludwick]);
- Common::String tmpStr = Common::String::format("Can you get me %s, please?%c2%c",
+ Common::String tmpStr = Common::String::format("Can you get me %s, please?%c2%c",
objStr.c_str(), kControlRegister, kControlSpeechBubble);
displayText(tmpStr);
}
return;
case 3:
- displayScrollChain('q', 30); // Need any help with the game?
+ displayScrollChain('Q', 30); // Need any help with the game?
return;
}
} else {
- displayScrollChain('q', 42); // Haven't talked to Crapulus. Go and talk to him.
+ displayScrollChain('Q', 42); // Haven't talked to Crapulus. Go and talk to him.
return;
}
break;
case kPeopleIbythneth:
if (_vm->_givenBadgeToIby) {
- displayScrollChain('q', 33); // Thanks a lot!
+ displayScrollChain('Q', 33); // Thanks a lot!
return; // And leave the proc.
}
break; // Or... just continue, 'cos he hasn't got it.
case kPeopleDogfood:
if (_vm->_wonNim) { // We've won the game.
- displayScrollChain('q', 6); // "I'm Not Playing!"
+ displayScrollChain('Q', 6); // "I'm Not Playing!"
return; // Zap back.
} else
_vm->_askedDogfoodAboutNim = true;
break;
case kPeopleAyles:
if (!_vm->_aylesIsAwake) {
- displayScrollChain('q', 43); // He's fast asleep!
+ displayScrollChain('Q', 43); // He's fast asleep!
return;
} else if (!_vm->_givenPenToAyles) {
- displayScrollChain('q', 44); // Can you get me a pen, Avvy?
+ displayScrollChain('Q', 44); // Can you get me a pen, Avvy?
return;
}
break;
case kPeopleJacques:
- displayScrollChain('q', 43);
+ displayScrollChain('Q', 43);
return;
case kPeopleGeida:
if (_vm->_givenPotionToGeida)
_vm->_geidaFollows = true;
else {
- displayScrollChain('u', 17);
+ displayScrollChain('U', 17);
return;
}
break;
case kPeopleSpurge:
if (!_vm->_sittingInPub) {
- displayScrollChain('q', 71); // Try going over and sitting down.
+ displayScrollChain('Q', 71); // Try going over and sitting down.
return;
} else {
if (_vm->_spurgeTalkCount < 5)
_vm->_spurgeTalkCount++;
if (_vm->_spurgeTalkCount > 1) { // no. 1 falls through
- displayScrollChain('q', 70 + _vm->_spurgeTalkCount);
+ displayScrollChain('Q', 70 + _vm->_spurgeTalkCount);
return;
}
}
@@ -1069,7 +1087,7 @@ void Dialogs::talkTo(byte whom) {
}
// On a subject. Is there any reason to block it?
} else if ((whom == kPeopleAyles) && (!_vm->_aylesIsAwake)) {
- displayScrollChain('q', 43); // He's fast asleep!
+ displayScrollChain('Q', 43); // He's fast asleep!
return;
}
@@ -1094,12 +1112,12 @@ void Dialogs::talkTo(byte whom) {
speak(whom, _vm->_subjectNum);
if (!_noError)
- displayScrollChain('n', whom); // File not found!
+ displayScrollChain('N', whom); // File not found!
if ((_vm->_subjectNum == 0) && ((whom + 149) == kPeopleCrapulus)) { // Crapulus: get the badge - first time only
_vm->_objects[kObjectBadge - 1] = true;
_vm->refreshObjectList();
- displayScrollChain('q', 1); // Circular from Cardiff.
+ displayScrollChain('Q', 1); // Circular from Cardiff.
_vm->_talkedToCrapulus = true;
_vm->setRoom(kPeopleCrapulus, kRoomDummy); // Crapulus walks off.
@@ -1164,7 +1182,9 @@ void Dialogs::sayThanks(byte thing) {
Common::String tmpStr = personSpeaks();
tmpStr += Common::String::format("Hey, thanks!%c(But now, you've lost it!)", kControlSpeechBubble);
displayText(tmpStr);
- _vm->_objects[thing] = false;
+
+ if (thing < kObjectNum)
+ _vm->_objects[thing] = false;
}
/**
diff --git a/engines/avalanche/dialogs.h b/engines/avalanche/dialogs.h
index 43e6a4fec6..4b50a61732 100644
--- a/engines/avalanche/dialogs.h
+++ b/engines/avalanche/dialogs.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -70,6 +70,9 @@ private:
kFontStyleItalic
};
+ typedef int8 TuneType[31];
+
+ static const TuneType kTune;
static const int16 kHalfIconWidth = 19;
static const QuasipedType kQuasipeds[16];
diff --git a/engines/avalanche/menu.cpp b/engines/avalanche/dropdown.cpp
index bba8e862a9..97adfc2581 100644
--- a/engines/avalanche/menu.cpp
+++ b/engines/avalanche/dropdown.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -28,43 +28,43 @@
/* Original name: DROPDOWN A customized version of Oopmenu (qv). */
#include "avalanche/avalanche.h"
-#include "avalanche/menu.h"
+#include "avalanche/dropdown.h"
namespace Avalanche {
-void HeadType::init(char trig, char altTrig, Common::String title, byte pos, MenuFunc setupFunc, MenuFunc chooseFunc, Menu *menu) {
+void HeadType::init(char trig, char altTrig, Common::String title, byte pos, MenuFunc setupFunc, MenuFunc chooseFunc, DropDownMenu *menu) {
_trigger = trig;
_altTrigger = altTrig;
_title = title;
_position = pos;
- _xpos = _position * _menu->kSpacing + _menu->kIndent;
- _xright = (_position + 1) * _menu->kSpacing + _menu->kIndent;
+ _xpos = _position * _dropdown->kSpacing + _dropdown->kIndent;
+ _xright = (_position + 1) * _dropdown->kSpacing + _dropdown->kIndent;
_setupFunc = setupFunc;
_chooseFunc = chooseFunc;
- _menu = menu;
+ _dropdown = menu;
}
void HeadType::draw() {
CursorMan.showMouse(false);
- _menu->drawMenuText(_xpos, 1, _trigger, _title, true, false);
+ _dropdown->drawMenuText(_xpos, 1, _trigger, _title, true, false);
CursorMan.showMouse(true);
}
void HeadType::highlight() {
CursorMan.showMouse(false);
- _menu->_vm->_sound->stopSound();
- _menu->drawMenuText(_xpos, 1, _trigger, _title, true, true);
+ _dropdown->_vm->_sound->stopSound();
+ _dropdown->drawMenuText(_xpos, 1, _trigger, _title, true, true);
- _menu->_activeMenuItem._left = _xpos;
- _menu->_activeMenuItem._activeNow = true;
- _menu->_activeMenuItem._activeNum = _position;
- _menu->_menuActive = true;
+ _dropdown->_activeMenuItem._left = _xpos;
+ _dropdown->_activeMenuItem._activeNow = true;
+ _dropdown->_activeMenuItem._activeNum = _position;
+ _dropdown->_menuActive = true;
// Force reload and redraw of cursor.
- _menu->_vm->_currentMouse = 177;
-
+ _dropdown->_vm->_currentMouse = 177;
+
}
bool HeadType::parseAltTrigger(char key) {
@@ -73,12 +73,12 @@ bool HeadType::parseAltTrigger(char key) {
return false;
}
-void MenuItem::init(Menu *menu) {
- _menu = menu;
+void MenuItem::init(DropDownMenu *menu) {
+ _dropdown = menu;
_activeNow = false;
_activeNum = 1;
- _menu->_menuActive = false;
+ _dropdown->_menuActive = false;
}
void MenuItem::reset() {
@@ -113,8 +113,8 @@ void MenuItem::displayOption(byte y, bool highlit) {
else
backgroundColor = kColorLightgray;
- _menu->_vm->_graphics->drawMenuBlock((_flx1 + 1) * 8, 3 + (y + 1) * 10, (_flx2 + 1) * 8, 13 + (y + 1) * 10, backgroundColor);
- _menu->drawMenuText(_left, 4 + (y + 1) * 10, _options[y]._trigger, text, _options[y]._valid, highlit);
+ _dropdown->_vm->_graphics->drawMenuBlock((_flx1 + 1) * 8, 3 + (y + 1) * 10, (_flx2 + 1) * 8, 13 + (y + 1) * 10, backgroundColor);
+ _dropdown->drawMenuText(_left, 4 + (y + 1) * 10, _options[y]._trigger, text, _options[y]._valid, highlit);
}
void MenuItem::display() {
@@ -125,15 +125,15 @@ void MenuItem::display() {
_flx2 = _left + _width;
_fly = 15 + _optionNum * 10;
_activeNow = true;
- _menu->_menuActive = true;
+ _dropdown->_menuActive = true;
- _menu->_vm->_graphics->drawMenuItem((_flx1 + 1) * 8, 12, (_flx2 + 1) * 8, _fly);
+ _dropdown->_vm->_graphics->drawMenuItem((_flx1 + 1) * 8, 12, (_flx2 + 1) * 8, _fly);
displayOption(0, true);
for (int y = 1; y < _optionNum; y++)
displayOption(y, false);
- _menu->_vm->_currentMouse = 177;
+ _dropdown->_vm->_currentMouse = 177;
CursorMan.showMouse(true); // 4 = fletch
}
@@ -141,12 +141,12 @@ void MenuItem::display() {
void MenuItem::wipe() {
CursorMan.showMouse(false);
- _menu->drawMenuText(_menu->_menuBar._menuItems[_menu->_activeMenuItem._activeNum]._xpos, 1,
- _menu->_menuBar._menuItems[_menu->_activeMenuItem._activeNum]._trigger,
- _menu->_menuBar._menuItems[_menu->_activeMenuItem._activeNum]._title, true, false);
+ _dropdown->drawMenuText(_dropdown->_menuBar._menuItems[_dropdown->_activeMenuItem._activeNum]._xpos, 1,
+ _dropdown->_menuBar._menuItems[_dropdown->_activeMenuItem._activeNum]._trigger,
+ _dropdown->_menuBar._menuItems[_dropdown->_activeMenuItem._activeNum]._title, true, false);
_activeNow = false;
- _menu->_menuActive = false;
+ _dropdown->_menuActive = false;
_firstlix = false;
CursorMan.showMouse(true);
@@ -191,7 +191,7 @@ void MenuItem::select(byte which) {
if (_choiceNum > _optionNum)
_choiceNum = 0; // Off the top, I suppose.
- (_menu->*_menu->_menuBar._menuItems[_activeNum]._chooseFunc)();
+ (_dropdown->*_dropdown->_menuBar._menuItems[_activeNum]._chooseFunc)();
}
void MenuItem::parseKey(char c) {
@@ -204,29 +204,34 @@ void MenuItem::parseKey(char c) {
}
}
if (!found)
- _menu->_vm->_sound->blip();
+ _dropdown->_vm->_sound->blip();
+}
+
+MenuBar::MenuBar() {
+ _menuNum = 0;
+ _dropdown = nullptr;
}
-void MenuBar::init(Menu *menu) {
- _menu = menu;
+void MenuBar::init(DropDownMenu *menu) {
+ _dropdown = menu;
_menuNum = 0;
}
void MenuBar::createMenuItem(char trig, Common::String title, char altTrig, MenuFunc setupFunc, MenuFunc chooseFunc) {
- _menuItems[_menuNum].init(trig, altTrig, title, _menuNum, setupFunc, chooseFunc, _menu);
+ _menuItems[_menuNum].init(trig, altTrig, title, _menuNum, setupFunc, chooseFunc, _dropdown);
_menuNum++;
}
void MenuBar::draw() {
- _menu->_vm->_graphics->drawMenuBar(kMenuBackgroundColor);
+ _dropdown->_vm->_graphics->drawMenuBar(kMenuBackgroundColor);
- byte savecp = _menu->_vm->_cp;
- _menu->_vm->_cp = 3;
+ byte savecp = _dropdown->_vm->_cp;
+ _dropdown->_vm->_cp = 3;
for (int i = 0; i < _menuNum; i++)
_menuItems[i].draw();
- _menu->_vm->_cp = savecp;
+ _dropdown->_vm->_cp = savecp;
}
void MenuBar::parseAltTrigger(char c) {
@@ -239,13 +244,13 @@ void MenuBar::parseAltTrigger(char c) {
}
void MenuBar::setupMenuItem(byte which) {
- if (_menu->_activeMenuItem._activeNow) {
- _menu->_activeMenuItem.wipe(); // Get rid of menu.
- if (_menu->_activeMenuItem._activeNum == _menuItems[which]._position)
+ if (_dropdown->_activeMenuItem._activeNow) {
+ _dropdown->_activeMenuItem.wipe(); // Get rid of menu.
+ if (_dropdown->_activeMenuItem._activeNum == _menuItems[which]._position)
return; // Clicked on own highlight.
}
_menuItems[which].highlight();
- (_menu->*_menuItems[which]._setupFunc)();
+ (_dropdown->*_menuItems[which]._setupFunc)();
}
void MenuBar::chooseMenuItem(int16 x) {
@@ -257,13 +262,16 @@ void MenuBar::chooseMenuItem(int16 x) {
}
}
-Menu::Menu(AvalancheEngine *vm) {
+DropDownMenu::DropDownMenu(AvalancheEngine *vm) {
_vm = vm;
_activeMenuItem.init(this);
_menuBar.init(this);
+
+ _menuActive = false;
+ _lastPerson = kPeopleNone;
}
-void Menu::findWhatYouCanDoWithIt() {
+void DropDownMenu::findWhatYouCanDoWithIt() {
switch (_vm->_thinks) {
case kObjectWine:
case kObjectPotion:
@@ -291,7 +299,7 @@ void Menu::findWhatYouCanDoWithIt() {
}
}
-void Menu::drawMenuText(int16 x, int16 y, char trigger, Common::String text, bool valid, bool highlighted) {
+void DropDownMenu::drawMenuText(int16 x, int16 y, char trigger, Common::String text, bool valid, bool highlighted) {
Color fontColor;
Color backgroundColor;
if (highlighted) {
@@ -334,11 +342,11 @@ void Menu::drawMenuText(int16 x, int16 y, char trigger, Common::String text, boo
_vm->_graphics->refreshScreen();
}
-void Menu::bleep() {
+void DropDownMenu::bleep() {
_vm->_sound->playNote(177, 7);
}
-void Menu::parseKey(char r, char re) {
+void DropDownMenu::parseKey(char r, char re) {
#if 0
switch (r) {
case 0:
@@ -387,24 +395,24 @@ void Menu::parseKey(char r, char re) {
warning("STUB: Dropdown::parseKey()"); // To be implemented properly later! Don't remove the comment above!
}
-Common::String Menu::selectGender(byte x) {
+Common::String DropDownMenu::selectGender(byte x) {
if (x < 175)
return "im";
else
return "er";
}
-void Menu::setupMenuGame() {
+void DropDownMenu::setupMenuGame() {
_activeMenuItem.reset();
_activeMenuItem.setupOption("Help...", 'H', "f1", true);
- _activeMenuItem.setupOption("Boss Key", 'B', "alt-B", false);
- _activeMenuItem.setupOption("Untrash screen", 'U', "ctrl-f7", true);
+ _activeMenuItem.setupOption("Boss Key", 'B', "alt-B", true);
+ _activeMenuItem.setupOption("Untrash screen", 'U', "ctrl-f7", false);
_activeMenuItem.setupOption("Score and rank", 'S', "f9", true);
_activeMenuItem.setupOption("About Avvy...", 'A', "shift-f10", true);
_activeMenuItem.display();
}
-void Menu::setupMenuFile() {
+void DropDownMenu::setupMenuFile() {
_activeMenuItem.reset();
_activeMenuItem.setupOption("New game", 'N', "f4", true);
_activeMenuItem.setupOption("Load...", 'L', "^f3", true);
@@ -415,7 +423,7 @@ void Menu::setupMenuFile() {
_activeMenuItem.display();
}
-void Menu::setupMenuAction() {
+void DropDownMenu::setupMenuAction() {
_activeMenuItem.reset();
Common::String f5Does = _vm->f5Does();
@@ -441,7 +449,7 @@ void Menu::setupMenuAction() {
_activeMenuItem.display();
}
-void Menu::setupMenuPeople() {
+void DropDownMenu::setupMenuPeople() {
if (!people.empty())
people.clear();
@@ -457,7 +465,7 @@ void Menu::setupMenuPeople() {
_activeMenuItem.display();
}
-void Menu::setupMenuObjects() {
+void DropDownMenu::setupMenuObjects() {
_activeMenuItem.reset();
for (int i = 0; i < kObjectNum; i++) {
if (_vm->_objects[i])
@@ -466,7 +474,7 @@ void Menu::setupMenuObjects() {
_activeMenuItem.display();
}
-void Menu::setupMenuWith() {
+void DropDownMenu::setupMenuWith() {
_activeMenuItem.reset();
if (_vm->_thinkThing) {
@@ -523,7 +531,7 @@ void Menu::setupMenuWith() {
_activeMenuItem.display();
}
-void Menu::runMenuGame() {
+void DropDownMenu::runMenuGame() {
// Help, boss, untrash screen.
switch (_activeMenuItem._choiceNum) {
case 0:
@@ -533,7 +541,7 @@ void Menu::runMenuGame() {
_vm->callVerb(kVerbCodeBoss);
break;
case 2:
- _vm->majorRedraw();
+ _vm->_graphics->refreshScreen();
break;
case 3:
_vm->callVerb(kVerbCodeScore);
@@ -544,7 +552,7 @@ void Menu::runMenuGame() {
}
}
-void Menu::runMenuFile() {
+void DropDownMenu::runMenuFile() {
// New game, load, save, save as, DOS shell, about, quit.
switch (_activeMenuItem._choiceNum) {
case 0:
@@ -571,7 +579,7 @@ void Menu::runMenuFile() {
}
}
-void Menu::runMenuAction() {
+void DropDownMenu::runMenuAction() {
// Get up, pause game, open door, look, inventory, walk/run.
switch (_activeMenuItem._choiceNum) {
case 0: {
@@ -608,16 +616,16 @@ void Menu::runMenuAction() {
}
}
-void Menu::runMenuObjects() {
+void DropDownMenu::runMenuObjects() {
_vm->thinkAbout(_vm->_objectList[_activeMenuItem._choiceNum], AvalancheEngine::kThing);
}
-void Menu::runMenuPeople() {
+void DropDownMenu::runMenuPeople() {
_vm->thinkAbout(people[_activeMenuItem._choiceNum], AvalancheEngine::kPerson);
_lastPerson = (People)people[_activeMenuItem._choiceNum];
}
-void Menu::runMenuWith() {
+void DropDownMenu::runMenuWith() {
_vm->_parser->_thing = _vm->_thinks;
if (_vm->_thinkThing) {
@@ -656,21 +664,21 @@ void Menu::runMenuWith() {
_vm->callVerb((VerbCode)(byte)_verbStr[_activeMenuItem._choiceNum]);
}
-void Menu::setup() {
+void DropDownMenu::setup() {
_menuBar.init(this);
_activeMenuItem.init(this);
- _menuBar.createMenuItem('F', "File", '!', &Avalanche::Menu::setupMenuFile, &Avalanche::Menu::runMenuFile);
- _menuBar.createMenuItem('G', "Game", 34, &Avalanche::Menu::setupMenuGame, &Avalanche::Menu::runMenuGame);
- _menuBar.createMenuItem('A', "Action", 30, &Avalanche::Menu::setupMenuAction, &Avalanche::Menu::runMenuAction);
- _menuBar.createMenuItem('O', "Objects", 24, &Avalanche::Menu::setupMenuObjects, &Avalanche::Menu::runMenuObjects);
- _menuBar.createMenuItem('P', "People", 25, &Avalanche::Menu::setupMenuPeople, &Avalanche::Menu::runMenuPeople);
- _menuBar.createMenuItem('W', "With", 17, &Avalanche::Menu::setupMenuWith, &Avalanche::Menu::runMenuWith);
+ _menuBar.createMenuItem('F', "File", '!', &Avalanche::DropDownMenu::setupMenuFile, &Avalanche::DropDownMenu::runMenuFile);
+ _menuBar.createMenuItem('G', "Game", 34, &Avalanche::DropDownMenu::setupMenuGame, &Avalanche::DropDownMenu::runMenuGame);
+ _menuBar.createMenuItem('A', "Action", 30, &Avalanche::DropDownMenu::setupMenuAction, &Avalanche::DropDownMenu::runMenuAction);
+ _menuBar.createMenuItem('O', "Objects", 24, &Avalanche::DropDownMenu::setupMenuObjects, &Avalanche::DropDownMenu::runMenuObjects);
+ _menuBar.createMenuItem('P', "People", 25, &Avalanche::DropDownMenu::setupMenuPeople, &Avalanche::DropDownMenu::runMenuPeople);
+ _menuBar.createMenuItem('W', "With", 17, &Avalanche::DropDownMenu::setupMenuWith, &Avalanche::DropDownMenu::runMenuWith);
_menuBar.draw();
}
-void Menu::update() { // TODO: Optimize it ASAP!!! It really needs it...
+void DropDownMenu::update() {
_vm->_graphics->saveScreen();
Common::Point cursorPos = _vm->getMousePos();
@@ -761,7 +769,7 @@ void Menu::update() { // TODO: Optimize it ASAP!!! It really needs it...
_vm->_graphics->removeBackup();
}
-char Menu::getThingChar(byte which) {
+char DropDownMenu::getThingChar(byte which) {
static const char thingsChar[] = "WMBParCLguKeSnIohn"; // V=Vinegar
char result;
@@ -778,17 +786,19 @@ char Menu::getThingChar(byte which) {
return result;
}
-byte Menu::getNameChar(People whose) {
+byte DropDownMenu::getNameChar(People whose) {
static const char ladChar[] = "ASCDMTRwLfgeIyPu";
static const char lassChar[] = "kG\0xB1o";
- if (whose < kPeopleArkata)
+ if (whose <= kPeopleJacques)
return ladChar[whose - kPeopleAvalot];
- else
+ else if ((whose >= kPeopleArkata) && (whose <= kPeopleWisewoman))
return lassChar[whose - kPeopleArkata];
+ else
+ error("getName() - Unexpected character id %d", (byte) whose);
}
-Common::String Menu::getThing(byte which) {
+Common::String DropDownMenu::getThing(byte which) {
static const char things[kObjectNum][20] = {
"Wine", "Money-bag", "Bodkin", "Potion", "Chastity belt",
"Crossbow bolt", "Crossbow", "Lute", "Pilgrim's badge", "Mushroom", "Key",
@@ -820,15 +830,15 @@ Common::String Menu::getThing(byte which) {
return result;
}
-bool Menu::isActive() {
+bool DropDownMenu::isActive() {
return _menuActive;
}
-void Menu::init() {
+void DropDownMenu::init() {
_menuActive = false;
}
-void Menu::resetVariables() {
+void DropDownMenu::resetVariables() {
_lastPerson = kPeoplePardon;
}
} // End of namespace Avalanche.
diff --git a/engines/avalanche/menu.h b/engines/avalanche/dropdown.h
index a7ec8bf2db..417b775c3d 100644
--- a/engines/avalanche/menu.h
+++ b/engines/avalanche/dropdown.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -27,17 +27,17 @@
/* Original name: DROPDOWN A customized version of Oopmenu (qv). */
-#ifndef AVALANCHE_MENU_H
-#define AVALANCHE_MENU_H
+#ifndef AVALANCHE_DROPDOWN_H
+#define AVALANCHE_DROPDOWN_H
#include "common/str.h"
namespace Avalanche {
class AvalancheEngine;
-class Menu;
+class DropDownMenu;
-typedef void (Menu::*MenuFunc)();
+typedef void (DropDownMenu::*MenuFunc)();
static const Color kMenuBackgroundColor = kColorLightgray;
static const Color kMenuBorderColor = kColorBlack;
@@ -49,13 +49,13 @@ public:
int16 _xpos, _xright;
MenuFunc _setupFunc, _chooseFunc;
- void init(char trig, char alTtrig, Common::String title, byte pos, MenuFunc setupFunc, MenuFunc chooseFunc, Menu *menu);
+ void init(char trig, char alTtrig, Common::String title, byte pos, MenuFunc setupFunc, MenuFunc chooseFunc, DropDownMenu *menu);
void draw();
void highlight();
bool parseAltTrigger(char key);
private:
- Menu *_menu;
+ DropDownMenu *_dropdown;
};
struct OptionType {
@@ -75,7 +75,7 @@ public:
byte _activeNum; // And if so, which is it?
byte _choiceNum; // Your choice?
- void init(Menu *menu);
+ void init(DropDownMenu *menu);
void reset();
void setupOption(Common::String title, char trigger, Common::String shortcut, bool valid);
void display();
@@ -88,7 +88,7 @@ private:
byte _optionNum;
byte _highlightNum;
- Menu *_menu;
+ DropDownMenu *_dropdown;
void displayOption(byte y, bool highlit);
void moveHighlight(int8 inc);
@@ -102,20 +102,21 @@ public:
HeadType _menuItems[8];
byte _menuNum;
- void init(Menu *menu);
+ MenuBar();
+ void init(DropDownMenu *menu);
void createMenuItem(char trig, Common::String title, char altTrig, MenuFunc setupFunc, MenuFunc chooseFunc);
void draw();
void chooseMenuItem(int16 x);
private:
- Menu *_menu;
+ DropDownMenu *_dropdown;
void setupMenuItem(byte which);
// CHECKME: Useless function
void parseAltTrigger(char c);
};
-class Menu {
+class DropDownMenu {
public:
friend class HeadType;
friend class MenuItem;
@@ -124,7 +125,7 @@ public:
MenuItem _activeMenuItem;
MenuBar _menuBar;
- Menu(AvalancheEngine *vm);
+ DropDownMenu(AvalancheEngine *vm);
void update();
void setup(); // Standard menu bar.
@@ -178,4 +179,4 @@ private:
} // End of namespace Avalanche.
-#endif // AVALANCHE_MENU_H
+#endif // AVALANCHE_DROPDOWN_H
diff --git a/engines/avalanche/enums.h b/engines/avalanche/enums.h
index 604c62de84..0ba39321bc 100644
--- a/engines/avalanche/enums.h
+++ b/engines/avalanche/enums.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -29,6 +29,11 @@
#define AVALANCHE_ENUMS_H
namespace Avalanche {
+
+enum MonsterType { kMonsterTypeGhost, kMonsterTypeGlerk };
+
+enum Flavour { kFlavourEga, kFlavourBgi, kFlavourNatural, kFlavourTwo, kFlavourOne };
+
enum Color {
kColorBlack = 0, kColorBlue, kColorGreen, kColorCyan, kColorRed,
kColorMagenta = 5, kColorBrown, kColorLightgray, kColorDarkgray, kColorLightblue,
@@ -81,13 +86,13 @@ enum VerbCode {
kVerbCodeRestart = 31, kVerbCodeEat = 32, kVerbCodeListen = 33, kVerbCodeBuy = 34, kVerbCodeAttack = 35,
kVerbCodePasswd = 36, kVerbCodeDir = 37, kVerbCodeDie = 38, kVerbCodeScore = 39, kVerbCodePut = 40,
kVerbCodeKiss = 41, kVerbCodeClimb = 42, kVerbCodeJump = 43, kVerbCodeHiscores = 44, kVerbCodeWake = 45,
- kVerbCodeHello = 46, kVerbCodeThanks = 47,
+ kVerbCodeHello = 46, kVerbCodeThanks = 47,
kVerbCodeSmartAlec = 249, kVerbCodeExpletive = 253, kVerbCodePardon = 254
};
enum MouseCursor {
- kCurUpArrow = 0, kCurScrewDriver = 1, kCurRightArrow = 2, kCurFletch = 3, kCurWait = 4, kCurHand = 5,
- kCurCrosshair = 6, kCurIBeam = 7
+ kCurUpArrow = 0, kCurScrewDriver = 1, kCurRightArrow = 2, kCurFletch = 3, kCurWait = 4, kCurHand = 5,
+ kCurCrosshair = 6, kCurIBeam = 7, kCurHelp = 8
};
// Magic/portal constants:
@@ -127,7 +132,6 @@ static const int16 kScreenHeight = 200;
static const int16 kWalk = 3;
static const int16 kRun = 5;
-
} // End of namespace Avalanche
#endif // AVALANCHE_ENUMS_H
diff --git a/engines/avalanche/ghostroom.cpp b/engines/avalanche/ghostroom.cpp
new file mode 100644
index 0000000000..047a3670c2
--- /dev/null
+++ b/engines/avalanche/ghostroom.cpp
@@ -0,0 +1,398 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
+*/
+
+#include "avalanche/avalanche.h"
+#include "avalanche/ghostroom.h"
+
+#include "common/random.h"
+
+namespace Avalanche {
+
+const int8 GhostRoom::kAdjustment[5] = { 7, 0, 7, 7, 7 };
+const byte GhostRoom::kWaveOrder[5] = { 4, 0, 1, 2, 3 };
+const byte GhostRoom::kGlerkFade[26] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 0 };
+const byte GhostRoom::kGreldetFade[18] = { 0, 1, 2, 3, 4, 5, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0 };
+
+GhostRoom::GhostRoom(AvalancheEngine *vm) {
+ _vm = vm;
+
+ _glerkStage = 0;
+ _batX = 0;
+ _batY = 0;
+ _batCount = 0;
+ _aarghCount = 0;
+ _greldetX = _greldetY = 0;
+ _greldetCount = 0;
+ _redGreldet = false;
+ _wasLoaded = false;
+
+ _ghost = nullptr;
+ _glerk = nullptr;
+}
+
+GhostRoom::~GhostRoom() {
+ for (int i = 0; i < 2; i++)
+ _eyes[i].free();
+
+ _exclamation.free();
+
+ for (int i = 0; i < 3; i++)
+ _bat[i].free();
+
+ for (int i = 0; i < 6; i++)
+ _aargh[i].free();
+
+ for (int i = 0; i < 5; i++)
+ _greenEyes[i].free();
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 6; j++)
+ _greldet[j][i].free();
+ }
+
+ if (_wasLoaded) {
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 2; j++) {
+ for (int y = 0; y < 66; y++) {
+ delete[] _ghost[i][j][y];
+ }
+ delete[] _ghost[i][j];
+ }
+ delete[] _ghost[i];
+ }
+ delete[] _ghost;
+
+ for (int i = 0; i < 6; i++) {
+ for (int j = 0; j < 4; j++) {
+ for (int y = 0; y < 35; y++) {
+ delete[] _glerk[i][j][y];
+ }
+ delete[] _glerk[i][j];
+ }
+ delete[] _glerk[i];
+ }
+ delete[] _glerk;
+ }
+}
+
+void GhostRoom::wait(uint16 howLong) {
+ for (int i = 0; i < howLong; i++) {
+ Common::Event event;
+ _vm->getEvent(event);
+ if (event.type == Common::EVENT_KEYDOWN)
+ _vm->_sound->playNote(6177, 1);
+ _vm->_system->delayMillis(1);
+ }
+}
+
+void GhostRoom::doBat() {
+ _batCount++;
+
+ int8 dx = 0;
+ int8 iy = 0;
+ byte batImage = 0;
+ if ((_batCount % 2) == 1) {
+ if ((1 <= _batCount) && (_batCount <= 90)) {
+ dx = 2;
+ iy = 1;
+ batImage = 0;
+ } else if ((91 <= _batCount) && (_batCount <= 240)) {
+ dx = 1;
+ iy = 1;
+ batImage = 1;
+ } else if((241 <= _batCount) && (_batCount <= 260)) {
+ dx = 1;
+ iy = 4;
+ batImage = 2;
+ }
+
+ if ((_batCount == 91) || (_batCount == 241)) // When the bat changes, blank out the old one.
+ _vm->_graphics->drawFilledRectangle(Common::Rect(_batX + _bat[batImage].w, _batY, _batX + _bat[batImage - 1].w, _batY + _bat[batImage - 1].h), kColorBlack);
+
+ _vm->_graphics->drawFilledRectangle(Common::Rect(_batX, _batY, _batX + _bat[batImage].w, _batY + iy), kColorBlack);
+ _vm->_graphics->drawFilledRectangle(Common::Rect(_batX + _bat[batImage].w - dx, _batY, _batX + _bat[batImage].w, _batY + _bat[batImage].h), kColorBlack);
+
+ _batX -= dx;
+ _batY++;
+ _vm->_graphics->ghostDrawPicture(_bat[batImage], _batX, _batY);
+ }
+}
+
+void GhostRoom::bigGreenEyes(byte how) {
+ _vm->_graphics->ghostDrawPicture(_greenEyes[how], 330, 103);
+ _vm->_graphics->ghostDrawPicture(_greenEyes[how], 376, 103);
+ _vm->_graphics->refreshScreen();
+}
+
+ChunkBlock GhostRoom::readChunkBlock(Common::File &file) {
+ ChunkBlock cb;
+ cb._flavour = (Flavour)file.readByte();
+ cb._x = file.readSint16LE();
+ cb._y = file.readSint16LE();
+ cb._width = file.readSint16LE();
+ cb._height = file.readSint16LE();
+ cb._size = file.readSint32LE();
+ return cb;
+}
+
+void GhostRoom::loadPictures() {
+ Common::File file;
+
+ if (!file.open("spooky.avd"))
+ error("AVALANCHE: GhostRoom: File not found: spooky.avd");
+
+ file.seek(44);
+
+ // Initializing ghost's array.
+ _ghost = new byte***[5];
+ for (int i = 0; i < 5; i++) {
+ _ghost[i] = new byte**[2];
+ for (int j = 0; j < 2; j++) {
+ _ghost[i][j] = new byte*[66];
+ for (int y = 0; y < 66; y++) {
+ _ghost[i][j][y] = new byte[26];
+ for (int x = 0; x < 26; x++)
+ _ghost[i][j][y][x] = 0;
+ }
+ }
+ }
+
+ // Read in the pictures of the ghost.
+ for (int i = 0; i < 5; i++) {
+ ChunkBlock cb = readChunkBlock(file);
+ for (int j = 0; j < 2; j++) {
+ for (int y = 0; y <= cb._height; y++)
+ file.read(_ghost[i][j][y], cb._width / 8);
+ }
+ }
+
+ for (int i = 0; i < 2; i++)
+ _eyes[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
+
+ _exclamation = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
+
+ // Actually this function not just loads, but also draws the images, but they are part of the background
+ // and they are need to be drawn only once.
+ _vm->_graphics->ghostDrawBackgroundItems(file);
+
+ for (int i = 0; i < 3; i++)
+ _bat[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
+
+ // Initializing glerk's array.
+ _glerk = new byte***[6];
+ for (int i = 0; i < 6; i++) {
+ _glerk[i] = new byte**[4];
+ for (int j = 0; j < 4; j++) {
+ _glerk[i][j] = new byte*[35];
+ for (int y = 0; y < 35; y++) {
+ _glerk[i][j][y] = new byte[9];
+ for (int x = 0; x < 9; x++)
+ _glerk[i][j][y][x] = 0;
+ }
+ }
+ }
+
+ // Read in the pictures of the "glerk".
+ for (int i = 0; i < 6; i++) {
+ ChunkBlock cb = readChunkBlock(file);
+ for (int j = 0; j < 4; j++) {
+ for (int y = 0; y <= cb._height; y++)
+ file.read(_glerk[i][j][y], cb._width / 8);
+ }
+ }
+
+ for (int i = 0; i < 6; i++)
+ _aargh[i] = _vm->_graphics->ghostLoadPicture(file, _aarghWhere[i]);
+
+ for (int i = 0; i < 5; i++)
+ _greenEyes[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 6; j++)
+ _greldet[j][i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
+ }
+
+ file.close();
+}
+
+void GhostRoom::run() {
+ CursorMan.showMouse(false);
+ _vm->_graphics->saveScreen();
+ _vm->fadeOut();
+ _vm->_graphics->blackOutScreen();
+ _vm->fadeIn();
+
+ // Only load the pictures if it's our first time walking into the room.
+ // After that we simply use the already loaded images.
+ if (!_wasLoaded) {
+ loadPictures();
+ _wasLoaded = true;
+ }
+
+ // Avvy walks over:
+ _glerkStage = 0;
+ _batX = 277;
+ _batY = 40;
+ _batCount = 0;
+
+ for (int x = 500; x >= 217; x--) {
+ // The floating eyeballs:
+ int xBound = x % 30;
+ if ((22 <= xBound) && (xBound <= 27)) {
+ if (xBound == 27)
+ _vm->_graphics->drawFilledRectangle(Common::Rect(x, 135, x + 17, 137), kColorBlack);
+ _vm->_graphics->ghostDrawPicture(_eyes[0], x, 136);
+ _vm->_graphics->drawDot(x + 16, 137, kColorBlack);
+ } else {
+ if (xBound == 21)
+ _vm->_graphics->drawFilledRectangle(Common::Rect(x, 137, x + 18, 139), kColorBlack);
+ _vm->_graphics->ghostDrawPicture(_eyes[0], x, 135);
+ _vm->_graphics->drawDot(x + 16, 136, kColorBlack); // Eyes would leave a trail 1 pixel high behind them.
+ }
+
+ // Plot the Glerk:
+ if ((x % 10) == 0) {
+ if (_glerkStage > 25)
+ break;
+
+ _vm->_graphics->ghostDrawMonster(_glerk[kGlerkFade[_glerkStage]], 456, 14, kMonsterTypeGlerk);
+ _glerkStage++;
+ }
+
+ doBat();
+
+ _vm->_graphics->refreshScreen();
+
+ wait(15);
+ }
+
+ // Blank out the Glerk's space.
+ _vm->_graphics->drawFilledRectangle(Common::Rect(456, 14, 531, 51), kColorBlack);
+ _vm->_graphics->refreshScreen();
+
+
+ // Here comes the descending ghost:
+ for (int y = -64; y <= 103; y++) {
+ _vm->_graphics->ghostDrawMonster(_ghost[1 + (abs(y / 7) % 2) * 3], 0, y, kMonsterTypeGhost);
+ if (y > 0)
+ _vm->_graphics->drawFilledRectangle(Common::Rect(0, y - 1, 26 * 8 + 1, y + 1), kColorBlack);
+ _vm->_graphics->refreshScreen();
+
+ wait(27);
+ }
+
+ // Then it waves:
+ _aarghCount = -15;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 5; j++) {
+ _vm->_graphics->drawFilledRectangle(Common::Rect(0, 96, 26 * 8, 170), kColorBlack);
+ _vm->_graphics->ghostDrawMonster(_ghost[kWaveOrder[j]], 0, 96 + kAdjustment[j], kMonsterTypeGhost);
+
+ _aarghCount++;
+
+ if (_aarghCount >= 0) {
+ for (int k = 0; k <= _aarghCount; k++)
+ _vm->_graphics->ghostDrawPicture(_aargh[k], _aarghWhere[k].x, _aarghWhere[k].y);
+ }
+
+ _vm->_graphics->refreshScreen();
+
+ wait(177);
+ }
+ }
+
+ // The exclamation mark appears:
+ _vm->_graphics->ghostDrawPicture(_exclamation, 246, 127);
+ _vm->_graphics->refreshScreen();
+ wait(777);
+
+ // Erase "aargh":
+ _vm->_graphics->drawFilledRectangle(Common::Rect(172, 78, 348, 112), kColorBlack);
+ _vm->_graphics->refreshScreen();
+
+ for (int i = 4; i >= 0; i--) {
+ wait(377);
+ bigGreenEyes(i);
+ }
+
+ // Erase the exclamation mark:
+ _vm->_graphics->drawFilledRectangle(Common::Rect(246, 127, 252, 134), kColorBlack);
+ _vm->_graphics->refreshScreen();
+
+ // Avvy hurries back:
+ _glerkStage = 0;
+ _greldetCount = 18;
+ _redGreldet = false;
+
+ for (int x = 217; x <= 479; x++) {
+ // The floating eyeballs again:
+ int xBound = x % 30;
+ if ((22 <= xBound) && (xBound <= 27)) {
+ if (xBound == 22)
+ _vm->_graphics->drawFilledRectangle(Common::Rect(x + 22, 134, x + 39, 138), kColorBlack);
+ _vm->_graphics->ghostDrawPicture(_eyes[1], x + 23, 136);
+ _vm->_graphics->drawDot(x + 22, 137, kColorBlack);
+ } else {
+ if (xBound == 28)
+ _vm->_graphics->drawFilledRectangle(Common::Rect(x + 22, 135, x + 39, 139), kColorBlack);
+ _vm->_graphics->ghostDrawPicture(_eyes[1], x + 23, 135);
+ _vm->_graphics->drawDot(x + 22, 136, kColorBlack); // Eyes would leave a trail 1 pixel high behind them.
+ }
+
+ // Plot the Green Eyes:
+ if ((x % 53) == 5) {
+ bigGreenEyes(_glerkStage);
+ _glerkStage++;
+ }
+
+ // Plot the Greldet:
+ if (_greldetCount == 18) {
+ _greldetX = _vm->_rnd->getRandomNumber(599);
+ _greldetY = _vm->_rnd->getRandomNumber(79);
+ _greldetCount = 0;
+ _redGreldet = !_redGreldet;
+ }
+
+ _vm->_graphics->ghostDrawPicture(_greldet[kGreldetFade[_greldetCount]][_redGreldet], _greldetX, _greldetY);
+ _greldetCount++;
+
+ _vm->_graphics->refreshScreen();
+
+ wait(10);
+ }
+
+ CursorMan.showMouse(true);
+
+ _vm->fadeOut();
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+ _vm->_animation->animLink();
+ _vm->fadeIn();
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/ghostroom.h b/engines/avalanche/ghostroom.h
new file mode 100644
index 0000000000..ca1e8ac806
--- /dev/null
+++ b/engines/avalanche/ghostroom.h
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
+*/
+
+#ifndef AVALANCHE_GHOSTROOM_H
+#define AVALANCHE_GHOSTROOM_H
+
+#include "common/scummsys.h"
+#include "graphics/surface.h"
+
+namespace Avalanche {
+class AvalancheEngine;
+
+struct ChunkBlock {
+ Flavour _flavour;
+ int16 _x, _y;
+ int16 _width, _height;
+ int32 _size;
+};
+
+class GhostRoom {
+public:
+ GhostRoom(AvalancheEngine *vm);
+ ~GhostRoom();
+
+ void run();
+ ChunkBlock readChunkBlock(Common::File &file);
+
+private:
+ AvalancheEngine *_vm;
+
+ static const int8 kAdjustment[5];
+ static const byte kWaveOrder[5];
+ static const byte kGlerkFade[26];
+ static const byte kGreldetFade[18];
+
+ Common::Point dummyCoord;
+ byte ****_ghost;// [5][2][66][26]
+ Graphics::Surface _eyes[2];
+ Graphics::Surface _exclamation;
+ Graphics::Surface _bat[3];
+ byte ****_glerk; // [6][4][35][9]
+ Graphics::Surface _aargh[6];
+ Common::Point _aarghWhere[6];
+ Graphics::Surface _greenEyes[5];
+ Graphics::Surface _greldet[6][2];
+
+ int16 _batX, _batY;
+ uint16 _batCount;
+ byte _glerkStage;
+ int8 _aarghCount;
+ int16 _greldetX, _greldetY;
+ byte _greldetCount;
+ bool _redGreldet;
+ bool _wasLoaded;
+
+ void loadPictures();
+ void wait(uint16 howLong);
+ void doBat();
+ void bigGreenEyes(byte how);
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_GHOSTROOM_H
diff --git a/engines/avalanche/graphics.cpp b/engines/avalanche/graphics.cpp
index 25b01d65f3..60c23594d3 100644
--- a/engines/avalanche/graphics.cpp
+++ b/engines/avalanche/graphics.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -36,19 +36,20 @@ namespace Avalanche {
const byte GraphicManager::kEgaPaletteIndex[16] = {0, 1, 2, 3, 4, 5, 20, 7, 56, 57, 58, 59, 60, 61, 62, 63};
const MouseHotspotType GraphicManager::kMouseHotSpots[9] = {
- {8,0}, // 0 - up-arrow
- {0,0}, // 1 - screwdriver
+ {8,0}, // 0 - up-arrow
+ {0,0}, // 1 - screwdriver
{15,6}, // 2 - right-arrow
- {0,0}, // 3 - fletch
- {8,7}, // 4 - hourglass
- {4,0}, // 5 - TTHand
- {8,5}, // 6 - Mark's crosshairs
- {8,7}, // 7 - I-beam
- {0,0} // 8 - question mark
+ {0,0}, // 3 - fletch
+ {8,7}, // 4 - hourglass
+ {4,0}, // 5 - TTHand
+ {8,5}, // 6 - Mark's crosshairs
+ {8,7}, // 7 - I-beam
+ {0,0} // 8 - question mark
};
GraphicManager::GraphicManager(AvalancheEngine *vm) {
_vm = vm;
+ setDialogColor(kColorBlack, kColorWhite);
}
GraphicManager::~GraphicManager() {
@@ -126,7 +127,6 @@ void GraphicManager::loadMouse(byte which) {
cursor.create(16, 32, Graphics::PixelFormat::createFormatCLUT8());
cursor.fillRect(Common::Rect(0, 0, 16, 32), 255);
-
// The AND mask.
f.seek(kMouseSize * 2 * which + 134);
@@ -198,7 +198,7 @@ void GraphicManager::drawToolbar() {
Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) {
Common::Point endPoint;
- const float convfac = M_PI / 180.0;
+ const float convfac = (float)M_PI / 180.0f;
int32 xRadius = radius;
int32 yRadius = radius * kScreenWidth / (8 * kScreenHeight); // Just don't ask why...
@@ -231,7 +231,7 @@ Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16
uint16 numOfPixels = (uint16)floor(sqrt(3.0) * sqrt(pow(double(xRadius), 2) + pow(double(yRadius), 2)) + 0.5);
// Calculate the angle precision required.
- float delta = 90.0 / numOfPixels;
+ float delta = 90.0f / numOfPixels;
// Always just go over the first 90 degrees. Could be optimized a
// bit if startAngle and endAngle lie in the same quadrant, left as an
@@ -281,6 +281,14 @@ Common::Point GraphicManager::drawArc(Graphics::Surface &surface, int16 x, int16
return endPoint;
}
+void GraphicManager::drawDot(int x, int y, Color color) {
+ *(byte *)_surface.getBasePtr(x, y) = color;
+}
+
+void GraphicManager::drawLine(int x1, int y1, int x2, int y2, int penX, int penY, Color color) {
+ _surface.drawThickLine(x1, y1, x2, y2, penX, penY, color);
+}
+
Common::Point GraphicManager::drawScreenArc(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color) {
return drawArc(_surface, x, y, stAngle, endAngle, radius, color);
}
@@ -344,6 +352,25 @@ void GraphicManager::drawNormalText(const Common::String text, FontType font, by
drawText(_surface, text, font, fontHeight, x, y, color);
}
+/**
+ * Draws text double the size of the normal.
+ */
+void GraphicManager::drawBigText(Graphics::Surface &surface, const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color) {
+ for (uint i = 0; i < text.size(); i++) {
+ for (int j = 0; j < fontHeight; j++) {
+ byte pixel = font[(byte)text[i]][j];
+ byte pixelBit = 0;
+ for (int bit = 0; bit < 16; bit++) {
+ if ((bit % 2) == 0)
+ pixelBit = (pixel >> (bit / 2)) & 1;
+ for (int k = 0; k < 2; k++)
+ if (pixelBit)
+ *(byte *)surface.getBasePtr(x + i * 16 + 16 - bit, y + j * 2 + k) = color;
+ }
+ }
+ }
+}
+
void GraphicManager::drawScrollText(const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color) {
drawText(_scrolls, text, font, fontHeight, x, y, color);
}
@@ -451,6 +478,424 @@ void GraphicManager::drawDebugLines() {
}
}
+void GraphicManager::drawRectangle(Common::Rect rect, Color color) {
+ _surface.frameRect(rect, color);
+}
+
+void GraphicManager::drawFilledRectangle(Common::Rect rect, Color color) {
+ _surface.fillRect(rect, color);
+}
+
+void GraphicManager::blackOutScreen() {
+ _vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlack);
+}
+
+void GraphicManager::nimLoad() {
+ Common::File file;
+ Common::String filename = "nim.avd";
+
+ if (!file.open(filename))
+ error("AVALANCHE: Scrolls: File not found: %s", filename.c_str());
+
+ file.seek(41);
+
+ _nimStone = loadPictureSign(file, 7, 23);
+ for (int i = 0; i < 3; i++)
+ _nimInitials[i] = loadPictureSign(file, 7, 23);
+ _nimLogo = loadPictureSign(file, 30, 37);
+
+ file.close();
+}
+
+void GraphicManager::nimDrawStone(int x, int y) {
+ drawPicture(_surface, _nimStone, x, y);
+}
+
+void GraphicManager::nimDrawInitials() {
+ for (int i = 0; i < 3; i++)
+ drawPicture(_surface, _nimInitials[i], 0, 75 + i * 35);
+}
+
+void GraphicManager::nimDrawLogo() {
+ drawPicture(_surface, _nimLogo, 392, 5);
+}
+
+void GraphicManager::nimFree() {
+ _nimStone.free();
+ for (int i = 0; i < 3; i++)
+ _nimInitials[i].free();
+ _nimLogo.free();
+}
+
+void GraphicManager::ghostDrawMonster(byte ***picture, uint16 destX, int16 destY, MonsterType type) {
+ uint16 height = 0;
+ uint16 width = 0;
+ // Only for the Ghost:
+ const byte kPlaneToUse[4] = { 0, 0, 0, 1 };
+ int yStart = 0;
+
+ // Constants from the original code:
+ switch (type) {
+ case kMonsterTypeGhost:
+ height = 66;
+ width = 208; // 26 * 8
+
+ // We have to mess around with the coords and the sizes since
+ // the ghost isn't always placed fully on the screen.
+ if (destY < 0) {
+ yStart = abs(destY);
+ height -= yStart;
+ destY = 0;
+ }
+ break;
+ case kMonsterTypeGlerk:
+ height = 35;
+ width = 72; // 9 * 8
+ break;
+ default:
+ break;
+ }
+
+ Graphics::Surface monsterPicture;
+ monsterPicture.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int y = 0; y < height; y++) {
+ for (int plane = 0; plane < 4; plane++) {
+ for (uint16 x = 0; x < width / 8; x++) {
+ byte pixel = 0;
+
+ switch (type) {
+ case kMonsterTypeGhost:
+ pixel = picture[kPlaneToUse[plane]][y + yStart][x];
+ break;
+ case kMonsterTypeGlerk:
+ pixel = picture[plane][y][x];
+ break;
+ default:
+ break;
+ }
+
+ for (int bit = 0; bit < 8; bit++) {
+ byte pixelBit = (pixel >> bit) & 1;
+ *(byte *)monsterPicture.getBasePtr(x * 8 + 7 - bit, y) += (pixelBit << plane);
+ }
+ }
+ }
+ }
+
+ drawPicture(_surface, monsterPicture, destX, destY);
+
+ monsterPicture.free();
+}
+
+/**
+ * With the use of the second argument, it replaces get_meg_aargh as well.
+ * @remarks Originally called 'get_me' and was located in Ghostroom.
+ */
+Graphics::Surface GraphicManager::ghostLoadPicture(Common::File &file, Common::Point &coord) {
+ ChunkBlock cb = _vm->_ghostroom->readChunkBlock(file);
+
+ coord.x = cb._x;
+ coord.y = cb._y;
+
+ Graphics::Surface picture = loadPictureGraphic(file);
+
+ skipDifference(cb._size, picture, file);
+
+ return picture;
+}
+
+void GraphicManager::ghostDrawPicture(const Graphics::Surface &picture, uint16 destX, uint16 destY) {
+ drawPicture(_surface, picture, destX, destY);
+}
+
+/**
+ * Loads and puts 3 images (in this order: cobweb, Mark's signature, open door) into the background at the beginning of the ghostroom scene.
+ * @remarks Originally called 'plain_grab' and was located in Ghostroom. It was originally called 3 times. I unified these in one function, used a for cycle.
+ */
+void GraphicManager::ghostDrawBackgroundItems(Common::File &file) {
+ for (int num = 0; num < 3; num++) {
+ ChunkBlock cb = _vm->_ghostroom->readChunkBlock(file);
+
+ int width = cb._width;
+ int height = cb._height + 1;
+
+ Graphics::Surface picture;
+ picture.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ // Load the picture according to it's type.
+ switch (cb._flavour) {
+ case kFlavourOne: // There is only one plane.
+ for (uint16 y = 0; y < height; y++) {
+ for (uint16 x = 0; x < width; x += 8) {
+ byte pixel = file.readByte();
+ for (int i = 0; i < 8; i++) {
+ byte pixelBit = (pixel >> i) & 1;
+ *(byte *)picture.getBasePtr(x + 7 - i, y) = (pixelBit << 3);
+ }
+ }
+ }
+ break;
+ case kFlavourEga:
+ picture = loadPictureRaw(file, width, height);
+ break;
+ default:
+ break;
+ }
+
+ drawPicture(_surface, picture, cb._x, cb._y);
+
+ picture.free();
+ }
+ refreshScreen();
+}
+
+/**
+* @remarks Originally called 'plot_button'
+*/
+void GraphicManager::helpDrawButton(int y, byte which) {
+ if (y > 200) {
+ _vm->_graphics->setBackgroundColor(kColorGreen);
+ _vm->_system->delayMillis(10);
+ _vm->_graphics->setBackgroundColor(kColorBlack);
+ return;
+ }
+
+ Common::File file;
+
+ if (!file.open("buttons.avd"))
+ error("AVALANCHE: Help: File not found: buttons.avd");
+
+ file.seek(which * 930); // 930 is the size of one button.
+
+ Graphics::Surface button = loadPictureGraphic(file);
+
+ int x = 0;
+ if (y == -177) {
+ x = 229;
+ y = 5;
+ }
+ else
+ x = 470;
+
+ _vm->_graphics->drawPicture(_surface, button, x, y);
+
+ button.free();
+ file.close();
+}
+
+/**
+ * @remarks Originally called 'light'
+ */
+void GraphicManager::helpDrawHighlight(byte which, Color color) {
+ if (which == 177) // Dummy value for "no button at all".
+ return;
+
+ which &= 31;
+ drawRectangle(Common::Rect(466, 38 + which * 27, 556, 63 + which * 27), color);
+}
+
+void GraphicManager::helpDrawBigText(const Common::String text, int16 x, int16 y, Color color) {
+ drawBigText(_surface, text, _vm->_font, 8, x, y, color);
+}
+
+/**
+ * @remarks Originally called 'titles'
+ */
+void GraphicManager::seuDrawTitle() {
+ Common::File file;
+
+ if (!file.open("shoot1.avd"))
+ error("AVALANCHE: ShootEmUp: File not found: shoot1.avd");
+
+ const uint16 width = 320;
+ const uint16 height = 200;
+
+ Graphics::Surface picture = loadPictureRaw(file, width, height);
+
+ Graphics::Surface doubledPicture;
+ doubledPicture.create(width * 2, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ // These cycles are for doubling the picture's width.
+ for (int x = (width * 2) - 2 ; x >= 0; x -= 2) {
+ for (int y = 0; y < height; y++) {
+ *(byte *)doubledPicture.getBasePtr(x, y) = *(byte *)doubledPicture.getBasePtr(x + 1, y) = *(byte *)picture.getBasePtr(x / 2, y);
+ }
+ }
+
+ drawPicture(_surface, doubledPicture, 0, 0);
+ refreshScreen();
+
+ picture.free();
+ doubledPicture.free();
+
+ file.close();
+}
+
+void GraphicManager::seuLoad() {
+ Common::File file;
+
+ if (!file.open("notts.avd"))
+ error("AVALANCHE: ShootEmUp: File not found: notts.avd");
+
+ for (int i = 0; i < 99; i++) {
+ int size = file.readUint16LE();
+ _seuPictures[i] = loadPictureGraphic(file);
+ skipDifference(size, _seuPictures[i], file);
+ }
+
+ file.close();
+}
+
+void GraphicManager::seuFree() {
+ for (int i = 0; i < 99; i++)
+ _seuPictures[i].free();
+}
+
+/**
+ * @remarks Originally called 'display' and it also replaces 'display_const'
+ */
+void GraphicManager::seuDrawPicture(int x, int y, byte which) {
+ drawPicture(_surface, _seuPictures[which], x, y);
+}
+
+/**
+ * @remarks Originally called 'cameo_display'
+ */
+void GraphicManager::seuDrawCameo(int destX, int destY, byte w1, byte w2) {
+ // First we make the pixels of the previous sprite (cameo) blank:
+ uint16 maxX = _seuPictures[w2].w;
+ uint16 maxY = _seuPictures[w2].h;
+
+ if (destX + maxX > _surface.w)
+ maxX = _surface.w - destX;
+
+ if (destY + maxY > _surface.h)
+ maxY = _surface.h - destY;
+
+ for (uint16 y = 0; y < maxY; y++) {
+ for (uint16 x = 0; x < maxX; x++) {
+ if (*(const byte *)_seuPictures[w2].getBasePtr(x, y) != 0)
+ *(byte *)_surface.getBasePtr(x + destX, y + destY) = 0;
+ }
+ }
+
+ // Then we draw the desired sprite:
+ drawPicture(_surface, _seuPictures[w1], destX, destY);
+}
+
+uint16 GraphicManager::seuGetPicWidth(int which) {
+ return _seuPictures[which].w;
+}
+
+uint16 GraphicManager::seuGetPicHeight(int which) {
+ return _seuPictures[which].h;
+}
+
+void GraphicManager::menuRefreshScreen() {
+ g_system->copyRectToScreen(_menu.getPixels(), _menu.pitch, 0, 0, kScreenWidth, kMenuScreenHeight);
+ g_system->updateScreen();
+}
+
+void GraphicManager::menuInitialize() {
+ initGraphics(kScreenWidth, kMenuScreenHeight, true);
+ _menu.create(kScreenWidth, kMenuScreenHeight, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+void GraphicManager::menuFree() {
+ _menu.free();
+}
+
+void GraphicManager::menuRestoreScreen() {
+ initGraphics(kScreenWidth, 2 * kScreenHeight, true);
+}
+
+void GraphicManager::menuLoadPictures() {
+ _menu.fillRect(Common::Rect(0, 0, kScreenWidth, kMenuScreenHeight), kColorBlack);
+
+ Common::File file;
+
+ if (!file.open("menu.avd"))
+ error("AVALANCHE: MainMenu: File not found: menu.avd");
+
+ int height = 33;
+ int width = 9 * 8;
+
+ for (int plane = 0; plane < 4; plane++) {
+ // The icons themselves:
+ int n = 0;
+ for (uint16 y = 70; y < 70 + height * 6; y++) {
+ for (uint16 x = 48; x < 48 + width; x += 8) {
+ if (n < 1773) { // Magic value deciphered from the original code.
+ byte pixel = file.readByte();
+ n++;
+ for (int i = 0; i < 8; i++) {
+ byte pixelBit = (pixel >> i) & 1;
+ *(byte *)_menu.getBasePtr(x + 7 - i, y) += (pixelBit << plane);
+ }
+ }
+ }
+ }
+ // The right borders of the menuboxes:
+ for (int a = 0; a < 33; a++) {
+ byte pixel = file.readByte();
+ for (int b = 0; b < 6; b++) {
+ for (int i = 0; i < 8; i++) {
+ byte pixelBit = (pixel >> i) & 1;
+ *(byte *)_menu.getBasePtr(584 + 7 - i, 70 + b * 33 + a) += (pixelBit << plane);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < 6; i++) {
+ _menu.fillRect(Common::Rect(114, 73 + i * 33, 584, 100 + i * 33), kColorLightgray);
+ _menu.fillRect(Common::Rect(114, 70 + i * 33, 584, 73 + i * 33), kColorWhite);
+ _menu.fillRect(Common::Rect(114, 100 + i * 33, 584, 103 + i * 33), kColorDarkgray);
+ }
+
+ file.close();
+
+ // The title on the top of the screen:
+ if (!file.open("mainmenu.avd"))
+ error("AVALANCHE: MainMenu: File not found: mainmenu.avd");
+
+ Graphics::Surface title = loadPictureRaw(file, 640, 59);
+ drawPicture(_menu, title, 0, 0);
+ title.free();
+
+ file.close();
+}
+
+void GraphicManager::menuDrawBigText(FontType font, uint16 x, uint16 y, Common::String text, Color color) {
+ drawBigText(_menu, text, font, 14, x, y, color);
+}
+
+void GraphicManager::menuDrawIndicator(int x) { // TODO: Implement striped pattern for the indicator.
+ if (x > 0)
+ _menu.fillRect(Common::Rect(x - 1, 330, x, 337), kColorBlack);
+ _menu.fillRect(Common::Rect(x, 330, x + 1, 337), kColorWhite);
+ menuRefreshScreen();
+}
+
+/**
+ * This function is for skipping the difference between a stored 'size' value associated with a picture
+ * and the actual size of the pictures when reading them from files for Ghostroom and Shoot em' up.
+ * It's needed bacuse the original code loaded the pictures to arrays first and only used the useful parts
+ * of these arrays when drawing the images, but in the ScummVM version, we only read the
+ * useful parts from the files, so we have to skip these differences between readings.
+ */
+void GraphicManager::skipDifference(int size, const Graphics::Surface &picture, Common::File &file) {
+ int bytesPerRow = (picture.w / 8);
+ if ((picture.w % 8) > 0)
+ bytesPerRow += 1;
+ int loadedBytes = picture.h * bytesPerRow * 4 + 4;
+ // * 4 is for the four planes, + 4 is for the reading of the width and the height at loadPictureGraphic's beginning.
+
+ int bytesToSkip = size - loadedBytes;
+ file.skip(bytesToSkip);
+}
+
/**
* This function mimics Pascal's getimage().
*/
@@ -469,6 +914,8 @@ Graphics::Surface GraphicManager::loadPictureGraphic(Common::File &file) {
byte pixel = file.readByte();
for (int bit = 0; bit < 8; bit++) {
byte pixelBit = (pixel >> bit) & 1;
+ // If the picture's width is not a multiple of 8, and we get over the boundary with the 'x' cycle, pixelBit is surely == 0.
+ // Otherwise, it doesn't cause trouble, since addign 0 doesn't have an effect at all.
if (pixelBit != 0)
*(byte *)picture.getBasePtr(x + 7 - bit, y) += (pixelBit << plane);
}
@@ -503,6 +950,52 @@ Graphics::Surface GraphicManager::loadPictureRaw(Common::File &file, uint16 widt
return picture;
}
+Graphics::Surface GraphicManager::loadPictureSign(Common::File &file, uint16 width, uint16 height) {
+ // I know it looks very similar to the other loadPicture methods, but in truth it's the combination of the two.
+ width *= 8;
+
+ Graphics::Surface picture; // We make a Surface object for the picture itself.
+ picture.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+ // Produce the picture. We read it in row-by-row, and every row has 4 planes.
+ for (int y = 0; y < height; y++) {
+ for (int8 plane = 0; plane < 4; plane++) { // The planes are in the "right" order.
+ for (uint16 x = 0; x < width; x += 8) {
+ byte pixel = file.readByte();
+ for (int bit = 0; bit < 8; bit++) {
+ byte pixelBit = (pixel >> bit) & 1;
+ *(byte *)picture.getBasePtr(x + 7 - bit, y) += (pixelBit << plane);
+ }
+ }
+ }
+ }
+
+ return picture;
+}
+
+/**
+* Shifts the whole screen down by one line and fills the gap with black.
+*/
+void GraphicManager::shiftScreen() {
+ for (uint16 y = _surface.h - 1; y > 1; y--)
+ memcpy(_surface.getBasePtr(0, y), _surface.getBasePtr(0, y - 1), _surface.w);
+
+ _surface.drawLine(0, 0, _surface.w, 0, kColorBlack);
+}
+
+void GraphicManager::drawWinningPic() {
+ Common::File file;
+
+ if (!file.open("finale.avd"))
+ error("AVALANCHE: Timer: File not found: finale.avd");
+
+ Graphics::Surface winning = loadPictureRaw(file, 640, 200);
+ drawPicture(_surface, winning, 0, 0);
+
+ winning.free();
+ file.close();
+}
+
void GraphicManager::clearAlso() {
_magics.fillRect(Common::Rect(0, 0, 640, 200), 0);
_magics.frameRect(Common::Rect(0, 45, 640, 161), 15);
@@ -572,7 +1065,7 @@ void GraphicManager::drawPicture(Graphics::Surface &target, const Graphics::Surf
if (destX + maxX > target.w)
maxX = target.w - destX;
-
+
if (destY + maxY > target.h)
maxY = target.h - destY;
@@ -590,7 +1083,27 @@ void GraphicManager::drawCursor(byte pos) {
}
void GraphicManager::drawReadyLight(Color color) {
- _surface.fillRect(Common::Rect(419, 195, 438, 197), color);
+ _surface.fillRect(Common::Rect(419, 195, 439, 198), color);
+ _scrolls.fillRect(Common::Rect(419, 195, 439, 198), color);
+}
+
+void GraphicManager::drawSoundLight(bool state) {
+ Color color = kColorBlack;
+ if (state)
+ color = kColorCyan;
+ else
+ color = kColorBlack;
+ _surface.fillRect(Common::Rect(419, 175, 439, 178), color);
+}
+
+void GraphicManager::drawErrorLight(bool state) {
+ Color color = kColorBlack;
+ if (state)
+ color = kColorRed;
+ else
+ color = kColorBlack;
+ _surface.fillRect(Common::Rect(419, 184, 439, 187), color);
+ refreshScreen();
}
/**
@@ -603,28 +1116,10 @@ void GraphicManager::drawSign(Common::String fn, int16 xl, int16 yl, int16 y) {
if (!file.open(filename))
error("AVALANCHE: Scrolls: File not found: %s", filename.c_str());
- // I know it looks very similar to the loadPicture methods, but in truth it's the combination of the two.
- uint16 width = xl * 8;
- uint16 height = yl;
-
Graphics::Surface sign; // We make a Surface object for the picture itself.
- sign.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
-
- // Produce the picture. We read it in row-by-row, and every row has 4 planes.
- for (int yy = 0; yy < height; yy++) {
- for (int8 plane = 0; plane < 4; plane++) { // The planes are in the "right" order.
- for (uint16 xx = 0; xx < width; xx += 8) {
- byte pixel = file.readByte();
- for (int bit = 0; bit < 8; bit++) {
- byte pixelBit = (pixel >> bit) & 1;
- if (pixelBit != 0)
- *(byte *)sign.getBasePtr(xx + 7 - bit, yy) += (pixelBit << plane);
- }
- }
- }
- }
-
- drawPicture(_scrolls, sign, kScreenWidth / 2 - width / 2, y);
+ sign = loadPictureSign(file, xl, yl);
+ uint16 width = xl * 8;
+ drawPicture(_scrolls, sign, kScreenWidth / 2 - width / 2, y); // x coord: center the picture.
file.close();
}
@@ -668,7 +1163,7 @@ void GraphicManager::prepareBubble(int xc, int xw, int my, Common::Point points[
drawTriangle(points, _talkBackgroundColor);
}
-/**
+/**
* Set the background of the text to the desired color.
*/
void GraphicManager::wipeChar(int x, int y, Color color) {
@@ -733,10 +1228,10 @@ void GraphicManager::showScroll() {
void GraphicManager::getNaturalPicture(SpriteType &sprite) {
sprite._type = kNaturalImage; // We simply read from the screen and later, in drawSprite() we draw it right back.
- sprite._size = sprite._xl * 8 * sprite._yl + 1;
- sprite._picture.create(sprite._xl * 8, sprite._yl + 1, Graphics::PixelFormat::createFormatCLUT8());
- for (uint16 y = 0; y < sprite._yl + 1; y++) {
- for (uint16 x = 0; x < sprite._xl * 8; x++)
+ sprite._size = sprite._width * 8 * sprite._height + 1;
+ sprite._picture.create(sprite._width * 8, sprite._height + 1, Graphics::PixelFormat::createFormatCLUT8());
+ for (uint16 y = 0; y < sprite._height + 1; y++) {
+ for (uint16 x = 0; x < sprite._width * 8; x++)
*(byte *)sprite._picture.getBasePtr(x, y) = *(byte *)_vm->_graphics->_surface.getBasePtr(sprite._x * 8 + x, sprite._y + y);
}
}
@@ -759,9 +1254,12 @@ void GraphicManager::setDialogColor(Color bg, Color text) {
_talkFontColor = text;
}
-// Original name background()
-void GraphicManager::setBackgroundColor(Color x) {
- warning("STUB: setBackgroundColor()");
+/**
+* Changes the black color of the palette to the selected one.
+* @remarks Originally called 'background'
+*/
+void GraphicManager::setBackgroundColor(Color newColor) {
+ g_system->getPaletteManager()->setPalette(_egaPalette[kEgaPaletteIndex[newColor]], kColorBlack, 1);
}
} // End of namespace Avalanche
diff --git a/engines/avalanche/graphics.h b/engines/avalanche/graphics.h
index 4af6d4e8db..bd8fc6c8ff 100644
--- a/engines/avalanche/graphics.h
+++ b/engines/avalanche/graphics.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -38,6 +38,7 @@ namespace Avalanche {
class AvalancheEngine;
class AnimationType;
struct SpriteType;
+struct ChunkBlock;
typedef byte FontType[256][16];
typedef byte ManiType[2049];
@@ -58,6 +59,11 @@ public:
void loadDigits();
void loadMouse(byte which);
+ void drawRectangle(Common::Rect rect, Color color);
+ void drawFilledRectangle(Common::Rect rect, Color color);
+ void blackOutScreen();
+ void drawDot(int x, int y, Color color);
+ void drawLine(int x1, int y1, int x2, int y2, int penX, int penY, Color color);
Common::Point drawScreenArc(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color);
void drawPieSlice(int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color);
void drawTriangle(Common::Point *p, Color color);
@@ -77,22 +83,66 @@ public:
void drawChar(byte ander, int x, int y, Color color);
void drawDebugLines();
+ // For the mini-game "Nim".
+ void nimLoad();
+ void nimDrawStone(int x, int y);
+ void nimDrawInitials();
+ void nimDrawLogo();
+ void nimFree();
+
+ // Used in wobble()
+ void shiftScreen();
+
+ // Used in winning()
+ void drawWinningPic();
+
+ // Ghostroom's functions:
+ void ghostDrawMonster(byte ***picture, uint16 destX, int16 destY, MonsterType type);
+ Graphics::Surface ghostLoadPicture(Common::File &file, Common::Point &coord);
+ void ghostDrawPicture(const Graphics::Surface &picture, uint16 destX, uint16 destY);
+ void ghostDrawBackgroundItems(Common::File &file);
+
+ // Help's function:
+ void helpDrawButton(int y, byte which);
+ void helpDrawHighlight(byte which, Color color);
+ void helpDrawBigText(const Common::String text, int16 x, int16 y, Color color);
+
+ // Shoot em' up's functions:
+ void seuDrawTitle();
+ void seuLoad();
+ void seuFree();
+ void seuDrawPicture(int x, int y, byte which);
+ void seuDrawCameo(int destX, int destY, byte w1, byte w2);
+ uint16 seuGetPicWidth(int which);
+ uint16 seuGetPicHeight(int which);
+
+ // Main Menu's functions:
+ // The main menu uses a different screen height (350) from the game itself (200 * 2)
+ // so it needs it's own graphic functions on that matter.
+ void menuRefreshScreen();
+ void menuInitialize();
+ void menuFree();
+ void menuRestoreScreen();
+ void menuLoadPictures();
+ void menuDrawBigText(FontType font, uint16 x, uint16 y, Common::String text, Color color);
+ void menuDrawIndicator(int x);
+
void clearAlso();
void clearTextBar();
void setAlsoLine(int x1, int y1, int x2, int y2, Color color);
byte getAlsoColor(int x1, int y1, int x2, int y2);
byte getScreenColor(Common::Point pos);
- // The caller has to .free() the returned Surfaces!!!
- // Further information about these two: http://www.shikadi.net/moddingwiki/Raw_EGA_data
+ // Further information about this: http://www.shikadi.net/moddingwiki/Raw_EGA_data
Graphics::Surface loadPictureRaw(Common::File &file, uint16 width, uint16 height);
void drawSprite(AnimationType *sprite, byte picnum, int16 x, int16 y);
- void drawPicture(Graphics::Surface &target, const Graphics::Surface picture, uint16 destX, uint16 destY);
void drawThinkPic(Common::String filename, int id);
void drawToolbar();
void drawCursor(byte pos);
void drawReadyLight(Color color);
+ void drawSoundLight(bool state);
+ void drawErrorLight(bool state);
void drawSign(Common::String name, int16 xl, int16 yl, int16 y);
void drawIcon(int16 x, int16 y, byte which);
void drawScreenLine(int16 x, int16 y, int16 x2, int16 y2, Color color);
@@ -100,7 +150,7 @@ public:
void refreshScreen();
void loadBackground(Common::File &file);
void refreshBackground();
- void setBackgroundColor(Color x);
+ void setBackgroundColor(Color newColor);
void setDialogColor(Color bg, Color text);
void zoomOut(int16 x, int16 y);
@@ -108,14 +158,16 @@ public:
void getNaturalPicture(SpriteType &sprite);
void saveScreen();
- void removeBackup();
void restoreScreen();
+ void removeBackup();
private:
+ static const int16 kMouseSize = 134;
static const uint16 kBackgroundWidth = kScreenWidth;
static const byte kEgaPaletteIndex[16];
static const byte kBackgroundHeight = 8 * 12080 / kScreenWidth; // With 640 width it's 151.
// The 8 = number of bits in a byte, and 12080 comes from Lucerna::load().
+ static const uint16 kMenuScreenHeight = 350;
Graphics::Surface _background;
Graphics::Surface _backup;
@@ -125,15 +177,32 @@ private:
Graphics::Surface _screen; // Only used in refreshScreen() to make it more optimized. (No recreation of it at every call of the function.)
Graphics::Surface _scrolls;
Graphics::Surface _surface;
+ Graphics::Surface _menu;
+
+ // For the mini-game "Nim".
+ Graphics::Surface _nimStone;
+ Graphics::Surface _nimInitials[3];
+ Graphics::Surface _nimLogo;
+
+ // For the mini-game "Shoot em' up".
+ Graphics::Surface _seuPictures[99];
+
byte _egaPalette[64][3];
AvalancheEngine *_vm;
+ void skipDifference(int size, const Graphics::Surface &picture, Common::File &file);
+
+ // Further information about these two: http://www.shikadi.net/moddingwiki/Raw_EGA_data
Graphics::Surface loadPictureGraphic(Common::File &file); // Reads Graphic-planar EGA data.
+ Graphics::Surface loadPictureSign(Common::File &file, uint16 width, uint16 height); // Reads a tricky type of picture used for the "game over"/"about" scrolls and in the mini-game Nim.
+
void drawText(Graphics::Surface &surface, const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
+ void drawBigText(Graphics::Surface &surface, const Common::String text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
+ void drawPicture(Graphics::Surface &target, const Graphics::Surface picture, uint16 destX, uint16 destY);
+
// Taken from Free Pascal's Procedure InternalEllipseDefault. Used to replace Pascal's procedure arc.
// Returns the end point of the arc. (Needed in Clock.)
- // TODO: Make it more accurate later.
Common::Point drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color);
};
diff --git a/engines/avalanche/help.cpp b/engines/avalanche/help.cpp
new file mode 100644
index 0000000000..4d08e3d58b
--- /dev/null
+++ b/engines/avalanche/help.cpp
@@ -0,0 +1,270 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+*/
+
+/* Original name: HELPER The help system unit. */
+
+#include "avalanche/avalanche.h"
+#include "avalanche/help.h"
+
+#include "common/scummsys.h"
+
+namespace Avalanche {
+
+Help::Help(AvalancheEngine *vm) {
+ _vm = vm;
+
+ for (int i = 0; i < 10; i++) {
+ _buttons[i]._trigger = Common::KEYCODE_INVALID;
+ _buttons[i]._whither = 0;
+ }
+ _highlightWas = 0;
+ _buttonNum = 0;
+ _holdLeft = false;
+}
+
+/**
+ * Loads and draws the chosen page of the help.
+ * @remarks Originally called 'getme'
+ */
+void Help::switchPage(byte which) {
+ // Help icons are 80x20.
+
+ _highlightWas = 177; // Forget where the highlight was.
+
+ Common::File file;
+
+ if (!file.open("help.avd"))
+ error("AVALANCHE: Help: File not found: help.avd");
+
+ file.seek(which * 2);
+ uint16 offset = file.readUint16LE();
+ file.seek(offset);
+
+ Common::String title = getLine(file);
+
+ _vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlue);
+ _vm->_graphics->drawFilledRectangle(Common::Rect(8, 40, 450, 200), kColorWhite);
+
+ byte index = file.readByte();
+ _vm->_graphics->helpDrawButton(-177, index);
+
+ // Plot the title:
+ _vm->_graphics->drawNormalText(title, _vm->_font, 8, 629 - 8 * title.size(), 26, kColorBlack);
+ _vm->_graphics->drawNormalText(title, _vm->_font, 8, 630 - 8 * title.size(), 25, kColorCyan);
+
+ _vm->_graphics->helpDrawBigText("help!", 549, 1, kColorBlack);
+ _vm->_graphics->helpDrawBigText("help!", 550, 0, kColorCyan);
+
+ byte y = 0;
+ do {
+ Common::String line = getLine(file);
+ if (!line.empty()) {
+ if (line.compareTo(Common::String('!')) == 0) // End of the help text is signalled with a '!'.
+ break;
+ if (line[0] == '\\') {
+ line.deleteChar(0);
+ _vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorRed);
+ }
+ else
+ _vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorBlack);
+ }
+ y++;
+ } while (true);
+
+ // We are now at the end of the text. Next we must read the icons:
+ y = 0;
+ _buttonNum = 0;
+ while (!file.eos()) {
+ int trigger = file.readByte();
+
+ if (trigger == 177)
+ break;
+ switch (trigger) {
+ case 254: // Escape
+ trigger = 27;
+ break;
+ case 214: // PageUp
+ trigger = 280;
+ break;
+ case 216: // PageDown
+ trigger = 281;
+ break;
+ default: // A - Z
+ // The characters are stored in the file in uppercase, but we need the lowercase versions for KeyCode:
+ trigger = tolower(trigger);
+ break;
+ }
+
+ _buttons[y]._trigger = Common::KeyCode(trigger);
+ index = file.readByte();
+ if (_buttons[y]._trigger != Common::KEYCODE_INVALID)
+ _vm->_graphics->helpDrawButton(13 + (y + 1) * 27, index);
+ _buttons[y]._whither = file.readByte(); // This is the position to jump to.
+
+ Common::String text = "";
+ switch (_buttons[y]._trigger) {
+ case Common::KEYCODE_ESCAPE:
+ text = Common::String("Esc");
+ break;
+ case Common::KEYCODE_PAGEUP:
+ text = Common::String(24);
+ break;
+ case Common::KEYCODE_PAGEDOWN:
+ text = Common::String(25);
+ break;
+ default:
+ text = Common::String(toupper(_buttons[y]._trigger));
+ break;
+ }
+
+ _vm->_graphics->helpDrawBigText(text, 589 - (text.size() * 8), 18 + (y + 1) * 27, kColorBlack);
+ _vm->_graphics->helpDrawBigText(text, 590 - (text.size() * 8), 17 + (y + 1) * 27, kColorCyan);
+
+ y++;
+ _buttonNum++;
+ }
+
+ _vm->_graphics->refreshScreen();
+
+ file.close();
+}
+
+Common::String Help::getLine(Common::File &file) {
+ Common::String line;
+ byte length = file.readByte();
+ for (int i = 0; i < length; i++) {
+ char c = file.readByte();
+ line += (c ^ 177);
+ }
+ return line;
+}
+
+bool Help::handleMouse(const Common::Event &event) {
+ Common::Point mousePos;
+ mousePos.x = event.mouse.x;
+ mousePos.y = event.mouse.y / 2;
+
+ int index = -1;
+
+ if (event.type == Common::EVENT_LBUTTONUP) { // Clicked *somewhere*...
+ _holdLeft = false;
+
+ if ((mousePos.x < 470) || (mousePos.x > 550) || (((mousePos.y - 13) % 27) > 20))
+ index = -1;
+ else // Clicked on a button.
+ index = ((mousePos.y - 13) / 27) - 1;
+ } else { // LBUTTONDOWN or MOUSEMOVE
+ int highlightIs = 0;
+
+ // Decide which button we are hovering the cursor over:
+ if ((mousePos.x > 470) && (mousePos.x <= 550) && (((mousePos.y - 13) % 27) <= 20)) { // No click, so highlight.
+ highlightIs = (mousePos.y - 13) / 27 - 1;
+ if ((highlightIs < 0) || (5 < highlightIs))
+ highlightIs = 177; // In case of silly values.
+ } else
+ highlightIs = 177;
+
+ Color highlightColor = kColorLightblue;
+ // If we clicked on a button or we are holding down the button, we have to highlight it with cyan:
+ if (((highlightIs != 177) && (event.type == Common::EVENT_LBUTTONDOWN)) || _holdLeft) {
+ _holdLeft = true;
+ highlightColor = kColorLightcyan;
+ }
+
+ // Erase the previous highlight only if it's needed:
+ if (_highlightWas != highlightIs)
+ _vm->_graphics->helpDrawHighlight(_highlightWas, kColorBlue);
+
+ // Highlight the current one with the proper color:
+ if ((highlightIs != 177) && (_buttons[highlightIs]._trigger != Common::KEYCODE_INVALID)) {
+ _highlightWas = highlightIs;
+ _vm->_graphics->helpDrawHighlight(highlightIs, highlightColor);
+ }
+ }
+
+ if ((index >= 0) && (_buttons[index]._trigger != Common::KEYCODE_INVALID)) {
+ if (_buttons[index]._trigger == Common::KEYCODE_ESCAPE)
+ return true;
+ else {
+ _vm->fadeOut();
+ switchPage(_buttons[index]._whither);
+ _vm->fadeIn();
+ return false;
+ }
+ }
+
+ return false;
+}
+
+bool Help::handleKeyboard(const Common::Event &event) {
+ if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
+ return true;
+
+ for (int i = 0; i < _buttonNum; i++) {
+ if (_buttons[i]._trigger == event.kbd.keycode) {
+ _vm->fadeOut();
+ switchPage(_buttons[i]._whither);
+ _vm->fadeIn();
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * @remarks Originally called 'boot_help'
+ */
+void Help::run() {
+ _vm->_graphics->saveScreen();
+ _vm->fadeOut();
+ switchPage(0);
+ _vm->fadeIn();
+
+ _vm->_graphics->loadMouse(kCurHelp);
+
+ // Originally it was the body of 'continue_help':
+ bool close = false;
+ while (!_vm->shouldQuit() && !close) {
+ Common::Event event;
+ _vm->getEvent(event);
+ if (event.type == Common::EVENT_KEYDOWN)
+ close = handleKeyboard(event);
+ else if ((event.type == Common::EVENT_LBUTTONDOWN) || (event.type == Common::EVENT_LBUTTONUP) || (event.type == Common::EVENT_MOUSEMOVE))
+ close = handleMouse(event);
+
+ _vm->_graphics->refreshScreen();
+ }
+ // End of 'continue_help'.
+
+ _vm->fadeOut();
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+ _vm->fadeIn();
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/help.h b/engines/avalanche/help.h
new file mode 100644
index 0000000000..7543d87047
--- /dev/null
+++ b/engines/avalanche/help.h
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+*/
+
+/* Original name: HELPER The help system unit. */
+
+#ifndef AVALANCHE_HELP_H
+#define AVALANCHE_HELP_H
+
+namespace Avalanche {
+class AvalancheEngine;
+
+class Help {
+public:
+ Help(AvalancheEngine *vm);
+
+ void run();
+
+private:
+ struct Button {
+ Common::KeyCode _trigger;
+ byte _whither;
+ };
+
+ AvalancheEngine *_vm;
+
+ Button _buttons[10];
+ byte _highlightWas;
+ byte _buttonNum; // How many buttons do we have on the screen at the moment?
+ bool _holdLeft; // Is the left mouse button is still being held?
+
+ void switchPage(byte which);
+ Common::String getLine(Common::File &file); // It was a nested function in getMe().
+
+ // These two return true if we have to leave the Help:
+ bool handleMouse(const Common::Event &event);
+ bool handleKeyboard(const Common::Event &event);
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_HELP_H
diff --git a/engines/avalanche/highscore.cpp b/engines/avalanche/highscore.cpp
new file mode 100644
index 0000000000..5f47aeb894
--- /dev/null
+++ b/engines/avalanche/highscore.cpp
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
+*/
+
+#include "avalanche/avalanche.h"
+#include "avalanche/highscore.h"
+
+#include "common/savefile.h"
+
+namespace Avalanche {
+
+HighScore::HighScore(AvalancheEngine *vm) {
+ _vm = vm;
+}
+
+void HighScore::displayHighScores() {
+ warning("STUB: HighScore::displayHighScores(");
+}
+
+void HighScore::saveHighScores() {
+ int firstSmaller = 0;
+ while ((firstSmaller < 12) && (_data[firstSmaller]._score >= _vm->_score))
+ firstSmaller++;
+
+ if (firstSmaller < 12) {
+ // Shift all the lower scores down a space:
+ for (int i = firstSmaller; i < 11; i++)
+ _data[i + 1] = _data[i];
+ // Set the new high score:
+ _data[firstSmaller]._name = "Player"; // TODO: Come up with something for that. In the original it wasn't implemented at all...
+ _data[firstSmaller]._rank = _vm->_parser->rank();
+ _data[firstSmaller]._score = _vm->_score;
+ }
+
+ Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving("scores.avd");
+ if (!f) {
+ warning("Can't create file 'scores.avd', high scores are not saved.");
+ return;
+ }
+ Common::Serializer sz(NULL, f);
+ syncHighScores(sz);
+ f->finalize();
+ delete f;
+}
+
+void HighScore::loadHighScroes() {
+ Common::File file;
+ if (!file.exists("scores.avd")) {
+ produceDefaultHighScores();
+ } else {
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading("scores.avd");
+ if (!f)
+ return;
+ Common::Serializer sz(f, NULL);
+ syncHighScores(sz);
+ delete f;
+ }
+}
+
+void HighScore::produceDefaultHighScores() {
+ for (int i = 0; i < 12; i++) {
+ _data[i]._score = 32 - (i + 1) * 2;
+ _data[i]._rank = "...";
+ }
+ _data[0]._name = "Mike";
+ _data[1]._name = "Liz";
+ _data[2]._name = "Thomas";
+ _data[3]._name = "Mark";
+ _data[4]._name = "Mandy";
+ _data[5]._name = "Andrew";
+ _data[6]._name = "Lucy Tryphena";
+ _data[7]._name = "Tammy the dog";
+ _data[8]._name = "Avaricius";
+ _data[9]._name = "Spellchick";
+ _data[10]._name = "Caddelli";
+ _data[11]._name = "Spludwick";
+}
+
+void HighScore::syncHighScores(Common::Serializer &sz) {
+ for (int i = 0; i < 12; i++) {
+ sz.syncString(_data[i]._name);
+ sz.syncAsUint16LE(_data[i]._score);
+ sz.syncString(_data[i]._rank);
+ }
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/highscore.h b/engines/avalanche/highscore.h
new file mode 100644
index 0000000000..de7ec36ed5
--- /dev/null
+++ b/engines/avalanche/highscore.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
+*/
+
+#ifndef AVALANCHE_HIGHSCORE_H
+#define AVALANCHE_HIGHSCORE_H
+
+namespace Avalanche {
+class AvalancheEngine;
+
+struct HighScoreData {
+ Common::String _name;
+ uint16 _score;
+ Common::String _rank;
+};
+
+class HighScore {
+public:
+ HighScore(AvalancheEngine *vm);
+
+ void displayHighScores();
+ void saveHighScores();
+ void loadHighScroes();
+
+private:
+ AvalancheEngine *_vm;
+
+ HighScoreData _data[12];
+
+ void produceDefaultHighScores();
+ void syncHighScores(Common::Serializer &sz);
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_HIGHSCORE_H
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
new file mode 100644
index 0000000000..543684556c
--- /dev/null
+++ b/engines/avalanche/mainmenu.cpp
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+*/
+
+#include "avalanche/avalanche.h"
+#include "avalanche/mainmenu.h"
+
+namespace Avalanche {
+
+MainMenu::MainMenu(AvalancheEngine *vm) {
+ _vm = vm;
+
+ _registrant = Common::String("");
+}
+
+void MainMenu::run() {
+ CursorMan.showMouse(false);
+ _vm->_graphics->menuInitialize();
+ _vm->_graphics->menuLoadPictures();
+ loadRegiInfo();
+ loadFont();
+
+ option(1, "Play the game.");
+ option(2, "Read the background.");
+ option(3, "Preview... perhaps...");
+ option(4, "View the documentation.");
+ option(5, "Registration info.");
+ option(6, "Exit back to DOS.");
+ centre(274, _registrant);
+ centre(301, "Make your choice, or wait for the demo.");
+
+ _vm->_graphics->menuRefreshScreen();
+
+ wait();
+}
+
+void MainMenu::loadFont() {
+ Common::File file;
+ if (!file.open("avalot.fnt"))
+ error("AVALANCHE: Scrolls: File not found: avalot.fnt");
+ for (int16 i = 0; i < 256; i++)
+ file.read(_font[i], 16);
+ file.close();
+}
+
+void MainMenu::loadRegiInfo() {
+ _registrant = "(Unregistered evaluation copy.)";
+ warning("STUB: MainMenu::loadRegiInfo()");
+}
+
+void MainMenu::option(byte which, Common::String what) {
+ _vm->_graphics->menuDrawBigText(_font, 127, 39 + which * 33, Common::String(which + 48) + ')', kColorBlack);
+ _vm->_graphics->menuDrawBigText(_font, 191, 39 + which * 33, what, kColorBlack);
+}
+
+void MainMenu::centre(int16 y, Common::String text) {
+ _vm->_graphics->menuDrawBigText(_font, 320 - text.size() * 8, y, text, kColorLightgray);
+}
+
+void MainMenu::wait() {
+ int x = 0;
+ while (!_vm->shouldQuit()) {
+ _vm->_graphics->menuDrawIndicator(x);
+ _vm->_system->delayMillis(40);
+ x++;
+ if (x == 641)
+ x = 0;
+ Common::Event event;
+ _vm->getEvent(event);
+ if (event.type == Common::EVENT_KEYDOWN) {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_SPACE:
+ case Common::KEYCODE_RETURN:
+ case Common::KEYCODE_1: // Falltroughs are inteded.
+ // Play the game
+ _vm->_graphics->menuFree();
+ _vm->_graphics->menuRestoreScreen();
+ CursorMan.showMouse(true);
+ return;
+ case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_6: // Falltroughs are inteded.
+ // Exit back to DOS
+ _vm->_letMeOut = true;
+ _vm->_graphics->menuFree();
+ return;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/mainmenu.h b/engines/avalanche/mainmenu.h
new file mode 100644
index 0000000000..e973e0ccf3
--- /dev/null
+++ b/engines/avalanche/mainmenu.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+*/
+
+#ifndef AVALANCHE_MAINMENU_H
+#define AVALANCHE_MAINMENU_H
+
+namespace Avalanche {
+class AvalancheEngine;
+
+class MainMenu {
+public:
+ MainMenu(AvalancheEngine *vm);
+
+ void run();
+
+private:
+ AvalancheEngine *_vm;
+
+ Common::String _registrant;
+ FontType _font;
+
+ void loadFont();
+ void loadRegiInfo();
+ void option(byte which, Common::String what);
+ void centre(int16 y, Common::String text);
+ void wait();
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_MAINMENU_H
diff --git a/engines/avalanche/module.mk b/engines/avalanche/module.mk
index 9c1205df02..919ff0334f 100644
--- a/engines/avalanche/module.mk
+++ b/engines/avalanche/module.mk
@@ -9,14 +9,20 @@ MODULE_OBJS = \
console.o \
detection.o \
graphics.o \
- menu.o \
+ dropdown.o \
parser.o \
- pingo.o \
dialogs.o \
sequence.o \
sound.o \
- timer.o
-
+ timer.o \
+ nim.o \
+ clock.o \
+ ghostroom.o \
+ help.o \
+ shootemup.o \
+ mainmenu.o \
+ highscore.o
+
# This module can be built as a plugin
ifeq ($(ENABLE_AVALANCHE), DYNAMIC_PLUGIN)
PLUGIN := 1
diff --git a/engines/avalanche/nim.cpp b/engines/avalanche/nim.cpp
new file mode 100644
index 0000000000..79be16d3c3
--- /dev/null
+++ b/engines/avalanche/nim.cpp
@@ -0,0 +1,575 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+ * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+ */
+
+#include "avalanche/avalanche.h"
+#include "avalanche/nim.h"
+
+namespace Avalanche {
+
+const char * const Nim::kNames[2] = {"Avalot", "Dogfood"};
+
+Nim::Nim(AvalancheEngine *vm) {
+ _vm = vm;
+
+ resetVariables();
+}
+
+void Nim::resetVariables() {
+ _playedNim = 0;
+ _turns = 0;
+ _dogfoodsTurn = false;
+ _stonesLeft = 0;
+ _clicked = false;
+ _row = 0;
+ _number = 0;
+ _squeak = false;
+ _lmo = false;
+
+ for (int i = 0; i < 3; i++) {
+ _old[i] = 0;
+ _stones[i] = 0;
+ _inAp[i] = 0;
+ _r[i] = 0;
+ }
+}
+
+void Nim::synchronize(Common::Serializer &sz) {
+ if (sz.isLoading() && sz.getVersion() < 2)
+ return;
+
+ sz.syncAsByte(_playedNim);
+}
+
+void Nim::playNim() {
+ if (_vm->_wonNim) { // Already won the game.
+ _vm->_dialogs->displayScrollChain('Q', 6);
+ return;
+ }
+
+ if (!_vm->_askedDogfoodAboutNim) {
+ _vm->_dialogs->displayScrollChain('Q', 84);
+ return;
+ }
+
+ _vm->_dialogs->displayScrollChain('Q', 3);
+ _playedNim++;
+
+ _vm->_graphics->saveScreen();
+ _vm->fadeOut();
+
+ CursorMan.showMouse(false);
+ setup();
+ board();
+ //CursorMan.showMouse(true);
+
+ do {
+
+ startMove();
+ if (_dogfoodsTurn)
+ dogFood();
+ else {
+ CursorMan.showMouse(true);
+ takeSome();
+ CursorMan.showMouse(false);
+ }
+ _stones[_row] -= _number;
+ showChanges();
+ } while (_stonesLeft != 0);
+
+ endOfGame(); // Winning sequence is A1, B3, B1, C1, C1, btw.
+
+ _vm->fadeOut();
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+ _vm->fadeIn();
+ CursorMan.showMouse(true);
+
+ if (_dogfoodsTurn) {
+ // Dogfood won - as usual.
+ if (_playedNim == 1) // Your first game.
+ _vm->_dialogs->displayScrollChain('Q', 4); // Goody! Play me again?
+ else
+ _vm->_dialogs->displayScrollChain('Q', 5); // Oh, look at that! I've won again!
+ _vm->decreaseMoney(4); // And you've just lost 4d!
+ } else {
+ // You won - strange!
+ _vm->_dialogs->displayScrollChain('Q', 7);
+ _vm->_objects[kObjectLute - 1] = true;
+ _vm->refreshObjectList();
+ _vm->_wonNim = true;
+ _vm->_background->draw(-1, -1, 0); // Show the settle with no lute on it.
+
+ // 7 points for winning!
+ _vm->incScore(7);
+ }
+
+ if (_playedNim == 1) {
+ // 3 points for playing your 1st game.
+ _vm->incScore(3);
+ }
+}
+
+void Nim::chalk(int x, int y, Common::String text) {
+ const Color greys[] = { kColorBlack, kColorDarkgray, kColorLightgray, kColorWhite };
+
+ for (int i = 0; i < 4; i++) {
+ _vm->_graphics->drawNormalText(text, _vm->_font, 8, x - i, y, greys[i]);
+ _vm->_graphics->refreshScreen();
+ int freq = i * 100 * text.size();
+ if (freq == 0)
+ _vm->_system->delayMillis(3);
+ else
+ _vm->_sound->playNote(freq, 3);
+ _vm->_system->delayMillis(30);
+ }
+}
+
+void Nim::setup() {
+ _vm->fadeIn();
+ _vm->_graphics->nimLoad();
+
+ _vm->_graphics->blackOutScreen();
+ // Upper left rectangle.
+ _vm->_graphics->drawRectangle(Common::Rect(10, 5, 381, 71), kColorRed);
+ _vm->_graphics->drawFilledRectangle(Common::Rect(11, 6, 380, 70), kColorBrown);
+ // Bottom right rectangle.
+ _vm->_graphics->drawRectangle(Common::Rect(394, 50, 635, 198), kColorRed);
+ _vm->_graphics->drawFilledRectangle(Common::Rect(395, 51, 634, 197), kColorBrown);
+
+ _vm->_graphics->nimDrawLogo();
+ _vm->_graphics->nimDrawInitials();
+
+ _vm->_graphics->drawNormalText("SCOREBOARD:", _vm->_font, 8, 475, 45, kColorWhite);
+ _vm->_graphics->drawNormalText("Turn:", _vm->_font, 8, 420, 55, kColorYellow);
+ _vm->_graphics->drawNormalText("Player:", _vm->_font, 8, 490, 55, kColorYellow);
+ _vm->_graphics->drawNormalText("Move:", _vm->_font, 8, 570, 55, kColorYellow);
+
+ chalk(27, 7, "Take pieces away with:");
+ chalk(77, 17, "1) the mouse (click leftmost)");
+ chalk(53, 27, "or 2) the keyboard:");
+ chalk(220, 27, Common::String(24) + '/' + 25 + ": choose row,");
+ chalk(164, 37, Common::String("+/- or ") + 27 + '/' + 26 + ": more/fewer,");
+ chalk(204, 47, "Enter: take stones.");
+
+ _vm->_graphics->refreshScreen();
+
+ for (int i = 0; i < 3; i++)
+ _stones[i] = i + 3;
+ _stonesLeft = 12;
+
+ _turns = 0;
+ _dogfoodsTurn = true;
+
+ _row = 0;
+ _number = 1;
+ for (int i = 0; i < 3; i++)
+ _old[i] = 0;
+}
+
+void Nim::board() {
+ _vm->_graphics->drawFilledRectangle(Common::Rect(57, 72, 393, 200), kColorBlack);
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < _stones[i]; j++)
+ _vm->_graphics->nimDrawStone(64 + j * 8 * 8, 75 + i * 35);
+ // It's practically the body of the Pascal function "plotstone()", reimplemented.
+ // It's the only place where we use it, so there's no reason to keep it separated as a function.
+ _vm->_graphics->refreshScreen();
+}
+
+void Nim::startMove() {
+ _turns++;
+ Common::String turnsStr = Common::String::format("%d", _turns);
+ int y = 55 + _turns * 10;
+ _dogfoodsTurn = !_dogfoodsTurn;
+ chalk(433, y, turnsStr);
+ chalk(493, y, kNames[_dogfoodsTurn]);
+ for (int i = 0; i < 3; i++)
+ _old[i] = _stones[i];
+}
+
+void Nim::showChanges() {
+ chalk(573, 55 + _turns * 10, Common::String('A' + _row) + Common::String('0' + _number));
+ board();
+ _stonesLeft -= _number;
+}
+
+void Nim::blip() {
+ _vm->_sound->playNote(1771, 3);
+}
+
+void Nim::findNextUp() {
+ while (_stones[_row] == 0) {
+ _row--;
+ if (_row < 0)
+ _row = 2;
+ }
+
+ if (_number > _stones[_row])
+ _number = _stones[_row];
+}
+
+void Nim::findNextDown() {
+ while (_stones[_row] == 0) {
+ _row++;
+ if (_row > 2)
+ _row = 0;
+ }
+
+ if (_number > _stones[_row])
+ _number = _stones[_row];
+}
+
+bool Nim::checkInput() {
+ while (!_vm->shouldQuit()) {
+ _vm->_graphics->refreshScreen();
+ Common::Event event;
+ while (_vm->getEvent(event)) {
+ if (event.type == Common::EVENT_LBUTTONUP) {
+ Common::Point cursorPos = _vm->getMousePos();
+
+ int8 newRow = (cursorPos.y / 2 - 38) / 35 - 1;
+ if ((newRow < 0) || (newRow > 2)) {
+ blip();
+ return false;
+ }
+
+ int8 newNum = _stones[newRow] - ((cursorPos.x - 64) / 64);
+ if ((newNum < 1) || (newNum > _stones[newRow])) {
+ blip();
+ return false;
+ }
+
+ _number = newNum;
+ _row = newRow;
+
+ return true;
+ } else if (event.type == Common::EVENT_KEYDOWN) {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_KP_PLUS:
+ if (_stones[_row] > _number)
+ _number++;
+ return false;
+ case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_KP_MINUS:
+ if (_number > 1)
+ _number--;
+ return false;
+ case Common::KEYCODE_1:
+ _number = 1;
+ return false;
+ case Common::KEYCODE_2:
+ if (_stones[_row] >= 2)
+ _number = 2;
+ return false;
+ case Common::KEYCODE_3:
+ if (_stones[_row] >= 3)
+ _number = 3;
+ else
+ _number = _stones[_row];
+ return false;
+ case Common::KEYCODE_4:
+ if (_stones[_row] >= 4)
+ _number = 4;
+ else
+ _number = _stones[_row];
+ return false;
+ case Common::KEYCODE_5:
+ if (_stones[_row] == 5)
+ _number = 5;
+ else
+ _number = _stones[_row];
+ return false;
+ case Common::KEYCODE_HOME:
+ _number = _stones[_row];
+ return false;
+ case Common::KEYCODE_END:
+ _number = 1;
+ return false;
+ case Common::KEYCODE_UP:
+ _row--;
+ if (_row < 0)
+ _row = 2;
+ findNextUp();
+ return false;
+ case Common::KEYCODE_DOWN:
+ _row++;
+ if (_row > 2)
+ _row = 0;
+ findNextDown();
+ return false;
+ case Common::KEYCODE_a:
+ if (_stones[0] != 0) {
+ _row = 0;
+ if (_number > _stones[_row])
+ _number = _stones[_row];
+ }
+ return false;
+ case Common::KEYCODE_b:
+ if (_stones[1] != 0) {
+ _row = 1;
+ if (_number > _stones[_row])
+ _number = _stones[_row];
+ }
+ return false;
+ case Common::KEYCODE_c:
+ if (_stones[2] != 0) {
+ _row = 2;
+ if (_number > _stones[_row])
+ _number = _stones[_row];
+ }
+ return false;
+ case Common::KEYCODE_PAGEUP:
+ _row = 0;
+ findNextDown();
+ return false;
+ case Common::KEYCODE_PAGEDOWN:
+ _row = 2;
+ findNextUp();
+ return false;
+ case Common::KEYCODE_RETURN:
+ return true;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void Nim::takeSome() {
+ _number = 1;
+
+ do {
+ byte sr;
+ do {
+ sr = _stones[_row];
+ if (sr == 0) {
+ if (_row == 2)
+ _row = 0;
+ else
+ _row++;
+ _number = 1;
+ }
+ } while (sr == 0);
+
+ if (_number > sr)
+ _number = sr;
+
+ int x1 = 63 + (_stones[_row] - _number) * 64;
+ int y1 = 38 + 35 * (_row + 1);
+ int x2 = 55 + _stones[_row] * 64;
+ int y2 = 64 + 35 * (_row + 1);
+ _vm->_graphics->drawRectangle(Common::Rect(x1, y1, x2, y2), kColorBlue); // Draw the selection rectangle.
+ _vm->_graphics->refreshScreen();
+
+ bool confirm = false;
+ do {
+ confirm = checkInput();
+
+ if (!confirm) {
+ _vm->_graphics->drawRectangle(Common::Rect(x1, y1, x2, y2), kColorBlack); // Erase the previous selection.
+ x1 = 63 + (_stones[_row] - _number) * 64;
+ y1 = 38 + 35 * (_row + 1);
+ x2 = 55 + _stones[_row] * 64;
+ y2 = 64 + 35 * (_row + 1);
+ _vm->_graphics->drawRectangle(Common::Rect(x1, y1, x2, y2), kColorBlue); // Draw the new one.
+ _vm->_graphics->refreshScreen();
+ }
+ } while (!confirm);
+
+ return;
+
+ } while (true);
+}
+
+void Nim::endOfGame() {
+ chalk(595, 55 + _turns * 10, "Wins!");
+ _vm->_graphics->drawNormalText("- - - Press any key... - - -", _vm->_font, 8, 100, 190, kColorWhite);
+
+ Common::Event event;
+ bool escape = false;
+ while (!_vm->shouldQuit() && !escape) {
+ _vm->_graphics->refreshScreen();
+ while (_vm->getEvent(event)) {
+ if ((event.type == Common::EVENT_LBUTTONUP) || (event.type == Common::EVENT_KEYDOWN)) {
+ escape = true;
+ break;
+ }
+ }
+ }
+
+ _vm->_graphics->nimFree();
+}
+
+bool Nim::find(byte x) {
+ bool ret = false;
+ for (int i = 0; i < 3; i++) {
+ if (_stones[i] == x) {
+ ret = true;
+ _inAp[i] = true;
+ }
+ }
+ return ret;
+}
+
+void Nim::findAp(byte start, byte stepSize) {
+ byte thisOne = 0;
+ byte matches = 0;
+
+ for (int i = 0; i < 3; i++)
+ _inAp[i] = 0; // Blank 'em all!
+
+ for (int i = 0; i < 3; i++) {
+ if (find(start + i * stepSize))
+ matches++;
+ else
+ thisOne = i;
+ }
+
+ // Now... Matches must be 0, 1, 2, or 3.
+ // 0 / 1 mean there are no A.P.s here, so we'll keep looking,
+ // 2 means there is a potential A.P.that we can create (ideal!), and
+ // 3 means that we're already in an A.P. (Trouble!)
+
+ byte ooo = 0; // Odd one out.
+
+ switch (matches) {
+ case 2:
+ for (int i = 0; i < 3; i++) { // Find which one didn't fit the A.P.
+ if (!_inAp[i])
+ ooo = i;
+ }
+
+ if (_stones[ooo] > (start + thisOne * stepSize)) { // Check if it's possible!
+ // Create an A.P.
+ _row = ooo; // Already calculated.
+ // Start + thisone * stepsize will give the amount we SHOULD have here.
+ _number = _stones[_row] - (start + thisOne * stepSize);
+ _lmo = true;
+ return;
+ }
+ break;
+ case 3: // We're actually IN an A.P! Trouble! Oooh dear.
+ // Take 1 from the largest pile.
+ _row = _r[2];
+ _number = 1;
+ _lmo = true;
+ return;
+ default:
+ break;
+ }
+}
+
+void Nim::dogFood() {
+ _lmo = false;
+ byte live = 0;
+ byte sr[3];
+
+ for (int i = 0; i < 3; i++) {
+ if (_stones[i] > 0) {
+ _r[live] = i;
+ sr[live] = _stones[i];
+ live++;
+ }
+ }
+
+ switch (live) {
+ case 1: // Only one is free - so take 'em all!
+ _row = _r[0];
+ _number = _stones[_r[0]];
+ return;
+ case 2: // Two are free - make them equal!
+ if (sr[0] > sr[1]) { // T > b
+ _row = _r[0];
+ _number = sr[0] - sr[1];
+ }
+ else if (sr[0] < sr[1]) { // B > t
+ _row = _r[1];
+ _number = sr[1] - sr[0];
+ }
+ else { // B = t... oh no, we've lost!
+ _row = _r[0];
+ _number = 1;
+ }
+ return;
+ case 3: {
+ // Ho hum... this'll be difficult!
+ // There are three possible courses of action when we have 3 lines left:
+ // 1) Look for 2 equal lines, then take the odd one out.
+ // 2) Look for A.P.s, and capitalise on them.
+ // 3) Go any old where.
+ const byte other[3][2] = { { 2, 3 }, { 1, 3 }, { 1, 2 } };
+
+ for (int i = 0; i < 3; i++) { // Look for 2 equal lines.
+ if (_stones[other[i][0]] == _stones[other[i][1]]) {
+ _row = i; // This row.
+ _number = _stones[i]; // All of 'em.
+ return;
+ }
+ }
+
+ bool sorted;
+ do {
+ sorted = true;
+ for (int i = 0; i < 2; i++) {
+ if (sr[i] > sr[i + 1]) {
+ byte temp = sr[i + 1];
+ sr[i + 1] = sr[i];
+ sr[i] = temp;
+
+ temp = _r[i + 1];
+ _r[i + 1] = _r[i];
+ _r[i] = temp;
+
+ sorted = false;
+ }
+ }
+ } while (!sorted);
+
+ // Now we look for A.P.s...
+ for (int i = 1; i <= 3; i++) {
+ findAp(i, 1); // There are 3 "1"s.
+ if (_lmo)
+ return; // Cut - out.
+ }
+ findAp(1, 2); // Only "2" possible.
+ if (_lmo)
+ return;
+
+ // A.P.search must have failed - use the default move.
+ _row = _r[2];
+ _number = 1;
+ return;
+ }
+ default:
+ break;
+ }
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/nim.h b/engines/avalanche/nim.h
new file mode 100644
index 0000000000..3c2f0455cf
--- /dev/null
+++ b/engines/avalanche/nim.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+ * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+ */
+
+#ifndef AVALANCHE_NIM_H
+#define AVALANCHE_NIM_H
+
+namespace Avalanche {
+
+class Nim {
+public:
+ Nim(AvalancheEngine *vm);
+ void resetVariables();
+ void synchronize(Common::Serializer &sz);
+ void playNim();
+
+private:
+ AvalancheEngine *_vm;
+
+ static const char * const kNames[2];
+
+ byte _old[3];
+ byte _stones[3];
+ byte _turns;
+ bool _dogfoodsTurn;
+ byte _stonesLeft;
+ bool _clicked;
+ int8 _row;
+ byte _number;
+ bool _squeak;
+ byte _playedNim; // How many times you've played Nim.
+
+ // Inner variables for dogFood(), find() and findAp().
+ bool _inAp[3];
+ bool _lmo; // Let Me Out!
+ byte _r[3];
+
+ void chalk(int x, int y, Common::String text);
+ void setup();
+ void board();
+ void startMove();
+ void showChanges();
+ void blip();
+ void findNextUp(); // Inner function for checkInput().
+ void findNextDown(); // Same as above.
+ bool checkInput(); // It returns TRUE if the player confirmed his selection of stones either by pressing RETURN or by clicking on a stone.
+ void takeSome();
+ void endOfGame();
+ bool find(byte x); // This gives TRUE if there's a pile with x stones in.
+ void findAp(byte start, byte stepSize);
+ void dogFood(); // AI procedure to play the game.
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_NIM_H
diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp
index fc176c78b0..220186ca5e 100644
--- a/engines/avalanche/parser.cpp
+++ b/engines/avalanche/parser.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -27,6 +27,7 @@
#include "avalanche/avalanche.h"
#include "avalanche/parser.h"
+#include "avalanche/nim.h"
#include "gui/saveload.h"
@@ -37,6 +38,21 @@ const char *Parser::kVersionNum = "1.30";
Parser::Parser(AvalancheEngine *vm) {
_vm = vm;
+
+ _verb = kVerbCodePardon;
+ _thing = kPardon;
+ _person = kPeopleNone;
+ _polite = false;
+ _inputTextPos = 0;
+ _quote = false;
+ _cursorState = false;
+ _weirdWord = false;
+ _wearing = kNothing;
+ _thing2 = 0;
+ _sworeNum = 0;
+ _alcoholLevel = 0;
+
+ _boughtOnion = false;
}
void Parser::init() {
@@ -365,8 +381,8 @@ void Parser::init() {
void Parser::handleInputText(const Common::Event &event) {
byte inChar = event.kbd.ascii;
warning("STUB: Parser::handleInputText()");
-// if (_vm->_menu->_activeMenuItem._activeNow) {
-// _vm->_menu->parseKey(inChar, _vm->_enhanced->extd);
+// if (_vm->_dropdown->_activeMenuItem._activeNow) {
+// _vm->_dropdown->parseKey(inChar, _vm->_enhanced->extd);
// } else {
if (_inputText.size() < 76) {
if ((inChar == '"') || (inChar == '`')) {
@@ -386,7 +402,7 @@ void Parser::handleInputText(const Common::Event &event) {
}
void Parser::handleBackspace() {
- if (_vm->_menu->_activeMenuItem._activeNow)
+ if (_vm->_dropdown->_activeMenuItem._activeNow)
return;
if (_inputTextPos > 0) {
@@ -400,7 +416,7 @@ void Parser::handleBackspace() {
}
void Parser::handleReturn() {
- if (_vm->_menu->_activeMenuItem._activeNow)
+ if (_vm->_dropdown->_activeMenuItem._activeNow)
tryDropdown();
else if (!_inputText.empty()) {
_inputTextBackup = _inputText;
@@ -452,7 +468,7 @@ void Parser::handleFunctionKey(const Common::Event &event) {
break;
case Common::KEYCODE_F7:
if (event.kbd.flags & Common::KBD_CTRL)
- _vm->majorRedraw();
+ _vm->_graphics->refreshScreen();
else
_vm->callVerb(kVerbCodeOpen);
break;
@@ -506,10 +522,17 @@ void Parser::cursorOff() {
_cursorState = false;
}
+/**
+ * Asks the parsekey proc in Dropdown if it knows it.
+ */
void Parser::tryDropdown() {
- warning("STUB: Parser::tryDropdown()"); // TODO: Implement at the same time with Dropdown's keyboard handling.
+ // TODO: Implement at the same time with Dropdown's keyboard handling.
+ warning("STUB: Parser::tryDropdown()");
}
+/**
+ * Returns the index of the first appearance of crit in src.
+ */
int16 Parser::getPos(const Common::String &crit, const Common::String &src) {
if (src.contains(crit))
return strstr(src.c_str(),crit.c_str()) - src.c_str();
@@ -579,7 +602,7 @@ Common::String Parser::rank() {
};
for (int i = 0; i < 8; i++) {
- if ((_vm->_dnascore >= ranks[i]._score) && (_vm->_dnascore < ranks[i + 1]._score))
+ if ((_vm->_score >= ranks[i]._score) && (_vm->_score < ranks[i + 1]._score))
return Common::String(ranks[i]._title);
}
return "";
@@ -588,8 +611,12 @@ Common::String Parser::rank() {
Common::String Parser::totalTime() {
uint16 h, m, s;
- h = (uint16)(_vm->_totalTime / 65535);
- s = (uint16)(_vm->_totalTime % 65535);
+ uint32 curTime = _vm->getTimeInSeconds() - _vm->_startTime;
+ if (_vm->_isLoaded)
+ curTime += _vm->_totalTime;
+
+ h = (uint16)(curTime / 3600);
+ s = (uint16)(curTime % 3600);
m = s / 60;
s = s % 60;
@@ -605,6 +632,9 @@ void Parser::cheatParse(Common::String codes) {
warning("STUB: Parser::cheatParse()");
}
+/**
+ * Strips punctuation from word.
+ */
void Parser::stripPunctuation(Common::String &word) {
const char punct[] = "~`!@#$%^&*()_+-={}[]:\"|;'\\,./<>?";
@@ -692,13 +722,13 @@ void Parser::storeInterrogation(byte interrogation) {
case 1:
_inputText.toLowercase();
_vm->_dialogs->sayIt(_inputText);
- _vm->_favouriteDrink = _inputText;
+ _vm->_favoriteDrink = _inputText;
_vm->_cardiffQuestionNum = 2;
break;
case 2:
properNouns();
_vm->_dialogs->sayIt(_inputText);
- _vm->_favouriteSong = _inputText;
+ _vm->_favoriteSong = _inputText;
_vm->_cardiffQuestionNum = 3;
break;
case 3:
@@ -713,7 +743,7 @@ void Parser::storeInterrogation(byte interrogation) {
if (!_vm->_spareEvening.empty())
_vm->_spareEvening.clear();
_vm->_spareEvening = _inputText;
- _vm->_dialogs->displayScrollChain('z', 5); // His closing statement...
+ _vm->_dialogs->displayScrollChain('Z', 5); // His closing statement...
_vm->_animation->_sprites[1]->walkTo(3); // The end of the drawbridge
_vm->_animation->_sprites[1]->_vanishIfStill = true; // Then go away!
_vm->_magics[1]._operation = kMagicNothing;
@@ -729,8 +759,6 @@ void Parser::storeInterrogation(byte interrogation) {
_vm->_timer->cardiffSurvey();
}
-
-
void Parser::parse() {
// First parsing - word identification
if (!_thats.empty())
@@ -743,7 +771,6 @@ void Parser::parse() {
_person = kPeoplePardon;
clearWords();
-
// A cheat mode attempt.
if (_inputText[0] == '.') {
cheatParse(_inputText);
@@ -906,7 +933,7 @@ void Parser::parse() {
_polite = true;
}
- if ((!unkString.empty()) && (_verb != kVerbCodeExam) && (_verb != kVerbCodeTalk) &&
+ if ((!unkString.empty()) && (_verb != kVerbCodeExam) && (_verb != kVerbCodeTalk) &&
(_verb != kVerbCodeSave) && (_verb != kVerbCodeLoad) && (_verb != kVerbCodeDir)) {
Common::String tmpStr = Common::String::format("Sorry, but I have no idea what \"%s\" means. Can you rephrase it?", unkString.c_str());
_vm->_dialogs->displayText(tmpStr);
@@ -928,6 +955,9 @@ void Parser::parse() {
}
}
+/**
+ * Examine a standard object-thing
+ */
void Parser::examineObject() {
if (_thing != _vm->_thinks)
_vm->thinkAbout(_thing, AvalancheEngine::kThing);
@@ -937,29 +967,29 @@ void Parser::examineObject() {
switch (_vm->_wineState) {
case 1:
// Normal examine wine scroll
- _vm->_dialogs->displayScrollChain('t', 1);
+ _vm->_dialogs->displayScrollChain('T', 1);
break;
case 2:
// Bad wine
- _vm->_dialogs->displayScrollChain('d', 6);
+ _vm->_dialogs->displayScrollChain('D', 6);
break;
case 3:
// Vinegar
- _vm->_dialogs->displayScrollChain('d', 7);
+ _vm->_dialogs->displayScrollChain('D', 7);
break;
}
break;
case kObjectOnion:
if (_vm->_rottenOnion)
// Yucky onion
- _vm->_dialogs->displayScrollChain('q', 21);
+ _vm->_dialogs->displayScrollChain('Q', 21);
else
// Normal onion
- _vm->_dialogs->displayScrollChain('t', 18);
+ _vm->_dialogs->displayScrollChain('T', 18);
break;
default:
// Ordinarily
- _vm->_dialogs->displayScrollChain('t', _thing);
+ _vm->_dialogs->displayScrollChain('T', _thing);
}
}
@@ -992,7 +1022,7 @@ void Parser::exampers() {
// He's asleep.
_vm->_dialogs->displayScrollChain('Q', 65);
else
- _vm->_dialogs->displayScrollChain('p', newPerson);
+ _vm->_dialogs->displayScrollChain('P', newPerson);
if ((_person == kPeopleAyles) && !_vm->_aylesIsAwake)
_vm->_dialogs->displayScrollChain('Q', 13);
@@ -1010,15 +1040,20 @@ bool Parser::isHolding() {
// Also object
if ((51 <= _thing) && (_thing <= 99))
return true;
+ if (_thing == 0)
+ return false;
bool holdingResult = false;
- if (_thing > 100)
+ if (_thing >= 100)
_vm->_dialogs->displayText("Be reasonable!");
- else if (!_vm->_objects[_thing - 1])
- // Verbs that need "_thing" to be in the inventory.
- _vm->_dialogs->displayText("You're not holding it, Avvy.");
- else
+ else if (_thing <= kObjectNum) {
+ if (!_vm->_objects[_thing - 1])
+ // Verbs that need "_thing" to be in the inventory.
+ _vm->_dialogs->displayText("You're not holding it, Avvy.");
+ else
+ holdingResult = true;
+ } else
holdingResult = true;
return holdingResult;
@@ -1053,8 +1088,10 @@ void Parser::examine() {
examineObject();
else if ((50 <= _thing) && (_thing <= 100)) {
// Also _thing
+ int id = _thing - 50;
+ assert(id < 31);
openBox(true);
- _vm->_dialogs->displayText(*_vm->_also[_thing - 50][1]);
+ _vm->_dialogs->displayText(*_vm->_also[id][1]);
openBox(false);
}
}
@@ -1107,7 +1144,7 @@ void Parser::swallow() {
return;
}
_vm->_dialogs->displayScrollChain('U', 1);
- _vm->_pingo->wobble();
+ _vm->_animation->wobble();
_vm->_dialogs->displayScrollChain('U', 2);
_vm->_objects[kObjectWine - 1] = false;
_vm->refreshObjectList();
@@ -1116,7 +1153,7 @@ void Parser::swallow() {
case 2:
case 3:
// You can't drink it!
- _vm->_dialogs->displayScrollChain('d', 8);
+ _vm->_dialogs->displayScrollChain('D', 8);
break;
}
break;
@@ -1153,6 +1190,9 @@ void Parser::swallow() {
}
}
+/**
+ * this lists the other people in the room.
+ */
void Parser::peopleInRoom() {
// First compute the number of people in the room.
byte numPeople = 0;
@@ -1190,42 +1230,45 @@ void Parser::peopleInRoom() {
_vm->_dialogs->displayText(tmpStr + " here.");
}
+/**
+ * This is called when you say "look".
+ */
void Parser::lookAround() {
_vm->_dialogs->displayText(*_vm->_also[0][1]);
switch (_vm->_room) {
case kRoomSpludwicks:
if (_vm->_avariciusTalk > 0)
- _vm->_dialogs->displayScrollChain('q', 23);
+ _vm->_dialogs->displayScrollChain('Q', 23);
else
peopleInRoom();
break;
case kRoomRobins:
if (_vm->_tiedUp)
- _vm->_dialogs->displayScrollChain('q', 38);
+ _vm->_dialogs->displayScrollChain('Q', 38);
if (_vm->_mushroomGrowing)
- _vm->_dialogs->displayScrollChain('q', 55);
+ _vm->_dialogs->displayScrollChain('Q', 55);
break;
case kRoomInsideCardiffCastle:
if (!_vm->_takenPen)
- _vm->_dialogs->displayScrollChain('q', 49);
+ _vm->_dialogs->displayScrollChain('Q', 49);
break;
case kRoomLustiesRoom:
if (_vm->_lustieIsAsleep)
- _vm->_dialogs->displayScrollChain('q', 65);
+ _vm->_dialogs->displayScrollChain('Q', 65);
break;
case kRoomCatacombs:
switch (_vm->_catacombY * 256 + _vm->_catacombX) {
case 258 :
// Inside art gallery.
- _vm->_dialogs->displayScrollChain('q', 80);
+ _vm->_dialogs->displayScrollChain('Q', 80);
break;
case 514 :
// Outside ditto.
- _vm->_dialogs->displayScrollChain('q', 81);
+ _vm->_dialogs->displayScrollChain('Q', 81);
break;
case 260 :
// Outside Geida's room.
- _vm->_dialogs->displayScrollChain('q', 82);
+ _vm->_dialogs->displayScrollChain('Q', 82);
break;
}
break;
@@ -1248,7 +1291,7 @@ void Parser::openDoor() {
break;
case kRoomSpludwicks:
if (_thing == 61) {
- _vm->_dialogs->displayScrollChain('q', 85);
+ _vm->_dialogs->displayScrollChain('Q', 85);
return;
}
break;
@@ -1266,7 +1309,7 @@ void Parser::openDoor() {
switch (portal->_operation) {
case kMagicExclaim:
_vm->_animation->_sprites[0]->bounce();
- _vm->_dialogs->displayScrollChain('x', portal->_data);
+ _vm->_dialogs->displayScrollChain('X', portal->_data);
break;
case kMagicTransport:
_vm->flipRoom((Room)((portal->_data) >> 8), portal->_data & 0x0F);
@@ -1294,6 +1337,9 @@ void Parser::openDoor() {
_vm->_dialogs->displayText("Door? What door?");
}
+/**
+ * Called when you call kVerbCodeput.
+ */
void Parser::putProc() {
if (!isHolding())
return;
@@ -1322,7 +1368,7 @@ void Parser::putProc() {
// Put onion into vinegar! Yes!
_vm->_onionInVinegar = true;
_vm->incScore(7);
- _vm->_dialogs->displayScrollChain('u', 9);
+ _vm->_dialogs->displayScrollChain('U', 9);
}
}
} else
@@ -1400,6 +1446,7 @@ void Parser::goToCauldron() {
/**
* Check is it's possible to give something to Spludwick
+ * The result of this function is whether or not he says "Hey, thanks!".
* @remarks Originally called 'give2spludwick'
*/
bool Parser::giveToSpludwick() {
@@ -1412,10 +1459,10 @@ bool Parser::giveToSpludwick() {
case kObjectOnion:
_vm->_objects[kObjectOnion - 1] = false;
if (_vm->_rottenOnion)
- _vm->_dialogs->displayScrollChain('q', 22);
+ _vm->_dialogs->displayScrollChain('Q', 22);
else {
_vm->_givenToSpludwick++;
- _vm->_dialogs->displayScrollChain('q', 20);
+ _vm->_dialogs->displayScrollChain('Q', 20);
goToCauldron();
_vm->incScore(3);
}
@@ -1425,13 +1472,13 @@ bool Parser::giveToSpludwick() {
_vm->_objects[kObjectInk - 1] = false;
_vm->refreshObjectList();
_vm->_givenToSpludwick++;
- _vm->_dialogs->displayScrollChain('q', 24);
+ _vm->_dialogs->displayScrollChain('Q', 24);
goToCauldron();
_vm->incScore(3);
break;
case kObjectMushroom:
_vm->_objects[kObjectMushroom - 1] = false;
- _vm->_dialogs->displayScrollChain('q', 25);
+ _vm->_dialogs->displayScrollChain('Q', 25);
_vm->incScore(5);
_vm->_givenToSpludwick++;
goToCauldron();
@@ -1479,6 +1526,9 @@ void Parser::already() {
_vm->_dialogs->displayText("You're already standing!");
}
+/**
+ * Called when you ask Avvy to stand.
+ */
void Parser::standUp() {
switch (_vm->_room) {
case kRoomYours:
@@ -1486,9 +1536,9 @@ void Parser::standUp() {
if (_vm->_avvyIsAwake && _vm->_avvyInBed) {
// But he's in bed.
if (_vm->_teetotal) {
- _vm->_dialogs->displayScrollChain('d', 12);
+ _vm->_dialogs->displayScrollChain('D', 12);
_vm->_graphics->setBackgroundColor(kColorBlack);
- _vm->_dialogs->displayScrollChain('d', 14);
+ _vm->_dialogs->displayScrollChain('D', 14);
}
_vm->_animation->_sprites[0]->_visible = true;
_vm->_userMovesAvvy = true;
@@ -1543,7 +1593,7 @@ void Parser::getProc(char thing) {
_vm->_dialogs->displayText(tmpStr);
}
} else
- _vm->_dialogs->displayScrollChain('q', 57);
+ _vm->_dialogs->displayScrollChain('Q', 57);
break;
case kRoomInsideCardiffCastle:
switch (thing) {
@@ -1564,15 +1614,15 @@ void Parser::getProc(char thing) {
_vm->_dialogs->displayText("Taken.");
}
} else if (_vm->_standingOnDais)
- _vm->_dialogs->displayScrollChain('q', 53);
+ _vm->_dialogs->displayScrollChain('Q', 53);
else
- _vm->_dialogs->displayScrollChain('q', 51);
+ _vm->_dialogs->displayScrollChain('Q', 51);
break;
case kObjectBolt:
- _vm->_dialogs->displayScrollChain('q', 52);
+ _vm->_dialogs->displayScrollChain('Q', 52);
break;
default:
- _vm->_dialogs->displayScrollChain('q', 57);
+ _vm->_dialogs->displayScrollChain('Q', 57);
}
break;
case kRoomRobins:
@@ -1585,10 +1635,10 @@ void Parser::getProc(char thing) {
_vm->refreshObjectList();
_vm->incScore(3);
} else
- _vm->_dialogs->displayScrollChain('q', 57);
+ _vm->_dialogs->displayScrollChain('Q', 57);
break;
default:
- _vm->_dialogs->displayScrollChain('q', 57);
+ _vm->_dialogs->displayScrollChain('Q', 57);
}
}
@@ -1605,7 +1655,7 @@ void Parser::giveGeidaTheLute() {
_vm->_objects[kObjectLute - 1] = false;
_vm->refreshObjectList();
// She plays it.
- _vm->_dialogs->displayScrollChain('q', 64);
+ _vm->_dialogs->displayScrollChain('Q', 64);
_vm->_timer->addTimer(1, Timer::kProcGiveLuteToGeida, Timer::kReasonGeidaSings);
//_vm->_enid->backToBootstrap(4); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then!
@@ -1619,7 +1669,7 @@ void Parser::playHarp() {
}
void Parser::winSequence() {
- _vm->_dialogs->displayScrollChain('q', 78);
+ _vm->_dialogs->displayScrollChain('Q', 78);
_vm->_sequence->startWinSeq();
_vm->_timer->addTimer(30, Timer::kProcWinning, Timer::kReasonWinning);
}
@@ -1644,6 +1694,10 @@ void Parser::doThat() {
// "Slip" object
_thing -= 49;
+ if (_vm->_tiedUp) {
+ _vm->_dialogs->displayText("You better stay quiet now!");
+ return;
+ }
if ((_verb != kVerbCodeLoad) && (_verb != kVerbCodeSave) && (_verb != kVerbCodeQuit) && (_verb != kVerbCodeInfo) && (_verb != kVerbCodeHelp)
&& (_verb != kVerbCodeLarrypass) && (_verb != kVerbCodePhaon) && (_verb != kVerbCodeBoss) && (_verb != kVerbCodeCheat) && (_verb != kVerbCodeRestart)
@@ -1653,7 +1707,7 @@ void Parser::doThat() {
"Try restarting, or restoring a saved game!");
return;
}
- if (!_vm->_avvyIsAwake && (_verb != kVerbCodeDie) && (_verb != kVerbCodeExpletive) && (_verb != kVerbCodeWake)) {
+ if (!_vm->_avvyIsAwake && (_verb != kVerbCodeWake)) {
_vm->_dialogs->displayText("Talking in your sleep? Try waking up!");
return;
}
@@ -1666,7 +1720,7 @@ void Parser::doThat() {
case kVerbCodeOpen:
openDoor();
break;
- case kVerbCodePause: {
+ case kVerbCodePause: {
// Note that the original game doesn't care about the "O.K." box neither, it accepts
// clicks from everywhere on the screen to continue. Just like my code.
Common::String tmpStr = Common::String::format("Game paused.%c%c%cPress Enter, Esc, or click the mouse on the `O.K.\" " \
@@ -1758,7 +1812,7 @@ void Parser::doThat() {
break;
case kPeopleIbythneth:
if (_thing == kObjectBadge) {
- _vm->_dialogs->displayScrollChain('q', 32); // Thanks! Wow!
+ _vm->_dialogs->displayScrollChain('Q', 32); // Thanks! Wow!
_vm->incScore(3);
_vm->_objects[kObjectBadge - 1] = false;
_vm->_objects[kObjectHabit - 1] = true;
@@ -1772,7 +1826,7 @@ void Parser::doThat() {
if (_vm->_aylesIsAwake) {
if (_thing == kObjectPen) {
_vm->_objects[kObjectPen - 1] = false;
- _vm->_dialogs->displayScrollChain('q', 54);
+ _vm->_dialogs->displayScrollChain('Q', 54);
_vm->_objects[kObjectInk - 1] = true;
_vm->_givenPenToAyles = true;
_vm->refreshObjectList();
@@ -1787,7 +1841,7 @@ void Parser::doThat() {
case kObjectPotion:
_vm->_objects[kObjectPotion - 1] = false;
// She drinks it.
- _vm->_dialogs->displayScrollChain('u', 16);
+ _vm->_dialogs->displayScrollChain('U', 16);
_vm->incScore(2);
_vm->_givenPotionToGeida = true;
_vm->refreshObjectList();
@@ -1806,7 +1860,7 @@ void Parser::doThat() {
winSequence();
else
// That Geida woman!
- _vm->_dialogs->displayScrollChain('q', 77);
+ _vm->_dialogs->displayScrollChain('Q', 77);
break;
default:
_vm->_dialogs->sayThanks(_thing - 1);
@@ -1836,7 +1890,7 @@ void Parser::doThat() {
if (savegameId < 0)
// dialog aborted, nothing to load
return;
-
+
_vm->loadGame(savegameId);
}
break;
@@ -1940,45 +1994,7 @@ void Parser::doThat() {
// They just typed "play"...
switch (_vm->_room) {
case kRoomArgentPub:
- // ...in the pub, => play Nim.
- warning("STUB: Parser::doThat() - case kVerbCodeplay - play_nim()");
- // play_nim();
-
- // The following parts are copied from play_nim().
- // The player automatically wins the game everytime he wins, until I implement the mini-game.
- if (_vm->_wonNim) { // Already won the game.
- _vm->_dialogs->displayScrollChain('Q', 6);
- return;
- }
-
- if (!_vm->_askedDogfoodAboutNim) {
- _vm->_dialogs->displayScrollChain('q', 84);
- return;
- }
-
- _vm->_dialogs->displayScrollChain('Q', 3);
- _playedNim++;
-
- // You won - strange!
-
- // You won! Give us a lute!
- _vm->_dialogs->displayScrollChain('Q', 7);
- _vm->_objects[kObjectLute - 1] = true;
- _vm->refreshObjectList();
- _vm->_wonNim = true;
- // Show the settle with no lute on it.
- _vm->_background->draw(-1, -1, 0);
- // 7 points for winning!
- _vm->incScore(7);
-
- if (_playedNim == 1)
- // 3 points for playing your 1st game.
- _vm->incScore(3);
-
- // A warning to the player that there should have been a mini-game. TODO: Remove it later!!!
- _vm->_dialogs->displayText(Common::String("P.S.: There should have been the mini-game called \"Nim\", " \
- "but I haven't implemented it yet: you win and get the lute automatically.")
- + kControlNewLine + kControlNewLine + "Peter (uruk)");
+ _vm->_nim->playNim(); // ...in the pub, => play Nim.
break;
case kRoomMusicRoom:
playHarp();
@@ -2005,8 +2021,7 @@ void Parser::doThat() {
break;
case 55:
if (_vm->_room == kRoomArgentPub)
- // play_nim();
- warning("STUB: Parser::doThat() - case kVerbCodeplay - play_nim()");
+ _vm->_nim->playNim();
else
_vm->_dialogs->displayText(kWhat);
break;
@@ -2027,8 +2042,7 @@ void Parser::doThat() {
}
break;
case kVerbCodeHelp:
- // boot_help();
- warning("STUB: Parser::doThat() - case kVerbCodehelp");
+ _vm->_help->run();
break;
case kVerbCodeLarrypass:
_vm->_dialogs->displayText("Wrong game!");
@@ -2037,8 +2051,7 @@ void Parser::doThat() {
_vm->_dialogs->displayText("Hello, Phaon!");
break;
case kVerbCodeBoss:
- // bosskey();
- warning("STUB: Parser::doThat() - case kVerbCodeboss");
+ bossKey();
break;
case kVerbCodePee:
if (_vm->getFlag('P')) {
@@ -2057,13 +2070,13 @@ void Parser::doThat() {
break;
case kVerbCodeMagic:
if (_vm->_avariciusTalk > 0)
- _vm->_dialogs->displayScrollChain('q', 19);
+ _vm->_dialogs->displayScrollChain('Q', 19);
else {
if ((_vm->_room == kRoomSpludwicks) & (_vm->_animation->inField(1))) {
// Avaricius appears!
- _vm->_dialogs->displayScrollChain('q', 17);
+ _vm->_dialogs->displayScrollChain('Q', 17);
if (_vm->getRoom(kPeopleSpludwick) == kRoomSpludwicks)
- _vm->_dialogs->displayScrollChain('q', 18);
+ _vm->_dialogs->displayScrollChain('Q', 18);
else {
Avalanche::AnimationType *spr = _vm->_animation->_sprites[1];
// Avaricius
@@ -2097,7 +2110,7 @@ void Parser::doThat() {
}
break;
default: {
- _vm->_pingo->zonk();
+ _vm->_animation->thunder();
Common::String tmpStr = Common::String::format("A crack of lightning shoots from the sky, and fries you." \
"%c%c(`Such is the anger of the gods, Avvy!\")", kControlNewLine, kControlNewLine);
_vm->_dialogs->displayText(tmpStr);
@@ -2217,7 +2230,7 @@ void Parser::doThat() {
case kRoomNottsPub:
// Can't sell to southerners.
- _vm->_dialogs->displayScrollChain('n', 15);
+ _vm->_dialogs->displayScrollChain('N', 15);
break;
default:
// Can't buy that.
@@ -2293,7 +2306,7 @@ void Parser::doThat() {
break;
case kVerbCodeScore: {
Common::String tmpStr = Common::String::format("Your score is %d,%c%cout of a possible 128.%c%c " \
- "This gives you a rank of %s.%c%c%s", _vm->_dnascore, kControlCenter, kControlNewLine, kControlNewLine,
+ "This gives you a rank of %s.%c%c%s", _vm->_score, kControlCenter, kControlNewLine, kControlNewLine,
kControlNewLine, rank().c_str(), kControlNewLine, kControlNewLine, totalTime().c_str());
_vm->_dialogs->displayText(tmpStr);
}
@@ -2354,7 +2367,7 @@ void Parser::doThat() {
// Picture of Avvy, awake in bed.
_vm->_background->draw(-1, -1, 2);
if (_vm->_teetotal)
- _vm->_dialogs->displayScrollChain('d', 13);
+ _vm->_dialogs->displayScrollChain('D', 13);
} else
_vm->_dialogs->displayText("You're already awake, Avvy!");
break;
@@ -2411,6 +2424,25 @@ void Parser::doThat() {
}
}
+void Parser::bossKey() {
+ _vm->_graphics->saveScreen();
+ _vm->_graphics->blackOutScreen();
+ _vm->_graphics->loadMouse(kCurUpArrow);
+ _vm->loadBackground(98);
+ _vm->_graphics->drawNormalText("Graph/Histo/Draw/Sample: \"JANJUN93.GRA\": (W3-AB3)", _vm->_font, 8, 120, 169, kColorDarkgray);
+ _vm->_graphics->drawNormalText("Press any key or click the mouse to return.", _vm->_font, 8, 144, 182, kColorDarkgray);
+ _vm->_graphics->refreshScreen();
+ Common::Event event;
+ _vm->getEvent(event);
+ while ((!_vm->shouldQuit()) && (event.type != Common::EVENT_KEYDOWN) && (event.type != Common::EVENT_LBUTTONDOWN)){
+ _vm->getEvent(event);
+ _vm->_graphics->refreshScreen();
+ }
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+ _vm->loadBackground(_vm->_room);
+}
+
void Parser::verbOpt(byte verb, Common::String &answer, char &ansKey) {
// kVerbCodegive isn't dealt with by this procedure, but by ddm__with.
switch (verb) {
@@ -2452,10 +2484,9 @@ void Parser::doVerb(VerbCode id) {
}
void Parser::resetVariables() {
- _wearing = 0;
+ _wearing = kNothing;
_sworeNum = 0;
_alcoholLevel = 0;
- _playedNim = 0;
_boughtOnion = false;
}
@@ -2463,7 +2494,10 @@ void Parser::synchronize(Common::Serializer &sz) {
sz.syncAsByte(_wearing);
sz.syncAsByte(_sworeNum);
sz.syncAsByte(_alcoholLevel);
- sz.syncAsByte(_playedNim);
+ if (sz.isLoading() && sz.getVersion() < 2) {
+ int dummy;
+ sz.syncAsByte(dummy);
+ }
sz.syncAsByte(_boughtOnion);
}
diff --git a/engines/avalanche/parser.h b/engines/avalanche/parser.h
index 261e5ecefe..6133c41442 100644
--- a/engines/avalanche/parser.h
+++ b/engines/avalanche/parser.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -34,17 +34,16 @@
#include "common/str.h"
#include "common/serializer.h"
-
namespace Avalanche {
class AvalancheEngine;
class Parser {
public:
- static const byte kPardon = 254; // Didn't understand / wasn't given.
static const int16 kParserWordsNum = 277; // How many words does the parser know?
+ static const int16 kFirstPassword = 88; // words[kFirstPassword] should equal "TIROS".
+ static const byte kPardon = 254; // Didn't understand / wasn't given.
static const byte kNothing = 250;
- static const byte kMoved = 0; // This word was moved. (Usually because it was the subject of conversation.)
- static const int16 kFirstPassword = 88; // words[kFirstPassword] should equal "TIROS".
+ static const byte kMoved = 0; // This word was moved. (Usually because it was the subject of conversation.)
struct VocabEntry {
byte _number;
@@ -63,23 +62,21 @@ public:
byte _thing;
People _person;
bool _polite;
- Common::String _inputText; // Original name: current
+ Common::String _inputText;
Common::String _inputTextBackup;
- byte _inputTextPos; // Original name: curpos
- bool _quote; // 66 or 99 next?
+ byte _inputTextPos;
+ bool _quote;
bool _cursorState;
bool _weirdWord;
byte _wearing; // what you're wearing
Parser(AvalancheEngine *vm);
-
void init();
void parse();
void doThat();
void verbOpt(byte verb, Common::String &answer, char &ansKey);
void drink();
-
void handleInputText(const Common::Event &event);
void handleBackspace();
void handleReturn();
@@ -87,10 +84,10 @@ public:
void plotText();
void cursorOn();
void cursorOff();
- void tryDropdown(); // This asks the parsekey proc in Dropdown if it knows it.
- int16 getPos(const Common::String &crit, const Common::String &src); // Returns the index of the first appearance of crit in src.
+ void tryDropdown();
+ int16 getPos(const Common::String &crit, const Common::String &src);
void doVerb(VerbCode id);
-
+ Common::String rank();
void resetVariables();
void synchronize(Common::Serializer &sz);
@@ -107,27 +104,23 @@ private:
Common::String _thats;
byte _thing2;
- byte _sworeNum; // number of times you've sworn
+ byte _sworeNum; // number of times you've sworn
byte _alcoholLevel; // Your blood alcohol level.
- byte _playedNim; // How many times you've played Nim.
- bool _boughtOnion; // Have you bought an onion yet?
+ bool _boughtOnion; // Have you bought an onion yet?
byte wordNum(Common::String word);
void replace(Common::String oldChars, byte newChar);
-
- Common::String rank();
Common::String totalTime();
-
void clearWords();
void cheatParse(Common::String codes);
- void stripPunctuation(Common::String &word); // Strips punctuation from word.
- void displayWhat(byte target, bool animate, bool &ambiguous); // << It's an adjective!
+ void stripPunctuation(Common::String &word);
+ void displayWhat(byte target, bool animate, bool &ambiguous);
bool doPronouns();
void properNouns();
- void lookAround(); // This is called when you say "look".
+ void lookAround();
void openDoor();
void storeInterrogation(byte interrogation);
- void examineObject(); // Examine a standard object-thing
+ void examineObject();
bool isPersonHere();
void exampers();
bool isHolding();
@@ -135,19 +128,20 @@ private:
void examine();
void inventory();
void swallow();
- void peopleInRoom(); // This lists the other people in the room.
- void putProc(); // Called when you call kVerbCodeput.
+ void peopleInRoom();
+ void putProc();
void notInOrder();
void goToCauldron();
- bool giveToSpludwick(); // The result of this fn is whether or not he says "Hey, thanks!".
+ bool giveToSpludwick();
void cardiffClimbing();
void already();
- void standUp(); // Called when you ask Avvy to stand.
+ void standUp();
void getProc(char thing);
void giveGeidaTheLute();
void playHarp();
void winSequence();
void wipeText();
+ void bossKey();
};
} // End of namespace Avalanche
diff --git a/engines/avalanche/pingo.cpp b/engines/avalanche/pingo.cpp
deleted file mode 100644
index 433924f594..0000000000
--- a/engines/avalanche/pingo.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-/*
- * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
- * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
- */
-
-/* PINGO Full-screen sub-parts of the game. */
-
-#include "avalanche/avalanche.h"
-#include "avalanche/pingo.h"
-
-namespace Avalanche {
-
-Pingo::Pingo(AvalancheEngine *vm) {
- _vm = vm;
-}
-
-void Pingo::dPlot(int16 x, int16 y, Common::String z) {
- warning("STUB: Pingo::dPlot()");
-}
-
-void Pingo::bossKey() {
- warning("STUB: Pingo::bossKey()");
-}
-
-void Pingo::copy02() { // taken from Wobble (below)
- warning("STUB: Pingo::copy02()");
-}
-
-void Pingo::copy03() { // taken from Wobble (below)
- warning("STUB: Pingo::copy03()");
-}
-
-void Pingo::copyPage(byte frp, byte top) { // taken from Copy02 (above)
- warning("STUB: Pingo::copyPage()");
-}
-
-void Pingo::wobble() {
- warning("STUB: Pingo::wobble()");
-}
-
-void Pingo::zl(int16 x1, int16 y1, int16 x2, int16 y2) {
- warning("STUB: Pingo::zl()");
-}
-
-void Pingo::zonk() {
- warning("STUB: Pingo::zonk()");
-}
-
-void Pingo::winningPic() {
- Common::File f;
- _vm->fadeOut();
-
- if (!f.open("finale.avd"))
- error("AVALANCHE: File not found: finale.avd");
-
-#if 0
- for (int bit = 0; bit <= 3; bit++) {
- port[0x3c4] = 2;
- port[0x3ce] = 4;
- port[0x3c5] = 1 << bit;
- port[0x3cf] = bit;
- blockread(f, mem[0xa000 * 0], 16000);
- }
-#endif
-
- f.close();
-
- warning("STUB: Pingo::winningPic()");
-
- _vm->fadeIn();
-
-#if 0
- do {
- _vm->check();
- } while (!(keypressed() || (mrelease > 0)));
- while (keypressed())
- char r = readkey();
- major_redraw();
-#endif
-
- warning("STUB: Pingo::winningPic()");
-}
-
-} // End of namespace Avalanche.
diff --git a/engines/avalanche/sequence.cpp b/engines/avalanche/sequence.cpp
index 10fa7f0a00..d63532a457 100644
--- a/engines/avalanche/sequence.cpp
+++ b/engines/avalanche/sequence.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -34,6 +34,8 @@ namespace Avalanche {
Sequence::Sequence(AvalancheEngine *vm) {
_vm = vm;
+
+ resetVariables();
}
void Sequence::resetVariables() {
diff --git a/engines/avalanche/sequence.h b/engines/avalanche/sequence.h
index d3c1b54963..8062118059 100644
--- a/engines/avalanche/sequence.h
+++ b/engines/avalanche/sequence.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/engines/avalanche/shootemup.cpp b/engines/avalanche/shootemup.cpp
new file mode 100644
index 0000000000..e5e44ed934
--- /dev/null
+++ b/engines/avalanche/shootemup.cpp
@@ -0,0 +1,693 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+*/
+
+#include "avalanche/avalanche.h"
+#include "avalanche/shootemup.h"
+
+#include "common/random.h"
+
+namespace Avalanche {
+
+const byte ShootEmUp::kStocks = 27;
+const byte ShootEmUp::kAvvyShoots = 86;
+const byte ShootEmUp::kFacingRight = 87;
+const byte ShootEmUp::kFacingLeft = 93;
+const long int ShootEmUp::kFlag = -20047;
+const byte ShootEmUp::kFrameDelayMax = 2;
+const byte ShootEmUp::kAvvyY = 150;
+const byte ShootEmUp::kShooting[7] = { 86, 79, 80, 81, 80, 79, 86 };
+const byte ShootEmUp::kTimesASecond = 18;
+const byte ShootEmUp::kFlashTime = 20; // If flash_time is <= this, the word "time" will flash. Should be about 20.
+const byte ShootEmUp::kLeftMargin = 10;
+const int16 ShootEmUp::kRightMargin = 605;
+
+ShootEmUp::ShootEmUp(AvalancheEngine *vm) {
+ _vm = vm;
+
+ _time = 120;
+ for (int i = 0; i < 7; i++)
+ _stockStatus[i] = 0;
+ for (int i = 0; i < 99; i++) {
+ _sprites[i]._ix = 0;
+ _sprites[i]._iy = 0;
+ _sprites[i]._x = kFlag;
+ _sprites[i]._y = 0;
+ _sprites[i]._p = 0;
+ _sprites[i]._timeout = 0;
+ _sprites[i]._cameo = false;
+ _sprites[i]._cameoFrame = 0;
+ _sprites[i]._missile = false;
+ _sprites[i]._wipe = false;
+ }
+ _rectNum = 0;
+ _avvyWas = 320;
+ _avvyPos = 320;
+ _avvyAnim = 1;
+ _avvyFacing = kFacingLeft;
+ _altWasPressedBefore = false;
+ _throwNext = 73;
+ _firing = false;
+ for (int i = 0; i < 4; i++) {
+ _running[i]._x = kFlag;
+ _running[i]._y = 0;
+ _running[i]._frame = 0;
+ _running[i]._tooHigh = 0;
+ _running[i]._lowest = 0;
+ _running[i]._ix = 0;
+ _running[i]._iy = 0;
+ _running[i]._frameDelay = 0;
+ }
+ for (int i = 0; i < 7; i++)
+ _hasEscaped[i] = false;
+ _count321 = 255; // Counting down.
+ _howManyHaveEscaped = 0;
+ _escapeCount = 0;
+ _escaping = false;
+ _timeThisSecond = 0;
+ _cp = false;
+ _wasFacing = 0;
+ _score = 0;
+ _escapeStock = 0;
+ _gotOut = false;
+}
+
+uint16 ShootEmUp::run() {
+ CursorMan.showMouse(false);
+ _vm->_graphics->saveScreen();
+ _vm->fadeOut();
+ _vm->_graphics->seuDrawTitle();
+ _vm->fadeIn();
+
+ _vm->_graphics->seuLoad();
+
+ // Should we show the instructions?
+ while (!_vm->shouldQuit()) {
+ Common::Event event;
+ _vm->getEvent(event);
+ if (event.type == Common::EVENT_KEYDOWN) {
+ if ((event.kbd.keycode == Common::KEYCODE_i) || (event.kbd.keycode == Common::KEYCODE_F1))
+ instructions();
+ break; // We don't show the instructions and simply go on with the minigame if not I or F1 was pressed.
+ }
+ }
+
+ setup();
+
+ while ((_time != 0) && (!_vm->shouldQuit())) {
+ uint32 beginLoop = _vm->_system->getMillis();
+
+ blankIt();
+ hitPeople();
+ plotThem();
+ moveThem();
+ moveAvvy();
+ bumpFolk();
+ peopleRunning();
+ animate();
+ escapeCheck();
+ collisionCheck();
+ updateTime();
+ check321();
+ readKbd();
+
+ _cp = !_cp;
+
+ _vm->_graphics->refreshScreen();
+
+ uint32 delay = _vm->_system->getMillis() - beginLoop;
+ if (delay <= 55)
+ _vm->_system->delayMillis(55 - delay); // Replaces slowdown(); 55 comes from 18.2 Hz (B Flight).
+ };
+
+ _vm->fadeOut();
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+ _vm->fadeIn();
+ CursorMan.showMouse(true);
+
+ return _score;
+}
+
+bool ShootEmUp::overlap(uint16 a1x, uint16 a1y, uint16 a2x, uint16 a2y, uint16 b1x, uint16 b1y, uint16 b2x, uint16 b2y) {
+ // By De Morgan's law:
+ return (a2x >= b1x) && (b2x >= a1x) && (a2y >= b1y) && (b2y >= a1y);
+}
+
+byte ShootEmUp::getStockNumber(byte index) {
+ while (_hasEscaped[index]) {
+ index++;
+ if (index == 7)
+ index = 0;
+ }
+ return index;
+}
+
+void ShootEmUp::blankIt() {
+ for (int i = 0; i < _rectNum; i++)
+ _vm->_graphics->drawFilledRectangle(_rectangles[i], kColorBlack);
+ _rectNum = 0;
+}
+
+void ShootEmUp::moveThem() {
+ for (int i = 0; i < 99; i++) {
+ if (_sprites[i]._x != kFlag) {
+ _sprites[i]._x += _sprites[i]._ix;
+ _sprites[i]._y += _sprites[i]._iy;
+ }
+ }
+}
+
+void ShootEmUp::blank(Common::Rect rect) {
+ _rectangles[_rectNum++] = rect;
+}
+
+void ShootEmUp::plotThem() {
+ for (int i = 0; i < 99; i++) {
+ if (_sprites[i]._x != kFlag) {
+ if (_sprites[i]._cameo) {
+ _vm->_graphics->seuDrawCameo(_sprites[i]._x, _sprites[i]._y, _sprites[i]._p, _sprites[i]._cameoFrame);
+ if (!_cp) {
+ _sprites[i]._cameoFrame += 2;
+ _sprites[i]._p += 2;
+ }
+ } else
+ _vm->_graphics->seuDrawPicture(_sprites[i]._x, _sprites[i]._y, _sprites[i]._p);
+
+ if (_sprites[i]._wipe)
+ blank(Common::Rect(_sprites[i]._x, _sprites[i]._y, _sprites[i]._x + _vm->_graphics->seuGetPicWidth(_sprites[i]._p), _sprites[i]._y + _vm->_graphics->seuGetPicHeight(_sprites[i]._p)));
+
+ if (_sprites[i]._timeout > 0) {
+ _sprites[i]._timeout--;
+ if (_sprites[i]._timeout == 0)
+ _sprites[i]._x = kFlag;
+ }
+ }
+ }
+}
+
+void ShootEmUp::define(int16 x, int16 y, int8 p, int8 ix, int8 iy, int16 time, bool isAMissile, bool doWeWipe) {
+ for (int i = 0; i < 99; i++) {
+ if (_sprites[i]._x == kFlag) {
+ _sprites[i]._x = x;
+ _sprites[i]._y = y;
+ _sprites[i]._p = p;
+ _sprites[i]._ix = ix;
+ _sprites[i]._iy = iy;
+ _sprites[i]._timeout = time;
+ _sprites[i]._cameo = false;
+ _sprites[i]._missile = isAMissile;
+ _sprites[i]._wipe = doWeWipe;
+ return;
+ }
+ }
+}
+
+void ShootEmUp::defineCameo(int16 x, int16 y, int8 p, int16 time) {
+ for (int i = 0; i < 99; i++) {
+ if (_sprites[i]._x == kFlag) {
+ _sprites[i]._x = x;
+ _sprites[i]._y = y;
+ _sprites[i]._p = p;
+ _sprites[i]._ix = 0;
+ _sprites[i]._iy = 0;
+ _sprites[i]._timeout = time;
+ _sprites[i]._cameo = true;
+ _sprites[i]._cameoFrame = p + 1;
+ _sprites[i]._missile = false;
+ _sprites[i]._wipe = false;
+ return;
+ }
+ }
+}
+
+void ShootEmUp::showStock(byte index) {
+ if (_escaping && (index == _escapeStock)) {
+ _vm->_graphics->seuDrawPicture(index * 90 + 20, 30, kStocks + 2);
+ return;
+ }
+
+ if (_stockStatus[index] > 5)
+ return;
+
+ _vm->_graphics->seuDrawPicture(index * 90 + 20, 30, kStocks + _stockStatus[index]);
+ _stockStatus[index] = 1 - _stockStatus[index];
+}
+
+void ShootEmUp::drawNumber(int number, int size, int x) {
+ for (int i = 0; i < size - 1; i++) {
+ int divisor = 10;
+ for (int j = 0; j < size - 2 - i; j++)
+ divisor *= 10;
+ char value = number / divisor;
+ _vm->_graphics->seuDrawPicture(x + i * 10, 0, value);
+ number -= value * divisor;
+ }
+ _vm->_graphics->seuDrawPicture(x + (size - 1) * 10, 0, number % 10);
+}
+
+void ShootEmUp::showScore() {
+ drawNumber(_score, 5, 40);
+}
+
+void ShootEmUp::showTime() {
+ drawNumber(_time, 3, 140);
+}
+
+void ShootEmUp::gain(int8 howMuch) {
+ if ((_score + howMuch) < 0) // howMuch can be negative!
+ _score = 0;
+ else
+ _score += howMuch;
+
+ showScore();
+}
+
+void ShootEmUp::newEscape() {
+ _escapeCount = _vm->_rnd->getRandomNumber(17) * 20;
+ _escaping = false;
+}
+
+void ShootEmUp::nextPage() {
+ _vm->_graphics->drawNormalText("Press a key for next page >", _vm->_font, 8, 400, 190, kColorWhite);
+ _vm->_graphics->refreshScreen();
+
+ while (!_vm->shouldQuit()) {
+ Common::Event event;
+ _vm->getEvent(event);
+ if (event.type == Common::EVENT_KEYDOWN) {
+ break;
+ }
+ }
+
+ _vm->_graphics->blackOutScreen();
+}
+
+void ShootEmUp::instructions() {
+ _vm->_graphics->blackOutScreen();
+ _vm->_graphics->seuDrawPicture(25, 25, kFacingRight);
+ _vm->_graphics->drawNormalText("< Avvy, our hero, needs your help - you must move him around.", _vm->_font, 8, 60, 35, kColorWhite);
+ _vm->_graphics->drawNormalText("(He''s too terrified to move himself!)", _vm->_font, 8, 80, 45, kColorWhite);
+ _vm->_graphics->drawNormalText("Your task is to prevent the people in the stocks from escaping", _vm->_font, 8, 0, 75, kColorWhite);
+ _vm->_graphics->drawNormalText("by pelting them with rotten fruit, eggs and bread. The keys are:", _vm->_font, 8, 0, 85, kColorWhite);
+ _vm->_graphics->drawNormalText("LEFT SHIFT", _vm->_font, 8, 80, 115, kColorWhite);
+ _vm->_graphics->drawNormalText("Move left.", _vm->_font, 8, 200, 115, kColorWhite);
+ _vm->_graphics->drawNormalText("RIGHT SHIFT", _vm->_font, 8, 72, 135, kColorWhite);
+ _vm->_graphics->drawNormalText("Move right.", _vm->_font, 8, 200, 135, kColorWhite);
+ _vm->_graphics->drawNormalText("ALT", _vm->_font, 8, 136, 155, kColorWhite);
+ _vm->_graphics->drawNormalText("Throw something.", _vm->_font, 8, 200, 155, kColorWhite);
+
+ nextPage();
+
+ _vm->_graphics->seuDrawPicture(25, 35, kStocks);
+ _vm->_graphics->drawNormalText("This man is in the stocks. Your job is to stop him getting out.", _vm->_font, 8, 80, 35, kColorWhite);
+ _vm->_graphics->drawNormalText("UNFORTUNATELY... the locks on the stocks are loose, and every", _vm->_font, 8, 88, 45, kColorWhite);
+ _vm->_graphics->drawNormalText("so often, someone will discover this and try to get out.", _vm->_font, 8, 88, 55, kColorWhite);
+ _vm->_graphics->seuDrawPicture(25, 85, kStocks + 2);
+ _vm->_graphics->drawNormalText("< Someone who has found a way out!", _vm->_font, 8, 80, 85, kColorWhite);
+ _vm->_graphics->drawNormalText("You MUST IMMEDIATELY hit people smiling like this, or they", _vm->_font, 8, 88, 95, kColorWhite);
+ _vm->_graphics->drawNormalText("will disappear and lose you points.", _vm->_font, 8, 88, 105, kColorWhite);
+ _vm->_graphics->seuDrawPicture(25, 125, kStocks + 5);
+ _vm->_graphics->seuDrawPicture(25, 155, kStocks + 4);
+ _vm->_graphics->drawNormalText("< Oh dear!", _vm->_font, 8, 80, 125, kColorWhite);
+
+ nextPage();
+
+ _vm->_graphics->drawNormalText("Your task is made harder by:", _vm->_font, 8, 0, 35, kColorWhite);
+ _vm->_graphics->seuDrawPicture(25, 55, 48);
+ _vm->_graphics->drawNormalText("< Yokels. These people will run in front of you. If you hit", _vm->_font, 8, 60, 55, kColorWhite);
+ _vm->_graphics->drawNormalText("them, you will lose MORE points than you get hitting people", _vm->_font, 8, 68, 65, kColorWhite);
+ _vm->_graphics->drawNormalText("in the stocks. So BEWARE!", _vm->_font, 8, 68, 75, kColorWhite);
+ _vm->_graphics->drawNormalText("Good luck with the game!", _vm->_font, 8, 80, 125, kColorWhite);
+
+ nextPage();
+}
+
+void ShootEmUp::setup() {
+ _vm->_graphics->blackOutScreen();
+
+ newEscape();
+
+ for (int i = 0; i < 7; i++) {
+ _stockStatus[i] = _vm->_rnd->getRandomNumber(1);
+ showStock(i);
+ }
+
+ // Set up status line:
+ _vm->_graphics->seuDrawPicture(0, 0, 16); // Score:
+ showScore(); // Value of score (00000 here).
+ _vm->_graphics->seuDrawPicture(110, 0, 19); // Time:
+ showTime(); // Value of time.
+
+ _vm->_graphics->refreshScreen();
+
+ // From the original core cycle:
+ initRunner(20, 70, 48, 54, _vm->_rnd->getRandomNumber(4) + 1, _vm->_rnd->getRandomNumber(3) - 2);
+ initRunner(600, 70, 48, 54, _vm->_rnd->getRandomNumber(4) + 1, _vm->_rnd->getRandomNumber(3) - 2);
+ initRunner(600, 100, 61, 67, (-(int8)_vm->_rnd->getRandomNumber(4)) + 1, _vm->_rnd->getRandomNumber(3) - 2);
+ initRunner(20, 100, 61, 67, (-(int8)_vm->_rnd->getRandomNumber(4)) + 1, _vm->_rnd->getRandomNumber(3) - 2);
+}
+
+void ShootEmUp::initRunner(int16 x, int16 y, byte f1, byte f2, int8 ix, int8 iy) {
+ for (int i = 0; i < 4; i++) {
+ if (_running[i]._x == kFlag) {
+ _running[i]._x = x;
+ _running[i]._y = y;
+ _running[i]._frame = f1;
+ _running[i]._tooHigh = f2;
+ _running[i]._lowest = f1;
+ _running[i]._ix = ix;
+ _running[i]._iy = iy;
+ if ((ix == 0) && (iy == 0))
+ _running[i]._ix = 2; // To stop them running on the spot!
+ _running[i]._frameDelay = kFrameDelayMax;
+ return;
+ }
+ }
+}
+
+void ShootEmUp::moveAvvy() {
+ if (_avvyWas < _avvyPos)
+ _avvyFacing = kFacingRight;
+ else if (_avvyWas > _avvyPos)
+ _avvyFacing = kFacingLeft;
+
+ if (!_firing) {
+ if (_avvyWas == _avvyPos)
+ _avvyAnim = 1;
+ else {
+ _avvyAnim++;
+ if (_avvyAnim == 6)
+ _avvyAnim = 0;
+ }
+ }
+
+ if (_avvyFacing == kAvvyShoots)
+ define(_avvyPos, kAvvyY, kShooting[_avvyAnim], 0, 0, 1, false, true);
+ else
+ define(_avvyPos, kAvvyY, _avvyAnim + _avvyFacing, 0, 0, 1, false, true);
+
+ _avvyWas = _avvyPos;
+
+ if (_avvyFacing == kAvvyShoots) {
+ if (_avvyAnim == 6) {
+ _avvyFacing = _wasFacing;
+ _avvyAnim = 0;
+ _firing = false;
+ } else
+ _avvyAnim++;
+ }
+}
+
+void ShootEmUp::readKbd() {
+ Common::Event event;
+ _vm->getEvent(event);
+
+ if ((event.type == Common::EVENT_KEYUP) && ((event.kbd.keycode == Common::KEYCODE_LALT) || (event.kbd.keycode == Common::KEYCODE_RALT))) {
+ // Don't let the player fire continuously by holding down one of the ALT keys.
+ _altWasPressedBefore = false;
+ return;
+ }
+
+ if (_firing) // So you can't stack up shots while the shooting animation plays.
+ return;
+
+ if (event.type == Common::EVENT_KEYDOWN) {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_LALT: // Alt was pressed - shoot!
+ case Common::KEYCODE_RALT: // Falltrough is intended.
+ if (_altWasPressedBefore || (_count321 != 0))
+ return;
+
+ _altWasPressedBefore = true;
+ _firing = true;
+ define(_avvyPos + 27, kAvvyY + 5, _throwNext, 0, -2, 53, true, true);
+ _throwNext++;
+ if (_throwNext == 79)
+ _throwNext = 73;
+ _avvyAnim = 0;
+ _wasFacing = _avvyFacing;
+ _avvyFacing = kAvvyShoots;
+ return;
+ case Common::KEYCODE_RSHIFT: // Right shift: move right.
+ _avvyPos += 5;
+ if (_avvyPos > kRightMargin)
+ _avvyPos = kRightMargin;
+ return;
+ case Common::KEYCODE_LSHIFT: // Left shift: move left.
+ _avvyPos -= 5;
+ if (_avvyPos < kLeftMargin)
+ _avvyPos = kLeftMargin;
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+void ShootEmUp::animate() {
+ if (_vm->_rnd->getRandomNumber(9) == 1)
+ showStock(getStockNumber(_vm->_rnd->getRandomNumber(5)));
+ for (int i = 0; i < 7; i++) {
+ if (_stockStatus[i] > 5) {
+ _stockStatus[i]--;
+ if (_stockStatus[i] == 8) {
+ _stockStatus[i] = 0;
+ showStock(i);
+ }
+ }
+ }
+}
+
+void ShootEmUp::collisionCheck() {
+ for (int i = 0; i < 99; i++) {
+ if ((_sprites[i]._x != kFlag) && (_sprites[i]._missile) &&
+ (_sprites[i]._y < 60) && (_sprites[i]._timeout == 1)) {
+ int distFromSide = (_sprites[i]._x - 20) % 90;
+ int thisStock = (_sprites[i]._x - 20) / 90;
+ if ((!_hasEscaped[thisStock]) && (distFromSide > 17) && (distFromSide < 34)) {
+ _vm->_sound->playNote(999, 3);
+ _vm->_system->delayMillis(3);
+ define(_sprites[i]._x + 20, _sprites[i]._y, 25 + _vm->_rnd->getRandomNumber(1), 3, 1, 12, false, true); // Well done!
+ define(thisStock * 90 + 20, 30, 30, 0, 0, 7, false, false); // Face of man
+ defineCameo(thisStock * 90 + 20 + 10, 35, 40, 7); // Splat!
+ define(thisStock * 90 + 20 + 20, 50, 33 + _vm->_rnd->getRandomNumber(4), 0, 2, 9, false, true); // Oof!
+ _stockStatus[thisStock] = 17;
+ gain(3); // Score for hitting a face.
+
+ if (_escaping && (_escapeStock = thisStock)) { // Hit the escaper.
+ _vm->_sound->playNote(1777, 1);
+ _vm->_system->delayMillis(1);
+ gain(5); // Bonus for hitting escaper.
+ _escaping = false;
+ newEscape();
+ }
+ } else {
+ define(_sprites[i]._x, _sprites[i]._y, 82 + _vm->_rnd->getRandomNumber(2), 2, 2, 17, false, true); // Missed!
+ if ((!_hasEscaped[thisStock]) && (distFromSide > 3) && (distFromSide < 43)) {
+ define(thisStock * 90 + 20, 30, 29, 0, 0, 7, false, false); // Face of man
+ if (distFromSide > 35)
+ defineCameo(_sprites[i]._x - 27, 35, 40, 7); // Splat!
+ else
+ defineCameo(_sprites[i]._x - 7, 35, 40, 7);
+ _stockStatus[thisStock] = 17;
+ }
+ }
+ }
+ }
+}
+
+void ShootEmUp::turnAround(byte who, bool randomX) {
+ if (randomX) {
+ int8 ix = (_vm->_rnd->getRandomNumber(4) + 1);
+ if (_running[who]._ix > 0)
+ _running[who]._ix = -(ix);
+ else
+ _running[who]._ix = ix;
+ } else
+ _running[who]._ix = -(_running[who]._ix);
+
+ _running[who]._iy = -(_running[who]._iy);
+}
+
+void ShootEmUp::bumpFolk() {
+ for (int i = 0; i < 4; i++) {
+ if (_running[i]._x != kFlag) {
+ for (int j = i + 1; j < 4; j++) {
+ bool overlaps = overlap(_running[i]._x, _running[i]._y, _running[i]._x + 17, _running[i]._y + 24,
+ _running[j]._x, _running[j]._y, _running[j]._x + 17, _running[j]._y + 24);
+ if ((_running[i]._x != kFlag) && overlaps) {
+ turnAround(i, false); // Opp. directions.
+ turnAround(j, false);
+ }
+ }
+ }
+ }
+}
+
+void ShootEmUp::peopleRunning() {
+ if (_count321 != 0)
+ return;
+
+ for (int i = 0; i < 4; i++) {
+ if (_running[i]._x != kFlag) {
+ if (((_running[i]._y + _running[i]._iy) <= 53) || ((_running[i]._y + _running[i]._iy) >= 120))
+ _running[i]._iy = -(_running[i]._iy);
+
+ byte frame = 0;
+ if (_running[i]._ix < 0)
+ frame = _running[i]._frame - 1;
+ else
+ frame = _running[i]._frame + 6;
+ define(_running[i]._x, _running[i]._y, frame, 0, 0, 1, false, true);
+
+ if (_running[i]._frameDelay == 0) {
+ _running[i]._frame++;
+ if (_running[i]._frame == _running[i]._tooHigh)
+ _running[i]._frame = _running[i]._lowest;
+ _running[i]._frameDelay = kFrameDelayMax;
+ _running[i]._y += _running[i]._iy;
+ } else
+ _running[i]._frameDelay--;
+
+ if (((_running[i]._x + _running[i]._ix) <= 0) || ((_running[i]._x + _running[i]._ix) >= 620))
+ turnAround(i, true);
+
+ _running[i]._x += _running[i]._ix;
+ }
+ }
+}
+
+void ShootEmUp::updateTime() {
+ if (_count321 != 0)
+ return;
+
+ _timeThisSecond++;
+
+ if (_timeThisSecond < kTimesASecond)
+ return;
+
+ _time--;
+ showTime();
+ _timeThisSecond = 0;
+
+ if (_time <= kFlashTime) {
+ int timeMode = 0;
+ if ((_time % 2) == 1)
+ timeMode = 19; // Normal 'Time:'
+ else
+ timeMode = 85; // Flash 'Time:'
+
+ _vm->_graphics->seuDrawPicture(110, 0, timeMode);
+ }
+}
+
+void ShootEmUp::hitPeople() {
+ if (_count321 != 0)
+ return;
+
+ for (int i = 0; i < 99; i++) {
+ if ((_sprites[i]._missile) && (_sprites[i]._x != kFlag)) {
+ for (int j = 0; j < 4; j++) {
+
+ bool overlaps = overlap(_sprites[i]._x, _sprites[i]._y, _sprites[i]._x + 7, _sprites[i]._y + 10,
+ _running[j]._x, _running[j]._y, _running[j]._x + 17, _running[j]._y + 24);
+
+ if ((_running[j]._x != kFlag) && (overlaps)) {
+ _vm->_sound->playNote(7177, 1);
+ _sprites[i]._x = kFlag;
+ gain(-5);
+ define(_running[j]._x + 20, _running[j]._y + 3, 33 + _vm->_rnd->getRandomNumber(5), 1, 3, 9, false, true); // Oof!
+ define(_sprites[i]._x, _sprites[i]._y, 82, 1, 0, 17, false, true); // Oops!
+ }
+ }
+ }
+ }
+}
+
+void ShootEmUp::escapeCheck() {
+ if (_count321 != 0)
+ return;
+
+ if (_escapeCount > 0) {
+ _escapeCount--;
+ return;
+ }
+
+ // Escape_count = 0; now what ?
+
+ if (_escaping) {
+ if (_gotOut) {
+ newEscape();
+ _escaping = false;
+ _vm->_graphics->seuDrawPicture(_escapeStock * 90 + 20, 30, kStocks + 4);
+ } else {
+ _vm->_graphics->seuDrawPicture(_escapeStock * 90 + 20, 30, kStocks + 5);
+ _escapeCount = 20;
+ _gotOut = true;
+ define(_escapeStock * 90 + 20, 50, 24, 0, 2, 17, false, true); // Escaped!
+ gain(-10);
+ _hasEscaped[_escapeStock] = true;
+
+ _howManyHaveEscaped++;
+
+ if (_howManyHaveEscaped == 7) {
+ _vm->_graphics->seuDrawPicture(266, 90, 23);
+ _time = 0;
+ }
+ }
+ } else {
+ _escapeStock = getStockNumber(_vm->_rnd->getRandomNumber(6));
+ _escaping = true;
+ _gotOut = false;
+ _vm->_graphics->seuDrawPicture(_escapeStock * 90 + 20, 30, kStocks + 2); // Smiling!
+ _escapeCount = 200;
+ }
+}
+
+void ShootEmUp::check321() {
+ if (_count321 == 0)
+ return;
+
+ _count321--;
+
+ switch (_count321) {
+ case 84:
+ define(320, 60, 15, 2, 1, 94, false, true);
+ break;
+ case 169:
+ define(320, 60, 14, 0, 1, 94, false, true);
+ break;
+ case 254:
+ define(320, 60, 13, -2, 1, 94, false, true);
+ define(0, 100, 17, 2, 0, 254, false, true);
+ break;
+ default:
+ break;
+ }
+}
+
+} // End of namespace Avalanche
diff --git a/engines/avalanche/shootemup.h b/engines/avalanche/shootemup.h
new file mode 100644
index 0000000000..3cdcc1d5cd
--- /dev/null
+++ b/engines/avalanche/shootemup.h
@@ -0,0 +1,134 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+* Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+*/
+
+#ifndef AVALANCHE_SHOOTEMUP_H
+#define AVALANCHE_SHOOTEMUP_H
+
+namespace Avalanche {
+class AvalancheEngine;
+
+class ShootEmUp {
+public:
+ ShootEmUp(AvalancheEngine *vm);
+
+ uint16 run();
+
+private:
+ struct Sprite {
+ int8 _ix, _iy;
+ int16 _x, _y;
+ int8 _p;
+ int16 _timeout;
+ bool _cameo;
+ byte _cameoFrame;
+ bool _missile;
+ bool _wipe;
+ };
+
+ struct Runner {
+ int16 _x, _y;
+ byte _frame;
+ byte _tooHigh;
+ byte _lowest;
+ int8 _ix, _iy;
+ byte _frameDelay;
+ };
+
+ static const byte kStocks;
+ static const byte kAvvyShoots;
+ static const byte kFacingRight;
+ static const byte kFacingLeft;
+ static const long int kFlag;
+ static const byte kFrameDelayMax;
+ static const byte kAvvyY;
+ static const byte kShooting[7];
+ static const byte kTimesASecond;
+ static const byte kFlashTime;
+ static const byte kLeftMargin;
+ static const int16 kRightMargin;
+
+ AvalancheEngine *_vm;
+
+ uint16 _score;
+ byte _time;
+ byte _stockStatus[7];
+ Sprite _sprites[99];
+ byte _rectNum; // Original: 'rsize'
+ Common::Rect _rectangles[99];
+ uint16 _avvyWas;
+ uint16 _avvyPos;
+ byte _avvyAnim;
+ byte _avvyFacing;
+ bool _altWasPressedBefore;
+ byte _throwNext;
+ bool _firing;
+ Runner _running[4];
+ bool _hasEscaped[7];
+ byte _count321;
+ byte _howManyHaveEscaped;
+ uint16 _escapeCount;
+ bool _escaping;
+ byte _timeThisSecond;
+ bool _cp;
+ byte _wasFacing;
+ byte _escapeStock;
+ bool _gotOut;
+
+ bool overlap(uint16 a1x, uint16 a1y, uint16 a2x, uint16 a2y, uint16 b1x, uint16 b1y, uint16 b2x, uint16 b2y);
+ byte getStockNumber(byte index);
+ void blankIt();
+ void moveThem();
+ void blank(Common::Rect rect);
+ void plotThem();
+ void define(int16 x, int16 y, int8 p, int8 ix, int8 iy, int16 time, bool isAMissile, bool doWeWipe);
+ void defineCameo(int16 x, int16 y, int8 p, int16 time);
+ void showStock(byte index);
+ void drawNumber(int number, int size, int x);
+ void showScore();
+ void showTime();
+ void gain(int8 howMuch);
+ void newEscape();
+ void nextPage(); // Internal function of 'instructions' in the original.
+ void instructions();
+ void setup();
+ void initRunner(int16 xx, int16 yy, byte f1, byte f2, int8 ixx, int8 iyy);
+ void moveAvvy();
+ void readKbd();
+ void animate();
+ void collisionCheck();
+ void turnAround(byte who, bool randomX);
+ void bumpFolk();
+ void peopleRunning();
+ void updateTime();
+ void hitPeople();
+ void escapeCheck();
+ void check321();
+};
+
+} // End of namespace Avalanche
+
+#endif // AVALANCHE_SHOOTEMUP_H
diff --git a/engines/avalanche/sound.cpp b/engines/avalanche/sound.cpp
index c324df4713..0223bead48 100644
--- a/engines/avalanche/sound.cpp
+++ b/engines/avalanche/sound.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -51,6 +51,7 @@ void SoundHandler::stopSound() {
*/
void SoundHandler::toggleSound() {
_soundFl = !_soundFl;
+ _vm->_graphics->drawSoundLight(_soundFl);
}
void SoundHandler::syncVolume() {
diff --git a/engines/avalanche/sound.h b/engines/avalanche/sound.h
index 25b6b267d3..a67016a206 100644
--- a/engines/avalanche/sound.h
+++ b/engines/avalanche/sound.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
diff --git a/engines/avalanche/timer.cpp b/engines/avalanche/timer.cpp
index 4e90c7fe48..a9753b3cce 100644
--- a/engines/avalanche/timer.cpp
+++ b/engines/avalanche/timer.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -35,12 +35,7 @@ namespace Avalanche {
Timer::Timer(AvalancheEngine *vm) {
_vm = vm;
- for (int i = 0; i < 7; i++) {
- _times[i]._timeLeft = 0;
- _times[i]._action = 0;
- _times[i]._reason = 0;
- }
- _timerLost = false;
+ resetVariables();
}
/**
@@ -48,22 +43,20 @@ Timer::Timer(AvalancheEngine *vm) {
* @remarks Originally called 'set_up_timer'
*/
void Timer::addTimer(int32 duration, byte action, byte reason) {
- if ((_vm->_isLoaded == false) || (_timerLost == true)) {
- byte i = 0;
- while ((i < 7) && (_times[i]._timeLeft != 0))
- i++;
-
- if (i == 7)
- return; // Oh dear... No timer left
-
- // Everything's OK here!
- _times[i]._timeLeft = duration;
- _times[i]._action = action;
- _times[i]._reason = reason;
- } else {
- _vm->_isLoaded = false;
- return;
+ byte i = 0;
+ while ((i < 7) && (_times[i]._timeLeft != 0)) {
+ if (_times[i]._reason == reason) // We only add a timer if it's not already in the array.
+ return;
+ i++;
}
+
+ if (i == 7)
+ return; // Oh dear... No timer left
+
+ // Everything's OK here!
+ _times[i]._timeLeft = duration;
+ _times[i]._action = action;
+ _times[i]._reason = reason;
}
/**
@@ -71,7 +64,7 @@ void Timer::addTimer(int32 duration, byte action, byte reason) {
* @remarks Originally called 'one_tick'
*/
void Timer::updateTimer() {
- if (_vm->_menu->isActive())
+ if (_vm->_dropdown->isActive())
return;
for (int i = 0; i < 7; i++) {
@@ -208,8 +201,8 @@ void Timer::updateTimer() {
}
}
}
- _vm->_roomTime++; // Cycles since you've been in this room.
- _vm->_totalTime++; // Total amount of time for this game.
+
+ _vm->_roomCycles++; // Cycles since you've been in this room.
}
void Timer::loseTimer(byte which) {
@@ -218,7 +211,6 @@ void Timer::loseTimer(byte which) {
_times[i]._timeLeft = 0; // Cancel this one!
}
- _timerLost = true;
}
void Timer::openDrawbridge() {
@@ -232,7 +224,7 @@ void Timer::openDrawbridge() {
}
void Timer::avariciusTalks() {
- _vm->_dialogs->displayScrollChain('q', _vm->_avariciusTalk);
+ _vm->_dialogs->displayScrollChain('Q', _vm->_avariciusTalk);
_vm->_avariciusTalk++;
if (_vm->_avariciusTalk < 17)
@@ -275,25 +267,25 @@ void Timer::stairs() {
void Timer::cardiffSurvey() {
if (_vm->_cardiffQuestionNum == 0) {
_vm->_cardiffQuestionNum++;
- _vm->_dialogs->displayScrollChain('q', 27);
+ _vm->_dialogs->displayScrollChain('Q', 27);
}
- _vm->_dialogs->displayScrollChain('z', _vm->_cardiffQuestionNum);
+ _vm->_dialogs->displayScrollChain('Z', _vm->_cardiffQuestionNum);
_vm->_interrogation = _vm->_cardiffQuestionNum;
addTimer(182, kProcCardiffSurvey, kReasonCardiffsurvey);
}
void Timer::cardiffReturn() {
- _vm->_dialogs->displayScrollChain('q', 28);
+ _vm->_dialogs->displayScrollChain('Q', 28);
cardiffSurvey(); // Add end of question.
}
void Timer::cwytalotInHerts() {
- _vm->_dialogs->displayScrollChain('q', 29);
+ _vm->_dialogs->displayScrollChain('Q', 29);
}
void Timer::getTiedUp() {
- _vm->_dialogs->displayScrollChain('q', 34); // ...Trouble!
+ _vm->_dialogs->displayScrollChain('Q', 34); // ...Trouble!
_vm->_userMovesAvvy = false;
_vm->_beenTiedUp = true;
_vm->_animation->stopWalking();
@@ -320,31 +312,32 @@ void Timer::hangAround() {
avvy->init(7, true); // Robin Hood
_vm->setRoom(kPeopleRobinHood, kRoomRobins);
_vm->_animation->appearPed(0, 1);
- _vm->_dialogs->displayScrollChain('q', 39);
+ _vm->_dialogs->displayScrollChain('Q', 39);
avvy->walkTo(6);
addTimer(55, kProcHangAround2, kReasonHangingAround);
}
void Timer::hangAround2() {
- _vm->_dialogs->displayScrollChain('q', 40);
+ _vm->_dialogs->displayScrollChain('Q', 40);
AnimationType *spr = _vm->_animation->_sprites[1];
spr->_vanishIfStill = false;
spr->walkTo(3);
_vm->setRoom(kPeopleFriarTuck, kRoomRobins);
- _vm->_dialogs->displayScrollChain('q', 41);
+ _vm->_dialogs->displayScrollChain('Q', 41);
_vm->_animation->_sprites[0]->remove();
spr->remove(); // Get rid of Robin Hood and Friar Tuck.
- addTimer(1, kProcAfterTheShootemup, kReasonHangingAround);
- // Immediately call the following proc (when you have a chance).
+ addTimer(1, kProcAfterTheShootemup, kReasonHangingAround); // Immediately call the following proc (when you have a chance).
_vm->_tiedUp = false;
- // _vm->_enid->backToBootstrap(1); Call the shoot-'em-up. TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then!
+ // We don't need the ShootEmUp during the whole game, it's only playable once.
+ ShootEmUp *shootemup = new ShootEmUp(_vm);
+ _shootEmUpScore = shootemup->run();
+ delete shootemup;
}
void Timer::afterTheShootemup() {
- // Only placed this here to replace the minigame. TODO: Remove it when the shoot em' up is implemented!
_vm->flipRoom(_vm->_room, 1);
_vm->_animation->_sprites[0]->init(0, true); // Avalot.
@@ -353,29 +346,17 @@ void Timer::afterTheShootemup() {
_vm->_objects[kObjectCrossbow - 1] = true;
_vm->refreshObjectList();
- // Same as the added line above: TODO: Remove it later!!!
- _vm->_dialogs->displayText(Common::String("P.S.: There should have been the mini-game called \"shoot em' up\", " \
- "but I haven't implemented it yet: you get the crossbow automatically.") + kControlNewLine + kControlNewLine + "Peter (uruk)");
-
-#if 0
- byte shootscore, gain;
-
- shootscore = mem[storage_seg * storage_ofs];
- gain = (shootscore + 5) / 10; // Rounding up.
-
- display(string("\6Your score was ") + strf(shootscore) + '.' + "\r\rYou gain (" +
- strf(shootscore) + " 0xF6 10) = " + strf(gain) + " points.");
+ byte gain = (_shootEmUpScore + 5) / 10; // Rounding up.
+ _vm->_dialogs->displayText(Common::String::format("%cYour score was %d.%c%cYou gain (%d \xf6 10) = %d points.", kControlItalic, _shootEmUpScore, kControlNewLine, kControlNewLine, _shootEmUpScore, gain));
if (gain > 20) {
- display("But we won't let you have more than 20 points!");
- points(20);
+ _vm->_dialogs->displayText("But we won't let you have more than 20 points!");
+ _vm->incScore(20);
} else
- points(gain);
-#endif
+ _vm->incScore(gain);
- warning("STUB: Timer::after_the_shootemup()");
- _vm->_dialogs->displayScrollChain('q', 70);
+ _vm->_dialogs->displayScrollChain('Q', 70);
}
void Timer::jacquesWakesUp() {
@@ -431,7 +412,7 @@ void Timer::naughtyDuke() { // This is when the Duke comes in and takes your mon
void Timer::naughtyDuke2() {
AnimationType *spr = _vm->_animation->_sprites[1];
- _vm->_dialogs->displayScrollChain('q', 48); // "Ha ha, it worked again!"
+ _vm->_dialogs->displayScrollChain('Q', 48); // "Ha ha, it worked again!"
spr->walkTo(0); // Walk to the door.
spr->_vanishIfStill = true; // Then go away!
@@ -484,14 +465,14 @@ void Timer::jump() {
_vm->_arrowInTheDoor = false; // You've got it.
_vm->_objects[kObjectBolt - 1] = true;
_vm->refreshObjectList();
- _vm->_dialogs->displayScrollChain('q', 50);
+ _vm->_dialogs->displayScrollChain('Q', 50);
_vm->incScore(3);
}
}
}
void Timer::crapulusSaysSpludOut() {
- _vm->_dialogs->displayScrollChain('q', 56);
+ _vm->_dialogs->displayScrollChain('Q', 56);
_vm->_crapulusWillTell = false;
}
@@ -500,7 +481,7 @@ void Timer::buyDrinks() {
_vm->_malagauche = 0;
_vm->_dialogs->displayScrollChain('D', _vm->_drinking); // Display message about it.
- _vm->_pingo->wobble(); // Do the special effects.
+ _vm->_animation->wobble(); // Do the special effects.
_vm->_dialogs->displayScrollChain('D', 1); // That'll be thruppence.
if (_vm->decreaseMoney(3)) // Pay 3d.
_vm->_dialogs->displayScrollChain('D', 3); // Tell 'em you paid up.
@@ -586,7 +567,7 @@ void Timer::robinHoodAndGeida() {
}
void Timer::robinHoodAndGeidaTalk() {
- _vm->_dialogs->displayScrollChain('q', 66);
+ _vm->_dialogs->displayScrollChain('Q', 66);
AnimationType *avvy = _vm->_animation->_sprites[0];
AnimationType *spr = _vm->_animation->_sprites[1];
@@ -605,7 +586,7 @@ void Timer::avalotReturns() {
spr->remove();
avvy->init(0, true);
_vm->_animation->appearPed(0, 0);
- _vm->_dialogs->displayScrollChain('q', 67);
+ _vm->_dialogs->displayScrollChain('Q', 67);
_vm->_userMovesAvvy = true;
}
@@ -636,21 +617,43 @@ void Timer::arkataShouts() {
if (_vm->_teetotal)
return;
- _vm->_dialogs->displayScrollChain('q', 76);
+ _vm->_dialogs->displayScrollChain('Q', 76);
addTimer(160, kProcArkataShouts, kReasonArkataShouts);
}
+/**
+ * @remarks Contains the content of the function 'winning_pic', originally located in PINGO.
+ */
void Timer::winning() {
- _vm->_dialogs->displayScrollChain('q', 79);
- _vm->_pingo->winningPic();
+ _vm->_dialogs->displayScrollChain('Q', 79);
+
+ // This was originally located in winning_pic:
+ CursorMan.showMouse(false);
+ _vm->_graphics->saveScreen();
+ _vm->fadeOut();
+ _vm->_graphics->drawWinningPic();
+ _vm->_graphics->refreshScreen();
+ _vm->fadeIn();
+
+ // Waiting for a keypress or a left mouseclick:
+ Common::Event event;
+ bool escape = false;
+ while (!_vm->shouldQuit() && !escape) {
+ _vm->_graphics->refreshScreen();
+ while (_vm->getEvent(event)) {
+ if ((event.type == Common::EVENT_LBUTTONUP) || (event.type == Common::EVENT_KEYDOWN)) {
+ escape = true;
+ break;
+ }
+ }
+ }
- warning("STUB: Timer::winning()");
-#if 0
- do {
- _vm->checkclick();
- } while (!(_vm->mrelease == 0));
-#endif
- // TODO: To be implemented with Pingo::winningPic().
+ _vm->fadeOut();
+ _vm->_graphics->restoreScreen();
+ _vm->_graphics->removeBackup();
+ _vm->fadeIn();
+ CursorMan.showMouse(true);
+ // winning_pic's end.
_vm->callVerb(kVerbCodeScore);
_vm->_dialogs->displayText(" T H E E N D ");
@@ -690,4 +693,14 @@ void Timer::giveLuteToGeida() { // Moved here from Acci.
_vm->_sequence->startGeidaLuteSeq();
}
+void Timer::resetVariables() {
+ for (int i = 0; i < 7; i++) {
+ _times[i]._timeLeft = 0;
+ _times[i]._action = 0;
+ _times[i]._reason = 0;
+ }
+
+ _shootEmUpScore = 0;
+}
+
} // End of namespace Avalanche.
diff --git a/engines/avalanche/timer.h b/engines/avalanche/timer.h
index 6cd894b0a5..ad6ac0eae6 100644
--- a/engines/avalanche/timer.h
+++ b/engines/avalanche/timer.h
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
-
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -119,10 +119,10 @@ public:
};
TimerType _times[7];
- bool _timerLost; // Is the timer "lost"? (Because of using loseTimer())
Timer(AvalancheEngine *vm);
+ void resetVariables();
void addTimer(int32 duration, byte action, byte reason);
void updateTimer();
void loseTimer(byte which);
@@ -170,7 +170,7 @@ public:
private:
AvalancheEngine *_vm;
-
+ byte _shootEmUpScore;
};
} // End of namespace Avalanche.