Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1 @@
engines/avalanche/parser.cpp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: TRIP5 / Trippancy V - the sprite animation subsystem */
#ifndef AVALANCHE_ANIMATION_H
#define AVALANCHE_ANIMATION_H
namespace Avalanche {
class AvalancheEngine;
class Animation;
enum Direction {
kDirUp = 0, kDirRight, kDirDown, kDirLeft,
kDirUpRight, kDirDownRight, kDirDownLeft, kDirUpLeft,
kDirStopped, kDirNone = 177
};
class AnimationType {
public:
byte _id;
byte _xLength, _yLength;
ManiType *_mani[24];
SilType *_sil[24];
byte _frameNum; // Number of pictures.
byte _seq; // How many in one stride.
byte _characterId; // The number according to Acci. (1=Avvy, etc.)
byte _count; // Counts before changing step.
Direction _facingDir;
byte _stepNum;
int16 _x, _y; // Current xy coords.
int8 _moveX, _moveY; // Amount to move sprite by, each step.
bool _quick, _visible, _homing, _doCheck;
int16 _homingX, _homingY; // Homing x & y coords.
byte _speedX, _speedY;
bool _vanishIfStill;
bool _callEachStepFl;
byte _eachStepProc;
AnimationType(Animation *anim);
void init(byte spritenum, bool doCheck);
void reset();
void draw();
void turn(Direction whichway);
void appear(int16 wx, int16 wy, Direction wf);
void bounce();
void walk();
void walkTo(byte pednum);
void stopHoming();
void setSpeed(int8 xx, int8 yy);
void stopWalk();
void chatter();
void remove();
private:
Animation *_anim;
int16 _oldX[2], _oldY[2]; // Last xy coords.
Color _fgBubbleCol, _bgBubbleCol; // Foreground & background bubble colors.
bool checkCollision();
int8 getSign(int16 val);
void homeStep();
};
class Animation {
public:
friend class AnimationType;
static const byte kSpriteNumbMax = 5; // current max no. of sprites
enum Proc {
kProcNone = 0,
kProcFollowAvvyY,
kProcBackAndForth,
kProcFaceAvvy,
kProcArrow,
kProcGrabAvvy,
kProcFollowAvvy
};
AnimationType *_sprites[kSpriteNumbMax];
Animation(AvalancheEngine *vm);
~Animation();
void animLink();
void resetAnims();
void callSpecial(uint16 which);
void catacombMove(byte ped);
void stopWalking();
void setMoveSpeed(byte t, Direction dir);
void appearPed(byte sprNum, byte pedNum);
bool inField(byte which);
bool nearDoor();
void updateSpeed();
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();
Direction getOldDirection();
void setAvvyClothes(int id);
int getAvvyClothes();
void resetVariables();
void synchronize(Common::Serializer &sz);
private:
Direction _direction; // The direction Avvy is currently facing.
Direction _oldDirection;
static const int32 kCatacombMap[8][8];
bool _arrowTriggered; // And has the arrow been triggered?
bool _mustExclaim;
byte _geidaSpin, _geidaTime; // For the making "Geida dizzy" joke.
uint16 _sayWhat;
AvalancheEngine *_vm;
byte checkFeet(int16 x1, int16 x2, int16 oy, int16 y, byte yl);
byte geidaPed(byte ped);
void dawnDelay();
void grabAvvy(byte tripnum);
void arrowProcs(byte tripnum);
// Different movements for NPCs:
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 follow(byte tripnum);
void drawSprites();
};
} // End of namespace Avalanche.
#endif // AVALANCHE_ANIMATION_H

View File

@@ -0,0 +1,523 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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 "common/random.h"
#include "common/savefile.h"
#include "common/system.h"
#include "graphics/thumbnail.h"
namespace Avalanche {
AvalancheEngine::AvalancheEngine(OSystem *syst, const AvalancheGameDescription *gd) : Engine(syst), _gameDescription(gd), _fxHidden(false), _interrogation(0) {
setDebugger(new AvalancheConsole(this));
_rnd = new Common::RandomSource("avalanche");
_showDebugLines = false;
_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;
initVariables();
}
AvalancheEngine::~AvalancheEngine() {
delete _rnd;
delete _graphics;
delete _parser;
delete _clock;
delete _dialogs;
delete _background;
delete _sequence;
delete _timer;
delete _animation;
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++) {
if (_also[i][j] != nullptr) {
delete _also[i][j];
_also[i][j] = nullptr;
}
}
}
}
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);
_dialogs = new Dialogs(this);
_background = new Background(this);
_sequence = new Sequence(this);
_timer = new Timer(this);
_animation = new Animation(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();
init();
_parser->init();
return Common::kNoError;
}
bool AvalancheEngine::hasFeature(EngineFeature f) const {
return (f == kSupportsSavingDuringRuntime) || (f == kSupportsLoadingDuringRuntime);
}
const char *AvalancheEngine::getCopyrightString() const {
return "Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.";
}
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(_score);
sz.syncAsSint32LE(_money);
sz.syncAsByte(_room);
if (sz.isSaving())
_saveNum++;
sz.syncAsByte(_saveNum);
sz.syncBytes(_roomCount, 100);
sz.syncAsByte(_wonNim);
sz.syncAsByte(_wineState);
sz.syncAsByte(_cwytalotGone);
sz.syncAsByte(_passwordNum);
sz.syncAsByte(_aylesIsAwake);
sz.syncAsByte(_drawbridgeOpen);
sz.syncAsByte(_avariciusTalk);
sz.syncAsByte(_rottenOnion);
sz.syncAsByte(_onionInVinegar);
sz.syncAsByte(_givenToSpludwick);
sz.syncAsByte(_brummieStairs);
sz.syncAsByte(_cardiffQuestionNum);
sz.syncAsByte(_passedCwytalotInHerts);
sz.syncAsByte(_avvyIsAwake);
sz.syncAsByte(_avvyInBed);
sz.syncAsByte(_userMovesAvvy);
sz.syncAsByte(_npcFacing);
sz.syncAsByte(_givenBadgeToIby);
sz.syncAsByte(_friarWillTieYouUp);
sz.syncAsByte(_tiedUp);
sz.syncAsByte(_boxContent);
sz.syncAsByte(_talkedToCrapulus);
sz.syncAsByte(_jacquesState);
sz.syncAsByte(_bellsAreRinging);
sz.syncAsByte(_standingOnDais);
sz.syncAsByte(_takenPen);
sz.syncAsByte(_arrowInTheDoor);
if (sz.isSaving()) {
uint16 like2drinkSize = _favoriteDrink.size();
sz.syncAsUint16LE(like2drinkSize);
for (uint16 i = 0; i < like2drinkSize; i++) {
char actChr = _favoriteDrink[i];
sz.syncAsByte(actChr);
}
uint16 favoriteSongSize = _favoriteSong.size();
sz.syncAsUint16LE(favoriteSongSize);
for (uint16 i = 0; i < favoriteSongSize; i++) {
char actChr = _favoriteSong[i];
sz.syncAsByte(actChr);
}
uint16 worst_place_on_earthSize = _worstPlaceOnEarth.size();
sz.syncAsUint16LE(worst_place_on_earthSize);
for (uint16 i = 0; i < worst_place_on_earthSize; i++) {
char actChr = _worstPlaceOnEarth[i];
sz.syncAsByte(actChr);
}
uint16 spare_eveningSize = _spareEvening.size();
sz.syncAsUint16LE(spare_eveningSize);
for (uint16 i = 0; i < spare_eveningSize; i++) {
char actChr = _spareEvening[i];
sz.syncAsByte(actChr);
}
} else {
if (!_favoriteDrink.empty())
_favoriteDrink.clear();
uint16 like2drinkSize = 0;
char actChr = ' ';
sz.syncAsUint16LE(like2drinkSize);
for (uint16 i = 0; i < like2drinkSize; i++) {
sz.syncAsByte(actChr);
_favoriteDrink += actChr;
}
if (!_favoriteSong.empty())
_favoriteSong.clear();
uint16 favoriteSongSize = 0;
sz.syncAsUint16LE(favoriteSongSize);
for (uint16 i = 0; i < favoriteSongSize; i++) {
sz.syncAsByte(actChr);
_favoriteSong += actChr;
}
if (!_worstPlaceOnEarth.empty())
_worstPlaceOnEarth.clear();
uint16 worst_place_on_earthSize = 0;
sz.syncAsUint16LE(worst_place_on_earthSize);
for (uint16 i = 0; i < worst_place_on_earthSize; i++) {
sz.syncAsByte(actChr);
_worstPlaceOnEarth += actChr;
}
if (!_spareEvening.empty())
_spareEvening.clear();
uint16 spare_eveningSize = 0;
sz.syncAsUint16LE(spare_eveningSize);
for (uint16 i = 0; i < spare_eveningSize; i++) {
sz.syncAsByte(actChr);
_spareEvening += actChr;
}
}
sz.syncAsSint32LE(_totalTime);
sz.syncAsByte(_jumpStatus);
sz.syncAsByte(_mushroomGrowing);
sz.syncAsByte(_spludwickAtHome);
sz.syncAsByte(_lastRoom);
sz.syncAsByte(_lastRoomNotMap);
sz.syncAsByte(_crapulusWillTell);
sz.syncAsByte(_enterCatacombsFromLustiesRoom);
sz.syncAsByte(_teetotal);
sz.syncAsByte(_malagauche);
sz.syncAsByte(_drinking);
sz.syncAsByte(_enteredLustiesRoomAsMonk);
sz.syncAsByte(_catacombX);
sz.syncAsByte(_catacombY);
sz.syncAsByte(_avvysInTheCupboard);
sz.syncAsByte(_geidaFollows);
sz.syncAsByte(_givenPotionToGeida);
sz.syncAsByte(_lustieIsAsleep);
sz.syncAsByte(_beenTiedUp);
sz.syncAsByte(_sittingInPub);
sz.syncAsByte(_spurgeTalkCount);
sz.syncAsByte(_metAvaroid);
sz.syncAsByte(_takenMushroom);
sz.syncAsByte(_givenPenToAyles);
sz.syncAsByte(_askedDogfoodAboutNim);
for (int i = 0; i < 7; i++) {
sz.syncAsSint32LE(_timer->_times[i]._timeLeft);
sz.syncAsByte(_timer->_times[i]._action);
sz.syncAsByte(_timer->_times[i]._reason);
}
}
bool AvalancheEngine::canSaveGameStateCurrently(Common::U32String *msg) {
return (_animationsEnabled && _alive);
}
Common::Error AvalancheEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
return (saveGame(slot, desc) ? Common::kNoError : Common::kWritingFailed);
}
bool AvalancheEngine::saveGame(const int16 slot, const Common::String &desc) {
Common::String fileName = getSaveStateName(slot);
Common::OutSaveFile *f = g_system->getSavefileManager()->openForSaving(fileName);
if (!f) {
warning("Can't create file '%s', game not saved.", fileName.c_str());
return false;
}
f->writeUint32LE(MKTAG('A', 'V', 'A', 'L'));
// Write version. We can't restore from obsolete versions.
f->writeByte(kSavegameVersion);
f->writeUint32LE(desc.size());
f->write(desc.c_str(), desc.size());
Graphics::saveThumbnail(*f);
TimeDate t;
_system->getTimeAndDate(t);
f->writeSint16LE(t.tm_mday);
f->writeSint16LE(t.tm_mon);
f->writeSint16LE(t.tm_year);
_totalTime += getTimeInSeconds() - _startTime;
Common::Serializer sz(nullptr, f);
synchronize(sz);
f->finalize();
delete f;
return true;
}
bool AvalancheEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return (_animationsEnabled);
}
Common::Error AvalancheEngine::loadGameState(int slot) {
return (loadGame(slot) ? Common::kNoError : Common::kReadingFailed);
}
bool AvalancheEngine::loadGame(const int16 slot) {
Common::String fileName = getSaveStateName(slot);
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
if (!f)
return false;
uint32 signature = f->readUint32LE();
if (signature != MKTAG('A', 'V', 'A', 'L'))
return false;
// Check version. We can't restore from obsolete versions.
byte saveVersion = f->readByte();
if (saveVersion > kSavegameVersion) {
warning("Savegame of incompatible version!");
delete f;
return false;
}
// Read the description.
uint32 descSize = f->readUint32LE();
Common::String description;
for (uint32 i = 0; i < descSize; i++) {
char actChar = f->readByte();
description += actChar;
}
description.toUppercase();
Graphics::skipThumbnail(*f);
// Read the time the game was saved.
TimeDate t;
t.tm_mday = f->readSint16LE();
t.tm_mon = f->readSint16LE();
t.tm_year = f->readSint16LE();
resetAllVariables();
Common::Serializer sz(f, nullptr);
synchronize(sz);
delete f;
_isLoaded = true;
_animationsEnabled = false;
if (_holdTheDawn) {
_holdTheDawn = false;
fadeIn();
}
_background->release();
minorRedraw();
_dropdown->setup();
setRoom(kPeopleAvalot, _room);
_alive = true;
refreshObjectList();
_animation->updateSpeed();
drawDirection();
_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,
expandDate(t.tm_mday, t.tm_mon, t.tm_year).c_str());
_dialogs->displayText(tmpStr);
AnimationType *avvy = _animation->_sprites[0];
if (avvy->_quick && avvy->_visible)
_animation->setMoveSpeed(0, _animation->getDirection()); // We push Avvy in the right direction is he was moving.
return true;
}
Common::String AvalancheEngine::expandDate(int d, int m, int y) {
static const char months[12][10] = {
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
};
Common::String month = Common::String(months[m]);
Common::String day = intToStr(d);
if (((1 <= d) && (d <= 9)) || ((21 <= d) && (d <= 31)))
switch (d % 10) {
case 1:
day += "st";
break;
case 2:
day += "nd";
break;
case 3:
day += "rd";
break;
default:
day += "th";
}
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;
while (_eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
_holdLeftMouse = true; // Used in checkclick() and Menu::menu_link().
break;
case Common::EVENT_LBUTTONUP:
_holdLeftMouse = false; // Same as above.
break;
case Common::EVENT_KEYDOWN:
handleKeyDown(event);
break;
default:
break;
}
}
}
bool AvalancheEngine::getEvent(Common::Event &event) {
return _eventMan->pollEvent(event);
}
Common::Point AvalancheEngine::getMousePos() {
return _eventMan->getMousePos();
}
Common::Error AvalancheEngine::run() {
Common::ErrorCode err = initialize();
if (err != Common::kNoError)
return err;
do {
runAvalot();
} while (!_letMeOut && !shouldQuit());
return Common::kNoError;
}
} // End of namespace Avalanche

View File

@@ -0,0 +1,308 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_AVALANCHE_H
#define AVALANCHE_AVALANCHE_H
#include "avalanche/console.h"
#include "avalanche/graphics.h"
#include "avalanche/parser.h"
#include "avalanche/avalot.h"
#include "avalanche/dialogs.h"
#include "avalanche/background.h"
#include "avalanche/sequence.h"
#include "avalanche/timer.h"
#include "avalanche/animation.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/error.h"
#include "common/serializer.h"
#include "engines/engine.h"
#include "graphics/cursorman.h"
namespace Common {
class RandomSource;
}
namespace Avalanche {
struct AvalancheGameDescription;
static const int kSavegameVersion = 2;
enum Pitch {
kPitchInvalid,
kPitchLower,
kPitchSame,
kPitchHigher
};
class AvalancheEngine : public Engine {
public:
byte _saveNum; // number of times this game has been saved
Clock *_clock;
GraphicManager *_graphics;
Parser *_parser;
Dialogs *_dialogs;
Background *_background;
Sequence *_sequence;
Timer *_timer;
Animation *_animation;
DropDownMenu *_dropdown;
Closing *_closing;
SoundHandler *_sound;
Nim *_nim;
GhostRoom *_ghostroom;
Help *_help;
HighScore *_highscore;
AvalancheEngine(OSystem *syst, const AvalancheGameDescription *gd);
~AvalancheEngine() override;
Common::ErrorCode initialize();
Common::RandomSource *_rnd;
const AvalancheGameDescription *_gameDescription;
uint32 getFeatures() const;
const char *getGameId() const;
Common::Platform getPlatform() const;
bool hasFeature(EngineFeature f) const override;
const char *getCopyrightString() const;
void synchronize(Common::Serializer &sz);
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
bool saveGame(const int16 slot, const Common::String &desc);
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error loadGameState(int slot) override;
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.
Common::Point getMousePos();
protected:
// Engine APIs
Common::Error run() override;
public:
// For Thinkabout:
static const bool kThing = true;
static const bool kPerson = false;
static const char kSpludwicksOrder[3];
static const uint16 kNotes[12];
bool _holdLeftMouse;
// If this is greater than zero, the next line you type is stored in the DNA in a position dictated by the value.
// If a scroll comes up, or you leave the room, it's automatically set to zero.
byte _interrogation;
// Former DNA structure
byte _carryNum; // How many objects you're carrying...
bool _objects[kObjectNum]; // ...and which ones they are.
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.)
byte _wineState; // 0=good (Notts), 1=passable(Argent) ... 3=vinegar.
bool _cwytalotGone; // Has Cwytalot rushed off to Jerusalem yet?
byte _passwordNum; // Number of the passw for this game.
bool _aylesIsAwake; // pretty obvious!
byte _drawbridgeOpen; // Between 0 (shut) and 4 (open).
byte _avariciusTalk; // How much Avaricius has said to you.
bool _rottenOnion; // And has it rotted?
bool _onionInVinegar; // Is the onion in the vinegar?
byte _givenToSpludwick; // 0 = nothing given, 1 = onion...
byte _brummieStairs; // Progression through the stairs trick.
byte _cardiffQuestionNum; // Things you get asked in Cardiff.
bool _avvyIsAwake; // Well? Is Avvy awake? (Screen 1 only.)
bool _avvyInBed; // True if Avvy's in bed, but awake.
bool _userMovesAvvy; // If this is false, the user has no control over Avvy's movements.
byte _npcFacing; // If there's an NPC in the current room which turns it's head according to Avvy's movement (keep looking at him), this variable tells which way it's facing at the moment.
bool _givenBadgeToIby; // Have you given the badge to Iby yet?
bool _friarWillTieYouUp; // If you're going to get tied up.
bool _tiedUp; // You ARE tied up!
byte _boxContent; // 0 = money (sixpence), 254 = empty, any other number implies the contents of the box.
bool _talkedToCrapulus; // Pretty self-explanatory.
byte _jacquesState; // 0=asleep, 1=awake, 2=gets up, 3=gone.
bool _bellsAreRinging; // Is Jacques ringing the bells?
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 _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?
bool _enterCatacombsFromLustiesRoom;
bool _teetotal; // Are we touching any more drinks?
byte _malagauche; // Position of Malagauche. See Celer for more info.
char _drinking; // What's he getting you?
bool _enteredLustiesRoomAsMonk;
byte _catacombX, _catacombY; // XY coords in the catacombs.
bool _avvysInTheCupboard; // On screen 22.
bool _geidaFollows; // Is Geida following you?
bool _givenPotionToGeida; // Does Geida have the potion?
bool _lustieIsAsleep; // Is BDL asleep?
bool _beenTiedUp; // In r__Robins.
bool _sittingInPub; // Are you sitting down in the pub?
byte _spurgeTalkCount; // Count for talking to Spurge.
bool _metAvaroid;
bool _takenMushroom, _givenPenToAyles, _askedDogfoodAboutNim;
// End of former DNA Structure
bool _showDebugLines;
byte _lineNum; // Number of lines.
LineType _lines[50]; // For Also.
bool _dropsOk;
bool _cheat; // CHECKME: Currently unused
bool _letMeOut;
byte _thinks;
bool _thinkThing;
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().
byte _currentMouse; // current mouse-void
Common::String *_also[31][2];
PedType _peds[15];
MagicType _magics[15];
MagicType _portals[7];
FieldType _fields[30];
byte _fieldNum;
Common::String _listen;
byte _cp, _ledStatus;
FontType _font;
bool _alive;
byte _subjectNum; // The same thing.
People _him, _her;
byte _it;
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 _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
void fxToggle();
void refreshObjectList();
void errorLed();
void fadeOut();
void fadeIn();
void drawDirection(); // Draws the little icon at the left end of the text input field.
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 was replaced with GraphicManager::refreshScreen(), it redraws EVERYTHING.
void minorRedraw();
void spriteRun();
Common::String intToStr(int32 num);
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.
void openDoor(Room whither, byte ped, byte magicnum); // Handles slidey-open doors.
void flipRoom(Room room, byte ped);
void setRoom(People persId, Room roomId);
Room getRoom(People persId);
private:
static const int16 kMaxSprites = 2; // Current max no. of sprites.
static Room _whereIs[29];
// Will be used in dusk() and dawn().
bool _fxHidden;
byte _fxPal[16][16][3];
bool _spludwickAtHome; // Is Spludwick at home?
bool _passedCwytalotInHerts; // Have you passed Cwytalot in Herts?
bool _holdTheDawn; // If this is true, calling Dawn will do nothing. It's used, for example, at the start, to stop Load from dawning.
byte _lastRoom;
byte _lastRoomNotMap;
byte _roomCount[100]; // Add one to each every time you enter a room
Common::String _mouseText;
Common::String _flags;
Common::String _roomnName; // Name of actual room
int8 _scoreToDisplay[3];
Common::String readAlsoStringFromFile(Common::File &file);
void runAvalot();
void init();
void initVariables();
void setup();
void scram(Common::String &str);
void unScramble();
void handleKeyDown(Common::Event &event); // To replace Basher::keyboard_link() and Basher::typein().
void enterNewTown();
void findPeople(byte room);
void putGeidaAt(byte whichPed, byte ped);
void guideAvvy(Common::Point cursorPos);
void enterRoom(Room room, byte ped);
void exitRoom(byte x);
void drawToolbar();
void drawScore();
void useCompass(const Common::Point &cursorPos); // Click on the compass on the toolbar to control Avvy's movement.
void checkClick();
void fixFlashers();
void loadAlso(byte num);
void resetAllVariables();
void resetVariables();
};
} // End of namespace Avalanche
#endif // AVALANCHE_AVALANCHE_H

1690
engines/avalanche/avalot.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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.
*/
/* AVALOT The kernel of the program. */
#ifndef AVALANCHE_AVALOT_H
#define AVALANCHE_AVALOT_H
#include "avalanche/animation.h"
namespace Avalanche {
class AvalancheEngine;
static const byte kObjectNum = 18; // always preface with a #
static const int16 kCarryLimit = 12; // carry limit
struct PedType {
int16 _x, _y;
Direction _direction;
};
struct MagicType {
byte _operation; // one of the operations
uint16 _data; // data for them
};
struct FieldType {
int16 _x1, _y1, _x2, _y2;
};
struct LineType : public FieldType {
Color _color;
};
struct QuasipedType {
byte _whichPed;
Color _textColor;
Room _room;
Color _backgroundColor;
People _who;
};
} // End of namespace Avalanche
#endif // AVALANCHE_AVALOT_H

View File

@@ -0,0 +1,384 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: CELER The unit for updating the screen pics. */
#include "avalanche/avalanche.h"
#include "avalanche/background.h"
namespace Avalanche {
const int16 Background::kOnDisk = -1;
Background::Background(AvalancheEngine *vm) {
_vm = vm;
_spriteNum = 0;
_nextBell = 0;
for (int i = 0; i < 40; ++i)
_offsets[i] = 0;
}
Background::~Background() {
release();
}
/**
* @remarks Originally called 'pics_link'
*/
void Background::update() {
if (_vm->_dropdown->isActive())
return; // No animation when the menus are up.
switch (_vm->_room) {
case kRoomOutsideArgentPub:
if ((_vm->_roomCycles % 12) == 0)
draw(-1, -1, (_vm->_roomCycles / 12) % 4);
break;
case kRoomBrummieRoad:
if ((_vm->_roomCycles % 2) == 0)
draw(-1, -1, (_vm->_roomCycles / 2) % 4);
break;
case kRoomBridge:
if ((_vm->_roomCycles % 2) == 0)
draw(-1, -1, 3 + (_vm->_roomCycles / 2) % 4);
break;
case kRoomYours:
if ((!_vm->_avvyIsAwake) && ((_vm->_roomCycles % 4) == 0))
draw(-1, -1, (_vm->_roomCycles / 12) % 2);
break;
case kRoomArgentPub:
if (((_vm->_roomCycles % 7) == 1) && (_vm->_malagauche != 177)) {
// Malagauche cycle.
_vm->_malagauche++;
switch (_vm->_malagauche) {
case 1:
case 11:
case 21:
draw(-1, -1, 11); // Looks forwards.
break;
case 8:
case 18:
case 28:
case 32:
draw(-1, -1, 10); // Looks at you.
break;
case 30:
draw(-1, -1, 12); // Winks.
break;
case 33:
_vm->_malagauche = 0;
break;
default:
break;
}
}
switch (_vm->_roomCycles % 200) {
case 179:
case 197:
draw(-1, -1, 4); // Dogfood's drinking cycle.
break;
case 182:
case 194:
draw(-1, -1, 5);
break;
case 185:
draw(-1, -1, 6);
break;
case 199:
_vm->_npcFacing = 177; // Impossible value for this.
break;
default:
if (_vm->_roomCycles % 200 <= 178) { // Normally.
byte direction = 1;
uint16 angle = _vm->bearing(1);
if (((angle >= 1) && (angle <= 90)) || ((angle >= 358) && (angle <= 360)))
direction = 3;
else if ((angle >= 293) && (angle <= 357))
direction = 2;
else if ((angle >= 270) && (angle <= 292))
direction = 4;
if (direction != _vm->_npcFacing) { // Dogfood.
draw(-1, -1, direction - 1);
_vm->_npcFacing = direction;
}
}
}
break;
case kRoomWestHall:
if ((_vm->_roomCycles % 3) == 0) {
switch ((_vm->_roomCycles / 3) % 6) {
case 4:
draw(-1, -1, 0);
break;
case 1:
case 3:
case 5:
draw(-1, -1, 1);
break;
case 0:
case 2:
draw(-1, -1, 2);
break;
default:
break;
}
}
break;
case kRoomLustiesRoom:
if (!(_vm->_lustieIsAsleep)) {
byte direction = 0;
uint16 angle = _vm->bearing(1);
if ((_vm->_roomCycles % 45) > 42)
direction = 4; // du Lustie blinks.
// Bearing of Avvy from du Lustie.
else if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
direction = 1; // Middle.
else if (angle <= 180)
direction = 2; // Left.
else if (angle <= 314)
direction = 3; // Right.
if (direction != _vm->_npcFacing) { // du Lustie.
draw(-1, -1, direction - 1);
_vm->_npcFacing = direction;
}
}
break;
case kRoomAylesOffice:
if ((!_vm->_aylesIsAwake) && (_vm->_roomCycles % 14 == 0)) {
switch ((_vm->_roomCycles / 14) % 2) {
case 0:
draw(-1, -1, 0); // Frame 2: EGA.
break;
case 1:
draw(-1, -1, 2); // Frame 1: Natural.
break;
default:
break;
}
}
break;
case kRoomRobins:
if (_vm->_tiedUp) {
switch (_vm->_roomCycles % 54) {
case 20:
draw(-1, -1, 3); // Frame 4: Avalot blinks.
break;
case 23:
draw(-1, -1, 1); // Frame 1: Back to normal.
break;
default:
break;
}
}
break;
case kRoomNottsPub: {
// Bearing of Avvy from Port.
byte direction = 0;
uint16 angle = _vm->bearing(4);
if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
direction = 2; // Middle.
else if (angle <= 180)
direction = 6; // Left.
else if (angle <= 314)
direction = 8; // Right.
if ((_vm->_roomCycles % 60) > 57)
direction--; // Blinks.
if (direction != _vm->_npcFacing) { // Port.
draw(-1, -1, direction - 1);
_vm->_npcFacing = direction;
}
switch (_vm->_roomCycles % 50) {
case 45 :
draw(-1, -1, 8); // Spurge blinks.
break;
case 49 :
draw(-1, -1, 9);
break;
default:
break;
}
break;
}
case kRoomDucks: {
if ((_vm->_roomCycles % 3) == 0) // The fire flickers.
draw(-1, -1, (_vm->_roomCycles / 3) % 3);
// Bearing of Avvy from Duck.
byte direction = 0;
uint16 angle = _vm->bearing(1);
if ((angle <= 45) || ((angle >= 315) && (angle <= 360)))
direction = 4; // Middle.
else if (angle <= 180)
direction = 6; // Left.
else if (angle <= 314)
direction = 8; // Right.
if ((_vm->_roomCycles % 45) > 42)
direction++; // Duck blinks.
if (direction != _vm->_npcFacing) { // Duck.
draw(-1, -1, direction - 1);
_vm->_npcFacing = direction;
}
break;
}
default:
break;
}
if ((_vm->_bellsAreRinging) && (_vm->getFlag('B'))) {
// They're ringing the bells.
switch (_vm->_roomCycles % 4) {
case 1:
if (_nextBell < 5)
_nextBell = 12;
_nextBell--;
// CHECKME: 2 is a guess. No length in the original?
_vm->_sound->playNote(_vm->kNotes[_nextBell], 2);
break;
case 2:
_vm->_sound->stopSound();
break;
default:
break;
}
}
}
void Background::loadSprites(byte number) {
Common::File f;
_filename = Common::Path(Common::String::format("chunk%d.avd", number));
if (!f.open(_filename))
return; // We skip because some rooms don't have sprites in the background.
f.seek(44);
_spriteNum = f.readByte();
for (int i = 0; i < _spriteNum; i++)
_offsets[i] = f.readSint32LE();
for (int i = 0; i < _spriteNum; i++) {
f.seek(_offsets[i]);
SpriteType sprite;
sprite._type = (PictureType)(f.readByte());
sprite._x = f.readSint16LE();
sprite._y = 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]._width = sprite._width;
_sprites[i]._y = sprite._y;
_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]._width * 8, _sprites[i]._height + 1);
}
} else
_sprites[i]._x = kOnDisk;
}
f.close();
}
void Background::release() {
for (int i = 0; i < _spriteNum; i++) {
if (_sprites[i]._x > kOnDisk)
_sprites[i]._picture.free();
}
}
/**
* Draw background animation
* @remarks Originally called 'show_one'
*/
void Background::draw(int16 destX, int16 destY, byte sprId) {
assert(sprId < 40);
if (_sprites[sprId]._x > kOnDisk) {
if (destX < 0) {
destX = _sprites[sprId]._x * 8;
destY = _sprites[sprId]._y;
}
drawSprite(destX, destY, _sprites[sprId]);
} else {
Common::File f;
if (!f.open(_filename)) // Filename was set in loadBackgroundSprites().
return; // We skip because some rooms don't have sprites in the background.
f.seek(_offsets[sprId]);
SpriteType sprite;
sprite._type = (PictureType)(f.readByte());
sprite._x = f.readSint16LE();
sprite._y = 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._width * 8, sprite._height + 1);
if (destX < 0) {
destX = sprite._x * 8;
destY = sprite._y;
}
drawSprite(destX, destY, sprite);
sprite._picture.free();
f.close();
}
}
/**
* @remarks Originally called 'display_it'
*/
void Background::drawSprite(int16 x, int16 y, SpriteType &sprite) {
// These pictures are practically parts of the background. -10 is for the drop-down menu.
_vm->_graphics->drawBackgroundSprite(x, y - 10, sprite);
}
void Background::resetVariables() {
_nextBell = 0;
}
void Background::synchronize(Common::Serializer &sz) {
sz.syncAsByte(_nextBell);
}
} // End of namespace Avalanche.

View File

@@ -0,0 +1,78 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: CELER The unit for updating the screen pics. */
#ifndef AVALANCHE_BACKGROUND_H
#define AVALANCHE_BACKGROUND_H
#include "common/str.h"
namespace Avalanche {
class AvalancheEngine;
enum PictureType {kEga, kBgi, kNaturalImage};
struct SpriteType {
PictureType _type;
int16 _x, _y;
int16 _width, _height;
int32 _size;
Graphics::Surface _picture;
};
class Background {
public:
Background(AvalancheEngine *vm);
~Background();
void update();
void loadSprites(byte number);
void release();
// Setting the destination to negative coordinates means the picture should be drawn to it's original position.
// If you give it positive values, the picture will be plotted to the desired coordinates on the screen.
// By that we get rid of show_one_at(), which would be almost identical and cause a lot of code duplication.
void draw(int16 destX, int16 destY, byte sprId);
void resetVariables();
void synchronize(Common::Serializer &sz);
private:
AvalancheEngine *_vm;
byte _nextBell; // For the ringing.
int32 _offsets[40];
byte _spriteNum;
SpriteType _sprites[40];
Common::Path _filename;
static const int16 kOnDisk; // Value of _sprites[fv]._x when it's not in memory.
void drawSprite(int16 x, int16 y, SpriteType &sprite);
};
} // End of namespace Avalanche.
#endif // AVALANCHE_BACKGROUND_H

117
engines/avalanche/clock.cpp Normal file
View File

@@ -0,0 +1,117 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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"
#include "common/system.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

59
engines/avalanche/clock.h Normal file
View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_CLOCK_H
#define AVALANCHE_CLOCK_H
#include "common/rect.h"
#include "avalanche/enums.h"
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();
};
} // End of namespace Avalanche
#endif // AVALANCHE_CLOCK_H

View File

@@ -0,0 +1,74 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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.
*/
/* CLOSING The closing screen and error handler. */
#include "avalanche/avalanche.h"
#include "avalanche/closing.h"
#include "common/random.h"
namespace Avalanche {
Closing::Closing(AvalancheEngine *vm) {
_vm = vm;
warning("STUB: Closing::Closing()");
}
void Closing::getScreen(ScreenType which) {
warning("STUB: Closing::getScreen()");
}
void Closing::showScreen() {
warning("STUB: Closing::showScreen()");
}
void Closing::putIn(Common::String str, uint16 where) {
warning("STUB: Closing::putIn()");
}
void Closing::exitGame() {
static const char nouns[12][14] = {
"sackbut", "harpsichord", "camel", "conscience", "ice-cream", "serf",
"abacus", "castle", "carrots", "megaphone", "manticore", "drawbridge"
};
static const char verbs[12][12] = {
"haunt", "daunt", "tickle", "gobble", "erase", "provoke",
"surprise", "ignore", "stare at", "shriek at", "frighten", "quieten"
};
_vm->_sound->stopSound();
getScreen(kScreenNagScreen);
byte nounId = _vm->_rnd->getRandomNumber(11);
byte verbId = _vm->_rnd->getRandomNumber(11);
Common::String result = Common::String::format("%s will %s you", nouns[nounId], verbs[verbId]);
putIn(result, 1628);
showScreen(); // No halt- it's already set up.
}
} // End of namespace Avalanche.

View File

@@ -0,0 +1,61 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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.
*/
/* CLOSING The closing screen and error handler. */
#ifndef AVALANCHE_CLOSING_H
#define AVALANCHE_CLOSING_H
#include "common/str.h"
namespace Avalanche {
class AvalancheEngine;
class Closing {
public:
Closing(AvalancheEngine *vm);
void exitGame();
private:
// Will be needed during implementation of Closing.
enum ScreenType {
kScreenBugAlert = 1,
kScreenRamCram = 2,
kScreenNagScreen = 3,
kScreenTwoCopies = 5
};
AvalancheEngine *_vm;
void getScreen(ScreenType which);
void showScreen();
void putIn(Common::String str, uint16 where);
};
} // End of namespace Avalanche.
#endif // AVALANCHE_CLOSING_H

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine avalanche "Lord Avalot d'Argent" no "" "" "highres"

View File

@@ -0,0 +1,52 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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/console.h"
#include "avalanche/avalanche.h"
namespace Avalanche {
AvalancheConsole::AvalancheConsole(AvalancheEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("magic_lines", WRAP_METHOD(AvalancheConsole, Cmd_MagicLines));
}
AvalancheConsole::~AvalancheConsole() {
}
/**
* This command loads up the specified new scene number
*/
bool AvalancheConsole::Cmd_MagicLines(int argc, const char **argv) {
if (argc != 1) {
debugPrintf("Usage: %s\n", argv[0]);
return true;
}
_vm->_showDebugLines = !_vm->_showDebugLines;
return false;
}
} // End of namespace Avalanche

View File

@@ -0,0 +1,50 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_CONSOLE_H
#define AVALANCHE_CONSOLE_H
#include "gui/debugger.h"
namespace Avalanche {
class AvalancheEngine;
class AvalancheConsole : public GUI::Debugger {
public:
AvalancheConsole(AvalancheEngine *vm);
~AvalancheConsole(void) override;
protected:
bool Cmd_MagicLines(int argc, const char **argv);
private:
AvalancheEngine *_vm;
};
} // End of namespace Avalanche
#endif // AVALANCHE_CONSOLE_H

View File

@@ -0,0 +1,4 @@
begin_section("Avalanche");
add_person("Peter Bozs&oacute;", "uruk", "");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
end_section();

View File

@@ -0,0 +1,75 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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 "base/plugins.h"
#include "engines/advancedDetector.h"
#include "avalanche/detection.h"
namespace Avalanche {
static const PlainGameDescriptor avalancheGames[] = {
{"avalanche", "Lord Avalot d'Argent"},
{nullptr, nullptr}
};
static const AvalancheGameDescription gameDescriptions[] = {
{{
"avalanche", nullptr,
AD_ENTRY2s("avalot.sez", "de10eb353228013da3d3297784f81ff9", 48763,
"mainmenu.avd", "89f31211af579a872045b175cc264298", 18880),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_UNSTABLE,
GUIO1(GUIO_NOMIDI)
}},
{AD_TABLE_END_MARKER}
};
class AvalancheMetaEngineDetection : public AdvancedMetaEngineDetection<AvalancheGameDescription> {
public:
AvalancheMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, avalancheGames) {
}
const char *getName() const override {
return "avalanche";
}
const char *getEngineName() const override {
return "Avalanche";
}
const char *getOriginalCopyright() const override {
return "Avalanche (C) 1994-1995 Mike, Mark and Thomas Thurman.";
}
};
} // End of namespace Avalanche
REGISTER_PLUGIN_STATIC(AVALANCHE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, Avalanche::AvalancheMetaEngineDetection);

View File

@@ -0,0 +1,40 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_DETECTION_H
#define AVALANCHE_DETECTION_H
namespace Avalanche {
struct AvalancheGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
};
} // End of namespace Avalanche
#endif // AVALANCHE_DETECTION_H

File diff suppressed because it is too large Load Diff

118
engines/avalanche/dialogs.h Normal file
View File

@@ -0,0 +1,118 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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.
*/
/* SCROLLS The scroll driver. */
#ifndef AVALANCHE_DIALOGS_H
#define AVALANCHE_DIALOGS_H
namespace Avalanche {
class AvalancheEngine;
class Dialogs;
typedef void (Dialogs::*DialogFunctionType)();
class Dialogs {
public:
bool _aboutBox; // Is this the about box? - Used in scrollModeNormal(), not yet fully implemented
FontType _fonts[2];
Dialogs(AvalancheEngine *vm);
void init();
void reset();
void setReadyLight(byte state);
void displayText(Common::String text);
bool displayQuestion(Common::String question);
void setTalkPos(int16 x, int16 y);
int16 getTalkPosX();
void setBubbleStateNatural();
void displayMusicalScroll();
void displayScrollChain(char block, byte point, bool report = true, bool bubbling = false);
void talkTo(byte whom);
void sayIt(Common::String str);
Common::String personSpeaks();
void sayThanks(byte thing);
void sayHello();
void sayOK();
void saySilly();
private:
AvalancheEngine *_vm;
int16 _talkX, _talkY;
enum FontStyle {
kFontStyleRoman,
kFontStyleItalic
};
typedef int8 TuneType[31];
static const TuneType kTune;
static const int16 kHalfIconWidth = 19;
static const QuasipedType kQuasipeds[16];
Common::String _scroll[15];
Common::Point _dodgeCoord;
byte _maxLineNum;
bool _scReturn;
bool _noError;
byte _currentFont;
byte _param; // For using arguments code
byte _useIcon;
byte _scrollBells; // no. of times to ring the bell
int16 _underScroll; // Y-coord of just under the scroll text.
int16 _shadowBoxX, _shadowBoxY;
void drawBubble(DialogFunctionType modeFunc);
void drawScroll(DialogFunctionType modeFunc);
void scrollModeNormal();
void scrollModeDialogue();
void scrollModeMusic();
// These 2 are used only in musicalScroll().
void store(byte what, TuneType &played);
bool theyMatch(TuneType &played);
void stripTrailingSpaces(Common::String &str);
void solidify(byte n);
void dodgem();
void unDodgem();
Common::String displayMoney();
void easterEgg();
void say(int16 x, int16 y, Common::String text);
void resetScrollDriver();
void ringBell();
void loadFont();
void unSkrimble(Common::String &text);
void doTheBubble(Common::String &text);
void speak(byte who, byte subject);
};
} // End of namespace Avalanche
#endif // AVALANCHE_DIALOGS_H

View File

@@ -0,0 +1,849 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: DROPDOWN A customized version of Oopmenu (qv). */
#include "avalanche/avalanche.h"
#include "avalanche/dropdown.h"
namespace Avalanche {
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 * _dropdown->kSpacing + _dropdown->kIndent;
_xright = (_position + 1) * _dropdown->kSpacing + _dropdown->kIndent;
_setupFunc = setupFunc;
_chooseFunc = chooseFunc;
_dropdown = menu;
}
void HeadType::draw() {
CursorMan.showMouse(false);
_dropdown->drawMenuText(_xpos, 1, _trigger, _title, true, false);
CursorMan.showMouse(true);
}
void HeadType::highlight() {
CursorMan.showMouse(false);
_dropdown->_vm->_sound->stopSound();
_dropdown->drawMenuText(_xpos, 1, _trigger, _title, true, true);
_dropdown->_activeMenuItem._left = _xpos;
_dropdown->_activeMenuItem._activeNow = true;
_dropdown->_activeMenuItem._activeNum = _position;
_dropdown->_menuActive = true;
// Force reload and redraw of cursor.
_dropdown->_vm->_currentMouse = 177;
}
bool HeadType::parseAltTrigger(char key) {
if (key != _altTrigger)
return true;
return false;
}
void MenuItem::init(DropDownMenu *menu) {
_dropdown = menu;
_activeNow = false;
_activeNum = 1;
_dropdown->_menuActive = false;
}
void MenuItem::reset() {
_optionNum = 0;
_width = 0;
_firstlix = false;
_oldY = 0;
_highlightNum = 0;
}
void MenuItem::setupOption(Common::String title, char trigger, Common::String shortcut, bool valid) {
uint16 width = (title + shortcut).size() + 3;
if (_width < width)
_width = width;
_options[_optionNum]._title = title;
_options[_optionNum]._trigger = trigger;
_options[_optionNum]._shortcut = shortcut;
_options[_optionNum]._valid = valid;
_optionNum++;
}
void MenuItem::displayOption(byte y, bool highlit) {
Common::String text = _options[y]._title;
while (text.size() + _options[y]._shortcut.size() < _width)
text += ' '; // Pad _options[y] with spaces.
text += _options[y]._shortcut;
Color backgroundColor;
if (highlit)
backgroundColor = kColorBlack;
else
backgroundColor = kColorLightgray;
_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() {
CursorMan.showMouse(false);
_firstlix = true;
_flx1 = _left - 2;
_flx2 = _left + _width;
_fly = 15 + _optionNum * 10;
_activeNow = true;
_dropdown->_menuActive = true;
_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);
_dropdown->_vm->_currentMouse = 177;
CursorMan.showMouse(true); // 4 = fletch
}
void MenuItem::wipe() {
CursorMan.showMouse(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;
_dropdown->_menuActive = false;
_firstlix = false;
CursorMan.showMouse(true);
}
void MenuItem::moveHighlight(int8 inc) {
if (inc != 0) {
int8 highlightNum = _highlightNum + inc;
if ((highlightNum < 0) || (highlightNum >= _optionNum))
return;
_highlightNum = highlightNum;
}
CursorMan.showMouse(false);
displayOption(_oldY, false);
displayOption(_highlightNum, true);
_oldY = _highlightNum;
CursorMan.showMouse(true);
}
/**
* This makes the menu highlight follow the mouse.
* @remarks Originally called 'lightup'
*/
void MenuItem::lightUp(Common::Point cursorPos) {
if ((cursorPos.x < _flx1 * 8) || (cursorPos.x > _flx2 * 8) || (cursorPos.y <= 25) || (cursorPos.y > ((_fly - 3) * 2 + 1)))
return;
_highlightNum = (cursorPos.y - 26) / 20;
if (_highlightNum == _oldY)
return;
moveHighlight(0);
}
void MenuItem::select(byte which) {
if (!_options[which]._valid)
return;
_choiceNum = which;
wipe();
if (_choiceNum == _optionNum)
_choiceNum--; // Off the bottom.
if (_choiceNum > _optionNum)
_choiceNum = 0; // Off the top, I suppose.
(_dropdown->*_dropdown->_menuBar._menuItems[_activeNum]._chooseFunc)();
}
void MenuItem::parseKey(char c) {
c = toupper(c);
bool found = false;
for (int i = 0; i < _optionNum; i++) {
if ((toupper(_options[i]._trigger) == c) && _options[i]._valid) {
select(i);
found = true;
}
}
if (!found)
_dropdown->_vm->_sound->blip();
}
MenuBar::MenuBar() {
_menuNum = 0;
_dropdown = nullptr;
}
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, _dropdown);
_menuNum++;
}
void MenuBar::draw() {
_dropdown->_vm->_graphics->drawMenuBar(kMenuBackgroundColor);
byte savecp = _dropdown->_vm->_cp;
_dropdown->_vm->_cp = 3;
for (int i = 0; i < _menuNum; i++)
_menuItems[i].draw();
_dropdown->_vm->_cp = savecp;
}
void MenuBar::parseAltTrigger(char c) {
byte i = 0;
while ((i < _menuNum) && (_menuItems[i].parseAltTrigger(c)))
i++;
if (i == _menuNum)
return;
setupMenuItem(i);
}
void MenuBar::setupMenuItem(byte which) {
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();
(_dropdown->*_menuItems[which]._setupFunc)();
}
void MenuBar::chooseMenuItem(int16 x) {
for (int i = 0; i < _menuNum; i++) {
if ((x > _menuItems[i]._xpos * 8) && (x < _menuItems[i]._xright * 8)) {
setupMenuItem(i);
break;
}
}
}
DropDownMenu::DropDownMenu(AvalancheEngine *vm) {
_vm = vm;
_activeMenuItem.init(this);
_menuBar.init(this);
_menuActive = false;
_lastPerson = kPeopleNone;
}
void DropDownMenu::findWhatYouCanDoWithIt() {
switch (_vm->_thinks) {
case kObjectWine:
case kObjectPotion:
case kObjectInk:
_verbStr = Common::String(kVerbCodeExam) + kVerbCodeDrink;
break;
case kObjectBell:
_verbStr = Common::String(kVerbCodeExam) + kVerbCodeRing;
break;
case kObjectClothes:
case kObjectChastity:
_verbStr = Common::String(kVerbCodeExam) + kVerbCodeWear;
break;
case kObjectLute:
_verbStr = Common::String(kVerbCodeExam) + kVerbCodePlay;
break;
case kObjectMushroom:
case kObjectOnion:
_verbStr = Common::String(kVerbCodeExam) + kVerbCodeEat;
break;
default:
_verbStr = kVerbCodeExam; // Anything else.
}
}
void DropDownMenu::drawMenuText(int16 x, int16 y, char trigger, Common::String text, bool valid, bool highlighted) {
Color fontColor;
Color backgroundColor;
if (highlighted) {
fontColor = kColorWhite;
backgroundColor = kColorBlack;
} else {
fontColor = kColorBlack;
backgroundColor = kColorLightgray;
}
byte ander = valid ? 255 : 170;
FontType font;
for (uint i = 0; i < text.size(); i++) {
for (int j = 0; j < 8; j++) {
byte idx = text[i];
font[idx][j] = _vm->_font[idx][j] & ander; // Set the font.
// And set the background of the text to the desired color.
_vm->_graphics->wipeChar(x * 8 + i * 8, y + j, backgroundColor);
}
}
_vm->_graphics->drawNormalText(text, font, 8, x * 8, y, fontColor);
// Underline the selected character.
if ((trigger == 0) || !text.contains(trigger) )
return;
else {
byte i;
for (i = 0; text[i] != trigger; i++)
; // Search for the character in the string.
_vm->_graphics->drawChar(ander, x * 8 + i * 8, y + 8, fontColor);
}
_vm->_graphics->refreshScreen();
}
void DropDownMenu::bleep() {
_vm->_sound->playNote(177, 7);
}
void DropDownMenu::parseKey(char r, char re) {
#if 0
switch (r) {
case 0:
case 224: {
switch (re) {
case 'K':
if (_activeMenuItem._activeNum > 1) {
_activeMenuItem.wipe();
_menuBar.setupMenuItem(_activeMenuItem._activeNum - 1);
} else {
// Get menu on the left-hand side.
_activeMenuItem.wipe();
_menuBar.chooseMenuItem((_menuBar._menuNum - 1) * kSpacing + kIndent);
}
break;
case 'M':
if (_activeMenuItem._activeNum < _menuBar._menuNum) {
_activeMenuItem.wipe();
_menuBar.setupMenuItem(_activeMenuItem._activeNum + 1);
} else {
// Get menu on the far right-hand side.
_activeMenuItem.wipe();
_menuBar.chooseMenuItem(kIndent);
}
break;
case 'H':
_activeMenuItem.moveHighlight(-1);
break;
case 'P':
_activeMenuItem.moveHighlight(1);
break;
default:
_menuBar.parseAltTrigger(re);
}
}
break;
case 13:
_activeMenuItem.select(_activeMenuItem._highlightNum);
break;
default:
if (_activeMenuItem._activeNow)
_activeMenuItem.parseKey(r);
}
#endif
warning("STUB: Dropdown::parseKey()"); // To be implemented properly later! Don't remove the comment above!
}
Common::String DropDownMenu::selectGender(byte x) {
if (x < 175)
return "im";
else
return "er";
}
void DropDownMenu::setupMenuGame() {
_activeMenuItem.reset();
_activeMenuItem.setupOption("Help...", 'H', "f1", 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 DropDownMenu::setupMenuFile() {
_activeMenuItem.reset();
_activeMenuItem.setupOption("New game", 'N', "f4", true);
_activeMenuItem.setupOption("Load...", 'L', "^f3", true);
_activeMenuItem.setupOption("Save", 'S', "^f2", _vm->_alive);
_activeMenuItem.setupOption("Save As...", 'v', "", _vm->_alive);
_activeMenuItem.setupOption("DOS Shell", 'D', "alt-1", false);
_activeMenuItem.setupOption("Quit", 'Q', "alt-X", true);
_activeMenuItem.display();
}
void DropDownMenu::setupMenuAction() {
_activeMenuItem.reset();
Common::String f5Does = _vm->f5Does();
for (int i = 0; i < 2; i++)
if (!f5Does.empty())
f5Does.deleteChar(0);
if (f5Does.empty())
_activeMenuItem.setupOption("Do something", 'D', "f5", false);
else
_activeMenuItem.setupOption(f5Does, f5Does[0], "f5", true);
_activeMenuItem.setupOption("Pause game", 'P', "f6", true);
if (_vm->_room == kRoomMap)
_activeMenuItem.setupOption("Journey thither", 'J', "f7", _vm->_animation->nearDoor());
else
_activeMenuItem.setupOption("Open the door", 'O', "f7", _vm->_animation->nearDoor());
_activeMenuItem.setupOption("Look around", 'L', "f8", true);
_activeMenuItem.setupOption("Inventory", 'I', "Tab", true);
if (_vm->_animation->_sprites[0]->_speedX == kWalk)
_activeMenuItem.setupOption("Run fast", 'R', "^R", true);
else
_activeMenuItem.setupOption("Walk slowly", 'W', "^W", true);
_activeMenuItem.display();
}
void DropDownMenu::setupMenuPeople() {
if (!people.empty())
people.clear();
_activeMenuItem.reset();
for (int i = kPeopleAvalot; i <= kPeopleWisewoman; i++) {
if (_vm->getRoom((People)i) == _vm->_room) {
_activeMenuItem.setupOption(_vm->getName((People)i), getNameChar((People)i), "", true);
people += i;
}
}
_activeMenuItem.display();
}
void DropDownMenu::setupMenuObjects() {
_activeMenuItem.reset();
for (int i = 0; i < kObjectNum; i++) {
if (_vm->_objects[i])
_activeMenuItem.setupOption(getThing(i + 1), getThingChar(i + 1), "", true);
}
_activeMenuItem.display();
}
void DropDownMenu::setupMenuWith() {
_activeMenuItem.reset();
if (_vm->_thinkThing) {
findWhatYouCanDoWithIt();
for (uint i = 0; i < _verbStr.size(); i++) {
char vbchar;
Common::String verb;
_vm->_parser->verbOpt(_verbStr[i], verb, vbchar);
_activeMenuItem.setupOption(verb, vbchar, "", true);
}
// We disable the "give" option if: (a), you haven't selected anybody, (b), the _person you've selected isn't in the room,
// or (c), the _person you've selected is YOU!
if ((_lastPerson == kPeopleAvalot) || (_lastPerson == _vm->_parser->kNothing)
|| (_vm->getRoom(_lastPerson) != _vm->_room))
_activeMenuItem.setupOption("Give to...", 'G', "", false); // Not here.
else {
_activeMenuItem.setupOption(Common::String("Give to ") + _vm->getName(_lastPerson), 'G', "", true);
_verbStr = _verbStr + kVerbCodeGive;
}
} else {
_activeMenuItem.setupOption("Examine", 'x', "", true);
_activeMenuItem.setupOption(Common::String("Talk to h") + selectGender(_vm->_thinks), 'T', "", true);
_verbStr = Common::String(kVerbCodeExam) + kVerbCodeTalk;
switch (_vm->_thinks) {
case kPeopleGeida:
case kPeopleArkata:
_activeMenuItem.setupOption("Kiss her", 'K', "", true);
_verbStr = _verbStr + kVerbCodeKiss;
break;
case kPeopleDogfood:
_activeMenuItem.setupOption("Play his game", 'P', "", !_vm->_wonNim); // True if you HAVEN'T won.
_verbStr = _verbStr + kVerbCodePlay;
break;
case kPeopleMalagauche: {
bool isSober = !_vm->_teetotal;
_activeMenuItem.setupOption("Buy some wine", 'w', "", !_vm->_objects[kObjectWine - 1]);
_activeMenuItem.setupOption("Buy some beer", 'b', "", isSober);
_activeMenuItem.setupOption("Buy some whisky", 'h', "", isSober);
_activeMenuItem.setupOption("Buy some cider", 'c', "", isSober);
_activeMenuItem.setupOption("Buy some mead", 'm', "", isSober);
_verbStr = _verbStr + 101 + 100 + 102 + 103 + 104;
}
break;
case kPeopleTrader:
_activeMenuItem.setupOption("Buy an onion", 'o', "", !_vm->_objects[kObjectOnion - 1]);
_verbStr = _verbStr + 105;
break;
default:
break;
}
}
_activeMenuItem.display();
}
void DropDownMenu::runMenuGame() {
// Help, boss, untrash screen.
switch (_activeMenuItem._choiceNum) {
case 0:
_vm->callVerb(kVerbCodeHelp);
break;
case 1:
_vm->callVerb(kVerbCodeBoss);
break;
case 2:
_vm->_graphics->refreshScreen();
break;
case 3:
_vm->callVerb(kVerbCodeScore);
break;
case 4:
_vm->callVerb(kVerbCodeInfo);
break;
default:
break;
}
}
void DropDownMenu::runMenuFile() {
// New game, load, save, save as, DOS shell, about, quit.
switch (_activeMenuItem._choiceNum) {
case 0:
_vm->callVerb(kVerbCodeRestart);
break;
case 1:
if (!_vm->_parser->_realWords[1].empty())
_vm->_parser->_realWords[1].clear();
_vm->callVerb(kVerbCodeLoad);
break;
// Case 2 is 'Save', Case 3 is 'Save As'. Both triggers ScummVM save screen.
case 2:
case 3:
if (!_vm->_parser->_realWords[1].empty())
_vm->_parser->_realWords[1].clear();
_vm->callVerb(kVerbCodeSave);
break;
case 4:
// Command Prompt, disabled
break;
case 5:
_vm->callVerb(kVerbCodeQuit);
break;
default:
break;
}
}
void DropDownMenu::runMenuAction() {
// Get up, pause game, open door, look, inventory, walk/run.
switch (_activeMenuItem._choiceNum) {
case 0: {
_vm->_parser->_person = kPeoplePardon;
_vm->_parser->_thing = _vm->_parser->kPardon;
Common::String f5Does = _vm->f5Does();
VerbCode verb = (VerbCode)(byte)f5Does[0];
_vm->callVerb(verb);
}
break;
case 1:
_vm->_parser->_thing = _vm->_parser->kPardon;
_vm->callVerb(kVerbCodePause);
break;
case 2:
_vm->callVerb(kVerbCodeOpen);
break;
case 3:
_vm->_parser->_thing = _vm->_parser->kPardon;
_vm->callVerb(kVerbCodeLook);
break;
case 4:
_vm->callVerb(kVerbCodeInv);
break;
case 5: {
AnimationType *avvy = _vm->_animation->_sprites[0];
if (avvy->_speedX == kWalk)
avvy->_speedX = kRun;
else
avvy->_speedX = kWalk;
_vm->_animation->updateSpeed();
}
break;
default:
break;
}
}
void DropDownMenu::runMenuObjects() {
_vm->thinkAbout(_vm->_objectList[_activeMenuItem._choiceNum], AvalancheEngine::kThing);
}
void DropDownMenu::runMenuPeople() {
_vm->thinkAbout(people[_activeMenuItem._choiceNum], AvalancheEngine::kPerson);
_lastPerson = (People)people[_activeMenuItem._choiceNum];
}
void DropDownMenu::runMenuWith() {
_vm->_parser->_thing = _vm->_thinks;
if (_vm->_thinkThing) {
_vm->_parser->_thing += 49;
if (_verbStr[_activeMenuItem._choiceNum] == kVerbCodeGive)
_vm->_parser->_person = _lastPerson;
else
_vm->_parser->_person = kPeoplePardon;
} else {
switch (_verbStr[_activeMenuItem._choiceNum]) {
case 100: // Beer
case 102: // Whisky
case 103: // Cider
_vm->_parser->_thing = _verbStr[_activeMenuItem._choiceNum];
_vm->callVerb(kVerbCodeBuy);
return;
case 101: // Wine
_vm->_parser->_thing = 50;
_vm->callVerb(kVerbCodeBuy);
return;
case 104: // Mead
_vm->_parser->_thing = 107;
_vm->callVerb(kVerbCodeBuy);
return;
case 105: // Onion (trader)
_vm->_parser->_thing = 67;
_vm->callVerb(kVerbCodeBuy);
return;
default:
_vm->_parser->_person = (People)_vm->_parser->_thing;
_vm->_parser->_thing = Parser::kPardon;
_vm->_subjectNum = 0;
}
}
_vm->callVerb((VerbCode)(byte)_verbStr[_activeMenuItem._choiceNum]);
}
void DropDownMenu::setup() {
_menuBar.init(this);
_activeMenuItem.init(this);
_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 DropDownMenu::update() {
_vm->_graphics->saveScreen();
Common::Point cursorPos = _vm->getMousePos();
while (!_activeMenuItem._activeNow && (cursorPos.y <= 21) && _vm->_holdLeftMouse) {
_menuBar.chooseMenuItem(cursorPos.x);
do {
_vm->updateEvents();
} while (_vm->_holdLeftMouse && !_vm->shouldQuit());
while (!_vm->shouldQuit()) {
do {
_vm->updateEvents();
// We update the cursor's picture.
cursorPos = _vm->getMousePos();
// Change arrow...
if ((0 <= cursorPos.y) && (cursorPos.y <= 21))
_vm->_graphics->loadMouse(kCurUpArrow); // Up arrow
else if ((22 <= cursorPos.y) && (cursorPos.y <= 339)) {
if ((cursorPos.x >= _activeMenuItem._flx1 * 8) && (cursorPos.x <= _activeMenuItem._flx2 * 8) && (cursorPos.y <= _activeMenuItem._fly * 2 + 1))
_vm->_graphics->loadMouse(kCurRightArrow); // Right-arrow
else
_vm->_graphics->loadMouse(kCurFletch); // Fletch
} else if ((340 <= cursorPos.y) && (cursorPos.y <= 399))
_vm->_graphics->loadMouse(kCurScrewDriver); // Screwdriver
_activeMenuItem.lightUp(cursorPos);
_vm->_graphics->refreshScreen();
} while (!_vm->_holdLeftMouse && !_vm->shouldQuit());
if (_vm->_holdLeftMouse) {
if (cursorPos.y > 21) {
if (!((_activeMenuItem._firstlix) && ((cursorPos.x >= _activeMenuItem._flx1 * 8) && (cursorPos.x <= _activeMenuItem._flx2 * 8)
&& (cursorPos.y >= 24) && (cursorPos.y <= (_activeMenuItem._fly * 2 + 1))))) {
// Clicked OUTSIDE the menu.
if (_activeMenuItem._activeNow) {
_activeMenuItem.wipe();
_vm->_holdLeftMouse = false;
_vm->_graphics->removeBackup();
return;
} // No "else"- clicking on menu has no effect (only releasing).
}
} else {
// Clicked on menu bar.
if (_activeMenuItem._activeNow) {
_activeMenuItem.wipe();
_vm->_graphics->restoreScreen();
if (((_activeMenuItem._left * 8) <= cursorPos.x) && (cursorPos.x <= (_activeMenuItem._left * 8 + 80))) { // 80: the width of one menu item on the bar in pixels.
// If we clicked on the same menu item (the one that is already active) on the bar...
_vm->_holdLeftMouse = false;
_vm->_graphics->removeBackup();
return;
} else {
_vm->_holdLeftMouse = true;
break;
}
}
}
// NOT clicked button...
if ((_activeMenuItem._firstlix) && ((cursorPos.x >= _activeMenuItem._flx1 * 8) && (cursorPos.x <= _activeMenuItem._flx2 * 8)
&& (cursorPos.y >= 12) && (cursorPos.y <= (_activeMenuItem._fly * 2 + 1)))) {
// We act only if the button is released over a menu item.
while (!_vm->shouldQuit()) {
cursorPos = _vm->getMousePos();
_activeMenuItem.lightUp(cursorPos);
_vm->_graphics->refreshScreen();
_vm->updateEvents();
if (!_vm->_holdLeftMouse)
break;
}
uint16 which = (cursorPos.y - 26) / 20;
_activeMenuItem.select(which);
if (_activeMenuItem._options[which]._valid) { // If the menu item wasn't active, we do nothing.
_vm->_graphics->removeBackup();
return;
}
}
}
}
}
_vm->_graphics->removeBackup();
}
char DropDownMenu::getThingChar(byte which) {
static const char thingsChar[] = "WMBParCLguKeSnIohn"; // V=Vinegar
char result;
switch (which) {
case kObjectWine:
if (_vm->_wineState == 3)
result = 'V'; // Vinegar
else
result = thingsChar[which - 1];
break;
default:
result = thingsChar[which - 1];
}
return result;
}
byte DropDownMenu::getNameChar(People whose) {
static const char ladChar[] = "ASCDMTRwLfgeIyPu";
static const char lassChar[] = "kG\xB1o";
if (whose <= kPeopleJacques)
return ladChar[whose - kPeopleAvalot];
else if ((whose >= kPeopleArkata) && (whose <= kPeopleWisewoman))
return lassChar[whose - kPeopleArkata];
else
error("getName() - Unexpected character id %d", (byte) whose);
}
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",
"Bell", "Scroll", "Pen", "Ink", "Clothes", "Habit", "Onion"
};
Common::String result;
switch (which) {
case kObjectWine:
switch (_vm->_wineState) {
case 1:
case 4:
result = Common::String(things[which - 1]);
break;
case 3:
result = "Vinegar";
break;
default:
break;
}
break;
case kObjectOnion:
if (_vm->_rottenOnion) {
result = Common::String("rotten onion");
} else {
result = Common::String(things[which - 1]);
}
break;
default:
result = Common::String(things[which - 1]);
break;
}
return result;
}
bool DropDownMenu::isActive() {
return _menuActive;
}
void DropDownMenu::init() {
_menuActive = false;
}
void DropDownMenu::resetVariables() {
_lastPerson = kPeoplePardon;
}
} // End of namespace Avalanche.

View File

@@ -0,0 +1,181 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: DROPDOWN A customized version of Oopmenu (qv). */
#ifndef AVALANCHE_DROPDOWN_H
#define AVALANCHE_DROPDOWN_H
#include "common/str.h"
namespace Avalanche {
class AvalancheEngine;
class DropDownMenu;
typedef void (DropDownMenu::*MenuFunc)();
static const Color kMenuBackgroundColor = kColorLightgray;
static const Color kMenuBorderColor = kColorBlack;
class HeadType {
public:
Common::String _title;
char _trigger, _altTrigger;
byte _position;
int16 _xpos, _xright;
MenuFunc _setupFunc, _chooseFunc;
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:
DropDownMenu *_dropdown;
};
struct OptionType {
Common::String _title;
byte _trigger;
Common::String _shortcut;
bool _valid;
};
class MenuItem {
public:
OptionType _options[12];
uint16 _width, _left;
bool _firstlix;
int16 _flx1, _flx2, _fly;
bool _activeNow; // Is there an active option now?
byte _activeNum; // And if so, which is it?
byte _choiceNum; // Your choice?
void init(DropDownMenu *menu);
void reset();
void setupOption(Common::String title, char trigger, Common::String shortcut, bool valid);
void display();
void wipe();
void lightUp(Common::Point cursorPos);
void select(byte which);
private:
byte _oldY; // used by lightUp
byte _optionNum;
byte _highlightNum;
DropDownMenu *_dropdown;
void displayOption(byte y, bool highlit);
void moveHighlight(int8 inc);
// CHECKME: Useless function?
void parseKey(char c);
};
class MenuBar {
public:
HeadType _menuItems[8];
byte _menuNum;
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:
DropDownMenu *_dropdown;
void setupMenuItem(byte which);
// CHECKME: Useless function
void parseAltTrigger(char c);
};
class DropDownMenu {
public:
friend class HeadType;
friend class MenuItem;
friend class MenuBar;
MenuItem _activeMenuItem;
MenuBar _menuBar;
DropDownMenu(AvalancheEngine *vm);
void update();
void setup(); // Standard menu bar.
bool isActive();
void init();
void resetVariables();
private:
static const byte kIndent = 5;
static const byte kSpacing = 10;
// Checkme: Useless constants?
// static const Color kMenuFontColor = kColorBlack;
// static const Color kHighlightBackgroundColor = kColorBlack;
// static const Color kHighlightFontColor = kColorWhite;
// static const Color kDisabledColor = kColorDarkgray;
Common::String people;
Common::String _verbStr; // what you can do with your object. :-)
bool _menuActive; // Kludge so we don't have to keep referring to the menu.
People _lastPerson; // Last person to have been selected using the People menu.
AvalancheEngine *_vm;
Common::String selectGender(byte x); // Returns "im" for boys, and "er" for girls.
void findWhatYouCanDoWithIt();
void drawMenuText(int16 x, int16 y, char trigger, Common::String text, bool valid, bool highlighted);
void bleep();
char getThingChar(byte which);
byte getNameChar(People whose);
Common::String getThing(byte which);
void setupMenuGame();
void setupMenuFile();
void setupMenuAction();
void setupMenuPeople();
void setupMenuObjects();
void setupMenuWith();
void runMenuGame();
void runMenuFile();
void runMenuAction();
void runMenuObjects();
void runMenuPeople();
void runMenuWith();
// CHECKME: Useless function?
void parseKey(char r, char re);
};
} // End of namespace Avalanche.
#endif // AVALANCHE_DROPDOWN_H

136
engines/avalanche/enums.h Normal file
View File

@@ -0,0 +1,136 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_ENUMS_H
#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,
kColorLightgreen = 10, kColorLightcyan, kColorLightred, kColorLightmagenta, kColorYellow,
kColorWhite = 15
};
// CHECKME: kRoomBossKey is a guess
enum Room {
kRoomNowhere = 0, kRoomYours = 1, kRoomOutsideYours = 2, kRoomOutsideSpludwicks = 3,
kRoomYourHall = 5, kRoomMusicRoom = 7, kRoomOutsideArgentPub = 9, kRoomArgentRoad = 10,
kRoomWiseWomans = 11, kRoomSpludwicks = 12, kRoomInsideAbbey = 13, kRoomOutsideAbbey = 14,
kRoomAvvysGarden = 15, kRoomAylesOffice = 16, kRoomArgentPub = 19, kRoomBrummieRoad = 20,
kRoomBridge = 21, kRoomLusties = 22, kRoomLustiesRoom = 23, kRoomWestHall = 25,
kRoomEastHall = 26, kRoomOubliette = 27, kRoomGeidas = 28, kRoomCatacombs = 29,
kRoomEntranceHall = 40, kRoomRobins = 42, kRoomOutsideNottsPub = 46, kRoomNottsPub = 47,
kRoomOutsideDucks = 50, kRoomDucks = 51, kRoomOutsideCardiffCastle = 70, kRoomInsideCardiffCastle = 71,
kRoomBossKey = 98, kRoomMap = 99, kRoomDummy = 177 // Dummy room
};
// Objects you can hold:
enum Object {
kObjectWine = 1, kObjectMoney, kObjectBodkin, kObjectPotion, kObjectChastity,
kObjectBolt, kObjectCrossbow, kObjectLute, kObjectBadge, kObjectMushroom,
kObjectKey, kObjectBell, kObjectPrescription, kObjectPen, kObjectInk,
kObjectClothes, kObjectHabit, kObjectOnion, kObjectDummy = 177
};
// People who hang around this game.
enum People {
// Boys:
kPeopleAvalot = 150, kPeopleSpludwick = 151, kPeopleCrapulus = 152, kPeopleDrDuck = 153,
kPeopleMalagauche = 154, kPeopleFriarTuck = 155, kPeopleRobinHood = 156, kPeopleCwytalot = 157,
kPeopleDuLustie = 158, kPeopleDuke = 159, kPeopleDogfood = 160, kPeopleTrader = 161,
kPeopleIbythneth = 162, kPeopleAyles = 163, kPeoplePort = 164, kPeopleSpurge = 165,
kPeopleJacques = 166,
// Girls:
kPeopleArkata = 175, kPeopleGeida = 176, kPeopleInvisible = 177, kPeopleWisewoman = 178,
//
kPeoplePardon = 254, kPeopleNone = 0
};
enum VerbCode {
kVerbCodeExam = 1, kVerbCodeOpen = 2, kVerbCodePause = 3, kVerbCodeGet = 4, kVerbCodeDrop = 5,
kVerbCodeInv = 6, kVerbCodeTalk = 7, kVerbCodeGive = 8, kVerbCodeDrink = 9, kVerbCodeLoad = 10,
kVerbCodeSave = 11, kVerbCodePay = 12, kVerbCodeLook = 13, kVerbCodeBreak = 14, kVerbCodeQuit = 15,
kVerbCodeSit = 16, kVerbCodeStand = 17, kVerbCodeGo = 18, kVerbCodeInfo = 19, kVerbCodeUndress = 20,
kVerbCodeWear = 21, kVerbCodePlay = 22, kVerbCodeRing = 23, kVerbCodeHelp = 24, kVerbCodeLarrypass = 25,
kVerbCodePhaon = 26, kVerbCodeBoss = 27, kVerbCodePee = 28, kVerbCodeCheat = 29, kVerbCodeMagic = 30,
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,
kVerbCodeSmartAlec = 249, kVerbCodeExpletive = 253, kVerbCodePardon = 254
};
enum MouseCursor {
kCurUpArrow = 0, kCurScrewDriver = 1, kCurRightArrow = 2, kCurFletch = 3, kCurWait = 4, kCurHand = 5,
kCurCrosshair = 6, kCurIBeam = 7, kCurHelp = 8
};
// Magic/portal constants:
enum Magics {
kMagicNothing, // Ignore it if this line is touched.
kMagicBounce, // Bounce off this line. Not valid for portals.
kMagicExclaim, // Put up a chain of scrolls.
kMagicTransport, // Enter new room.
kMagicUnfinished, // Unfinished connection.
kMagicSpecial, // Special function.
kMagicOpenDoor // Opening door.
};
// Constants to replace the command characters from Pascal.
// For more information, see: https://github.com/marnanel/avalot/wiki/Scrolldrivers
enum ControlCharacter {
kControlSpeechBubble = 2, // ^B
kControlCenter = 3, // ^C
kControlToBuffer = 4, // ^D
kControlItalic = 6, // ^F
kControlBell = 7, // ^G
kControlBackspace = 8, // ^H
kControlInsertSpaces = 9, // ^I
kControlLeftJustified = 12, // ^L
kControlNewLine = 13, // ^M
kControlParagraph = 16, // ^P
kControlQuestion = 17, // ^Q
kControlRoman = 18, // ^R
kControlRegister = 19, // ^S
kControlNegative = 21, // ^U
kControlIcon = 22 // ^V
};
static const int16 kScreenWidth = 640;
static const int16 kScreenHeight = 200;
static const int16 kWalk = 3;
static const int16 kRun = 5;
} // End of namespace Avalanche
#endif // AVALANCHE_ENUMS_H

View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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"
#include "common/system.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 (batImage && (_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

View File

@@ -0,0 +1,87 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,210 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_GRAPHICS_H
#define AVALANCHE_GRAPHICS_H
#include "avalanche/enums.h"
#include "common/file.h"
#include "common/rect.h"
#include "graphics/surface.h"
namespace Avalanche {
class AvalancheEngine;
class AnimationType;
struct SpriteType;
struct ChunkBlock;
typedef byte FontType[256][16];
typedef byte ManiType[2049];
typedef byte SilType[51][11]; // 35, 4
struct MouseHotspotType {
int16 _horizontal, _vertical;
};
class GraphicManager {
public:
static const MouseHotspotType kMouseHotSpots[9];
Color _talkBackgroundColor, _talkFontColor;
GraphicManager(AvalancheEngine *vm);
~GraphicManager();
void init();
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);
void drawNormalText(const Common::String &text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
void drawScrollText(const Common::String &text, FontType font, byte fontHeight, int16 x, int16 y, Color color);
void drawDigit(int index, int x, int y);
void drawDirection(int index, int x, int y);
void drawScrollShadow(int16 x1, int16 y1, int16 x2, int16 y2);
void drawShadowBox(int16 x1, int16 y1, int16 x2, int16 y2, Common::String text);
void drawScroll(int mx, int lx, int my, int ly);
void drawMenuBar(Color color);
void drawSpeedBar(int speed);
void drawBackgroundSprite(int16 x, int16 y, SpriteType &sprite);
void drawMenuBlock(int x1, int y1, int x2, int y2, Color color);
void drawMenuItem(int x1, int y1, int x2, int y2);
void wipeChar(int x, int y, Color color);
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);
// Further information about this: https://moddingwiki.shikadi.net/wiki/Raw_EGA_data
Graphics::Surface loadPictureRaw(Common::File &file, uint16 width, uint16 height);
void drawSprite(AnimationType *sprite, byte picnum, int16 x, int16 y);
void drawThinkPic(const Common::Path &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);
void prepareBubble(int xc, int xw, int my, Common::Point points[3]);
void refreshScreen();
void loadBackground(Common::File &file);
void refreshBackground();
void setBackgroundColor(Color newColor);
void setDialogColor(Color bg, Color text);
void zoomOut(int16 x, int16 y);
void showScroll();
void getNaturalPicture(SpriteType &sprite);
void saveScreen();
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;
Graphics::Surface _digits[10]; // digitsize and rwlitesize are defined in loadDigits() !!!
Graphics::Surface _directions[9]; // Maybe it will be needed to move them to the class itself instead.
Graphics::Surface _magics; // Lucerna::draw_also_lines() draws the "magical" lines here. Further information: https://github.com/marnanel/avalot/wiki/Also
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: https://moddingwiki.shikadi.net/wiki/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.)
Common::Point drawArc(Graphics::Surface &surface, int16 x, int16 y, int16 stAngle, int16 endAngle, uint16 radius, Color color);
};
} // End of namespace Avalanche
#endif // AVALANCHE_GRAPHICS_H

269
engines/avalanche/help.cpp Normal file
View File

@@ -0,0 +1,269 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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;
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;
index = -1;
// 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;
_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

64
engines/avalanche/help.h Normal file
View File

@@ -0,0 +1,64 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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

View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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"
#include "common/system.h"
namespace Avalanche {
HighScore::HighScore(AvalancheEngine *vm) {
_vm = vm;
for (int i = 0; i < 12; ++i) {
_data[i]._name = "";
_data[i]._rank = "";
_data[i]._score = 0;
}
}
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(nullptr, 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, nullptr);
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

View File

@@ -0,0 +1,58 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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

View File

@@ -0,0 +1,117 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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"
#include "common/system.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

View File

@@ -0,0 +1,54 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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

View File

@@ -0,0 +1,195 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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 "common/system.h"
#include "common/savefile.h"
#include "engines/advancedDetector.h"
#include "graphics/thumbnail.h"
#include "avalanche/detection.h"
namespace Avalanche {
uint32 AvalancheEngine::getFeatures() const {
return _gameDescription->desc.flags;
}
const char *AvalancheEngine::getGameId() const {
return _gameDescription->desc.gameId;
}
Common::Platform AvalancheEngine::getPlatform() const {
return _gameDescription->desc.platform;
}
} // End of namespace Avalanche
namespace Avalanche {
class AvalancheMetaEngine : public AdvancedMetaEngine<AvalancheGameDescription> {
public:
const char *getName() const override {
return "avalanche";
}
Common::Error createInstance(OSystem *syst, Engine **engine, const AvalancheGameDescription *gd) const override;
bool hasFeature(MetaEngineFeature f) const override;
int getMaximumSaveSlot() const override { return 99; }
SaveStateList listSaves(const char *target) const override;
bool removeSaveState(const char *target, int slot) const override;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
};
Common::Error AvalancheMetaEngine::createInstance(OSystem *syst, Engine **engine, const AvalancheGameDescription *gd) const {
*engine = new AvalancheEngine(syst,gd);
return Common::kNoError;
}
bool AvalancheMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
(f == kSupportsDeleteSave) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSimpleSavesNames);
}
SaveStateList AvalancheMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern = target;
pattern.toUppercase();
pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
for (const auto &filename : filenames) {
int slotNum = atoi(filename.c_str() + filename.size() - 3);
if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
Common::InSaveFile *file = saveFileMan->openForLoading(filename);
if (file) {
// Check for our signature.
uint32 signature = file->readUint32LE();
if (signature != MKTAG('A', 'V', 'A', 'L')) {
warning("Savegame of incompatible type!");
delete file;
continue;
}
// Check version.
byte saveVersion = file->readByte();
if (saveVersion > kSavegameVersion) {
warning("Savegame of incompatible version!");
delete file;
continue;
}
// Read name.
uint32 nameSize = file->readUint32LE();
if (nameSize >= 255) {
delete file;
continue;
}
char *name = new char[nameSize + 1];
file->read(name, nameSize);
name[nameSize] = 0;
saveList.push_back(SaveStateDescriptor(this, slotNum, name));
delete[] name;
delete file;
}
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
bool AvalancheMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
SaveStateDescriptor AvalancheMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
if (f) {
// Check for our signature.
uint32 signature = f->readUint32LE();
if (signature != MKTAG('A', 'V', 'A', 'L')) {
warning("Savegame of incompatible type!");
delete f;
return SaveStateDescriptor();
}
// Check version.
byte saveVersion = f->readByte();
if (saveVersion > kSavegameVersion) {
warning("Savegame of a too recent version!");
delete f;
return SaveStateDescriptor();
}
// Read the description.
uint32 descSize = f->readUint32LE();
Common::String description;
for (uint32 i = 0; i < descSize; i++) {
char actChar = f->readByte();
description += actChar;
}
SaveStateDescriptor desc(this, slot, description);
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*f, thumbnail)) {
warning("Cannot read thumbnail data, possibly broken savegame");
delete f;
return SaveStateDescriptor();
}
desc.setThumbnail(thumbnail);
delete f;
return desc;
}
return SaveStateDescriptor();
}
} // End of namespace Avalanche
#if PLUGIN_ENABLED_DYNAMIC(AVALANCHE)
REGISTER_PLUGIN_DYNAMIC(AVALANCHE, PLUGIN_TYPE_ENGINE, Avalanche::AvalancheMetaEngine);
#else
REGISTER_PLUGIN_STATIC(AVALANCHE, PLUGIN_TYPE_ENGINE, Avalanche::AvalancheMetaEngine);
#endif

View File

@@ -0,0 +1,35 @@
MODULE := engines/avalanche
MODULE_OBJS = \
animation.o \
avalanche.o \
avalot.o \
background.o \
closing.o \
console.o \
graphics.o \
dropdown.o \
parser.o \
dialogs.o \
sequence.o \
sound.o \
timer.o \
metaengine.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
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

574
engines/avalanche/nim.cpp Normal file
View File

@@ -0,0 +1,574 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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"
#include "common/system.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] = false;
_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_END:
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_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] = { { 1, 2 }, { 0, 2 }, { 0, 1 } };
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

78
engines/avalanche/nim.h Normal file
View File

@@ -0,0 +1,78 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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

2526
engines/avalanche/parser.cpp Normal file

File diff suppressed because it is too large Load Diff

148
engines/avalanche/parser.h Normal file
View File

@@ -0,0 +1,148 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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_PARSER_H
#define AVALANCHE_PARSER_H
#include "avalanche/enums.h"
#include "common/events.h"
#include "common/str.h"
#include "common/serializer.h"
namespace Avalanche {
class AvalancheEngine;
class Parser {
public:
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.)
struct VocabEntry {
byte _number;
Common::String _word;
void init(byte number, Common::String word) {
_number = number;
_word = word;
}
};
VocabEntry _vocabulary[kParserWordsNum];
Common::String _realWords[11];
VerbCode _verb;
byte _thing;
People _person;
bool _polite;
Common::String _inputText;
Common::String _inputTextBackup;
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();
void handleFunctionKey(const Common::Event &event);
void plotText();
void cursorOn();
void cursorOff();
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);
private:
AvalancheEngine *_vm;
struct RankType {
uint16 _score;
char _title[20];
};
static const char *kCopyright;
static const char *kVersionNum;
Common::String _thats;
byte _thing2;
byte _sworeNum; // number of times you've sworn
byte _alcoholLevel; // Your blood alcohol level.
bool _boughtOnion; // Have you bought an onion yet?
byte wordNum(Common::String word);
void replace(Common::String oldChars, byte newChar);
Common::String totalTime();
void clearWords();
void cheatParse(Common::String codes);
void stripPunctuation(Common::String &word);
void displayWhat(byte target, bool animate, bool &ambiguous);
bool doPronouns();
void properNouns();
void lookAround();
void openDoor();
void storeInterrogation(byte interrogation);
void examineObject();
bool isPersonHere();
void exampers();
bool isHolding();
void openBox(bool isOpening);
void examine();
void inventory();
void swallow();
void peopleInRoom();
void putProc();
void notInOrder();
void goToCauldron();
bool giveToSpludwick();
void cardiffClimbing();
void already();
void standUp();
void getProc(char thing);
void giveGeidaTheLute();
void playHarp();
void winSequence();
void wipeText();
void bossKey();
};
} // End of namespace Avalanche
#endif // AVALANCHE_PARSER_H

View File

@@ -0,0 +1,231 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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.
*/
/* SEQUENCE The sequencer. */
#include "avalanche/avalanche.h"
#include "avalanche/sequence.h"
namespace Avalanche {
Sequence::Sequence(AvalancheEngine *vm) {
_vm = vm;
resetVariables();
}
void Sequence::resetVariables() {
_flipToWhere = kRoomNowhere;
_flipToPed = 0;
}
void Sequence::init(byte what) {
_seq[0] = what;
for (int i = 1; i < kSeqLength; i++)
_seq[i] = 0;
}
void Sequence::add(byte what) {
for (int16 i = 0; i < kSeqLength; i++) {
if (_seq[i] == 0) {
_seq[i] = what;
return;
}
}
}
void Sequence::switchRoom(Room where, byte ped) {
add(kNowFlip);
_flipToWhere = where;
_flipToPed = ped;
}
void Sequence::startTimer() {
_vm->_timer->loseTimer(Timer::kReasonSequencer);
_vm->_timer->addTimer(7, Timer::kProcSequence, Timer::kReasonSequencer);
}
void Sequence::startTimerImmobilized() {
// They can't move.
_vm->_userMovesAvvy = false;
// And they're not moving now.
_vm->_animation->stopWalking();
// Apart from that, it's the same thing.
startTimer();
}
void Sequence::shoveLeft() {
for (uint i = 0; i < kSeqLength - 1; i++)
_seq[i] = _seq[i + 1];
_seq[kSeqLength - 1] = 0;
}
void Sequence::callSequencer() {
byte curSeq = _seq[0];
switch (curSeq) {
case 0:
// No more routines.
return;
break;
case kNowFlip:
// Flip room.
_vm->_userMovesAvvy = true;
_vm->flipRoom(_flipToWhere, _flipToPed);
shoveLeft();
break;
default:
break;
}
if (curSeq <= 176) {
// Show a frame.
_vm->_background->draw(-1, -1, curSeq - 1);
shoveLeft();
}
// Make sure this PROC gets called again.
startTimer();
}
void Sequence::startHallSeq(Room whither, byte ped) {
init(1);
add(2);
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::startOutsideSeq(Room whither, byte ped) {
init(1);
add(2);
add(3);
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::startCardiffSeq(Room whither, byte ped) {
init(1);
add(5);
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::startNaughtyDukeSeq() {
init(2);
startTimer();
}
void Sequence::startGardenSeq() {
init(2);
add(1);
add(3);
startTimer();
}
void Sequence::startDuckSeq() {
init(3);
add(2);
add(1);
add(4);
startTimer();
}
void Sequence::startLustiesSeq3(Room whither, byte ped) {
init(4);
add(5);
add(6);
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::startMusicRoomSeq2(Room whither, byte ped) {
init(5);
add(6);
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::startGeidaLuteSeq() {
init(5);
// He falls asleep...
add(6);
// Not really closing, but we're using the same procedure.
startTimer();
}
void Sequence::startMusicRoomSeq() {
init(6);
add(5);
add(7);
startTimer();
}
void Sequence::startWinSeq() {
init(7);
add(8);
add(9);
startTimer();
}
void Sequence::startCupboardSeq() {
init(8);
add(7);
startTimer();
}
void Sequence::startLustiesSeq2(Room whither, byte ped) {
init(8);
add(9);
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::startCardiffSeq2() {
init(1);
if (_vm->_arrowInTheDoor)
add(3);
else
add(2);
if (_vm->_takenPen)
_vm->_background->draw(-1, -1, 3);
startTimer();
}
void Sequence::startDummySeq(Room whither, byte ped) {
switchRoom(whither, ped);
startTimerImmobilized();
}
void Sequence::synchronize(Common::Serializer &sz) {
sz.syncBytes(_seq, kSeqLength);
sz.syncAsByte(_flipToWhere);
sz.syncAsByte(_flipToPed);
}
} // End of namespace Avalanche.

View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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.
*/
/* SEQUENCE The sequencer. */
#ifndef AVALANCHE_SEQUENCE_H
#define AVALANCHE_SEQUENCE_H
namespace Avalanche {
class AvalancheEngine;
class Sequence {
private:
static const int16 kNowFlip = 177;
static const int16 kSeqLength = 10;
byte _seq[kSeqLength];
Room _flipToWhere;
byte _flipToPed;
AvalancheEngine *_vm;
void shoveLeft(); // This is called by Timer when it's time to do another frame. It shifts everything to the left.
void init(byte what);
void add(byte what);
void switchRoom(Room where, byte ped);
void startTimer();
void startTimerImmobilized();
public:
Sequence(AvalancheEngine *vm);
void synchronize(Common::Serializer &sz);
void resetVariables();
void callSequencer();
void startCupboardSeq();
void startMusicRoomSeq();
void startMusicRoomSeq2(Room whither, byte ped);
void startGardenSeq();
void startGeidaLuteSeq();
void startWinSeq();
void startNaughtyDukeSeq();
void startLustiesSeq2(Room whither, byte ped);
void startLustiesSeq3(Room whither, byte ped);
void startHallSeq(Room whither, byte ped);
void startCardiffSeq(Room whither, byte ped);
void startOutsideSeq(Room whither, byte ped);
void startDuckSeq();
void startCardiffSeq2();
void startDummySeq(Room whither, byte ped);
};
} // End of namespace Avalanche.
#endif // AVALANCHE_SEQUENCE_H

View File

@@ -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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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"
#include "common/system.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

View File

@@ -0,0 +1,133 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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

View File

@@ -0,0 +1,87 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "avalanche/avalanche.h"
#include "avalanche/sound.h"
#include "audio/softsynth/pcspk.h"
#include "common/config-manager.h"
namespace Avalanche {
SoundHandler::SoundHandler(AvalancheEngine *vm) : _vm(vm) {
_soundFl = true;
_speaker = new Audio::PCSpeaker();
_speaker->init();
}
SoundHandler::~SoundHandler() {
delete _speaker;
}
/**
* Stop any sound that might be playing
*/
void SoundHandler::stopSound() {
_vm->_mixer->stopAll();
}
/**
* Turn digitized sound on and off
*/
void SoundHandler::toggleSound() {
_soundFl = !_soundFl;
_vm->_graphics->drawSoundLight(_soundFl);
}
void SoundHandler::syncVolume() {
int soundVolume;
if (ConfMan.getBool("sfx_mute") || ConfMan.getBool("mute"))
soundVolume = -1;
else
soundVolume = MIN(255, ConfMan.getInt("sfx_volume"));
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolume);
}
void SoundHandler::playNote(int freq, int length) {
// Does the user not want any sound?
if (!_soundFl || !_vm->_mixer->isReady())
return;
// Start a note playing (we will stop it when the timer expires).
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, freq, length);
}
void SoundHandler::click() {
_vm->_mixer->stopAll();
playNote(7177, 1);
}
void SoundHandler::blip() {
_vm->_mixer->stopAll();
playNote(177, 77);
}
} // End of namespace Avalanche

54
engines/avalanche/sound.h Normal file
View File

@@ -0,0 +1,54 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AVALANCHE_SOUND_H
#define AVALANCHE_SOUND_H
#include "audio/mixer.h"
namespace Audio {
class PCSpeaker;
}
namespace Avalanche {
class SoundHandler {
public:
bool _soundFl;
SoundHandler(AvalancheEngine *vm);
~SoundHandler();
void toggleSound();
void playNote(int freq, int length);
void click();
void blip();
void syncVolume();
void stopSound();
private:
AvalancheEngine *_vm;
Audio::PCSpeaker *_speaker;
};
} // End of namespace Avalanche
#endif // AVALANCHE_SOUND_H

713
engines/avalanche/timer.cpp Normal file
View File

@@ -0,0 +1,713 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: TIMEOUT The scheduling unit. */
#include "avalanche/avalanche.h"
#include "avalanche/timer.h"
namespace Avalanche {
Timer::Timer(AvalancheEngine *vm) {
_vm = vm;
resetVariables();
}
/**
* Add a nex timer
* @remarks Originally called 'set_up_timer'
*/
void Timer::addTimer(int32 duration, byte action, byte reason) {
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;
}
/**
* Update the timers
* @remarks Originally called 'one_tick'
*/
void Timer::updateTimer() {
if (_vm->_dropdown->isActive())
return;
for (int i = 0; i < 7; i++) {
if (_times[i]._timeLeft <= 0)
continue;
_times[i]._timeLeft--;
if (_times[i]._timeLeft == 0) {
switch (_times[i]._action) {
case kProcOpenDrawbridge :
openDrawbridge();
break;
case kProcAvariciusTalks :
avariciusTalks();
break;
case kProcUrinate :
urinate();
break;
case kProcToilet :
toilet();
break;
case kProcBang:
bang();
break;
case kProcBang2:
bang2();
break;
case kProcStairs:
stairs();
break;
case kProcCardiffSurvey:
cardiffSurvey();
break;
case kProcCardiffReturn:
cardiffReturn();
break;
case kProcCwytalotInHerts:
cwytalotInHerts();
break;
case kProcGetTiedUp:
getTiedUp();
break;
case kProcGetTiedUp2:
getTiedUp2();
break;
case kProcHangAround:
hangAround();
break;
case kProcHangAround2:
hangAround2();
break;
case kProcAfterTheShootemup:
afterTheShootemup();
break;
case kProcJacquesWakesUp:
jacquesWakesUp();
break;
case kProcNaughtyDuke:
naughtyDuke();
break;
case kProcNaughtyDuke2:
naughtyDuke2();
break;
case kProcNaughtyDuke3:
naughtyDuke3();
break;
case kProcJump:
jump();
break;
case kProcSequence:
_vm->_sequence->callSequencer();
break;
case kProcCrapulusSpludOut:
crapulusSaysSpludOut();
break;
case kProcDawnDelay:
_vm->fadeIn();
break;
case kProcBuyDrinks:
buyDrinks();
break;
case kProcBuyWine:
buyWine();
break;
case kProcCallsGuards:
callsGuards();
break;
case kProcGreetsMonk:
greetsMonk();
break;
case kProcFallDownOubliette:
fallDownOubliette();
break;
case kProcMeetAvaroid:
meetAvaroid();
break;
case kProcRiseUpOubliette:
riseUpOubliette();
break;
case kProcRobinHoodAndGeida:
robinHoodAndGeida();
break;
case kProcRobinHoodAndGeidaTalk:
robinHoodAndGeidaTalk();
break;
case kProcAvalotReturns:
avalotReturns();
break;
case kProcAvvySitDown:
avvySitDown();
break;
case kProcGhostRoomPhew:
ghostRoomPhew();
break;
case kProcArkataShouts:
arkataShouts();
break;
case kProcWinning:
winning();
break;
case kProcAvalotFalls:
avalotFalls();
break;
case kProcSpludwickGoesToCauldron:
spludwickGoesToCauldron();
break;
case kProcSpludwickLeavesCauldron:
spludwickLeavesCauldron();
break;
case kProcGiveLuteToGeida:
giveLuteToGeida();
break;
default:
break;
}
}
}
_vm->_roomCycles++; // Cycles since you've been in this room.
}
void Timer::loseTimer(byte which) {
for (int i = 0; i < 7; i++) {
if (_times[i]._reason == which)
_times[i]._timeLeft = 0; // Cancel this one!
}
}
void Timer::openDrawbridge() {
_vm->_drawbridgeOpen++;
_vm->_background->draw(-1, -1, _vm->_drawbridgeOpen - 2);
if (_vm->_drawbridgeOpen == 4)
_vm->_magics[1]._operation = kMagicNothing; // You may enter the drawbridge.
else
addTimer(7, kProcOpenDrawbridge, kReasonDrawbridgeFalls);
}
void Timer::avariciusTalks() {
_vm->_dialogs->displayScrollChain('Q', _vm->_avariciusTalk);
_vm->_avariciusTalk++;
if (_vm->_avariciusTalk < 17)
addTimer(177, kProcAvariciusTalks, kReasonAvariciusTalks);
else
_vm->incScore(3);
}
void Timer::urinate() {
_vm->_animation->_sprites[0]->turn(kDirUp);
_vm->_animation->stopWalking();
_vm->drawDirection();
addTimer(14, kProcToilet, kReasonGoToToilet);
}
void Timer::toilet() {
_vm->_dialogs->displayText("That's better!");
}
void Timer::bang() {
Common::String tmpStr = Common::String::format("%c< BANG! >", kControlItalic);
_vm->_dialogs->displayText(tmpStr);
addTimer(30, kProcBang2, kReasonExplosion);
}
void Timer::bang2() {
_vm->_dialogs->displayText("Hmm... sounds like Spludwick's up to something...");
}
void Timer::stairs() {
_vm->_sound->blip();
_vm->_animation->_sprites[0]->walkTo(3);
_vm->_background->draw(-1, -1, 1);
_vm->_brummieStairs = 2;
_vm->_magics[10]._operation = kMagicSpecial;
_vm->_magics[10]._data = 2; // Reached the bottom of the stairs.
_vm->_magics[3]._operation = kMagicNothing; // Stop them hitting the sides (or the game will hang.)
}
void Timer::cardiffSurvey() {
if (_vm->_cardiffQuestionNum == 0) {
_vm->_cardiffQuestionNum++;
_vm->_dialogs->displayScrollChain('Q', 27);
}
_vm->_dialogs->displayScrollChain('Z', _vm->_cardiffQuestionNum);
_vm->_interrogation = _vm->_cardiffQuestionNum;
addTimer(182, kProcCardiffSurvey, kReasonCardiffsurvey);
}
void Timer::cardiffReturn() {
_vm->_dialogs->displayScrollChain('Q', 28);
cardiffSurvey(); // Add end of question.
}
void Timer::cwytalotInHerts() {
_vm->_dialogs->displayScrollChain('Q', 29);
}
void Timer::getTiedUp() {
_vm->_dialogs->displayScrollChain('Q', 34); // ...Trouble!
_vm->_userMovesAvvy = false;
_vm->_beenTiedUp = true;
_vm->_animation->stopWalking();
AnimationType *spr = _vm->_animation->_sprites[1];
spr->stopWalk();
spr->stopHoming();
spr->_callEachStepFl = true;
spr->_eachStepProc = Animation::kProcGrabAvvy;
addTimer(70, kProcGetTiedUp2, kReasonGettingTiedUp);
}
void Timer::getTiedUp2() {
_vm->_animation->_sprites[0]->walkTo(3);
_vm->_animation->_sprites[1]->walkTo(4);
_vm->_magics[3]._operation = kMagicNothing; // No effect when you touch the boundaries.
_vm->_friarWillTieYouUp = true;
}
void Timer::hangAround() {
_vm->_animation->_sprites[1]->_doCheck = false;
AnimationType *avvy = _vm->_animation->_sprites[0];
avvy->init(7, true); // Robin Hood
_vm->setRoom(kPeopleRobinHood, kRoomRobins);
_vm->_animation->appearPed(0, 1);
_vm->_dialogs->displayScrollChain('Q', 39);
avvy->walkTo(6);
addTimer(55, kProcHangAround2, kReasonHangingAround);
}
void Timer::hangAround2() {
_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->_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).
_vm->_tiedUp = false;
// 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() {
_vm->flipRoom(_vm->_room, 1);
_vm->_animation->_sprites[0]->init(0, true); // Avalot.
_vm->_animation->appearPed(0, 1);
_vm->_userMovesAvvy = true;
_vm->_objects[kObjectCrossbow - 1] = true;
_vm->refreshObjectList();
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) {
_vm->_dialogs->displayText("But we won't let you have more than 20 points!");
_vm->incScore(20);
} else
_vm->incScore(gain);
_vm->_dialogs->displayScrollChain('Q', 70);
}
void Timer::jacquesWakesUp() {
_vm->_jacquesState++;
switch (_vm->_jacquesState) { // Additional pictures.
case 1:
_vm->_background->draw(-1, -1, 0); // Eyes open.
_vm->_dialogs->displayScrollChain('Q', 45);
break;
case 2: // Going through the door.
_vm->_background->draw(-1, -1, 1); // Not on the floor.
_vm->_background->draw(-1, -1, 2); // But going through the door.
_vm->_magics[5]._operation = kMagicNothing; // You can't wake him up now.
break;
case 3: // Gone through the door.
_vm->_background->draw(-1, -1, 1); // Not on the floor, either.
_vm->_background->draw(-1, -1, 3); // He's gone... so the door's open.
_vm->setRoom(kPeopleJacques, kRoomNowhere); // Gone!
break;
default:
break;
}
if (_vm->_jacquesState == 5) {
_vm->_bellsAreRinging = true;
_vm->_aylesIsAwake = true;
_vm->incScore(2);
}
switch (_vm->_jacquesState) {
case 1:
case 2:
case 3:
addTimer(12, kProcJacquesWakesUp, kReasonJacquesWakingUp);
break;
case 4:
addTimer(24, kProcJacquesWakesUp, kReasonJacquesWakingUp);
break;
default:
break;
}
}
void Timer::naughtyDuke() { // This is when the Duke comes in and takes your money.
AnimationType *spr = _vm->_animation->_sprites[1];
spr->init(9, false); // Here comes the Duke.
_vm->_animation->appearPed(1, 0); // He starts at the door...
spr->walkTo(2); // He walks over to you.
// Let's get the door opening.
_vm->_background->draw(-1, -1, 0);
_vm->_sequence->startNaughtyDukeSeq();
addTimer(50, kProcNaughtyDuke2, kReasonNaughtyDuke);
}
void Timer::naughtyDuke2() {
AnimationType *spr = _vm->_animation->_sprites[1];
_vm->_dialogs->displayScrollChain('Q', 48); // "Ha ha, it worked again!"
spr->walkTo(0); // Walk to the door.
spr->_vanishIfStill = true; // Then go away!
addTimer(32, kProcNaughtyDuke3, kReasonNaughtyDuke);
}
void Timer::naughtyDuke3() {
_vm->_background->draw(-1, -1, 0);
_vm->_sequence->startNaughtyDukeSeq();
}
void Timer::jump() {
AnimationType *avvy = _vm->_animation->_sprites[0];
_vm->_jumpStatus++;
switch (_vm->_jumpStatus) {
case 1:
case 2:
case 3:
case 5:
case 7:
case 9:
avvy->_y--;
break;
case 12:
case 13:
case 14:
case 16:
case 18:
case 19:
avvy->_y++;
break;
default:
break;
}
if (_vm->_jumpStatus == 20) { // End of jump.
_vm->_userMovesAvvy = true;
_vm->_jumpStatus = 0;
} else // Still jumping.
addTimer(1, kProcJump, kReasonJumping);
if ((_vm->_jumpStatus == 10) // You're at the highest point of your jump.
&& (_vm->_room == kRoomInsideCardiffCastle)
&& (_vm->_arrowInTheDoor == true)
&& (_vm->_animation->inField(2))) { // Beside the wall
// Grab the arrow!
if (_vm->_carryNum >= kCarryLimit)
_vm->_dialogs->displayText("You fail to grab it, because your hands are full.");
else {
_vm->_background->draw(-1, -1, 1);
_vm->_arrowInTheDoor = false; // You've got it.
_vm->_objects[kObjectBolt - 1] = true;
_vm->refreshObjectList();
_vm->_dialogs->displayScrollChain('Q', 50);
_vm->incScore(3);
}
}
}
void Timer::crapulusSaysSpludOut() {
_vm->_dialogs->displayScrollChain('Q', 56);
_vm->_crapulusWillTell = false;
}
void Timer::buyDrinks() {
_vm->_background->draw(-1, -1, 10); // Malagauche gets up again.
_vm->_malagauche = 0;
_vm->_dialogs->displayScrollChain('D', _vm->_drinking); // Display message about it.
_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.
_vm->_parser->drink();
}
void Timer::buyWine() {
_vm->_background->draw(-1, -1, 10); // Malagauche gets up again.
_vm->_malagauche = 0;
_vm->_dialogs->displayScrollChain('D', 50); // You buy the wine.
_vm->_dialogs->displayScrollChain('D', 1); // It'll be thruppence.
if (_vm->decreaseMoney(3)) {
_vm->_dialogs->displayScrollChain('D', 4); // You paid up.
_vm->_objects[kObjectWine - 1] = true;
_vm->refreshObjectList();
_vm->_wineState = 1; // OK Wine.
}
}
void Timer::callsGuards() {
_vm->_dialogs->displayScrollChain('Q', 58); // "GUARDS!!!"
_vm->gameOver();
}
void Timer::greetsMonk() {
_vm->_dialogs->displayScrollChain('Q', 59);
_vm->_enteredLustiesRoomAsMonk = true;
}
void Timer::fallDownOubliette() {
_vm->_magics[8]._operation = kMagicNothing;
AnimationType *avvy = _vm->_animation->_sprites[0];
avvy->_moveY++; // Increments dx/dy!
avvy->_y += avvy->_moveY; // Dowwwn we go...
addTimer(3, kProcFallDownOubliette, kReasonFallingDownOubliette);
}
void Timer::meetAvaroid() {
if (_vm->_metAvaroid) {
Common::String tmpStr = Common::String::format("You can't expect to be %cthat%c lucky twice in a row!",
kControlItalic, kControlRoman);
_vm->_dialogs->displayText(tmpStr);
_vm->gameOver();
} else {
_vm->_dialogs->displayScrollChain('Q', 60);
_vm->_metAvaroid = true;
addTimer(1, kProcRiseUpOubliette, kReasonRisingUpOubliette);
AnimationType *avvy = _vm->_animation->_sprites[0];
avvy->_facingDir = kDirLeft;
avvy->_x = 151;
avvy->_moveX = -3;
avvy->_moveY = -5;
_vm->_graphics->setBackgroundColor(kColorGreen);
}
}
void Timer::riseUpOubliette() {
AnimationType *avvy = _vm->_animation->_sprites[0];
avvy->_visible = true;
avvy->_moveY++; // Decrements dx/dy!
avvy->_y -= avvy->_moveY; // Uuuupppp we go...
if (avvy->_moveY > 0)
addTimer(3, kProcRiseUpOubliette, kReasonRisingUpOubliette);
else
_vm->_userMovesAvvy = true;
}
void Timer::robinHoodAndGeida() {
AnimationType *avvy = _vm->_animation->_sprites[0];
avvy->init(7, true);
_vm->_animation->appearPed(0, 6);
avvy->walkTo(5);
AnimationType *spr = _vm->_animation->_sprites[1];
spr->stopWalk();
spr->_facingDir = kDirLeft;
addTimer(20, kProcRobinHoodAndGeidaTalk, kReasonRobinHoodAndGeida);
_vm->_geidaFollows = false;
}
void Timer::robinHoodAndGeidaTalk() {
_vm->_dialogs->displayScrollChain('Q', 66);
AnimationType *avvy = _vm->_animation->_sprites[0];
AnimationType *spr = _vm->_animation->_sprites[1];
avvy->walkTo(1);
spr->walkTo(1);
avvy->_vanishIfStill = true;
spr->_vanishIfStill = true;
addTimer(162, kProcAvalotReturns, kReasonRobinHoodAndGeida);
}
void Timer::avalotReturns() {
AnimationType *avvy = _vm->_animation->_sprites[0];
AnimationType *spr = _vm->_animation->_sprites[1];
avvy->remove();
spr->remove();
avvy->init(0, true);
_vm->_animation->appearPed(0, 0);
_vm->_dialogs->displayScrollChain('Q', 67);
_vm->_userMovesAvvy = true;
}
/**
* This is used when you sit down in the pub in Notts. It loops around
* so that it will happen when Avvy stops walking.
* @remarks Originally called 'avvy_sit_down'
*/
void Timer::avvySitDown() {
AnimationType *avvy = _vm->_animation->_sprites[0];
if (avvy->_homing) // Still walking.
addTimer(1, kProcAvvySitDown, kReasonSittingDown);
else {
_vm->_background->draw(-1, -1, 2);
_vm->_sittingInPub = true;
_vm->_userMovesAvvy = false;
avvy->_visible = false;
}
}
void Timer::ghostRoomPhew() {
Common::String tmpStr = Common::String::format("%cPHEW!%c You're glad to get out of %cthere!",
kControlItalic, kControlRoman, kControlItalic);
_vm->_dialogs->displayText(tmpStr);
}
void Timer::arkataShouts() {
if (_vm->_teetotal)
return;
_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);
// 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;
}
}
}
_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 ");
_vm->_letMeOut = true;
}
void Timer::avalotFalls() {
AnimationType *avvy = _vm->_animation->_sprites[0];
if (avvy->_stepNum < 5) {
avvy->_stepNum++;
addTimer(3, kProcAvalotFalls, kReasonFallingOver);
} else {
Common::String toDisplay = Common::String::format("%c%c%c%c%c%c%c%c%c%c%c%c%cZ%c",
kControlNewLine, kControlNewLine, kControlNewLine, kControlNewLine,
kControlNewLine, kControlNewLine, kControlInsertSpaces, kControlInsertSpaces,
kControlInsertSpaces, kControlInsertSpaces, kControlInsertSpaces,
kControlInsertSpaces, kControlRegister, kControlIcon);
_vm->_dialogs->displayText(toDisplay);
}
}
void Timer::spludwickGoesToCauldron() {
if (_vm->_animation->_sprites[1]->_homing)
addTimer(1, kProcSpludwickGoesToCauldron, kReasonSpludwickWalk);
else
addTimer(17, kProcSpludwickLeavesCauldron, kReasonSpludwickWalk);
}
void Timer::spludwickLeavesCauldron() {
_vm->_animation->_sprites[1]->_callEachStepFl = true; // So that normal procs will continue.
}
void Timer::giveLuteToGeida() { // Moved here from Acci.
_vm->_dialogs->displayScrollChain('Q', 86);
_vm->incScore(4);
_vm->_lustieIsAsleep = true;
_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.

177
engines/avalanche/timer.h Normal file
View File

@@ -0,0 +1,177 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
/*
* 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: TIMEOUT The scheduling unit. */
#ifndef AVALANCHE_TIMER_H
#define AVALANCHE_TIMER_H
namespace Avalanche {
class AvalancheEngine;
class Timer {
public:
// Reason runs between 1 and 28.
enum Reason {
kReasonDrawbridgeFalls = 2,
kReasonAvariciusTalks = 3,
kReasonGoToToilet = 4,
kReasonExplosion = 5,
kReasonBrummieStairs = 6,
kReasonCardiffsurvey = 7,
kReasonCwytalotInHerts = 8,
kReasonGettingTiedUp = 9,
kReasonHangingAround = 10, // Tied to the tree in Nottingham.
kReasonJacquesWakingUp = 11,
kReasonNaughtyDuke = 12,
kReasonJumping = 13,
kReasonSequencer = 14,
kReasonCrapulusSaysSpludwickOut = 15,
kReasonDawndelay = 16,
kReasonDrinks = 17,
kReasonDuLustieTalks = 18,
kReasonFallingDownOubliette = 19,
kReasonMeetingAvaroid = 20,
kReasonRisingUpOubliette = 21,
kReasonRobinHoodAndGeida = 22,
kReasonSittingDown = 23,
kReasonGhostRoomPhew = 1,
kReasonArkataShouts = 24,
kReasonWinning = 25,
kReasonFallingOver = 26,
kReasonSpludwickWalk = 27,
kReasonGeidaSings = 28
};
// Proc runs between 1 and 41.
enum Proc {
kProcOpenDrawbridge = 3,
kProcAvariciusTalks = 4,
kProcUrinate = 5,
kProcToilet = 6,
kProcBang = 7,
kProcBang2 = 8,
kProcStairs = 9,
kProcCardiffSurvey = 10,
kProcCardiffReturn = 11,
kProcCwytalotInHerts = 12,
kProcGetTiedUp = 13,
kProcGetTiedUp2 = 1,
kProcHangAround = 14,
kProcHangAround2 = 15,
kProcAfterTheShootemup = 32,
kProcJacquesWakesUp = 16,
kProcNaughtyDuke = 17,
kProcNaughtyDuke2 = 18,
kProcNaughtyDuke3 = 38,
kProcJump = 19,
kProcSequence = 20,
kProcCrapulusSpludOut = 21,
kProcDawnDelay = 22,
kProcBuyDrinks = 23,
kProcBuyWine = 24,
kProcCallsGuards = 25,
kProcGreetsMonk = 26,
kProcFallDownOubliette = 27,
kProcMeetAvaroid = 28,
kProcRiseUpOubliette = 29,
kProcRobinHoodAndGeida = 2,
kProcRobinHoodAndGeidaTalk = 30,
kProcAvalotReturns = 31,
kProcAvvySitDown = 33, // In Nottingham.
kProcGhostRoomPhew = 34,
kProcArkataShouts = 35,
kProcWinning = 36,
kProcAvalotFalls = 37,
kProcSpludwickGoesToCauldron = 39,
kProcSpludwickLeavesCauldron = 40,
kProcGiveLuteToGeida = 41
};
struct TimerType {
int32 _timeLeft;
byte _action;
byte _reason;
};
TimerType _times[7];
Timer(AvalancheEngine *vm);
void resetVariables();
void addTimer(int32 duration, byte action, byte reason);
void updateTimer();
void loseTimer(byte which);
// Procedures to do things at the end of amounts of time:
void openDrawbridge();
void avariciusTalks();
void urinate();
void toilet();
void bang();
void bang2();
void stairs();
void cardiffSurvey();
void cardiffReturn();
void cwytalotInHerts();
void getTiedUp();
void getTiedUp2();
void hangAround();
void hangAround2();
void afterTheShootemup();
void jacquesWakesUp();
void naughtyDuke();
void naughtyDuke2();
void naughtyDuke3();
void jump();
void crapulusSaysSpludOut();
void buyDrinks();
void buyWine();
void callsGuards();
void greetsMonk();
void fallDownOubliette();
void meetAvaroid();
void riseUpOubliette();
void robinHoodAndGeida();
void robinHoodAndGeidaTalk();
void avalotReturns();
void avvySitDown();
void ghostRoomPhew();
void arkataShouts();
void winning();
void avalotFalls();
void spludwickGoesToCauldron();
void spludwickLeavesCauldron();
void giveLuteToGeida();
private:
AvalancheEngine *_vm;
byte _shootEmUpScore;
};
} // End of namespace Avalanche.
#endif // AVALANCHE_TIMER_H